diff options
Diffstat (limited to 'contrib/bmake/var.c')
-rw-r--r-- | contrib/bmake/var.c | 99 |
1 files changed, 52 insertions, 47 deletions
diff --git a/contrib/bmake/var.c b/contrib/bmake/var.c index 53d325d0d95a..6d015ff2661a 100644 --- a/contrib/bmake/var.c +++ b/contrib/bmake/var.c @@ -1,4 +1,4 @@ -/* $NetBSD: var.c,v 1.1009 2022/02/04 23:43:10 rillig Exp $ */ +/* $NetBSD: var.c,v 1.1019 2022/03/27 18:39:01 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -147,7 +147,7 @@ #include "metachar.h" /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ -MAKE_RCSID("$NetBSD: var.c,v 1.1009 2022/02/04 23:43:10 rillig Exp $"); +MAKE_RCSID("$NetBSD: var.c,v 1.1019 2022/03/27 18:39:01 rillig Exp $"); /* * Variables are defined using one of the VAR=value assignments. Their @@ -440,11 +440,6 @@ VarFindSubstring(Substring name, GNode *scope, bool elsewhere) FStr envName; const char *envValue; - /* - * TODO: try setting an environment variable with the empty - * name, which should be technically possible, just to see - * how make reacts. All .for loops should be broken then. - */ envName = Substring_Str(name); envValue = getenv(envName.str); if (envValue != NULL) @@ -484,6 +479,16 @@ VarFreeShortLived(Var *v) free(v); } +static const char * +ValueDescription(const char *value) +{ + if (value[0] == '\0') + return "# (empty)"; + if (ch_isspace(value[strlen(value) - 1])) + return "# (ends with space)"; + return ""; +} + /* Add a new variable of the given name and value to the given scope. */ static Var * VarAdd(const char *name, const char *value, GNode *scope, VarSetFlags flags) @@ -492,7 +497,8 @@ VarAdd(const char *name, const char *value, GNode *scope, VarSetFlags flags) Var *v = VarNew(FStr_InitRefer(/* aliased to */ he->key), value, false, false, (flags & VAR_SET_READONLY) != 0); HashEntry_Set(he, v); - DEBUG3(VAR, "%s: %s = %s\n", scope->name, name, value); + DEBUG4(VAR, "%s: %s = %s%s\n", + scope->name, name, value, ValueDescription(value)); return v; } @@ -507,11 +513,12 @@ Var_Delete(GNode *scope, const char *varname) Var *v; if (he == NULL) { - DEBUG2(VAR, "%s:delete %s (not found)\n", scope->name, varname); + DEBUG2(VAR, "%s: delete %s (not found)\n", + scope->name, varname); return; } - DEBUG2(VAR, "%s:delete %s\n", scope->name, varname); + DEBUG2(VAR, "%s: delete %s\n", scope->name, varname); v = he->value; if (v->inUse) { Parse_Error(PARSE_FATAL, @@ -519,10 +526,12 @@ Var_Delete(GNode *scope, const char *varname) v->name.str); return; } + if (v->exported) unsetenv(v->name.str); if (strcmp(v->name.str, MAKE_EXPORTED) == 0) var_exportedVars = VAR_EXPORTED_NONE; + assert(v->name.freeIt == NULL); HashTable_DeleteEntry(&scope->vars, he); Buf_Done(&v->val); @@ -989,7 +998,8 @@ Var_SetWithFlags(GNode *scope, const char *name, const char *val, Buf_Clear(&v->val); Buf_AddStr(&v->val, val); - DEBUG3(VAR, "%s: %s = %s\n", scope->name, name, val); + DEBUG4(VAR, "%s: %s = %s%s\n", + scope->name, name, val, ValueDescription(val)); if (v->exported) ExportVar(name, VEM_PLAIN); } @@ -1101,20 +1111,14 @@ Var_Append(GNode *scope, const char *name, const char *val) DEBUG3(VAR, "%s: %s = %s\n", scope->name, name, v->val.data); if (v->fromEnvironment) { - /* - * The variable originally came from the environment. - * Install it in the global scope (we could place it - * in the environment, but then we should provide a - * way to export other variables...) - */ - v->fromEnvironment = false; + /* See VarAdd. */ + HashEntry *he = + HashTable_CreateEntry(&scope->vars, name, NULL); + HashEntry_Set(he, v); + FStr_Done(&v->name); + v->name = FStr_InitRefer(/* aliased to */ he->key); v->shortLived = false; - /* - * This is the only place where a variable is - * created in a scope, where v->name does not alias - * scope->vars->key. - */ - HashTable_Set(&scope->vars, name, v); + v->fromEnvironment = false; } } } @@ -1438,10 +1442,11 @@ ModifyWord_SysVSubst(Substring word, SepBuf *buf, void *data) if (Substring_IsEmpty(word)) return; - if (!Substring_HasPrefix(word, args->lhsPrefix)) - goto no_match; - if (!Substring_HasSuffix(word, args->lhsSuffix)) - goto no_match; + if (!Substring_HasPrefix(word, args->lhsPrefix) || + !Substring_HasSuffix(word, args->lhsSuffix)) { + SepBuf_AddSubstring(buf, word); + return; + } rhs = FStr_InitRefer(args->rhs); Var_Expand(&rhs, args->scope, VARE_WANTRES); @@ -1457,10 +1462,6 @@ ModifyWord_SysVSubst(Substring word, SepBuf *buf, void *data) SepBuf_AddStr(buf, percent != NULL ? percent + 1 : rhs.str); FStr_Done(&rhs); - return; - -no_match: - SepBuf_AddSubstring(buf, word); } #endif @@ -2711,9 +2712,8 @@ ApplyModifier_Range(const char **pp, ModChain *ch) } /* Parse a ':M' or ':N' modifier. */ -static void -ParseModifier_Match(const char **pp, const ModChain *ch, - char **out_pattern) +static char * +ParseModifier_Match(const char **pp, const ModChain *ch) { const char *mod = *pp; Expr *expr = ch->expr; @@ -2777,6 +2777,10 @@ ParseModifier_Match(const char **pp, const ModChain *ch, if (needSubst) { char *old_pattern = pattern; + /* + * XXX: Contrary to ParseModifierPart, a dollar in a ':M' or + * ':N' modifier must be escaped as '$$', not as '\$'. + */ (void)Var_Subst(pattern, expr->scope, expr->emode, &pattern); /* TODO: handle errors */ free(old_pattern); @@ -2784,7 +2788,7 @@ ParseModifier_Match(const char **pp, const ModChain *ch, DEBUG2(VAR, "Pattern for ':%c' is \"%s\"\n", mod[0], pattern); - *out_pattern = pattern; + return pattern; } /* :Mpattern or :Npattern */ @@ -2794,7 +2798,7 @@ ApplyModifier_Match(const char **pp, ModChain *ch) char mod = **pp; char *pattern; - ParseModifier_Match(pp, ch, &pattern); + pattern = ParseModifier_Match(pp, ch); if (ModChain_ShouldEval(ch)) { ModifyWordProc modifyWord = @@ -3225,7 +3229,7 @@ ApplyModifier_Words(const char **pp, ModChain *ch) /* Normal case: select the words described by first and last. */ Expr_SetValueOwn(expr, VarSelectWords(Expr_Str(expr), first, last, - ch->sep, ch->oneBigWord)); + ch->sep, ch->oneBigWord)); ok: FStr_Done(&festr); @@ -3488,11 +3492,11 @@ found_op: scope = expr->scope; /* scope where v belongs */ if (expr->defined == DEF_REGULAR && expr->scope != SCOPE_GLOBAL) { - Var *gv = VarFind(expr->name, expr->scope, false); - if (gv == NULL) + Var *v = VarFind(expr->name, expr->scope, false); + if (v == NULL) scope = SCOPE_GLOBAL; else - VarFreeShortLived(gv); + VarFreeShortLived(v); } if (op[0] == '+') @@ -4035,9 +4039,9 @@ cleanup: /* * TODO: Use p + strlen(p) instead, to stop parsing immediately. * - * In the unit tests, this generates a few unterminated strings in the - * shell commands though. Instead of producing these unfinished - * strings, commands with evaluation errors should not be run at all. + * In the unit tests, this generates a few shell commands with + * unbalanced quotes. Instead of producing these incomplete strings, + * commands with evaluation errors should not be run at all. * * To make that happen, Var_Subst must report the actual errors * instead of returning VPR_OK unconditionally. @@ -4047,8 +4051,8 @@ cleanup: } /* - * Only 4 of the 7 local variables are treated specially as they are the only - * ones that will be set when dynamic sources are expanded. + * Only 4 of the 7 built-in local variables are treated specially as they are + * the only ones that will be set when dynamic sources are expanded. */ static bool VarnameIsDynamic(Substring varname) @@ -4798,7 +4802,8 @@ Var_Dump(GNode *scope) for (i = 0; i < vec.len; i++) { const char *varname = varnames[i]; Var *var = HashTable_FindValue(&scope->vars, varname); - debug_printf("%-16s = %s\n", varname, var->val.data); + debug_printf("%-16s = %s%s\n", varname, + var->val.data, ValueDescription(var->val.data)); } Vector_Done(&vec); |