/* 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; }