<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/11084">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  Harald Welte: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Add new osmo-config-merge utility<br><br>This utility allows you to merge an incremental config "patch"<br>into an osmocom-style config file.<br><br>The patch file follows the same syntax as the original config file.<br><br>It works by appending the leaf nodes of the patch file to the respective<br>nodes of the input config file.<br><br>This process allows configuration file changes/updates to be performed<br>in a more stable/reliable way than by means of [unified] diff files,<br>as they break every time the context lines break.<br><br>osmo-config-merge doesn't suffer from this problem, as it understands<br>the tree-like nature of VTY config files.<br><br>NITE: This only works with configuration files that have proper<br>indenting, i.e. every level in the hierarchy must be indented excatly<br>one character, not multiple.<br><br>Change-Id: I61997a3668cc3a40d12ca023272f6d782e6fbefe<br>---<br>M .gitignore<br>M debian/control<br>M debian/libosmocore-utils.install<br>M utils/Makefile.am<br>A utils/osmo-config-merge.c<br>5 files changed, 275 insertions(+), 2 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/.gitignore b/.gitignore</span><br><span>index 369277c..451c883 100644</span><br><span>--- a/.gitignore</span><br><span>+++ b/.gitignore</span><br><span>@@ -67,6 +67,7 @@</span><br><span> </span><br><span> utils/osmo-arfcn</span><br><span> utils/osmo-auc-gen</span><br><span style="color: hsl(120, 100%, 40%);">+utils/osmo-config-merge</span><br><span> utils/osmo-sim-test</span><br><span> </span><br><span> doc/codec</span><br><span>diff --git a/debian/control b/debian/control</span><br><span>index 540a8b5..33ae2d4 100644</span><br><span>--- a/debian/control</span><br><span>+++ b/debian/control</span><br><span>@@ -315,7 +315,8 @@</span><br><span> Description: Utilities for gsm</span><br><span>  This package contains a program for frequency calculation for GSM called</span><br><span>  'osmo-arfcn' and a program called 'osmo-auc-gen' that is used for testing GSM</span><br><span style="color: hsl(0, 100%, 40%);">- authentication.</span><br><span style="color: hsl(120, 100%, 40%);">+ authentication, as well as 'osmo-config-merge', a tool for merging Osmocom</span><br><span style="color: hsl(120, 100%, 40%);">+ configuration files.</span><br><span>  .</span><br><span>  They use the libosmocore library. The libosmocore library contain various</span><br><span>  utility functions that were originally developed as part of the OpenBSC</span><br><span>diff --git a/debian/libosmocore-utils.install b/debian/libosmocore-utils.install</span><br><span>index 9c3b8dc..d23cc73 100644</span><br><span>--- a/debian/libosmocore-utils.install</span><br><span>+++ b/debian/libosmocore-utils.install</span><br><span>@@ -1,2 +1,3 @@</span><br><span> usr/bin/osmo-arfcn</span><br><span> usr/bin/osmo-auc-gen</span><br><span style="color: hsl(120, 100%, 40%);">+usr/bin/osmo-config-merge</span><br><span>diff --git a/utils/Makefile.am b/utils/Makefile.am</span><br><span>index d4999bd..fb79190 100644</span><br><span>--- a/utils/Makefile.am</span><br><span>+++ b/utils/Makefile.am</span><br><span>@@ -5,12 +5,16 @@</span><br><span> </span><br><span> EXTRA_DIST = conv_gen.py conv_codes_gsm.py</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-bin_PROGRAMS = osmo-arfcn osmo-auc-gen</span><br><span style="color: hsl(120, 100%, 40%);">+bin_PROGRAMS = osmo-arfcn osmo-auc-gen osmo-config-merge</span><br><span> </span><br><span> osmo_arfcn_SOURCES = osmo-arfcn.c</span><br><span> </span><br><span> osmo_auc_gen_SOURCES = osmo-auc-gen.c</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+osmo_config_merge_SOURCES = osmo-config-merge.c</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_config_merge_LDADD = $(LDADD) $(TALLOC_LIBS)</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_config_merge_CFLAGS = $(TALLOC_CFLAGS)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if ENABLE_PCSC</span><br><span> noinst_PROGRAMS = osmo-sim-test</span><br><span> osmo_sim_test_SOURCES = osmo-sim-test.c</span><br><span>diff --git a/utils/osmo-config-merge.c b/utils/osmo-config-merge.c</span><br><span>new file mode 100644</span><br><span>index 0000000..131486c</span><br><span>--- /dev/null</span><br><span>+++ b/utils/osmo-config-merge.c</span><br><span>@@ -0,0 +1,266 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file osmo-config-merge.c</span><br><span style="color: hsl(120, 100%, 40%);">+ * Utility program for merging config files with patches */</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2018 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License along</span><br><span style="color: hsl(120, 100%, 40%);">+ * with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(120, 100%, 40%);">+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+    This utility allows you to merge an incremental config "patch"</span><br><span style="color: hsl(120, 100%, 40%);">+    into an osmocom-style config file.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    The patch file follows the same syntax as the original config file.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    It works by appending the leaf nodes of the patch file to the respective</span><br><span style="color: hsl(120, 100%, 40%);">+    nodes of the input config file.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    This process allows configuration file changes/updates to be performed</span><br><span style="color: hsl(120, 100%, 40%);">+    in a more stable/reliable way than by means of [unified] diff files,</span><br><span style="color: hsl(120, 100%, 40%);">+    as they break every time the context lines break.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo-config-merge doesn't suffer from this problem, as it understands</span><br><span style="color: hsl(120, 100%, 40%);">+    the tree-like nature of VTY config files.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    NITE: This only works with configuration files that have proper</span><br><span style="color: hsl(120, 100%, 40%);">+    indenting, i.e. every level in the hierarchy must be indented excatly</span><br><span style="color: hsl(120, 100%, 40%);">+    one character, not multiple.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct node {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct node *parent;            /* back-pointer */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct llist_head list;         /* part of parent->children */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_head children;     /* our own children */</span><br><span style="color: hsl(120, 100%, 40%);">+        char *line;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* allocate a new node */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct node *node_alloc(void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct node *node = talloc_zero(ctx, struct node);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(node);</span><br><span style="color: hsl(120, 100%, 40%);">+    INIT_LLIST_HEAD(&node->children);</span><br><span style="color: hsl(120, 100%, 40%);">+      return node;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* allocate a new node as child of given parent */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct node *node_alloc_child(struct node *parent)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct node *node = node_alloc(parent);</span><br><span style="color: hsl(120, 100%, 40%);">+       node->parent = parent;</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_add_tail(&node->list, &parent->children);</span><br><span style="color: hsl(120, 100%, 40%);">+ return node;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* find a given child specified by name/line string within given parent */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct node *node_find_child(struct node *parent, const char *line)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct node *n;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(n, &parent->children, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!strcmp(line, n->line))</span><br><span style="color: hsl(120, 100%, 40%);">+                        return n;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* count the number of spaces / indent level */</span><br><span style="color: hsl(120, 100%, 40%);">+static int count_indent(const char *line)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < strlen(line); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (line[i] != ' ')</span><br><span style="color: hsl(120, 100%, 40%);">+                   return i;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return i;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* strip any triling CR / LF */</span><br><span style="color: hsl(120, 100%, 40%);">+static void chomp(char *line)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     while (1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           int len = strlen(line);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (len == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                 return;</span><br><span style="color: hsl(120, 100%, 40%);">+               char *lastch = &line[len-1];</span><br><span style="color: hsl(120, 100%, 40%);">+              switch (*lastch) {</span><br><span style="color: hsl(120, 100%, 40%);">+            case '\n':</span><br><span style="color: hsl(120, 100%, 40%);">+            case '\r':</span><br><span style="color: hsl(120, 100%, 40%);">+                    *lastch = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+               default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      return;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* read a config file and parse it into a tree of nodes */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct node *file_read(void *ctx, const char *fname)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct node *root, *last;</span><br><span style="color: hsl(120, 100%, 40%);">+     FILE *infile;</span><br><span style="color: hsl(120, 100%, 40%);">+ char line[1024];</span><br><span style="color: hsl(120, 100%, 40%);">+      int cur_indent = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned int line_num = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  infile = fopen(fname, "r");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!infile)</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        root = node_alloc(ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+       last = root;</span><br><span style="color: hsl(120, 100%, 40%);">+  while (fgets(line, sizeof(line), infile)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           line_num++;</span><br><span style="color: hsl(120, 100%, 40%);">+           chomp(line);</span><br><span style="color: hsl(120, 100%, 40%);">+          int indent = count_indent(line);</span><br><span style="color: hsl(120, 100%, 40%);">+              struct node *n;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (indent > cur_indent) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (indent > cur_indent+1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               fprintf(stderr, "File '%s' isn't well-formed in line %u, aborting!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                  fname, line_num);</span><br><span style="color: hsl(120, 100%, 40%);">+                             exit(2);</span><br><span style="color: hsl(120, 100%, 40%);">+                      }</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* new child to last node */</span><br><span style="color: hsl(120, 100%, 40%);">+                  n = node_alloc_child(last);</span><br><span style="color: hsl(120, 100%, 40%);">+           } else if (indent < cur_indent) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  for (int i = 0; i < cur_indent - indent; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            /* go to parent, add another sibling */</span><br><span style="color: hsl(120, 100%, 40%);">+                               if (last->parent)</span><br><span style="color: hsl(120, 100%, 40%);">+                                  last = last->parent;</span><br><span style="color: hsl(120, 100%, 40%);">+                       }</span><br><span style="color: hsl(120, 100%, 40%);">+                     n = node_alloc_child(last->parent);</span><br><span style="color: hsl(120, 100%, 40%);">+                } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* add a new sibling (child of parent) */</span><br><span style="color: hsl(120, 100%, 40%);">+                     n = node_alloc_child(last->parent);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             n->line = talloc_strdup(n, line);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                last = n;</span><br><span style="color: hsl(120, 100%, 40%);">+             cur_indent = indent;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return root;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void append_patch(struct node *cfg, struct node *patch)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct node *n;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(n, &patch->children, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (llist_empty(&n->children)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       struct node *t;</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* we are an end-node, i.e. something that needs to be</span><br><span style="color: hsl(120, 100%, 40%);">+                         * patched into the original tree.  We do this by simply</span><br><span style="color: hsl(120, 100%, 40%);">+                       * appending it to the list of siblings */</span><br><span style="color: hsl(120, 100%, 40%);">+                    t = node_alloc_child(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+                    t->line = talloc_strdup(t, n->line);</span><br><span style="color: hsl(120, 100%, 40%);">+            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct node *c;</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* we need to iterate / recurse further */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  /* try to find the matching original node */</span><br><span style="color: hsl(120, 100%, 40%);">+                  c = node_find_child(cfg, n->line);</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (!c) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             /* create it, if it's missing */</span><br><span style="color: hsl(120, 100%, 40%);">+                          c = node_alloc_child(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+                            c->line = talloc_strdup(c, n->line);</span><br><span style="color: hsl(120, 100%, 40%);">+                    }</span><br><span style="color: hsl(120, 100%, 40%);">+                     append_patch(c, n);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int level = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void dump_node(struct node *root, FILE *out, bool print_node_depth)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct node *n;</span><br><span style="color: hsl(120, 100%, 40%);">+       level++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (root->line) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (print_node_depth) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       for (int i = 0; i < level; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                            fputc('*', out);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           fprintf(out, "%s\n", root->line);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(n, &root->children, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+               dump_node(n, out, print_node_depth);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     level--;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void exit_usage(int rc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      fprintf(stderr, "Usage: osmo-config-merge <config-file> <config-patch> [--debug]\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   exit(rc);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int main(int argc, char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *base_fname, *patch_fname;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct node *base_tree, *patch_tree;</span><br><span style="color: hsl(120, 100%, 40%);">+  bool debug_enabled = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ void *ctx = talloc_named_const(NULL, 0, "root");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (argc < 3)</span><br><span style="color: hsl(120, 100%, 40%);">+              exit_usage(1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      base_fname = argv[1];</span><br><span style="color: hsl(120, 100%, 40%);">+ patch_fname = argv[2];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (argc > 3) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!strcmp(argv[3], "--debug"))</span><br><span style="color: hsl(120, 100%, 40%);">+                    debug_enabled = true;</span><br><span style="color: hsl(120, 100%, 40%);">+         else</span><br><span style="color: hsl(120, 100%, 40%);">+                  exit_usage(1);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   base_tree = file_read(ctx, base_fname);</span><br><span style="color: hsl(120, 100%, 40%);">+       patch_tree = file_read(ctx, patch_fname);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (debug_enabled) {</span><br><span style="color: hsl(120, 100%, 40%);">+          fprintf(stderr, "====== dumping tree (base)\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            dump_node(base_tree, stderr, true);</span><br><span style="color: hsl(120, 100%, 40%);">+           fprintf(stderr, "====== dumping tree (patch)\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           dump_node(patch_tree, stderr, true);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   append_patch(base_tree, patch_tree);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (debug_enabled)</span><br><span style="color: hsl(120, 100%, 40%);">+            fprintf(stderr, "====== dumping tree (patched)\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ dump_node(base_tree, stdout, false);</span><br><span style="color: hsl(120, 100%, 40%);">+  fflush(stdout);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* make AddressSanitizer / LeakSanitizer happy by recursively freeing the trees */</span><br><span style="color: hsl(120, 100%, 40%);">+    talloc_free(patch_tree);</span><br><span style="color: hsl(120, 100%, 40%);">+      talloc_free(base_tree);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/11084">change 11084</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/11084"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I61997a3668cc3a40d12ca023272f6d782e6fbefe </div>
<div style="display:none"> Gerrit-Change-Number: 11084 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>