chiark / gitweb /
conf-parser: support continuation lines with trailing backslashes in lines
[elogind.git] / src / conf-parser.c
index 6994211..df3584d 100644 (file)
@@ -32,7 +32,6 @@
 #include "log.h"
 
 #define COMMENTS "#;\n"
-#define LINE_MAX 4096
 
 /* Run the user supplied parser for an assignment */
 static int next_assignment(
@@ -40,6 +39,7 @@ static int next_assignment(
                 unsigned line,
                 const char *section,
                 const ConfigItem *t,
+                bool relaxed,
                 const char *lvalue,
                 const char *rvalue,
                 void *userdata) {
@@ -49,7 +49,7 @@ static int next_assignment(
         assert(lvalue);
         assert(rvalue);
 
-        for (; t->parse; t++) {
+        for (; t->parse || t->lvalue; t++) {
 
                 if (t->lvalue && !streq(lvalue, t->lvalue))
                         continue;
@@ -60,18 +60,21 @@ static int next_assignment(
                 if (t->section && !streq(section, t->section))
                         continue;
 
+                if (!t->parse)
+                        return 0;
+
                 return t->parse(filename, line, section, lvalue, rvalue, t->data, userdata);
         }
 
         /* Warn about unknown non-extension fields. */
-        if (!startswith(lvalue, "X-"))
+        if (!relaxed && !startswith(lvalue, "X-"))
                 log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, strna(section));
 
         return 0;
 }
 
 /* Parse a variable assignment line */
-static int parse_line(const char *filename, unsigned line, char **section, const char* const * sections, const ConfigItem *t, char *l, void *userdata) {
+static int parse_line(const char *filename, unsigned line, char **section, const char* const * sections, const ConfigItem *t, bool relaxed, char *l, void *userdata) {
         char *e;
 
         l = strstrip(l);
@@ -89,7 +92,7 @@ static int parse_line(const char *filename, unsigned line, char **section, const
                 if (!(fn = file_in_same_dir(filename, strstrip(l+9))))
                         return -ENOMEM;
 
-                r = config_parse(fn, NULL, sections, t, userdata);
+                r = config_parse(fn, NULL, sections, t, relaxed, userdata);
                 free(fn);
 
                 return r;
@@ -110,11 +113,8 @@ static int parse_line(const char *filename, unsigned line, char **section, const
                 if (!(n = strndup(l+1, k-2)))
                         return -ENOMEM;
 
-                if (sections && !strv_contains((char**) sections, n)) {
-                        log_error("[%s:%u] Unknown section '%s'.", filename, line, n);
-                        free(n);
-                        return -EBADMSG;
-                }
+                if (!relaxed && sections && !strv_contains((char**) sections, n))
+                        log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n);
 
                 free(*section);
                 *section = n;
@@ -122,6 +122,9 @@ static int parse_line(const char *filename, unsigned line, char **section, const
                 return 0;
         }
 
+        if (sections && !strv_contains((char**) sections, *section))
+                return 0;
+
         if (!(e = strchr(l, '='))) {
                 log_error("[%s:%u] Missing '='.", filename, line);
                 return -EBADMSG;
@@ -130,15 +133,16 @@ static int parse_line(const char *filename, unsigned line, char **section, const
         *e = 0;
         e++;
 
-        return next_assignment(filename, line, *section, t, strstrip(l), strstrip(e), userdata);
+        return next_assignment(filename, line, *section, t, relaxed, strstrip(l), strstrip(e), userdata);
 }
 
 /* Go through the file and parse each line */
-int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, void *userdata) {
+int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, bool relaxed, void *userdata) {
         unsigned line = 0;
         char *section = NULL;
         int r;
         bool ours = false;
+        char *continuation = NULL;
 
         assert(filename);
         assert(t);
@@ -154,7 +158,8 @@ int config_parse(const char *filename, FILE *f, const char* const * sections, co
         }
 
         while (!feof(f)) {
-                char l[LINE_MAX];
+                char l[LINE_MAX], *p, *c = NULL, *e;
+                bool escaped = false;
 
                 if (!fgets(l, sizeof(l), f)) {
                         if (feof(f))
@@ -165,7 +170,44 @@ int config_parse(const char *filename, FILE *f, const char* const * sections, co
                         goto finish;
                 }
 
-                if ((r = parse_line(filename, ++line, &section, sections, t, l, userdata)) < 0)
+                truncate_nl(l);
+
+                if (continuation) {
+                        if (!(c = strappend(continuation, l))) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        free(continuation);
+                        continuation = NULL;
+                        p = c;
+                } else
+                        p = l;
+
+                for (e = p; *e; e++) {
+                        if (escaped)
+                                escaped = false;
+                        else if (*e == '\\')
+                                escaped = true;
+                }
+
+                if (escaped) {
+                        *(e-1) = ' ';
+
+                        if (c)
+                                continuation = c;
+                        else if (!(continuation = strdup(l))) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        continue;
+                }
+
+                r = parse_line(filename, ++line, &section, sections, t, relaxed, p, userdata);
+                free(c);
+
+                if (r < 0)
                         goto finish;
         }
 
@@ -173,6 +215,7 @@ int config_parse(const char *filename, FILE *f, const char* const * sections, co
 
 finish:
         free(section);
+        free(continuation);
 
         if (f && ours)
                 fclose(f);
@@ -337,6 +380,8 @@ int config_parse_path(
         if (!(n = strdup(rvalue)))
                 return -ENOMEM;
 
+        path_kill_slashes(n);
+
         free(*s);
         *s = n;
 
@@ -441,6 +486,8 @@ int config_parse_path_strv(
                         goto fail;
                 }
 
+                path_kill_slashes(n[k]);
+
                 k++;
         }