static Token CondHandleDefault(bool doEval) { bool t; bool (*evalProc)(struct Name *); bool invert = false; struct Name arg; size_t arglen; evalProc = NULL; if (strncmp(condExpr, "empty", 5) == 0) { /* Use Var_Parse to parse the spec in parens and return * True if the resulting string is empty. */ size_t length; bool doFree; char *val; condExpr += 5; for (arglen = 0; condExpr[arglen] != '(' && condExpr[arglen] != '\0';) arglen++; if (condExpr[arglen] != '\0') { val = Var_Parse(&condExpr[arglen - 1], NULL, doEval, &length, &doFree); if (val == var_Error) t = Err; else { /* A variable is empty when it just contains * spaces... 4/15/92, christos */ char *p; for (p = val; isspace(*p); p++) continue; t = *p == '\0' ? True : False; } if (doFree) free(val); /* Advance condExpr to beyond the closing ). Note that * we subtract one from arglen + length b/c length * is calculated from condExpr[arglen - 1]. */ condExpr += arglen + length - 1; return t; } else condExpr -= 5; } else { struct operator *op; for (op = ops; op != NULL; op++) if (strncmp(condExpr, op->s, op->len) == 0) { condExpr += op->len; if (CondGetArg(&condExpr, &arg, op->s, true)) evalProc = op->proc; else condExpr -= op->len; break; } } if (evalProc == NULL) { /* The symbol is itself the argument to the default * function. We advance condExpr to the end of the symbol * by hand (the next whitespace, closing paren or * binary operator) and set to invert the evaluation * function if condInvert is true. */ invert = condInvert; evalProc = condDefProc; /* XXX should we ignore problems now ? */ CondGetArg(&condExpr, &arg, "", false); } /* Evaluate the argument using the set function. If invert * is true, we invert the sense of the function. */ t = (!doEval || (*evalProc)(&arg) ? (invert ? False : True) : (invert ? True : False)); VarName_Free(&arg); return t; }
static Token compare_function(Boolean doEval) { static const struct fn_def { const char *fn_name; int fn_name_len; int (*fn_getarg)(char **, char **, const char *); Boolean (*fn_proc)(int, const char *); } fn_defs[] = { { "defined", 7, CondGetArg, CondDoDefined }, { "make", 4, CondGetArg, CondDoMake }, { "exists", 6, CondGetArg, CondDoExists }, { "empty", 5, get_mpt_arg, CondDoEmpty }, { "target", 6, CondGetArg, CondDoTarget }, { "commands", 8, CondGetArg, CondDoCommands }, { NULL, 0, NULL, NULL }, }; const struct fn_def *fn_def; Token t; char *arg = NULL; int arglen; char *cp = condExpr; char *cp1; for (fn_def = fn_defs; fn_def->fn_name != NULL; fn_def++) { if (!istoken(cp, fn_def->fn_name, fn_def->fn_name_len)) continue; cp += fn_def->fn_name_len; /* There can only be whitespace before the '(' */ while (isspace(*(unsigned char *)cp)) cp++; if (*cp != '(') break; arglen = fn_def->fn_getarg(&cp, &arg, fn_def->fn_name); if (arglen <= 0) { condExpr = cp; return arglen < 0 ? TOK_ERROR : TOK_FALSE; } /* Evaluate the argument using the required function. */ t = !doEval || fn_def->fn_proc(arglen, arg); if (arg) free(arg); condExpr = cp; return t; } /* Push anything numeric through the compare expression */ cp = condExpr; if (isdigit((unsigned char)cp[0]) || strchr("+-", cp[0])) return compare_expression(doEval); /* * Most likely we have a naked token to apply the default function to. * However ".if a == b" gets here when the "a" is unquoted and doesn't * start with a '$'. This surprises people. * If what follows the function argument is a '=' or '!' then the syntax * would be invalid if we did "defined(a)" - so instead treat as an * expression. */ arglen = CondGetArg(&cp, &arg, NULL); for (cp1 = cp; isspace(*(unsigned char *)cp1); cp1++) continue; if (*cp1 == '=' || *cp1 == '!') return compare_expression(doEval); condExpr = cp; /* * Evaluate the argument using the default function. * This path always treats .if as .ifdef. To get here the character * after .if must have been taken literally, so the argument cannot * be empty - even if it contained a variable expansion. */ t = !doEval || if_info->defProc(arglen, arg) != if_info->doNot; if (arg) free(arg); return t; }