X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=lib%2Fconf-input.c;h=b890295d99742025c5fecbe69c89544770d6c86d;hb=88714d18176f047eb4d298bb3f22520217671513;hp=786725bda7b455fb613924dda12a08473049d4a7;hpb=62960fb405a1ec443797e64c8ee34adb01924917;p=libucw.git diff --git a/lib/conf-input.c b/lib/conf-input.c index 786725bd..b890295d 100644 --- a/lib/conf-input.c +++ b/lib/conf-input.c @@ -23,13 +23,13 @@ /* Text file parser */ -static byte *name_parse_fb; +static const char *name_parse_fb; static struct fastbuf *parse_fb; static uns line_num; #define MAX_LINE 4096 -static byte line_buf[MAX_LINE]; -static byte *line = line_buf; +static char line_buf[MAX_LINE]; +static char *line = line_buf; #include "lib/bbuf.h" static bb_t copy_buf; @@ -43,11 +43,14 @@ static uns words; static uns ends_by_brace; // the line is ended by "{" static int -get_line(void) +get_line(char **msg) { - if (!bgets(parse_fb, line_buf, MAX_LINE)) - return 0; + int err = bgets_nodie(parse_fb, line_buf, MAX_LINE); line_num++; + if (err <= 0) { + *msg = err < 0 ? "Line too long" : NULL; + return 0; + } line = line_buf; while (Cblank(*line)) line++; @@ -55,7 +58,7 @@ get_line(void) } static void -append(byte *start, byte *end) +append(char *start, char *end) { uns len = end - start; bb_grow(©_buf, copied + len + 1); @@ -64,24 +67,22 @@ append(byte *start, byte *end) copy_buf.ptr[copied-1] = 0; } -#define CONTROL_CHAR(x) (x == '{' || x == '}' || x == ';') - // these characters separate words like blanks - -static byte * +static char * get_word(uns is_command_name) { + char *msg; if (*line == '\'') { line++; while (1) { - byte *start = line; + char *start = line; while (*line && *line != '\'') line++; append(start, line); if (*line) break; copy_buf.ptr[copied-1] = '\n'; - if (!get_line()) - return "Unterminated apostrophe word at the end"; + if (!get_line(&msg)) + return msg ? : "Unterminated apostrophe word at the end"; } line++; @@ -89,7 +90,7 @@ get_word(uns is_command_name) line++; uns start_copy = copied; while (1) { - byte *start = line; + char *start = line; uns escape = 0; while (*line) { if (*line == '"' && !escape) @@ -107,12 +108,12 @@ get_word(uns is_command_name) copy_buf.ptr[copied-1] = '\n'; else // merge two lines copied -= 2; - if (!get_line()) - return "Unterminated quoted word at the end"; + if (!get_line(&msg)) + return msg ? : "Unterminated quoted word at the end"; } line++; - byte *tmp = stk_str_unesc(copy_buf.ptr + start_copy); + char *tmp = stk_str_unesc(copy_buf.ptr + start_copy); uns l = strlen(tmp); bb_grow(©_buf, start_copy + l + 1); strcpy(copy_buf.ptr + start_copy, tmp); @@ -120,8 +121,9 @@ get_word(uns is_command_name) } else { // promised that *line is non-null and non-blank - byte *start = line; - while (*line && !Cblank(*line) && !CONTROL_CHAR(*line) + char *start = line; + while (*line && !Cblank(*line) + && *line != '{' && *line != '}' && *line != ';' && (*line != '=' || !is_command_name)) line++; if (*line == '=') { // nice for setting from a command-line @@ -138,40 +140,41 @@ get_word(uns is_command_name) return NULL; } -static byte * -get_token(uns is_command_name, byte **msg) +static char * +get_token(uns is_command_name, char **err) { - *msg = NULL; + *err = NULL; while (1) { if (!*line || *line == '#') { - if (!is_command_name || !get_line()) + if (!is_command_name || !get_line(err)) return NULL; } else if (*line == ';') { - *msg = get_word(0); - if (!is_command_name || *msg) + *err = get_word(0); + if (!is_command_name || *err) return NULL; } else if (*line == '\\' && !line[1]) { - if (!get_line()) { - *msg = "Last line ends by a backslash"; + if (!get_line(err)) { + if (!*err) + *err = "Last line ends by a backslash"; return NULL; } if (!*line || *line == '#') - log(L_WARN, "The line %s:%d following a backslash is empty", name_parse_fb, line_num); + msg(L_WARN, "The line %s:%d following a backslash is empty", name_parse_fb ? : "", line_num); } else { split_grow(&word_buf, words+1); uns start = copied; word_buf.ptr[words++] = copied; - *msg = get_word(is_command_name); - return *msg ? NULL : copy_buf.ptr + start; + *err = get_word(is_command_name); + return *err ? NULL : copy_buf.ptr + start; } } } -static byte * +static char * split_command(void) { words = copied = ends_by_brace = 0; - byte *msg, *start_word; + char *msg, *start_word; if (!(start_word = get_token(1, &msg))) return msg; if (*start_word == '{') // only one opening brace @@ -191,10 +194,10 @@ split_command(void) /* Parsing multiple files */ -static byte * -parse_fastbuf(byte *name_fb, struct fastbuf *fb, uns depth) +static char * +parse_fastbuf(const char *name_fb, struct fastbuf *fb, uns depth) { - byte *msg; + char *err; name_parse_fb = name_fb; parse_fb = fb; line_num = 0; @@ -202,41 +205,41 @@ parse_fastbuf(byte *name_fb, struct fastbuf *fb, uns depth) *line = 0; while (1) { - msg = split_command(); - if (msg) + err = split_command(); + if (err) goto error; if (!words) return NULL; - byte *name = copy_buf.ptr + word_buf.ptr[0]; - byte *pars[words-1]; + char *name = copy_buf.ptr + word_buf.ptr[0]; + char *pars[words-1]; for (uns i=1; i 8) - msg = "Too many nested files"; + err = "Too many nested files"; else if (*line && *line != '#') // because the contents of line_buf is not re-entrant and will be cleared - msg = "The input command must be the last one on a line"; - if (msg) + err = "The input command must be the last one on a line"; + if (err) goto error; struct fastbuf *new_fb = bopen_try(pars[0], O_RDONLY, 1<<14); if (!new_fb) { - msg = cf_printf("Cannot open file %s: %m", pars[0]); + err = cf_printf("Cannot open file %s: %m", pars[0]); goto error; } uns ll = line_num; - msg = parse_fastbuf(stk_strdup(pars[0]), new_fb, depth+1); + err = parse_fastbuf(stk_strdup(pars[0]), new_fb, depth+1); line_num = ll; bclose(new_fb); - if (msg) + if (err) goto error; parse_fb = fb; continue; } enum cf_operation op; - byte *c = strchr(name, ':'); + char *c = strchr(name, ':'); if (!c) op = strcmp(name, "}") ? OP_SET : OP_CLOSE; else { @@ -244,7 +247,11 @@ parse_fastbuf(byte *name_fb, struct fastbuf *fb, uns depth) switch (Clocase(*c)) { case 's': op = OP_SET; break; case 'c': op = Clocase(c[1]) == 'l' ? OP_CLEAR: OP_COPY; break; - case 'a': op = Clocase(c[1]) == 'p' ? OP_APPEND : OP_AFTER; break; + case 'a': switch (Clocase(c[1])) { + case 'p': op = OP_APPEND; break; + case 'f': op = OP_AFTER; break; + default: op = OP_ALL; + }; break; case 'p': op = OP_PREPEND; break; case 'r': op = OP_REMOVE; break; case 'e': op = OP_EDIT; break; @@ -252,25 +259,35 @@ parse_fastbuf(byte *name_fb, struct fastbuf *fb, uns depth) default: op = OP_SET; break; } if (strcasecmp(c, cf_op_names[op])) { - msg = cf_printf("Unknown operation %s", c); + err = cf_printf("Unknown operation %s", c); goto error; } } if (ends_by_brace) op |= OP_OPEN; - msg = cf_interpret_line(name, op, words-1, pars); - if (msg) + err = cf_interpret_line(name, op, words-1, pars); + if (err) goto error; } error: - log(L_ERROR, "File %s, line %d: %s", name_fb, line_num, msg); + if (name_fb) + msg(L_ERROR, "File %s, line %d: %s", name_fb, line_num, err); + else if (line_num == 1) + msg(L_ERROR, "Manual setting of configuration: %s", err); + else + msg(L_ERROR, "Manual setting of configuration, line %d: %s", line_num, err); return "included from here"; } #ifndef DEFAULT_CONFIG #define DEFAULT_CONFIG NULL #endif -byte *cf_def_file = DEFAULT_CONFIG; +char *cf_def_file = DEFAULT_CONFIG; + +#ifndef ENV_VAR_CONFIG +#define ENV_VAR_CONFIG NULL +#endif +char *cf_env_file = ENV_VAR_CONFIG; static uns postpone_commit; // only for cf_getopt() static uns everything_committed; // after the 1st load, this flag is set on @@ -288,36 +305,36 @@ done_stack(void) } static int -load_file(byte *file) +load_file(const char *file) { cf_init_stack(); struct fastbuf *fb = bopen_try(file, O_RDONLY, 1<<14); if (!fb) { - log(L_ERROR, "Cannot open %s: %m", file); + msg(L_ERROR, "Cannot open %s: %m", file); return 1; } - byte *msg = parse_fastbuf(file, fb, 0); + char *err_msg = parse_fastbuf(file, fb, 0); bclose(fb); - int err = !!msg || done_stack(); + int err = !!err_msg || done_stack(); if (!err) cf_def_file = NULL; return err; } static int -load_string(byte *string) +load_string(const char *string) { cf_init_stack(); struct fastbuf fb; - fbbuf_init_read(&fb, string, strlen(string), 0); - byte *msg = parse_fastbuf("memory string", &fb, 0); + fbbuf_init_read(&fb, (byte *)string, strlen(string), 0); + char *msg = parse_fastbuf(NULL, &fb, 0); return !!msg || done_stack(); } /* Safe loading and reloading */ int -cf_reload(byte *file) +cf_reload(const char *file) { cf_journal_swap(); struct cf_journal_item *oldj = cf_journal_new_transaction(1); @@ -339,7 +356,7 @@ cf_reload(byte *file) } int -cf_load(byte *file) +cf_load(const char *file) { struct cf_journal_item *oldj = cf_journal_new_transaction(1); int err = load_file(file); @@ -351,7 +368,7 @@ cf_load(byte *file) } int -cf_set(byte *string) +cf_set(const char *string) { struct cf_journal_item *oldj = cf_journal_new_transaction(0); int err = load_string(string); @@ -368,8 +385,16 @@ static void load_default(void) { if (cf_def_file) - if (cf_load(cf_def_file)) - die("Cannot load default config %s", cf_def_file); + { + char *env; + if (cf_env_file && (env = getenv(cf_env_file))) + { + if (cf_load(env)) + die("Cannot load config file %s", env); + } + else if (cf_load(cf_def_file)) + die("Cannot load default config %s", cf_def_file); + } } static void