/* VARARGS */ void Parse_Error(int type, const char *fmt, ...) { va_list ap; va_start(ap, fmt); ParseVErrorInternal(Parse_Getfilename(), Parse_Getlineno(), type, fmt, ap); va_end(ap); }
/* Evaluate conditional in line. * returns COND_SKIP, COND_PARSE, COND_INVALID, COND_ISFOR, COND_ISINCLUDE, * COND_ISUNDEF. * A conditional line looks like this: * <cond-type> <expr> * where <cond-type> is any of if, ifmake, ifnmake, ifdef, * ifndef, elif, elifmake, elifnmake, elifdef, elifndef * and <expr> consists of &&, ||, !, make(target), defined(variable) * and parenthetical groupings thereof. */ int Cond_Eval(const char *line) { /* find end of keyword */ const char *end; uint32_t k; size_t len; struct If *ifp; bool value = false; int level; /* Level at which to report errors. */ level = PARSE_FATAL; for (end = line; islower(*end); end++) ; /* quick path: recognize special targets early on */ if (*end == '.' || *end == ':') return COND_INVALID; len = end - line; k = ohash_interval(line, &end); switch(k % MAGICSLOTS2) { case K_COND_IF % MAGICSLOTS2: if (k == K_COND_IF && len == strlen(COND_IF) && strncmp(line, COND_IF, len) == 0) { ifp = ifs + COND_IF_INDEX; } else return COND_INVALID; break; case K_COND_IFDEF % MAGICSLOTS2: if (k == K_COND_IFDEF && len == strlen(COND_IFDEF) && strncmp(line, COND_IFDEF, len) == 0) { ifp = ifs + COND_IFDEF_INDEX; } else return COND_INVALID; break; case K_COND_IFNDEF % MAGICSLOTS2: if (k == K_COND_IFNDEF && len == strlen(COND_IFNDEF) && strncmp(line, COND_IFNDEF, len) == 0) { ifp = ifs + COND_IFNDEF_INDEX; } else return COND_INVALID; break; case K_COND_IFMAKE % MAGICSLOTS2: if (k == K_COND_IFMAKE && len == strlen(COND_IFMAKE) && strncmp(line, COND_IFMAKE, len) == 0) { ifp = ifs + COND_IFMAKE_INDEX; } else return COND_INVALID; break; case K_COND_IFNMAKE % MAGICSLOTS2: if (k == K_COND_IFNMAKE && len == strlen(COND_IFNMAKE) && strncmp(line, COND_IFNMAKE, len) == 0) { ifp = ifs + COND_IFNMAKE_INDEX; } else return COND_INVALID; break; case K_COND_ELIF % MAGICSLOTS2: if (k == K_COND_ELIF && len == strlen(COND_ELIF) && strncmp(line, COND_ELIF, len) == 0) { ifp = ifs + COND_ELIF_INDEX; } else return COND_INVALID; break; case K_COND_ELIFDEF % MAGICSLOTS2: if (k == K_COND_ELIFDEF && len == strlen(COND_ELIFDEF) && strncmp(line, COND_ELIFDEF, len) == 0) { ifp = ifs + COND_ELIFDEF_INDEX; } else return COND_INVALID; break; case K_COND_ELIFNDEF % MAGICSLOTS2: if (k == K_COND_ELIFNDEF && len == strlen(COND_ELIFNDEF) && strncmp(line, COND_ELIFNDEF, len) == 0) { ifp = ifs + COND_ELIFNDEF_INDEX; } else return COND_INVALID; break; case K_COND_ELIFMAKE % MAGICSLOTS2: if (k == K_COND_ELIFMAKE && len == strlen(COND_ELIFMAKE) && strncmp(line, COND_ELIFMAKE, len) == 0) { ifp = ifs + COND_ELIFMAKE_INDEX; } else return COND_INVALID; break; case K_COND_ELIFNMAKE % MAGICSLOTS2: if (k == K_COND_ELIFNMAKE && len == strlen(COND_ELIFNMAKE) && strncmp(line, COND_ELIFNMAKE, len) == 0) { ifp = ifs + COND_ELIFNMAKE_INDEX; } else return COND_INVALID; break; case K_COND_ELSE % MAGICSLOTS2: /* valid conditional whose value is the inverse * of the previous if we parsed. */ if (k == K_COND_ELSE && len == strlen(COND_ELSE) && strncmp(line, COND_ELSE, len) == 0) { if (condTop == MAXIF) { Parse_Error(level, "if-less else"); return COND_INVALID; } else if (skipIfLevel == 0) { value = !condStack[condTop].value; ifp = ifs + COND_ELSE_INDEX; } else return COND_SKIP; } else return COND_INVALID; break; case K_COND_ENDIF % MAGICSLOTS2: if (k == K_COND_ENDIF && len == strlen(COND_ENDIF) && strncmp(line, COND_ENDIF, len) == 0) { /* End of a conditional section. If skipIfLevel is * non-zero, that conditional was skipped, so lines * following it should also be skipped. Hence, we * return COND_SKIP. Otherwise, the conditional was * read so succeeding lines should be parsed (think * about it...) so we return COND_PARSE, unless this * endif isn't paired with a decent if. */ if (skipIfLevel != 0) { skipIfLevel--; return COND_SKIP; } else { if (condTop == MAXIF) { Parse_Error(level, "if-less endif"); return COND_INVALID; } else { skipLine = false; condTop++; return COND_PARSE; } } } else return COND_INVALID; break; /* Recognize other keywords there, to simplify parser's task */ case K_COND_FOR % MAGICSLOTS2: if (k == K_COND_FOR && len == strlen(COND_FOR) && strncmp(line, COND_FOR, len) == 0) return COND_ISFOR; else return COND_INVALID; case K_COND_UNDEF % MAGICSLOTS2: if (k == K_COND_UNDEF && len == strlen(COND_UNDEF) && strncmp(line, COND_UNDEF, len) == 0) return COND_ISUNDEF; else return COND_INVALID; case K_COND_POISON % MAGICSLOTS2: if (k == K_COND_POISON && len == strlen(COND_POISON) && strncmp(line, COND_POISON, len) == 0) return COND_ISPOISON; else return COND_INVALID; case K_COND_INCLUDE % MAGICSLOTS2: if (k == K_COND_INCLUDE && len == strlen(COND_INCLUDE) && strncmp(line, COND_INCLUDE, len) == 0) return COND_ISINCLUDE; else return COND_INVALID; default: /* Not a valid conditional type. No error... */ return COND_INVALID; } if (ifp->isElse) { if (condTop == MAXIF) { Parse_Error(level, "if-less elif"); return COND_INVALID; } else if (skipIfLevel != 0 || condStack[condTop].value) { /* * Skip if we're meant to or is an else-type * conditional and previous corresponding one was * evaluated to true. */ skipLine = true; return COND_SKIP; } } else if (skipLine) { /* Don't even try to evaluate a conditional that's not an else * if we're skipping things... */ skipIfLevel++; return COND_SKIP; } else condTop--; if (condTop < 0) { /* This is the one case where we can definitely proclaim a fatal * error. If we don't, we're hosed. */ Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); condTop = 0; return COND_INVALID; } if (ifp->defProc) { /* Initialize file-global variables for parsing. */ condDefProc = ifp->defProc; condInvert = ifp->doNot; line += len; while (*line == ' ' || *line == '\t') line++; condExpr = line; condPushBack = None; switch (CondE(true)) { case True: if (CondToken(true) == EndOfFile) { value = true; break; } goto err; /* FALLTHROUGH */ case False: if (CondToken(true) == EndOfFile) { value = false; break; } /* FALLTHROUGH */ case Err: err: Parse_Error(level, "Malformed conditional (%s)", line); return COND_INVALID; default: break; } } condStack[condTop].value = value; condStack[condTop].lineno = Parse_Getlineno(); condStack[condTop].filename = Parse_Getfilename(); skipLine = !value; return value ? COND_PARSE : COND_SKIP; }
For * For_Eval(const char *line) { const char *ptr = line; const char *wrd; char *sub; const char *endVar; For *arg; unsigned long n; while (ISSPACE(*ptr)) ptr++; /* Parse loop. */ arg = emalloc(sizeof(*arg)); arg->nvars = 0; Lst_Init(&arg->vars); for (;;) { /* Grab the variables. */ for (wrd = ptr; *ptr && !ISSPACE(*ptr); ptr++) continue; if (ptr - wrd == 0) { Parse_Error(PARSE_FATAL, "Syntax error in for"); return 0; } endVar = ptr++; while (ISSPACE(*ptr)) ptr++; /* End of variable list ? */ if (endVar - wrd == 2 && wrd[0] == 'i' && wrd[1] == 'n') break; Lst_AtEnd(&arg->vars, Var_NewLoopVar(wrd, endVar)); arg->nvars++; } if (arg->nvars == 0) { Parse_Error(PARSE_FATAL, "Missing variable in for"); return 0; } /* Make a list with the remaining words. */ sub = Var_Subst(ptr, NULL, false); if (DEBUG(FOR)) { LstNode ln; (void)fprintf(stderr, "For: Iterator "); for (ln = Lst_First(&arg->vars); ln != NULL; ln = Lst_Adv(ln)) (void)fprintf(stderr, "%s ", Var_LoopVarName(Lst_Datum(ln))); (void)fprintf(stderr, "List %s\n", sub); } Lst_Init(&arg->lst); n = build_words_list(&arg->lst, sub); free(sub); if (arg->nvars != 1 && n % arg->nvars != 0) { LstNode ln; Parse_Error(PARSE_FATAL, "Wrong number of items in for loop"); (void)fprintf(stderr, "%lu items for %d variables:", n, arg->nvars); for (ln = Lst_First(&arg->lst); ln != NULL; ln = Lst_Adv(ln)) { char *p = Lst_Datum(ln); (void)fprintf(stderr, " %s", p); } (void)fprintf(stderr, "\n"); return 0; } arg->lineno = Parse_Getlineno(); arg->level = 1; Buf_Init(&arg->buf, 0); return arg; }