static void ForExec(void *valuep, void *argp) { char *value = (char *)valuep; For *arg = (For *)argp; BUFFER buf; /* Parse_FromString pushes stuff back, so we need to go over vars in reverse. */ if (arg->var == NULL) { arg->var = Lst_Last(&arg->vars); arg->text = Buf_Retrieve(&arg->buf); arg->freeold = false; } if (DEBUG(FOR)) (void)fprintf(stderr, "--- %s = %s\n", Var_LoopVarName(Lst_Datum(arg->var)), value); Buf_Init(&buf, arg->guess); Var_SubstVar(&buf, arg->text, Lst_Datum(arg->var), value); if (arg->freeold) free(arg->text); arg->text = Buf_Retrieve(&buf); arg->freeold = true; arg->var = Lst_Rev(arg->var); if (arg->var == NULL) Parse_FromString(arg->text, arg->lineno); }
/* POSIX says that variable assignments passed on the command line should be * propagated to sub makes through MAKEFLAGS. */ void Var_AddCmdline(const char *name) { Var *v; unsigned int i; BUFFER buf; char *s; Buf_Init(&buf, MAKE_BSIZE); for (v = ohash_first(&global_variables, &i); v != NULL; v = ohash_next(&global_variables, &i)) { /* This is not as expensive as it looks: this function is * called before parsing Makefiles, so there are just a * few non cmdling variables in there. */ if (!(v->flags & VAR_FROM_CMD)) { continue; } /* We assume variable names don't need quoting */ Buf_AddString(&buf, v->name); Buf_AddChar(&buf, '='); for (s = var_get_value(v); *s != '\0'; s++) { if (strchr(quotable, *s)) Buf_AddChar(&buf, '\\'); Buf_AddChar(&buf, *s); } Buf_AddSpace(&buf); } Var_Append(name, Buf_Retrieve(&buf)); Buf_Destroy(&buf); }
char * Parse_ReadUnparsedLine(Buffer linebuf, const char *type) { int c; Buf_Reset(linebuf); c = read_char(); if (c == EOF) { Parse_Error(PARSE_FATAL, "Unclosed %s", type); return NULL; } /* Handle '\' at beginning of line, since \\n needs special treatment */ while (c == '\\') { c = read_char(); if (c == '\n') { current->lineno++; do { c = read_char(); } while (c == ' ' || c == '\t'); } else { Buf_AddChar(linebuf, '\\'); if (c == '\\') { Buf_AddChar(linebuf, '\\'); c = read_char(); } break; } } read_logical_line(linebuf, c); return Buf_Retrieve(linebuf); }
/* we would like to subst on intervals, but it's complicated, so we cheat * by storing the interval in a static buffer. */ char * Var_Substi(const char *str, const char *estr, SymTable *ctxt, bool undefErr) { /* delimited string: no need to copy */ if (estr == NULL || *estr == '\0') return Var_Subst(str, ctxt, undefErr); Buf_Reset(&subst_buffer); Buf_Addi(&subst_buffer, str, estr); return Var_Subst(Buf_Retrieve(&subst_buffer), ctxt, undefErr); }
/* Parse_ReadNormalLine removes beginning and trailing blanks (but keeps * the first tab), handles escaped newlines, and skips over uninteresting * lines. * * The line number is incremented, which implies that continuation * lines are numbered with the last line number (we could do better, at a * price). * * Trivial comments are also removed, but we can't do more, as * we don't know which lines are shell commands or not. */ char * Parse_ReadNormalLine(Buffer linebuf) { int c; /* the current character */ c = skip_empty_lines_and_read_char(linebuf); if (c == EOF) return NULL; else { read_logical_line(linebuf, c); Buf_KillTrailingSpaces(linebuf); return Buf_Retrieve(linebuf); } }
static Token CondHandleString(bool doEval) { char *lhs; const char *begin; BUFFER buf; /* find the extent of the string */ begin = ++condExpr; while (*condExpr && *condExpr != '"') { condExpr++; } Buf_Init(&buf, 0); Buf_Addi(&buf, begin, condExpr); if (*condExpr == '"') condExpr++; lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval); Buf_Destroy(&buf); return CondHandleComparison(lhs, true, doEval); }
static Token CondHandleVarSpec(bool doEval) { char *lhs; size_t varSpecLen; bool doFree; /* Parse the variable spec and skip over it, saving its * value in lhs. */ lhs = Var_Parse(condExpr, NULL, doEval,&varSpecLen,&doFree); if (lhs == var_Error) /* Even if !doEval, we still report syntax errors, which * is what getting var_Error back with !doEval means. */ return Err; condExpr += varSpecLen; if (!isspace(*condExpr) && strchr("!=><", *condExpr) == NULL) { BUFFER buf; Buf_Init(&buf, 0); Buf_AddString(&buf, lhs); if (doFree) free(lhs); for (;*condExpr && !isspace(*condExpr); condExpr++) Buf_AddChar(&buf, *condExpr); lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval); Buf_Destroy(&buf); doFree = true; } return CondHandleComparison(lhs, doFree, doEval); }
char * Var_Subst(const char *str, /* the string in which to substitute */ SymTable *ctxt, /* the context wherein to find variables */ bool undefErr) /* true if undefineds are an error */ { BUFFER buf; /* Buffer for forming things */ static bool errorReported; Buf_Init(&buf, MAKE_BSIZE); errorReported = false; for (;;) { char *val; /* Value to substitute for a variable */ size_t length; /* Length of the variable invocation */ bool doFree; /* Set true if val should be freed */ const char *cp; /* copy uninteresting stuff */ for (cp = str; *str != '\0' && *str != '$'; str++) ; Buf_Addi(&buf, cp, str); if (*str == '\0') break; if (str[1] == '$') { /* A $ may be escaped with another $. */ Buf_AddChar(&buf, '$'); str += 2; continue; } val = Var_Parse(str, ctxt, undefErr, &length, &doFree); /* When we come down here, val should either point to the * value of this variable, suitably modified, or be NULL. * Length should be the total length of the potential * variable invocation (from $ to end character...) */ if (val == var_Error || val == varNoError) { /* If errors are not an issue, skip over the variable * and continue with the substitution. Otherwise, store * the dollar sign and advance str so we continue with * the string... */ if (errorIsOkay) str += length; else if (undefErr) { /* If variable is undefined, complain and * skip the variable name. The complaint * will stop us from doing anything when * the file is parsed. */ if (!errorReported) Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"", length, str); str += length; errorReported = true; } else { Buf_AddChar(&buf, *str); str++; } } else { /* We've now got a variable structure to store in. * But first, advance the string pointer. */ str += length; /* Copy all the characters from the variable value * straight into the new string. */ Buf_AddString(&buf, val); if (doFree) free(val); } } return Buf_Retrieve(&buf); }
static Token CondHandleComparison(char *lhs, bool doFree, bool doEval) { Token t; const char *rhs; const char *op; t = Err; /* Skip whitespace to get to the operator. */ while (isspace(*condExpr)) condExpr++; /* Make sure the operator is a valid one. If it isn't a * known relational operator, pretend we got a * != 0 comparison. */ op = condExpr; switch (*condExpr) { case '!': case '=': case '<': case '>': if (condExpr[1] == '=') condExpr += 2; else condExpr += 1; break; default: op = "!="; rhs = "0"; goto do_compare; } while (isspace(*condExpr)) condExpr++; if (*condExpr == '\0') { Parse_Error(PARSE_WARNING, "Missing right-hand-side of operator"); goto error; } rhs = condExpr; do_compare: if (*rhs == '"') { /* Doing a string comparison. Only allow == and != for * operators. */ char *string; const char *cp; int qt; BUFFER buf; do_string_compare: if ((*op != '!' && *op != '=') || op[1] != '=') { Parse_Error(PARSE_WARNING, "String comparison operator should be either == or !="); goto error; } Buf_Init(&buf, 0); qt = *rhs == '"' ? 1 : 0; for (cp = &rhs[qt]; ((qt && *cp != '"') || (!qt && strchr(" \t)", *cp) == NULL)) && *cp != '\0';) { if (*cp == '$') { size_t len; if (Var_ParseBuffer(&buf, cp, NULL, doEval, &len)) { cp += len; continue; } } else if (*cp == '\\' && cp[1] != '\0') /* Backslash escapes things -- skip over next * character, if it exists. */ cp++; Buf_AddChar(&buf, *cp++); } string = Buf_Retrieve(&buf); if (DEBUG(COND)) printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n", lhs, string, op); /* Null-terminate rhs and perform the comparison. * t is set to the result. */ if (*op == '=') t = strcmp(lhs, string) ? False : True; else t = strcmp(lhs, string) ? True : False; free(string); if (rhs == condExpr) { if (!qt && *cp == ')') condExpr = cp; else if (*cp == '\0') condExpr = cp; else condExpr = cp + 1; } } else { /* rhs is either a float or an integer. Convert both the * lhs and the rhs to a double and compare the two. */ double left, right; char *string; if (!CondCvtArg(lhs, &left)) goto do_string_compare; if (*rhs == '$') { size_t len; bool freeIt; string = Var_Parse(rhs, NULL, doEval,&len,&freeIt); if (string == var_Error) right = 0.0; else { if (!CondCvtArg(string, &right)) { if (freeIt) free(string); goto do_string_compare; } if (freeIt) free(string); if (rhs == condExpr) condExpr += len; } } else { if (!CondCvtArg(rhs, &right)) goto do_string_compare; if (rhs == condExpr) { /* Skip over the right-hand side. */ while (!isspace(*condExpr) && *condExpr != '\0') condExpr++; } } if (DEBUG(COND)) printf("left = %f, right = %f, op = %.2s\n", left, right, op); switch (op[0]) { case '!': if (op[1] != '=') { Parse_Error(PARSE_WARNING, "Unknown operator"); goto error; } t = left != right ? True : False; break; case '=': if (op[1] != '=') { Parse_Error(PARSE_WARNING, "Unknown operator"); goto error; } t = left == right ? True : False; break; case '<': if (op[1] == '=') t = left <= right ? True : False; else t = left < right ? True : False; break; case '>': if (op[1] == '=') t = left >= right ? True : False; else t = left > right ? True : False; break; } } error: if (doFree) free(lhs); return t; }
void Make_DoAllVar(GNode *gn) { GNode *child; LstNode ln; BUFFER allsrc, oodate; char *target; bool do_oodate; int oodate_count, allsrc_count = 0; oodate_count = 0; allsrc_count = 0; for (ln = Lst_First(&gn->children); ln != NULL; ln = Lst_Adv(ln)) { child = (GNode *)Lst_Datum(ln); if ((child->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) != 0) continue; if (OP_NOP(child->type) || (target = Var(TARGET_INDEX, child)) == NULL) { /* * this node is only source; use the specific pathname * for it */ target = child->path != NULL ? child->path : child->name; } /* * It goes in the OODATE variable if the parent is younger than * the child or if the child has been modified more recently * than the start of the make. This is to keep make from * getting confused if something else updates the parent after * the make starts (shouldn't happen, I know, but sometimes it * does). In such a case, if we've updated the kid, the parent * is likely to have a modification time later than that of the * kid and anything that relies on the OODATE variable will be * hosed. */ do_oodate = false; if (gn->type & OP_JOIN) { if (child->built_status == MADE) do_oodate = true; } else if (is_strictly_before(gn->mtime, child->mtime) || (!is_strictly_before(child->mtime, now) && child->built_status == MADE)) do_oodate = true; if (do_oodate) { oodate_count++; if (oodate_count == 1) Var(OODATE_INDEX, gn) = target; else { if (oodate_count == 2) { Buf_Init(&oodate, 0); Buf_AddString(&oodate, Var(OODATE_INDEX, gn)); } Buf_AddSpace(&oodate); Buf_AddString(&oodate, target); } } allsrc_count++; if (allsrc_count == 1) Var(ALLSRC_INDEX, gn) = target; else { if (allsrc_count == 2) { Buf_Init(&allsrc, 0); Buf_AddString(&allsrc, Var(ALLSRC_INDEX, gn)); } Buf_AddSpace(&allsrc); Buf_AddString(&allsrc, target); } } if (allsrc_count > 1) Var(ALLSRC_INDEX, gn) = Buf_Retrieve(&allsrc); if (oodate_count > 1) Var(OODATE_INDEX, gn) = Buf_Retrieve(&oodate); if (gn->impliedsrc) Var(IMPSRC_INDEX, gn) = Var(TARGET_INDEX, gn->impliedsrc); if (gn->type & OP_JOIN) Var(TARGET_INDEX, gn) = Var(ALLSRC_INDEX, gn); }
void For_Run(For *arg) { arg->text = Buf_Retrieve(&arg->buf); arg->guess = Buf_Size(&arg->buf) + GUESS_EXPANSION; arg->var = NULL; Lst_ForEach(&arg->lst, ForExec, arg); Buf_Destroy(&arg->buf); Lst_Destroy(&arg->vars, (SimpleProc)Var_DeleteLoopVar); Lst_Destroy(&arg->lst, (SimpleProc)free); free(arg); }