cfparser: %include directive
authorMarko Kreen <markokr@gmail.com>
Sat, 3 May 2014 10:06:21 +0000 (13:06 +0300)
committerMarko Kreen <markokr@gmail.com>
Sat, 3 May 2014 10:16:08 +0000 (13:16 +0300)
This includes body of other file into current one.

Based on patch by Andrew Dunstan.

usual/cfparser.c

index b216d9a566678e58a1c965012e7cf8649981ad27..7e5e4c7c3447b5bbda5690ff45f7a3d29f415b18 100644 (file)
@@ -29,6 +29,8 @@
 #include <usual/logging.h>
 #include <usual/time.h>
 
+#define MAX_INCLUDE 10
+
 /*
  * INI file parser.
  */
@@ -43,7 +45,7 @@ static int count_lines(const char *s, const char *end)
        return lineno;
 }
 
-bool parse_ini_file(const char *fn, cf_handler_f user_handler, void *arg)
+static bool parse_ini_file_internal(const char *fn, cf_handler_f user_handler, void *arg, int inclevel)
 {
        char *buf;
        char *p, *key, *val;
@@ -60,6 +62,38 @@ bool parse_ini_file(const char *fn, cf_handler_f user_handler, void *arg)
                /* space at the start of line - including empty lines */
                while (*p && isspace(*p)) p++;
 
+               if (strncmp(p, "%include", 8) == 0 && p[8] != 0 && isblank(p[8])) {
+                       if (inclevel >= MAX_INCLUDE) {
+                               log_error("include nesting level too deep (%s:%d), stopping loading",
+                                         fn, count_lines(buf, p));
+                               goto failed;
+                       }
+                       p += 8;
+                       while (*p && isblank(*p)) p++;
+                       /* now read value */
+                       val = p;
+                       while (*p && (*p != '\n'))
+                               p++;
+                       vlen = p - val;
+                       /* eat space at end */
+                       while (vlen > 0 && isspace(val[vlen - 1]))
+                               vlen--;
+
+                       /*
+                        * val now has the name of the file to be included.
+                        * Process it recursively.
+                        */
+                       o1 = val[vlen];
+                       val[vlen] = 0;
+                       log_debug("processing include: %s", val);
+                       ok = parse_ini_file_internal(val, user_handler, arg, inclevel + 1);
+                       val[vlen] = o1;
+                       if (!ok)
+                               goto failed;
+                       log_debug("returned to processing file %s", fn);
+                       continue;
+               }
+
                /* skip comment lines */
                if (*p == '#' || *p == ';') {
                        while (*p && *p != '\n') p++;
@@ -141,6 +175,11 @@ failed:
        return false;
 }
 
+bool parse_ini_file(const char *fn, cf_handler_f user_handler, void *arg)
+{
+       return parse_ini_file_internal(fn, user_handler, arg, 0);
+}
+
 /*
  * Config framework.
  */