diff --git a/usr.sbin/config/config.h b/usr.sbin/config/config.h --- a/usr.sbin/config/config.h +++ b/usr.sbin/config/config.h @@ -183,7 +183,7 @@ extern int do_trace; extern int incignore; -char *get_word(FILE *); +char *get_word(FILE *, const char *); char *get_quoted_word(FILE *); char *path(const char *); char *raisestr(char *); diff --git a/usr.sbin/config/configvers.h b/usr.sbin/config/configvers.h --- a/usr.sbin/config/configvers.h +++ b/usr.sbin/config/configvers.h @@ -49,7 +49,7 @@ * * $FreeBSD$ */ -#define CONFIGVERS 600018 +#define CONFIGVERS 600019 #define MAJOR_VERS(x) ((x) / 100000) /* Last config(8) version to require envmode/hintmode */ diff --git a/usr.sbin/config/main.c b/usr.sbin/config/main.c --- a/usr.sbin/config/main.c +++ b/usr.sbin/config/main.c @@ -341,10 +341,10 @@ * pointer to the word otherwise */ char * -get_word(FILE *fp) +get_word(FILE *fp, const char *keywords) { int ch; - int escaped_nl = 0; + bool escaped_nl = false; init_line_buf(); begin: @@ -353,25 +353,25 @@ break; if (ch == EOF) return ((char *)EOF); - if (ch == '\\'){ - escaped_nl = 1; + if (ch == '\\') { + escaped_nl = true; goto begin; } if (ch == '\n') { - if (escaped_nl){ - escaped_nl = 0; + if (escaped_nl) { + escaped_nl = false; goto begin; - } - else + } else return (NULL); } sbuf_putc(line_buf, ch); - /* Negation operator is a word by itself. */ - if (ch == '!') { + + if (keywords != NULL && strchr(keywords, ch) != NULL) return get_line_buf(); - } + while ((ch = getc(fp)) != EOF) { - if (isspace(ch)) + if (isspace(ch) || + (keywords != NULL && strchr(keywords, ch) != NULL)) break; sbuf_putc(line_buf, ch); } diff --git a/usr.sbin/config/mkmakefile.c b/usr.sbin/config/mkmakefile.c --- a/usr.sbin/config/mkmakefile.c +++ b/usr.sbin/config/mkmakefile.c @@ -69,6 +69,8 @@ static void process_into_nvlist(char *line, nvlist_t *nvl); static void dump_nvlist(nvlist_t *nvl, FILE *ofp); +static const char keywords[] = { "!|()" }; + static void errout(const char *fmt, ...) { va_list ap; @@ -384,6 +386,8 @@ moveifchanged(path("env.c.new"), path("env.c")); } +#define MAX_NESTING_LEVEL 8 + static void read_file(char *fname) { @@ -394,8 +398,18 @@ struct opt *op; char *wd, *this, *compilewith, *depends, *clean, *warning; const char *objprefix; - int compile, match, nreqs, std, filetype, not, - imp_rule, no_ctfconvert, no_obj, before_depend, nowerror; + int level; + int filetype; + bool std; + bool no_obj; + bool nowerror; + bool imp_rule; + bool no_ctfconvert; + bool before_depend; + bool compile[MAX_NESTING_LEVEL]; + bool match[MAX_NESTING_LEVEL]; + bool not[MAX_NESTING_LEVEL]; + bool anyreqs[MAX_NESTING_LEVEL]; fp = fopen(fname, "r"); if (fp == NULL) @@ -410,8 +424,12 @@ * [ clean "file-list"] [ warning "text warning" ] * [ obj-prefix "file prefix"] * [ nowerror ] [ local ] + * + * NOTE: When parsing device keywords, space or tab which + * means logical and, has precedence over "|" which means + * logical or. Use parenthesis if needed. */ - wd = get_word(fp); + wd = get_word(fp, NULL); if (wd == (char *)EOF) { (void) fclose(fp); return; @@ -420,7 +438,7 @@ goto next; if (wd[0] == '#') { - while (((wd = get_word(fp)) != (char *)EOF) && wd) + while (((wd = get_word(fp, NULL)) != (char *)EOF) && wd) ; goto next; } @@ -430,60 +448,88 @@ errout("%s: missing include filename.\n", fname); (void) snprintf(ifname, sizeof(ifname), "../../%s", wd); read_file(ifname); - while (((wd = get_word(fp)) != (char *)EOF) && wd) + while (((wd = get_word(fp, NULL)) != (char *)EOF) && wd) ; goto next; } this = ns(wd); - wd = get_word(fp); + wd = get_word(fp, keywords); if (wd == (char *)EOF) return; if (wd == NULL) errout("%s: No type for %s.\n", fname, this); tp = fl_lookup(this); - compile = 0; - match = 1; - nreqs = 0; + level = 0; + /* reset logic state */ + compile[level] = false; + match[level] = true; + not[level] = false; + anyreqs[level] = false; compilewith = NULL; depends = NULL; clean = NULL; warning = NULL; - std = 0; - imp_rule = 0; - no_ctfconvert = 0; - no_obj = 0; - before_depend = 0; - nowerror = 0; - not = 0; + std = false; + imp_rule = false; + no_ctfconvert = false; + no_obj = false; + before_depend = false; + nowerror = false; filetype = NORMAL; objprefix = ""; if (eq(wd, "standard")) - std = 1; + std = true; else if (!eq(wd, "optional")) errout("%s: \"%s\" %s must be optional or standard\n", fname, wd, this); - for (wd = get_word(fp); wd; wd = get_word(fp)) { + for (wd = get_word(fp, keywords); wd; wd = get_word(fp, keywords)) { if (wd == (char *)EOF) return; if (eq(wd, "!")) { - not = 1; + not[level] = true; + continue; + } + if (eq(wd, "(")) { + anyreqs[level] = true; + if (++level == MAX_NESTING_LEVEL) + errout("%s: maximum nesting level reached: %d\n", + fname, level); + /* reset logic state */ + compile[level] = false; + match[level] = true; + not[level] = false; + anyreqs[level] = false; + continue; + } + if (eq(wd, ")")) { + if (anyreqs[level] == false) + errout("%s: syntax error describing %s\n", + fname, this); + if (--level == -1) + errout("%s: unbalanced use of parenthesis\n", + fname); + /* entries are anded together unless "|" is specified */ + match[level] &= + (match[level + 1] | compile[level + 1]) ^ not[level]; + anyreqs[level] = true; + not[level] = false; continue; } if (eq(wd, "|")) { - if (nreqs == 0) + if (anyreqs[level] == false) errout("%s: syntax error describing %s\n", fname, this); - compile += match; - match = 1; - nreqs = 0; + compile[level] |= match[level]; + match[level] = true; + anyreqs[level] = false; continue; } if (eq(wd, "no-ctfconvert")) { - no_ctfconvert++; + no_ctfconvert = true; continue; } if (eq(wd, "no-obj")) { - no_obj++; + no_obj = true; continue; } if (eq(wd, "no-implicit-rule")) { @@ -492,11 +538,11 @@ "\"no-implicit-rule\" is specified for" " %s.\n", fname, this); - imp_rule++; + imp_rule = true; continue; } if (eq(wd, "before-depend")) { - before_depend++; + before_depend = true; continue; } if (eq(wd, "dependency")) { @@ -540,7 +586,7 @@ continue; } if (eq(wd, "nowerror")) { - nowerror = 1; + nowerror = true; continue; } if (eq(wd, "local")) { @@ -551,14 +597,14 @@ filetype = NODEPEND; continue; } - nreqs++; + anyreqs[level] = true; if (std) errout("standard entry %s has optional inclusion specifier %s!\n", this, wd); STAILQ_FOREACH(dp, &dtab, d_next) if (eq(dp->d_name, wd)) { - if (not) - match = 0; + if (not[level]) + match[level] = false; else dp->d_done |= DEVDONE; goto nextparam; @@ -566,17 +612,20 @@ SLIST_FOREACH(op, &opt, op_next) if (op->op_value == 0 && strcasecmp(op->op_name, wd) == 0) { - if (not) - match = 0; + if (not[level]) + match[level] = false; goto nextparam; } - match &= not; + match[level] &= not[level]; nextparam:; - not = 0; + not[level] = 0; } - compile += match; - if (compile && tp == NULL) { - if (std == 0 && nreqs == 0) + if (level != 0) + errout("%s: unbalanced use of parenthesis\n", + fname); + compile[level] |= match[level]; + if (compile[level] && tp == NULL) { + if (std == false && anyreqs[level] == false) errout("%s: what is %s optional on?\n", fname, this); tp = new_fent(); diff --git a/usr.sbin/config/mkoptions.c b/usr.sbin/config/mkoptions.c --- a/usr.sbin/config/mkoptions.c +++ b/usr.sbin/config/mkoptions.c @@ -202,14 +202,14 @@ char *invalue; /* get the #define */ - if ((inw = get_word(inf)) == NULL || inw == (char *)EOF) + if ((inw = get_word(inf, NULL)) == NULL || inw == (char *)EOF) break; /* get the option name */ - if ((inw = get_word(inf)) == NULL || inw == (char *)EOF) + if ((inw = get_word(inf, NULL)) == NULL || inw == (char *)EOF) break; inw = ns(inw); /* get the option value */ - if ((cp = get_word(inf)) == NULL || cp == (char *)EOF) + if ((cp = get_word(inf, NULL)) == NULL || cp == (char *)EOF) break; /* option value */ invalue = ns(cp); /* malloced */ @@ -241,7 +241,7 @@ } /* EOL? */ - cp = get_word(inf); + cp = get_word(inf, NULL); if (cp == (char *)EOF) break; } @@ -370,16 +370,16 @@ fp = fopen(fname, "r"); if (fp == NULL) return (0); - while ((wd = get_word(fp)) != (char *)EOF) { + while ((wd = get_word(fp, NULL)) != (char *)EOF) { if (wd == NULL) continue; if (wd[0] == '#') { - while (((wd = get_word(fp)) != (char *)EOF) && wd) + while (((wd = get_word(fp, NULL)) != (char *)EOF) && wd) continue; continue; } this = ns(wd); - val = get_word(fp); + val = get_word(fp, NULL); if (val == (char *)EOF) return (1); if (val == NULL) {