diff --git a/src/config.c b/src/config.c index 0714721..6739f77 100644 --- a/src/config.c +++ b/src/config.c @@ -181,7 +181,8 @@ void conf_bar_section(void) { struct conf_sec *bar, **mouse, *selbar, *systray; - char *barbg, sc = screen_count(); + char *barbg; + int sc = screen_count(); bar = fetch_section_first(NULL, "bar"); @@ -230,7 +231,6 @@ conf_bar_section(void) } free(mouse); - free(barbg); return; } diff --git a/src/parse/api.c b/src/parse/api.c index 0284dcd..592dbf4 100644 --- a/src/parse/api.c +++ b/src/parse/api.c @@ -71,45 +71,6 @@ print_unused(struct conf_sec *sec) print_unused(s); } -void -free_conf(struct conf_sec *sec) -{ - struct conf_sec *s; - struct conf_opt *o; - size_t n; - - if (!sec) - { - TAILQ_FOREACH(s, &config, entry) - { - free(s->name); - free_conf(s); - free(s); - } - return; - } - - while (!SLIST_EMPTY(&sec->optlist)) - { - o = SLIST_FIRST(&sec->optlist); - SLIST_REMOVE_HEAD(&sec->optlist, entry); - free(o->name); - - for (n = 0; o->val[n]; n++) - free(o->val[n]); - - free(o); - } - - while (!TAILQ_EMPTY(&sec->sub)) - { - s = TAILQ_FIRST(&sec->sub); - TAILQ_REMOVE(&sec->sub, s, entry); - free_conf(s); - } - -} - struct conf_sec ** fetch_section(struct conf_sec *s, char *name) { diff --git a/src/parse/parse.c b/src/parse/parse.c index 880a5c5..bf1371f 100644 --- a/src/parse/parse.c +++ b/src/parse/parse.c @@ -122,8 +122,12 @@ syntax(struct keyword *kw, const char *fmt, ...) { va_list args; - fprintf(stderr, "%s: %s:%d", __progname, kw->file->name, kw->line); - if (kw->name) + fprintf(stderr, "%s:", __progname); + + if (kw && kw->file && kw->file->name) + fprintf(stderr, "%s:%d", kw->file->name, kw->line); + + if (kw && kw->name) fprintf(stderr, ", near '%s'", kw->name); fprintf(stderr, ": "); @@ -132,8 +136,6 @@ syntax(struct keyword *kw, const char *fmt, ...) va_end(args); fprintf(stderr, "\n"); - - exit(EXIT_FAILURE); } @@ -154,6 +156,7 @@ parse_keywords(const char *filename) char path[PATH_MAX]; size_t i, j; int line; + bool_t error = False; if ((fd = open(filename, O_RDONLY)) == -1 || stat(filename, &st) == -1) { @@ -161,28 +164,27 @@ parse_keywords(const char *filename) return NULL; } - buf = (char *)mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, SEEK_SET); - - if (buf == (char*)MAP_FAILED) { - warn("%s", filename); - return NULL; - } - if (!realpath(filename, path)) { warn("%s", filename); return NULL; } file = xcalloc(1, sizeof(*file)); + bufname = xcalloc(1, sizeof(*bufname) * BUFSIZ); file->name = strdup(path); file->parent = NULL; - bufname = xcalloc(1, sizeof(*bufname) * BUFSIZ); + buf = (char *)mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, SEEK_SET); + + if (buf == (char*)MAP_FAILED) { + warn("%s", filename); + return NULL; + } for(i = 0, j = 0, line = 1; i < (size_t)st.st_size; i++) { - if (tail && !head) + if (!head && tail) head = tail; if (buf[i] == '\n' && s.comment == True) { @@ -199,94 +201,106 @@ parse_keywords(const char *filename) if (s.comment == True) continue; - if (buf[i] == s.quote_char && s.quote == True) { + if (s.quote == True && buf[i] == s.quote_char) { /* end of quotted string */ PUSH_KEYWORD(WORD); s.quote = False; continue; } - if ((buf[i] == '"' || buf[i] == '\'') && - s.quote == False) - { - PUSH_KEYWORD(WORD); - /* begin quotted string */ - s.quote_char = buf[i]; - s.quote = True; - continue; - } - - if (buf[i] == '[' && s.quote == False) { - PUSH_KEYWORD(WORD); - if (buf[i+1] == '/') { - i +=2; - type = SEC_END; - } - else { - i++; - type = SEC_START; + if (s.quote == False) { + if ((buf[i] == '"' || buf[i] == '\'')) { + PUSH_KEYWORD(WORD); + /* begin quotted string */ + s.quote_char = buf[i]; + s.quote = True; + continue; } - /* get section name */ - while (buf[i] != ']') { - - if (i >= ((size_t)st.st_size-1) || j >= (BUFSIZ-1)) { - bufname[j] = '\0'; - syntax(NULL, "word too long in %s:%d near '%s'", - file->name, line, bufname); + if (buf[i] == '[') { + PUSH_KEYWORD(WORD); + if (buf[i+1] == '/') { + i +=2; + type = SEC_END; + } + else { + i++; + type = SEC_START; } - bufname[j++] = buf[i++]; + /* get section name */ + while (buf[i] != ']') { + + if (i >= ((size_t)st.st_size-1) || j >= (BUFSIZ-1)) { + bufname[j] = '\0'; + syntax(NULL, "word too long in %s:%d near '%s'", + file->name, line, bufname); + error = True; + break; + } + + bufname[j++] = buf[i++]; + } + PUSH_KEYWORD(type); + continue; } - PUSH_KEYWORD(type); - continue; - } - if (buf[i] == '{' && s.quote == False) { - PUSH_KEYWORD(WORD); - PUSH_KEYWORD(LIST_START); - continue; - } + if (buf[i] == '{') { + PUSH_KEYWORD(WORD); + PUSH_KEYWORD(LIST_START); + continue; + } - if (buf[i] == '}' && s.quote == False) { - PUSH_KEYWORD(WORD); - PUSH_KEYWORD(LIST_END); - continue; - } + if (buf[i] == '}') { + PUSH_KEYWORD(WORD); + PUSH_KEYWORD(LIST_END); + continue; + } - if (buf[i] == ',' && s.quote == False) { - PUSH_KEYWORD(WORD); - continue; - } + if (buf[i] == ',') { + PUSH_KEYWORD(WORD); + continue; + } - if (buf[i] == '=' && s.quote == False) { - PUSH_KEYWORD(WORD); - PUSH_KEYWORD(EQUAL); - continue; - } + if (buf[i] == '=') { + PUSH_KEYWORD(WORD); + PUSH_KEYWORD(EQUAL); + continue; + } - if (strchr("\t\n ", buf[i]) && s.quote == False) { - PUSH_KEYWORD(WORD); + if (strchr("\t\n ", buf[i])) { + PUSH_KEYWORD(WORD); - if (buf[i] == '\n') - line++; + if (buf[i] == '\n') + line++; - continue; - } + continue; + } + } /* s.quote == False */ if (j >= (BUFSIZ - 1)) { bufname[j] = '\0'; syntax(NULL, "word too long in %s:%d near '%s'", file->name, line, bufname); + error = True; + break; } bufname[j++] = buf[i]; } + munmap(buf, st.st_size); + free(bufname); warnx("%s read", file->name); - return head; + + return (error ? NULL: head); } +/* + * return NULL on failure and head->next if + * no config found (of file doesn't exist) + * NOTE to devs: head->name is the file to include + */ static struct keyword * include(struct keyword *head) { @@ -299,8 +313,10 @@ include(struct keyword *head) head = head->next; - if (!head || head->type != WORD) + if (!head || head->type != WORD) { syntax(head, "missing filename to include"); + return NULL; + } /* replace ~ by user directory */ if (head->name && head->name[0] == '~') { @@ -322,19 +338,29 @@ include(struct keyword *head) if (!(kw = parse_keywords(filename))) { warnx("no config fond in include file %s", head->name); - return head->next; + + if (filename != head->name) + free(filename); + + return NULL; } kw->file->parent = head->file; - head = head->next; /* detect circular include */ - for (file = kw->file->parent; file != NULL; file = file->parent) - { - if (!strcmp(file->name, kw->file->name)) + for (file = kw->file->parent; file != NULL; file = file->parent) { + if (!strcmp(file->name, kw->file->name)) { syntax(kw, "circular include of %s", kw->file->name); + + if (filename != head->name) + free(filename); + + return NULL; + } } + head = head->next; + if (kw) { for (tail = kw; tail->next; tail = tail->next); tail->next = head; @@ -343,6 +369,20 @@ include(struct keyword *head) return kw; } +static void * +free_opt(struct conf_opt *o) +{ + int i; + if (o) { + if (o->name) + free(o->name); + for (i = 0; o->val[i]; i++) + free(o->val[i]); + free(o); + } + return NULL; +} + static struct conf_opt * get_option(struct keyword **head) { @@ -358,18 +398,23 @@ get_option(struct keyword **head) kw = kw->next; - if (kw->type != EQUAL) + if (kw->type != EQUAL) { syntax(kw, "missing '=' here"); + return free_opt(o); + } kw = kw->next; - if (!kw) + if (!kw) { syntax(kw, "missing value"); + return free_opt(o); + } switch (kw->type) { case INCLUDE: - kw = include(kw); + if (!(kw = include(kw))) + return free_opt(o); break; case WORD: o->val[0] = kw->name; @@ -381,27 +426,34 @@ get_option(struct keyword **head) while (kw && kw->type != LIST_END) { switch (kw->type) { case WORD: - if (j > 9) + if (j > (PARSE_MAX_LIST - 1)) { syntax(kw, "too much values in list"); + return free_opt(o); + } o->val[j++] = kw->name; kw = kw->next; break; case INCLUDE: - kw = include(kw); + if (!(kw = include(kw))) + return free_opt(o); break; default: syntax(kw, "declaration into a list"); + return free_opt(o); break; } } - if (!kw) + if (!kw) { syntax(kw, "list unclosed"); + return free_opt(o); + } kw = kw->next; break; default: syntax(kw, "missing value"); + return free_opt(o); break; } @@ -409,6 +461,29 @@ get_option(struct keyword **head) return o; } +static void * +free_sec(struct conf_sec *sec) +{ + struct conf_opt *o; + struct conf_sec *s; + + if (sec) { + while (!SLIST_EMPTY(&sec->optlist)) { + o = SLIST_FIRST(&sec->optlist); + SLIST_REMOVE_HEAD(&sec->optlist, entry); + free_opt(o); + } + while (!TAILQ_EMPTY(&sec->sub)) { + s = TAILQ_FIRST(&sec->sub); + TAILQ_REMOVE(&sec->sub, s, entry); + free_sec(s); + } + free(sec->name); + free(sec); + } + return NULL; +} + static struct conf_sec * get_section(struct keyword **head) { @@ -427,26 +502,32 @@ get_section(struct keyword **head) while (kw && kw->type != SEC_END) { switch (kw->type) { case INCLUDE: - kw = include(kw); + if (!(kw = include(kw))) + return free_sec(s); break; case SEC_START: - sub = get_section(&kw); + if (!(sub = get_section(&kw))) + return free_sec(s); TAILQ_INSERT_TAIL(&s->sub, sub, entry); s->nsub++; break; case WORD: - o = get_option(&kw); + if (!(o = get_option(&kw))) + return free_sec(s); SLIST_INSERT_HEAD(&s->optlist, o, entry); s->nopt++; break; default: syntax(kw, "syntax error"); + return free_sec(s); break; } } - if (!kw || strcmp(kw->name, s->name)) + if (!kw || strcmp(kw->name, s->name)) { syntax(kw, "missing end section %s", s->name); + return free_sec(s); + } kw = kw->next; *head = kw; @@ -454,6 +535,20 @@ get_section(struct keyword **head) return s; } +int +free_conf(void) +{ + struct conf_sec *s; + struct keyword *kw = NULL; + + while (!TAILQ_EMPTY(&config)) { + s = TAILQ_FIRST(&config); + TAILQ_REMOVE(&config, s, entry); + free_sec(s); + } + return -1; +} + int get_conf(const char *filename) { @@ -461,6 +556,7 @@ get_conf(const char *filename) struct keyword *head, *kw; kw = head = parse_keywords(filename); + if (!head) return -1; /* TODO ERREUR */ @@ -469,14 +565,17 @@ get_conf(const char *filename) while (kw) { switch (kw->type) { case INCLUDE: - kw = include(kw); + if (!(kw = include(kw))) + return free_conf(); break; case SEC_START: - s = get_section(&kw); + if (!(s = get_section(&kw))) + return free_conf(); TAILQ_INSERT_TAIL(&config, s, entry); break; default: syntax(kw, "out of any section"); + return free_conf(); break; } } diff --git a/src/parse/parse.h b/src/parse/parse.h index 8b1497e..8a0f9f2 100644 --- a/src/parse/parse.h +++ b/src/parse/parse.h @@ -20,6 +20,7 @@ #include #define INCLUDE_CMD "@include" +#define PARSE_MAX_LIST 10 #if defined(Bool) #define bool_t Bool @@ -29,7 +30,7 @@ typedef enum { False, True } bool_t; struct conf_opt { char *name; - char *val[10]; + char *val[PARSE_MAX_LIST]; size_t nval; bool_t used; int line; @@ -70,7 +71,7 @@ void print_unused(struct conf_sec *s); * WARNING: This make all string * returned by fetch_(opt|section)(_first) unusable. */ -void free_conf(struct conf_sec *s); +int free_conf(void); /* * Get all subsection matching the given name on the given diff --git a/src/wmfs.c b/src/wmfs.c index fc11c6f..d1c666a 100644 --- a/src/wmfs.c +++ b/src/wmfs.c @@ -126,7 +126,7 @@ quit(void) IFREE(conf.client.mouse); IFREE(conf.root.mouse); - free_conf(NULL); + free_conf(); XSync(dpy, False); XCloseDisplay(dpy);