1 /*        $NetBSD: var.c,v 1.1162 2025/05/03 08:18:33 rillig Exp $    */
2 
3 /*
4  * Copyright (c) 1988, 1989, 1990, 1993
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Adam de Boor.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 /*
36  * Copyright (c) 1989 by Berkeley Softworks
37  * All rights reserved.
38  *
39  * This code is derived from software contributed to Berkeley by
40  * Adam de Boor.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions
44  * are met:
45  * 1. Redistributions of source code must retain the above copyright
46  *    notice, this list of conditions and the following disclaimer.
47  * 2. Redistributions in binary form must reproduce the above copyright
48  *    notice, this list of conditions and the following disclaimer in the
49  *    documentation and/or other materials provided with the distribution.
50  * 3. All advertising materials mentioning features or use of this software
51  *    must display the following acknowledgement:
52  *        This product includes software developed by the University of
53  *        California, Berkeley and its contributors.
54  * 4. Neither the name of the University nor the names of its contributors
55  *    may be used to endorse or promote products derived from this software
56  *    without specific prior written permission.
57  *
58  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68  * SUCH DAMAGE.
69  */
70 
71 /*
72  * Handling of variables and the expressions formed from them.
73  *
74  * Variables are set using lines of the form VAR=value.  Both the variable
75  * name and the value can contain references to other variables, by using
76  * expressions like ${VAR}, ${VAR:Modifiers}, ${${VARNAME}} or ${VAR:${MODS}}.
77  *
78  * Interface:
79  *        Var_Set
80  *        Var_SetExpand       Set the value of the variable, creating it if
81  *                            necessary.
82  *
83  *        Var_Append
84  *        Var_AppendExpand
85  *                            Append more characters to the variable, creating it if
86  *                            necessary. A space is placed between the old value and
87  *                            the new one.
88  *
89  *        Var_Exists
90  *        Var_ExistsExpand
91  *                            See if a variable exists.
92  *
93  *        Var_Value Return the unexpanded value of a variable, or NULL if
94  *                            the variable is undefined.
95  *
96  *        Var_Subst Substitute all expressions in a string.
97  *
98  *        Var_Parse Parse an expression such as ${VAR:Mpattern}.
99  *
100  *        Var_Delete          Delete a variable.
101  *
102  *        Var_ReexportVars
103  *                            Export some or even all variables to the environment
104  *                            of this process and its child processes.
105  *
106  *        Var_Export          Export the variable to the environment of this process
107  *                            and its child processes.
108  *
109  *        Var_UnExport        Don't export the variable anymore.
110  *
111  * Debugging:
112  *        Var_Stats Print out hashing statistics if in -dh mode.
113  *
114  *        Var_Dump  Print out all variables defined in the given scope.
115  */
116 
117 #include <sys/stat.h>
118 #include <sys/types.h>
119 #include <regex.h>
120 #include <errno.h>
121 #include <inttypes.h>
122 #include <limits.h>
123 #include <time.h>
124 
125 #include "make.h"
126 #include "dir.h"
127 #include "job.h"
128 #include "metachar.h"
129 
130 /*        "@(#)var.c          8.3 (Berkeley) 3/19/94" */
131 MAKE_RCSID("$NetBSD: var.c,v 1.1162 2025/05/03 08:18:33 rillig Exp $");
132 
133 /*
134  * Variables are defined using one of the VAR=value assignments.  Their
135  * value can be queried by expressions such as $V, ${VAR}, or with modifiers
136  * such as ${VAR:S,from,to,g:Q}.
137  *
138  * There are 3 kinds of variables: scope variables, environment variables,
139  * undefined variables.
140  *
141  * Scope variables are stored in GNode.vars.  The only way to undefine
142  * a scope variable is using the .undef directive.  In particular, it must
143  * not be possible to undefine a variable during the evaluation of an
144  * expression, or Var.name might point nowhere.  (There is another,
145  * unintended way to undefine a scope variable, see varmod-loop-delete.mk.)
146  *
147  * Environment variables are short-lived.  They are returned by VarFind, and
148  * after using them, they must be freed using VarFreeShortLived.
149  *
150  * Undefined variables occur during evaluation of expressions such
151  * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers.
152  */
153 typedef struct Var {
154           /*
155            * The name of the variable, once set, doesn't change anymore.
156            * For scope variables, it aliases the corresponding HashEntry name.
157            * For environment and undefined variables, it is allocated.
158            */
159           FStr name;
160 
161           /* The unexpanded value of the variable. */
162           Buffer val;
163 
164           /* The variable came from the command line. */
165           bool fromCmd:1;
166 
167           /*
168            * The variable is short-lived.
169            * These variables are not registered in any GNode, therefore they
170            * must be freed after use.
171            */
172           bool shortLived:1;
173 
174           /*
175            * The variable comes from the environment.
176            * Appending to its value depends on the scope, see var-op-append.mk.
177            */
178           bool fromEnvironment:1;
179 
180           /*
181            * The variable value cannot be changed anymore, and the variable
182            * cannot be deleted.  Any attempts to do so are silently ignored,
183            * they are logged with -dv though.
184            * Use .[NO]READONLY: to adjust.
185            *
186            * See VAR_SET_READONLY.
187            */
188           bool readOnly:1;
189 
190           /*
191            * The variable is read-only and immune to the .NOREADONLY special
192            * target.  Any attempt to modify it results in an error.
193            */
194           bool readOnlyLoud:1;
195 
196           /*
197            * The variable is currently being accessed by Var_Parse or Var_Subst.
198            * This temporary marker is used to avoid endless recursion.
199            */
200           bool inUse:1;
201 
202           /*
203            * The variable is exported to the environment, to be used by child
204            * processes.
205            */
206           bool exported:1;
207 
208           /*
209            * At the point where this variable was exported, it contained an
210            * unresolved reference to another variable.  Before any child
211            * process is started, it needs to be actually exported, resolving
212            * the referenced variable just in time.
213            */
214           bool reexport:1;
215 } Var;
216 
217 /*
218  * Exporting variables is expensive and may leak memory, so skip it if we
219  * can.
220  */
221 typedef enum VarExportedMode {
222           VAR_EXPORTED_NONE,
223           VAR_EXPORTED_SOME,
224           VAR_EXPORTED_ALL
225 } VarExportedMode;
226 
227 typedef enum UnexportWhat {
228           /* Unexport the variables given by name. */
229           UNEXPORT_NAMED,
230           /*
231            * Unexport all globals previously exported, but keep the environment
232            * inherited from the parent.
233            */
234           UNEXPORT_ALL,
235           /*
236            * Unexport all globals previously exported and clear the environment
237            * inherited from the parent.
238            */
239           UNEXPORT_ENV
240 } UnexportWhat;
241 
242 /* Flags for pattern matching in the :S and :C modifiers */
243 typedef struct PatternFlags {
244           bool subGlobal:1;   /* 'g': replace as often as possible */
245           bool subOnce:1;               /* '1': replace only once */
246           bool anchorStart:1; /* '^': match only at start of word */
247           bool anchorEnd:1;   /* '$': match only at end of word */
248 } PatternFlags;
249 
250 /* SepBuf builds a string from words interleaved with separators. */
251 typedef struct SepBuf {
252           Buffer buf;
253           bool needSep;
254           /* Usually ' ', but see the ':ts' modifier. */
255           char sep;
256 } SepBuf;
257 
258 typedef enum {
259           VSK_TARGET,
260           VSK_COMMAND,
261           VSK_VARNAME,
262           VSK_INDIRECT_MODIFIERS,
263           VSK_COND,
264           VSK_COND_THEN,
265           VSK_COND_ELSE,
266           VSK_EXPR,
267           VSK_EXPR_PARSE
268 } EvalStackElementKind;
269 
270 typedef struct {
271           EvalStackElementKind kind;
272           const char *str;
273           const FStr *value;
274 } EvalStackElement;
275 
276 typedef struct {
277           EvalStackElement *elems;
278           size_t len;
279           size_t cap;
280 } EvalStack;
281 
282 /* Whether we have replaced the original environ (which we cannot free). */
283 char **savedEnv = NULL;
284 
285 /*
286  * Special return value for Var_Parse, indicating a parse error.  It may be
287  * caused by an undefined variable, a syntax error in a modifier or
288  * something entirely different.
289  */
290 char var_Error[] = "";
291 
292 /*
293  * Special return value for Var_Parse, indicating an undefined variable in
294  * a case where VARE_EVAL_DEFINED is not set.  This undefined variable is
295  * typically a dynamic variable such as ${.TARGET}, whose expansion needs to
296  * be deferred until it is defined in an actual target.
297  *
298  * See VARE_EVAL_KEEP_UNDEFINED.
299  */
300 static char varUndefined[] = "";
301 
302 /*
303  * Traditionally this make consumed $$ during := like any other expansion.
304  * Other make's do not, and this make follows straight since 2016-01-09.
305  *
306  * This knob allows controlling the behavior:
307  *        false to consume $$ during := assignment.
308  *        true to preserve $$ during := assignment.
309  */
310 #define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
311 static bool save_dollars = true;
312 
313 /*
314  * A scope collects variable names and their values.
315  *
316  * The main scope is SCOPE_GLOBAL, which contains the variables that are set
317  * in the makefiles.  SCOPE_INTERNAL acts as a fallback for SCOPE_GLOBAL and
318  * contains some internal make variables.  These internal variables can thus
319  * be overridden, they can also be restored by undefining the overriding
320  * variable.
321  *
322  * SCOPE_CMDLINE contains variables from the command line arguments.  These
323  * override variables from SCOPE_GLOBAL.
324  *
325  * There is no scope for environment variables, these are generated on-the-fly
326  * whenever they are referenced.
327  *
328  * Each target has its own scope, containing the 7 target-local variables
329  * .TARGET, .ALLSRC, etc.  Variables set on dependency lines also go in
330  * this scope.
331  */
332 
333 GNode *SCOPE_CMDLINE;
334 GNode *SCOPE_GLOBAL;
335 GNode *SCOPE_INTERNAL;
336 
337 static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
338 
339 static const char VarEvalMode_Name[][32] = {
340           "parse",
341           "parse-balanced",
342           "eval",
343           "eval-defined-loud",
344           "eval-defined",
345           "eval-keep-undefined",
346           "eval-keep-dollar-and-undefined",
347 };
348 
349 static EvalStack evalStack;
350 
351 
352 static void
EvalStack_Push(EvalStackElementKind kind,const char * str,const FStr * value)353 EvalStack_Push(EvalStackElementKind kind, const char *str, const FStr *value)
354 {
355           if (evalStack.len >= evalStack.cap) {
356                     evalStack.cap = 16 + 2 * evalStack.cap;
357                     evalStack.elems = bmake_realloc(evalStack.elems,
358                         evalStack.cap * sizeof(*evalStack.elems));
359           }
360           evalStack.elems[evalStack.len].kind = kind;
361           evalStack.elems[evalStack.len].str = str;
362           evalStack.elems[evalStack.len].value = value;
363           evalStack.len++;
364 }
365 
366 static void
EvalStack_Pop(void)367 EvalStack_Pop(void)
368 {
369           assert(evalStack.len > 0);
370           evalStack.len--;
371 }
372 
373 bool
EvalStack_PrintDetails(void)374 EvalStack_PrintDetails(void)
375 {
376           size_t i;
377 
378           for (i = evalStack.len; i > 0; i--) {
379                     static const char descr[][42] = {
380                               "in target",
381                               "in command",
382                               "while evaluating variable",
383                               "while evaluating indirect modifiers",
384                               "while evaluating condition",
385                               "while evaluating then-branch of condition",
386                               "while evaluating else-branch of condition",
387                               "while evaluating",
388                               "while parsing",
389                     };
390                     EvalStackElement *elem = evalStack.elems + i - 1;
391                     EvalStackElementKind kind = elem->kind;
392                     const char* value = elem->value != NULL
393                         && (kind == VSK_VARNAME || kind == VSK_EXPR)
394                         ? elem->value->str : NULL;
395 
396                     debug_printf("\t%s \"%s%s%s\"\n", descr[kind], elem->str,
397                         value != NULL ? "\" with value \"" : "",
398                         value != NULL ? value : "");
399           }
400           return evalStack.len > 0;
401 }
402 
403 static Var *
VarNew(FStr name,const char * value,bool shortLived,bool fromEnvironment,bool readOnly)404 VarNew(FStr name, const char *value,
405        bool shortLived, bool fromEnvironment, bool readOnly)
406 {
407           size_t value_len = strlen(value);
408           Var *var = bmake_malloc(sizeof *var);
409           var->name = name;
410           Buf_InitSize(&var->val, value_len + 1);
411           Buf_AddBytes(&var->val, value, value_len);
412           var->fromCmd = false;
413           var->shortLived = shortLived;
414           var->fromEnvironment = fromEnvironment;
415           var->readOnly = readOnly;
416           var->readOnlyLoud = false;
417           var->inUse = false;
418           var->exported = false;
419           var->reexport = false;
420           return var;
421 }
422 
423 static Substring
CanonicalVarname(Substring name)424 CanonicalVarname(Substring name)
425 {
426 
427           if (!(Substring_Length(name) > 0 && name.start[0] == '.'))
428                     return name;
429 
430           if (Substring_Equals(name, ".ALLSRC"))
431                     return Substring_InitStr(ALLSRC);
432           if (Substring_Equals(name, ".ARCHIVE"))
433                     return Substring_InitStr(ARCHIVE);
434           if (Substring_Equals(name, ".IMPSRC"))
435                     return Substring_InitStr(IMPSRC);
436           if (Substring_Equals(name, ".MEMBER"))
437                     return Substring_InitStr(MEMBER);
438           if (Substring_Equals(name, ".OODATE"))
439                     return Substring_InitStr(OODATE);
440           if (Substring_Equals(name, ".PREFIX"))
441                     return Substring_InitStr(PREFIX);
442           if (Substring_Equals(name, ".TARGET"))
443                     return Substring_InitStr(TARGET);
444 
445           /* GNU make has an additional alias $^ == ${.ALLSRC}. */
446 
447           if (Substring_Equals(name, ".SHELL") && shellPath == NULL)
448                     Shell_Init();
449 
450           return name;
451 }
452 
453 static Var *
GNode_FindVar(GNode * scope,Substring varname,unsigned hash)454 GNode_FindVar(GNode *scope, Substring varname, unsigned hash)
455 {
456           return HashTable_FindValueBySubstringHash(&scope->vars, varname, hash);
457 }
458 
459 /*
460  * Find the variable in the scope, and maybe in other scopes as well.
461  *
462  * Input:
463  *        name                name to find, is not expanded any further
464  *        scope               scope in which to look first
465  *        elsewhere true to look in other scopes as well
466  *
467  * Results:
468  *        The found variable, or NULL if the variable does not exist.
469  *        If the variable is short-lived (such as environment variables), it
470  *        must be freed using VarFreeShortLived after use.
471  */
472 static Var *
VarFindSubstring(Substring name,GNode * scope,bool elsewhere)473 VarFindSubstring(Substring name, GNode *scope, bool elsewhere)
474 {
475           Var *var;
476           unsigned nameHash;
477 
478           /* Replace '.TARGET' with '@', likewise for other local variables. */
479           name = CanonicalVarname(name);
480           nameHash = Hash_Substring(name);
481 
482           var = GNode_FindVar(scope, name, nameHash);
483           if (!elsewhere)
484                     return var;
485 
486           if (var == NULL && scope != SCOPE_CMDLINE)
487                     var = GNode_FindVar(SCOPE_CMDLINE, name, nameHash);
488 
489           if (!opts.checkEnvFirst && var == NULL && scope != SCOPE_GLOBAL) {
490                     var = GNode_FindVar(SCOPE_GLOBAL, name, nameHash);
491                     if (var == NULL && scope != SCOPE_INTERNAL) {
492                               /* SCOPE_INTERNAL is subordinate to SCOPE_GLOBAL */
493                               var = GNode_FindVar(SCOPE_INTERNAL, name, nameHash);
494                     }
495           }
496 
497           if (var == NULL) {
498                     FStr envName = Substring_Str(name);
499                     const char *envValue = getenv(envName.str);
500                     if (envValue != NULL)
501                               return VarNew(envName, envValue, true, true, false);
502                     FStr_Done(&envName);
503 
504                     if (opts.checkEnvFirst && scope != SCOPE_GLOBAL) {
505                               var = GNode_FindVar(SCOPE_GLOBAL, name, nameHash);
506                               if (var == NULL && scope != SCOPE_INTERNAL)
507                                         var = GNode_FindVar(SCOPE_INTERNAL, name,
508                                             nameHash);
509                               return var;
510                     }
511 
512                     return NULL;
513           }
514 
515           return var;
516 }
517 
518 static Var *
VarFind(const char * name,GNode * scope,bool elsewhere)519 VarFind(const char *name, GNode *scope, bool elsewhere)
520 {
521           return VarFindSubstring(Substring_InitStr(name), scope, elsewhere);
522 }
523 
524 /* If the variable is short-lived, free it, including its value. */
525 static void
VarFreeShortLived(Var * v)526 VarFreeShortLived(Var *v)
527 {
528           if (!v->shortLived)
529                     return;
530 
531           FStr_Done(&v->name);
532           Buf_Done(&v->val);
533           free(v);
534 }
535 
536 static const char *
ValueDescription(const char * value)537 ValueDescription(const char *value)
538 {
539           if (value[0] == '\0')
540                     return "# (empty)";
541           if (ch_isspace(value[strlen(value) - 1]))
542                     return "# (ends with space)";
543           return "";
544 }
545 
546 /* Add a new variable of the given name and value to the given scope. */
547 static Var *
VarAdd(const char * name,const char * value,GNode * scope,VarSetFlags flags)548 VarAdd(const char *name, const char *value, GNode *scope, VarSetFlags flags)
549 {
550           HashEntry *he = HashTable_CreateEntry(&scope->vars, name, NULL);
551           Var *v = VarNew(FStr_InitRefer(/* aliased to */ he->key), value,
552               false, false, (flags & VAR_SET_READONLY) != 0);
553           HashEntry_Set(he, v);
554           DEBUG4(VAR, "%s: %s = %s%s\n",
555               scope->name, name, value, ValueDescription(value));
556           return v;
557 }
558 
559 /*
560  * Remove a variable from a scope, freeing all related memory as well.
561  * The variable name is kept as-is, it is not expanded.
562  */
563 void
Var_Delete(GNode * scope,const char * varname)564 Var_Delete(GNode *scope, const char *varname)
565 {
566           HashEntry *he = HashTable_FindEntry(&scope->vars, varname);
567           Var *v;
568 
569           if (he == NULL) {
570                     DEBUG2(VAR, "%s: ignoring delete '%s' as it is not found\n",
571                         scope->name, varname);
572                     return;
573           }
574 
575           v = he->value;
576           if (v->readOnlyLoud) {
577                     Parse_Error(PARSE_FATAL,
578                         "Cannot delete \"%s\" as it is read-only",
579                         v->name.str);
580                     return;
581           }
582           if (v->readOnly) {
583                     DEBUG2(VAR, "%s: ignoring delete '%s' as it is read-only\n",
584                         scope->name, varname);
585                     return;
586           }
587           if (v->inUse) {
588                     Parse_Error(PARSE_FATAL,
589                         "Cannot delete variable \"%s\" while it is used",
590                         v->name.str);
591                     return;
592           }
593 
594           DEBUG2(VAR, "%s: delete %s\n", scope->name, varname);
595           if (v->exported)
596                     unsetenv(v->name.str);
597           if (strcmp(v->name.str, ".MAKE.EXPORTED") == 0)
598                     var_exportedVars = VAR_EXPORTED_NONE;
599 
600           assert(v->name.freeIt == NULL);
601           HashTable_DeleteEntry(&scope->vars, he);
602           Buf_Done(&v->val);
603           free(v);
604 }
605 
606 #ifdef CLEANUP
607 void
Var_DeleteAll(GNode * scope)608 Var_DeleteAll(GNode *scope)
609 {
610           HashIter hi;
611           HashIter_Init(&hi, &scope->vars);
612           while (HashIter_Next(&hi)) {
613                     Var *v = hi.entry->value;
614                     Buf_Done(&v->val);
615                     free(v);
616           }
617 }
618 #endif
619 
620 /*
621  * Undefine one or more variables from the global scope.
622  * The argument is expanded exactly once and then split into words.
623  */
624 void
Var_Undef(const char * arg)625 Var_Undef(const char *arg)
626 {
627           char *expanded;
628           Words varnames;
629           size_t i;
630 
631           if (arg[0] == '\0') {
632                     Parse_Error(PARSE_FATAL,
633                         "The .undef directive requires an argument");
634                     return;
635           }
636 
637           expanded = Var_Subst(arg, SCOPE_GLOBAL, VARE_EVAL);
638           if (expanded == var_Error) {
639                     /* TODO: Make this part of the code reachable. */
640                     Parse_Error(PARSE_FATAL,
641                         "Error in variable names to be undefined");
642                     return;
643           }
644 
645           varnames = Str_Words(expanded, false);
646           if (varnames.len == 1 && varnames.words[0][0] == '\0')
647                     varnames.len = 0;
648 
649           for (i = 0; i < varnames.len; i++) {
650                     const char *varname = varnames.words[i];
651                     Global_Delete(varname);
652           }
653 
654           Words_Free(varnames);
655           free(expanded);
656 }
657 
658 static bool
MayExport(const char * name)659 MayExport(const char *name)
660 {
661           if (name[0] == '.')
662                     return false;       /* skip internals */
663           if (name[0] == '-')
664                     return false;       /* skip misnamed variables */
665           if (name[1] == '\0') {
666                     /*
667                      * A single char.
668                      * If it is one of the variables that should only appear in
669                      * local scope, skip it, else we can get Var_Subst
670                      * into a loop.
671                      */
672                     switch (name[0]) {
673                     case '@':
674                     case '%':
675                     case '*':
676                     case '!':
677                               return false;
678                     }
679           }
680           return true;
681 }
682 
683 static bool
ExportVarEnv(Var * v,GNode * scope)684 ExportVarEnv(Var *v, GNode *scope)
685 {
686           const char *name = v->name.str;
687           char *val = v->val.data;
688           char *expr;
689 
690           if (v->exported && !v->reexport)
691                     return false;       /* nothing to do */
692 
693           if (strchr(val, '$') == NULL) {
694                     if (!v->exported)
695                               setenv(name, val, 1);
696                     return true;
697           }
698 
699           if (v->inUse)
700                     return false;       /* see EMPTY_SHELL in directive-export.mk */
701 
702           /* XXX: name is injected without escaping it */
703           expr = str_concat3("${", name, "}");
704           val = Var_Subst(expr, scope, VARE_EVAL);
705           if (scope != SCOPE_GLOBAL) {
706                     /* we will need to re-export the global version */
707                     v = VarFind(name, SCOPE_GLOBAL, false);
708                     if (v != NULL)
709                               v->exported = false;
710           }
711           /* TODO: handle errors */
712           setenv(name, val, 1);
713           free(val);
714           free(expr);
715           return true;
716 }
717 
718 static bool
ExportVarPlain(Var * v)719 ExportVarPlain(Var *v)
720 {
721           if (strchr(v->val.data, '$') == NULL) {
722                     setenv(v->name.str, v->val.data, 1);
723                     v->exported = true;
724                     v->reexport = false;
725                     return true;
726           }
727 
728           /*
729            * Flag the variable as something we need to re-export.
730            * No point actually exporting it now though,
731            * the child process can do it at the last minute.
732            * Avoid calling setenv more often than necessary since it can leak.
733            */
734           v->exported = true;
735           v->reexport = true;
736           return true;
737 }
738 
739 static bool
ExportVarLiteral(Var * v)740 ExportVarLiteral(Var *v)
741 {
742           if (v->exported && !v->reexport)
743                     return false;
744 
745           if (!v->exported)
746                     setenv(v->name.str, v->val.data, 1);
747 
748           return true;
749 }
750 
751 /*
752  * Mark a single variable to be exported later for subprocesses.
753  *
754  * Internal variables are not exported.
755  */
756 static bool
ExportVar(const char * name,GNode * scope,VarExportMode mode)757 ExportVar(const char *name, GNode *scope, VarExportMode mode)
758 {
759           Var *v;
760 
761           if (!MayExport(name))
762                     return false;
763 
764           v = VarFind(name, scope, false);
765           if (v == NULL && scope != SCOPE_GLOBAL)
766                     v = VarFind(name, SCOPE_GLOBAL, false);
767           if (v == NULL)
768                     return false;
769 
770           if (mode == VEM_ENV)
771                     return ExportVarEnv(v, scope);
772           else if (mode == VEM_PLAIN)
773                     return ExportVarPlain(v);
774           else
775                     return ExportVarLiteral(v);
776 }
777 
778 /*
779  * Actually export the variables that have been marked as needing to be
780  * re-exported.
781  */
782 void
Var_ReexportVars(GNode * scope)783 Var_ReexportVars(GNode *scope)
784 {
785           char *xvarnames;
786 
787           /*
788            * Several make implementations support this sort of mechanism for
789            * tracking recursion - but each uses a different name.
790            * We allow the makefiles to update MAKELEVEL and ensure
791            * children see a correctly incremented value.
792            */
793           char level_buf[21];
794           snprintf(level_buf, sizeof level_buf, "%d", makelevel + 1);
795           setenv(MAKE_LEVEL_ENV, level_buf, 1);
796 
797           if (var_exportedVars == VAR_EXPORTED_NONE)
798                     return;
799 
800           if (var_exportedVars == VAR_EXPORTED_ALL) {
801                     HashIter hi;
802 
803                     /* Ouch! Exporting all variables at once is crazy. */
804                     HashIter_Init(&hi, &SCOPE_GLOBAL->vars);
805                     while (HashIter_Next(&hi)) {
806                               Var *var = hi.entry->value;
807                               ExportVar(var->name.str, scope, VEM_ENV);
808                     }
809                     return;
810           }
811 
812           xvarnames = Var_Subst("${.MAKE.EXPORTED:O:u}", SCOPE_GLOBAL,
813               VARE_EVAL);
814           /* TODO: handle errors */
815           if (xvarnames[0] != '\0') {
816                     Words varnames = Str_Words(xvarnames, false);
817                     size_t i;
818 
819                     for (i = 0; i < varnames.len; i++)
820                               ExportVar(varnames.words[i], scope, VEM_ENV);
821                     Words_Free(varnames);
822           }
823           free(xvarnames);
824 }
825 
826 static void
ExportVars(const char * varnames,bool isExport,VarExportMode mode)827 ExportVars(const char *varnames, bool isExport, VarExportMode mode)
828 /* TODO: try to combine the parameters 'isExport' and 'mode'. */
829 {
830           Words words = Str_Words(varnames, false);
831           size_t i;
832 
833           if (words.len == 1 && words.words[0][0] == '\0')
834                     words.len = 0;
835 
836           for (i = 0; i < words.len; i++) {
837                     const char *varname = words.words[i];
838                     if (!ExportVar(varname, SCOPE_GLOBAL, mode))
839                               continue;
840 
841                     if (var_exportedVars == VAR_EXPORTED_NONE)
842                               var_exportedVars = VAR_EXPORTED_SOME;
843 
844                     if (isExport && mode == VEM_PLAIN)
845                               Global_Append(".MAKE.EXPORTED", varname);
846           }
847           Words_Free(words);
848 }
849 
850 static void
ExportVarsExpand(const char * uvarnames,bool isExport,VarExportMode mode)851 ExportVarsExpand(const char *uvarnames, bool isExport, VarExportMode mode)
852 {
853           char *xvarnames = Var_Subst(uvarnames, SCOPE_GLOBAL, VARE_EVAL);
854           /* TODO: handle errors */
855           ExportVars(xvarnames, isExport, mode);
856           free(xvarnames);
857 }
858 
859 /* Export the named variables, or all variables. */
860 void
Var_Export(VarExportMode mode,const char * varnames)861 Var_Export(VarExportMode mode, const char *varnames)
862 {
863           if (mode == VEM_ALL) {
864                     var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
865                     return;
866           } else if (mode == VEM_PLAIN && varnames[0] == '\0') {
867                     Parse_Error(PARSE_WARNING, ".export requires an argument.");
868                     return;
869           }
870 
871           ExportVarsExpand(varnames, true, mode);
872 }
873 
874 void
Var_ExportVars(const char * varnames)875 Var_ExportVars(const char *varnames)
876 {
877           ExportVarsExpand(varnames, false, VEM_PLAIN);
878 }
879 
880 
881 static void
ClearEnv(void)882 ClearEnv(void)
883 {
884           const char *level;
885           char **newenv;
886 
887           level = getenv(MAKE_LEVEL_ENV);         /* we should preserve this */
888           if (environ == savedEnv) {
889                     /* we have been here before! */
890                     newenv = bmake_realloc(environ, 2 * sizeof(char *));
891           } else {
892                     if (savedEnv != NULL) {
893                               free(savedEnv);
894                               savedEnv = NULL;
895                     }
896                     newenv = bmake_malloc(2 * sizeof(char *));
897           }
898 
899           /* Note: we cannot safely free() the original environ. */
900           environ = savedEnv = newenv;
901           newenv[0] = NULL;
902           newenv[1] = NULL;
903           if (level != NULL && *level != '\0')
904                     setenv(MAKE_LEVEL_ENV, level, 1);
905 }
906 
907 static void
GetVarnamesToUnexport(bool isEnv,const char * arg,FStr * out_varnames,UnexportWhat * out_what)908 GetVarnamesToUnexport(bool isEnv, const char *arg,
909                           FStr *out_varnames, UnexportWhat *out_what)
910 {
911           UnexportWhat what;
912           FStr varnames = FStr_InitRefer("");
913 
914           if (isEnv) {
915                     if (arg[0] != '\0') {
916                               Parse_Error(PARSE_FATAL,
917                                   "The directive .unexport-env does not take "
918                                   "arguments");
919                               /* continue anyway */
920                     }
921                     what = UNEXPORT_ENV;
922 
923           } else {
924                     what = arg[0] != '\0' ? UNEXPORT_NAMED : UNEXPORT_ALL;
925                     if (what == UNEXPORT_NAMED)
926                               varnames = FStr_InitRefer(arg);
927           }
928 
929           if (what != UNEXPORT_NAMED) {
930                     char *expanded = Var_Subst("${.MAKE.EXPORTED:O:u}",
931                         SCOPE_GLOBAL, VARE_EVAL);
932                     /* TODO: handle errors */
933                     varnames = FStr_InitOwn(expanded);
934           }
935 
936           *out_varnames = varnames;
937           *out_what = what;
938 }
939 
940 static void
UnexportVar(Substring varname,UnexportWhat what)941 UnexportVar(Substring varname, UnexportWhat what)
942 {
943           Var *v = VarFindSubstring(varname, SCOPE_GLOBAL, false);
944           if (v == NULL) {
945                     DEBUG2(VAR, "Not unexporting \"%.*s\" (not found)\n",
946                         (int)Substring_Length(varname), varname.start);
947                     return;
948           }
949 
950           DEBUG2(VAR, "Unexporting \"%.*s\"\n",
951               (int)Substring_Length(varname), varname.start);
952           if (what != UNEXPORT_ENV && v->exported && !v->reexport)
953                     unsetenv(v->name.str);
954           v->exported = false;
955           v->reexport = false;
956 
957           if (what == UNEXPORT_NAMED) {
958                     /* Remove the variable names from .MAKE.EXPORTED. */
959                     /* XXX: v->name is injected without escaping it */
960                     char *expr = str_concat3(
961                         "${.MAKE.EXPORTED:N", v->name.str, "}");
962                     char *filtered = Var_Subst(expr, SCOPE_GLOBAL, VARE_EVAL);
963                     /* TODO: handle errors */
964                     Global_Set(".MAKE.EXPORTED", filtered);
965                     free(filtered);
966                     free(expr);
967           }
968 }
969 
970 static void
UnexportVars(const char * varnames,UnexportWhat what)971 UnexportVars(const char *varnames, UnexportWhat what)
972 {
973           size_t i;
974           SubstringWords words;
975 
976           if (what == UNEXPORT_ENV)
977                     ClearEnv();
978 
979           words = Substring_Words(varnames, false);
980           for (i = 0; i < words.len; i++)
981                     UnexportVar(words.words[i], what);
982           SubstringWords_Free(words);
983 
984           if (what != UNEXPORT_NAMED)
985                     Global_Delete(".MAKE.EXPORTED");
986 }
987 
988 /* Handle the .unexport and .unexport-env directives. */
989 void
Var_UnExport(bool isEnv,const char * arg)990 Var_UnExport(bool isEnv, const char *arg)
991 {
992           UnexportWhat what;
993           FStr varnames;
994 
995           GetVarnamesToUnexport(isEnv, arg, &varnames, &what);
996           UnexportVars(varnames.str, what);
997           FStr_Done(&varnames);
998 }
999 
1000 /* Set the variable to the value; the name is not expanded. */
1001 void
Var_SetWithFlags(GNode * scope,const char * name,const char * val,VarSetFlags flags)1002 Var_SetWithFlags(GNode *scope, const char *name, const char *val,
1003                      VarSetFlags flags)
1004 {
1005           Var *v;
1006 
1007           assert(val != NULL);
1008           if (name[0] == '\0') {
1009                     DEBUG3(VAR,
1010                         "%s: ignoring '%s = %s' as the variable name is empty\n",
1011                         scope->name, name, val);
1012                     return;
1013           }
1014 
1015           if (scope == SCOPE_GLOBAL
1016               && VarFind(name, SCOPE_CMDLINE, false) != NULL) {
1017                     /*
1018                      * The global variable would not be visible anywhere.
1019                      * Therefore, there is no point in setting it at all.
1020                      */
1021                     DEBUG3(VAR,
1022                         "%s: ignoring '%s = %s' "
1023                         "due to a command line variable of the same name\n",
1024                         scope->name, name, val);
1025                     return;
1026           }
1027 
1028           /*
1029            * Only look for a variable in the given scope since anything set
1030            * here will override anything in a lower scope, so there's not much
1031            * point in searching them all.
1032            */
1033           v = VarFind(name, scope, false);
1034           if (v == NULL) {
1035                     if (scope == SCOPE_CMDLINE && !(flags & VAR_SET_NO_EXPORT)) {
1036                               /*
1037                                * This variable would normally prevent the same name
1038                                * being added to SCOPE_GLOBAL, so delete it from
1039                                * there if needed. Otherwise -V name may show the
1040                                * wrong value.
1041                                *
1042                                * See ExistsInCmdline.
1043                                */
1044                               Var *gl = VarFind(name, SCOPE_GLOBAL, false);
1045                               if (gl != NULL && strcmp(gl->val.data, val) == 0) {
1046                                         DEBUG3(VAR,
1047                                             "%s: ignoring to override the global "
1048                                             "'%s = %s' from a command line variable "
1049                                             "as the value wouldn't change\n",
1050                                             scope->name, name, val);
1051                               } else if (gl != NULL && gl->readOnlyLoud)
1052                                         Parse_Error(PARSE_FATAL,
1053                                             "Cannot override "
1054                                             "read-only global variable \"%s\" "
1055                                             "with a command line variable", name);
1056                               else
1057                                         Var_Delete(SCOPE_GLOBAL, name);
1058                     }
1059                     if (strcmp(name, ".SUFFIXES") == 0) {
1060                               /* special: treat as read-only */
1061                               DEBUG3(VAR,
1062                                   "%s: ignoring '%s = %s' as it is read-only\n",
1063                                   scope->name, name, val);
1064                               return;
1065                     }
1066                     v = VarAdd(name, val, scope, flags);
1067           } else {
1068                     if (v->readOnlyLoud) {
1069                               Parse_Error(PARSE_FATAL,
1070                                   "Cannot overwrite \"%s\" as it is read-only",
1071                                   name);
1072                               return;
1073                     }
1074                     if (v->readOnly && !(flags & VAR_SET_READONLY)) {
1075                               DEBUG3(VAR,
1076                                   "%s: ignoring '%s = %s' as it is read-only\n",
1077                                   scope->name, name, val);
1078                               return;
1079                     }
1080                     Buf_Clear(&v->val);
1081                     Buf_AddStr(&v->val, val);
1082 
1083                     DEBUG4(VAR, "%s: %s = %s%s\n",
1084                         scope->name, name, val, ValueDescription(val));
1085                     if (v->exported)
1086                               ExportVar(name, scope, VEM_PLAIN);
1087           }
1088 
1089           if (scope == SCOPE_CMDLINE) {
1090                     v->fromCmd = true;
1091 
1092                     /*
1093                      * Any variables given on the command line are automatically
1094                      * exported to the environment (as per POSIX standard), except
1095                      * for internals.
1096                      */
1097                     if (!(flags & VAR_SET_NO_EXPORT)) {
1098 
1099                               /*
1100                                * If requested, don't export these in the
1101                                * environment individually.  We still put
1102                                * them in .MAKEOVERRIDES so that the
1103                                * command-line settings continue to override
1104                                * Makefile settings.
1105                                */
1106                               if (!opts.varNoExportEnv && name[0] != '.')
1107                                         setenv(name, val, 1);
1108 
1109                               if (!(flags & VAR_SET_INTERNAL))
1110                                         Global_Append(".MAKEOVERRIDES", name);
1111                     }
1112           }
1113 
1114           if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0)
1115                     save_dollars = ParseBoolean(val, save_dollars);
1116 
1117           if (v != NULL)
1118                     VarFreeShortLived(v);
1119 }
1120 
1121 void
Var_Set(GNode * scope,const char * name,const char * val)1122 Var_Set(GNode *scope, const char *name, const char *val)
1123 {
1124           Var_SetWithFlags(scope, name, val, VAR_SET_NONE);
1125 }
1126 
1127 /*
1128  * In the scope, expand the variable name once, then create the variable or
1129  * replace its value.
1130  */
1131 void
Var_SetExpand(GNode * scope,const char * name,const char * val)1132 Var_SetExpand(GNode *scope, const char *name, const char *val)
1133 {
1134           FStr varname = FStr_InitRefer(name);
1135 
1136           assert(val != NULL);
1137 
1138           Var_Expand(&varname, scope, VARE_EVAL);
1139 
1140           if (varname.str[0] == '\0') {
1141                     DEBUG4(VAR,
1142                         "%s: ignoring '%s = %s' "
1143                         "as the variable name '%s' expands to empty\n",
1144                         scope->name, varname.str, val, name);
1145           } else
1146                     Var_SetWithFlags(scope, varname.str, val, VAR_SET_NONE);
1147 
1148           FStr_Done(&varname);
1149 }
1150 
1151 void
Global_Set(const char * name,const char * value)1152 Global_Set(const char *name, const char *value)
1153 {
1154           Var_Set(SCOPE_GLOBAL, name, value);
1155 }
1156 
1157 void
Global_Delete(const char * name)1158 Global_Delete(const char *name)
1159 {
1160           Var_Delete(SCOPE_GLOBAL, name);
1161 }
1162 
1163 void
Global_Set_ReadOnly(const char * name,const char * value)1164 Global_Set_ReadOnly(const char *name, const char *value)
1165 {
1166           Var_SetWithFlags(SCOPE_GLOBAL, name, value, VAR_SET_NONE);
1167           VarFind(name, SCOPE_GLOBAL, false)->readOnlyLoud = true;
1168 }
1169 
1170 /*
1171  * Append the value to the named variable.
1172  *
1173  * If the variable doesn't exist, it is created.  Otherwise a single space
1174  * and the given value are appended.
1175  */
1176 void
Var_Append(GNode * scope,const char * name,const char * val)1177 Var_Append(GNode *scope, const char *name, const char *val)
1178 {
1179           Var *v;
1180 
1181           v = VarFind(name, scope, scope == SCOPE_GLOBAL);
1182 
1183           if (v == NULL) {
1184                     Var_SetWithFlags(scope, name, val, VAR_SET_NONE);
1185           } else if (v->readOnlyLoud) {
1186                     Parse_Error(PARSE_FATAL,
1187                         "Cannot append to \"%s\" as it is read-only", name);
1188                     return;
1189           } else if (v->readOnly) {
1190                     DEBUG3(VAR, "%s: ignoring '%s += %s' as it is read-only\n",
1191                         scope->name, name, val);
1192           } else if (scope == SCOPE_CMDLINE || !v->fromCmd) {
1193                     Buf_AddByte(&v->val, ' ');
1194                     Buf_AddStr(&v->val, val);
1195 
1196                     DEBUG3(VAR, "%s: %s = %s\n", scope->name, name, v->val.data);
1197 
1198                     if (v->fromEnvironment) {
1199                               /* See VarAdd. */
1200                               HashEntry *he =
1201                                   HashTable_CreateEntry(&scope->vars, name, NULL);
1202                               HashEntry_Set(he, v);
1203                               FStr_Done(&v->name);
1204                               v->name = FStr_InitRefer(/* aliased to */ he->key);
1205                               v->shortLived = false;
1206                               v->fromEnvironment = false;
1207                     }
1208           }
1209 }
1210 
1211 /*
1212  * In the scope, expand the variable name once.  If the variable exists in the
1213  * scope, add a space and the value, otherwise set the variable to the value.
1214  *
1215  * Appending to an environment variable only works in the global scope, that
1216  * is, for variable assignments in makefiles, but not inside conditions or the
1217  * commands of a target.
1218  */
1219 void
Var_AppendExpand(GNode * scope,const char * name,const char * val)1220 Var_AppendExpand(GNode *scope, const char *name, const char *val)
1221 {
1222           FStr xname = FStr_InitRefer(name);
1223 
1224           assert(val != NULL);
1225 
1226           Var_Expand(&xname, scope, VARE_EVAL);
1227           if (xname.str != name && xname.str[0] == '\0')
1228                     DEBUG4(VAR,
1229                         "%s: ignoring '%s += %s' "
1230                         "as the variable name '%s' expands to empty\n",
1231                         scope->name, xname.str, val, name);
1232           else
1233                     Var_Append(scope, xname.str, val);
1234 
1235           FStr_Done(&xname);
1236 }
1237 
1238 void
Global_Append(const char * name,const char * value)1239 Global_Append(const char *name, const char *value)
1240 {
1241           Var_Append(SCOPE_GLOBAL, name, value);
1242 }
1243 
1244 bool
Var_Exists(GNode * scope,const char * name)1245 Var_Exists(GNode *scope, const char *name)
1246 {
1247           Var *v = VarFind(name, scope, true);
1248           if (v == NULL)
1249                     return false;
1250 
1251           VarFreeShortLived(v);
1252           return true;
1253 }
1254 
1255 /*
1256  * See if the given variable exists, in the given scope or in other
1257  * fallback scopes.
1258  *
1259  * Input:
1260  *        scope               scope in which to start search
1261  *        name                name of the variable to find, is expanded once
1262  */
1263 bool
Var_ExistsExpand(GNode * scope,const char * name)1264 Var_ExistsExpand(GNode *scope, const char *name)
1265 {
1266           FStr varname = FStr_InitRefer(name);
1267           bool exists;
1268 
1269           Var_Expand(&varname, scope, VARE_EVAL);
1270           exists = Var_Exists(scope, varname.str);
1271           FStr_Done(&varname);
1272           return exists;
1273 }
1274 
1275 /*
1276  * Return the unexpanded value of the given variable in the given scope,
1277  * falling back to the command, global and environment scopes, in this order,
1278  * but see the -e option.
1279  *
1280  * Input:
1281  *        name                the name to find, is not expanded any further
1282  *
1283  * Results:
1284  *        The value if the variable exists, NULL if it doesn't.
1285  *        The value is valid until the next modification to any variable.
1286  */
1287 FStr
Var_Value(GNode * scope,const char * name)1288 Var_Value(GNode *scope, const char *name)
1289 {
1290           Var *v = VarFind(name, scope, true);
1291           char *value;
1292 
1293           if (v == NULL)
1294                     return FStr_InitRefer(NULL);
1295 
1296           if (!v->shortLived)
1297                     return FStr_InitRefer(v->val.data);
1298 
1299           value = v->val.data;
1300           v->val.data = NULL;
1301           VarFreeShortLived(v);
1302 
1303           return FStr_InitOwn(value);
1304 }
1305 
1306 /* Set or clear the read-only attribute of the variable if it exists. */
1307 void
Var_ReadOnly(const char * name,bool bf)1308 Var_ReadOnly(const char *name, bool bf)
1309 {
1310           Var *v;
1311 
1312           v = VarFind(name, SCOPE_GLOBAL, false);
1313           if (v == NULL) {
1314                     DEBUG1(VAR, "Var_ReadOnly: %s not found\n", name);
1315                     return;
1316           }
1317           v->readOnly = bf;
1318           DEBUG2(VAR, "Var_ReadOnly: %s %s\n", name, bf ? "true" : "false");
1319 }
1320 
1321 /*
1322  * Return the unexpanded variable value from this node, without trying to look
1323  * up the variable in any other scope.
1324  */
1325 const char *
GNode_ValueDirect(GNode * gn,const char * name)1326 GNode_ValueDirect(GNode *gn, const char *name)
1327 {
1328           Var *v = VarFind(name, gn, false);
1329           return v != NULL ? v->val.data : NULL;
1330 }
1331 
1332 static VarEvalMode
VarEvalMode_WithoutKeepDollar(VarEvalMode emode)1333 VarEvalMode_WithoutKeepDollar(VarEvalMode emode)
1334 {
1335           return emode == VARE_EVAL_KEEP_DOLLAR_AND_UNDEFINED
1336               ? VARE_EVAL_KEEP_UNDEFINED : emode;
1337 }
1338 
1339 static bool
VarEvalMode_ShouldEval(VarEvalMode emode)1340 VarEvalMode_ShouldEval(VarEvalMode emode)
1341 {
1342           return emode != VARE_PARSE;
1343 }
1344 
1345 static bool
VarEvalMode_ShouldKeepUndef(VarEvalMode emode)1346 VarEvalMode_ShouldKeepUndef(VarEvalMode emode)
1347 {
1348           return emode == VARE_EVAL_KEEP_UNDEFINED ||
1349                  emode == VARE_EVAL_KEEP_DOLLAR_AND_UNDEFINED;
1350 }
1351 
1352 static bool
VarEvalMode_ShouldKeepDollar(VarEvalMode emode)1353 VarEvalMode_ShouldKeepDollar(VarEvalMode emode)
1354 {
1355           return emode == VARE_EVAL_KEEP_DOLLAR_AND_UNDEFINED;
1356 }
1357 
1358 
1359 static void
SepBuf_Init(SepBuf * buf,char sep)1360 SepBuf_Init(SepBuf *buf, char sep)
1361 {
1362           Buf_InitSize(&buf->buf, 32);
1363           buf->needSep = false;
1364           buf->sep = sep;
1365 }
1366 
1367 static void
SepBuf_Sep(SepBuf * buf)1368 SepBuf_Sep(SepBuf *buf)
1369 {
1370           buf->needSep = true;
1371 }
1372 
1373 static void
SepBuf_AddBytes(SepBuf * buf,const char * mem,size_t mem_size)1374 SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1375 {
1376           if (mem_size == 0)
1377                     return;
1378           if (buf->needSep && buf->sep != '\0') {
1379                     Buf_AddByte(&buf->buf, buf->sep);
1380                     buf->needSep = false;
1381           }
1382           Buf_AddBytes(&buf->buf, mem, mem_size);
1383 }
1384 
1385 static void
SepBuf_AddRange(SepBuf * buf,const char * start,const char * end)1386 SepBuf_AddRange(SepBuf *buf, const char *start, const char *end)
1387 {
1388           SepBuf_AddBytes(buf, start, (size_t)(end - start));
1389 }
1390 
1391 static void
SepBuf_AddStr(SepBuf * buf,const char * str)1392 SepBuf_AddStr(SepBuf *buf, const char *str)
1393 {
1394           SepBuf_AddBytes(buf, str, strlen(str));
1395 }
1396 
1397 static void
SepBuf_AddSubstring(SepBuf * buf,Substring sub)1398 SepBuf_AddSubstring(SepBuf *buf, Substring sub)
1399 {
1400           SepBuf_AddRange(buf, sub.start, sub.end);
1401 }
1402 
1403 static char *
SepBuf_DoneData(SepBuf * buf)1404 SepBuf_DoneData(SepBuf *buf)
1405 {
1406           return Buf_DoneData(&buf->buf);
1407 }
1408 
1409 
1410 /*
1411  * This callback for ModifyWords gets a single word from an expression
1412  * and typically adds a modification of this word to the buffer. It may also
1413  * do nothing or add several words.
1414  *
1415  * For example, when evaluating the modifier ':M*b' in ${:Ua b c:M*b}, the
1416  * callback is called 3 times, once for "a", "b" and "c".
1417  *
1418  * Some ModifyWord functions assume that they are always passed a
1419  * null-terminated substring, which is currently guaranteed but may change in
1420  * the future.
1421  */
1422 typedef void (*ModifyWordProc)(Substring word, SepBuf *buf, void *data);
1423 
1424 
1425 static void
ModifyWord_Head(Substring word,SepBuf * buf,void * dummy MAKE_ATTR_UNUSED)1426 ModifyWord_Head(Substring word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1427 {
1428           SepBuf_AddSubstring(buf, Substring_Dirname(word));
1429 }
1430 
1431 static void
ModifyWord_Tail(Substring word,SepBuf * buf,void * dummy MAKE_ATTR_UNUSED)1432 ModifyWord_Tail(Substring word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1433 {
1434           SepBuf_AddSubstring(buf, Substring_Basename(word));
1435 }
1436 
1437 static void
ModifyWord_Suffix(Substring word,SepBuf * buf,void * dummy MAKE_ATTR_UNUSED)1438 ModifyWord_Suffix(Substring word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1439 {
1440           const char *lastDot = Substring_FindLast(word, '.');
1441           if (lastDot != NULL)
1442                     SepBuf_AddRange(buf, lastDot + 1, word.end);
1443 }
1444 
1445 static void
ModifyWord_Root(Substring word,SepBuf * buf,void * dummy MAKE_ATTR_UNUSED)1446 ModifyWord_Root(Substring word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1447 {
1448           const char *lastDot, *end;
1449 
1450           lastDot = Substring_FindLast(word, '.');
1451           end = lastDot != NULL ? lastDot : word.end;
1452           SepBuf_AddRange(buf, word.start, end);
1453 }
1454 
1455 struct ModifyWord_SysVSubstArgs {
1456           GNode *scope;
1457           Substring lhsPrefix;
1458           bool lhsPercent;
1459           Substring lhsSuffix;
1460           const char *rhs;
1461 };
1462 
1463 static void
ModifyWord_SysVSubst(Substring word,SepBuf * buf,void * data)1464 ModifyWord_SysVSubst(Substring word, SepBuf *buf, void *data)
1465 {
1466           const struct ModifyWord_SysVSubstArgs *args = data;
1467           FStr rhs;
1468           const char *percent;
1469 
1470           if (Substring_IsEmpty(word))
1471                     return;
1472 
1473           if (!Substring_HasPrefix(word, args->lhsPrefix) ||
1474               !Substring_HasSuffix(word, args->lhsSuffix)) {
1475                     SepBuf_AddSubstring(buf, word);
1476                     return;
1477           }
1478 
1479           rhs = FStr_InitRefer(args->rhs);
1480           Var_Expand(&rhs, args->scope, VARE_EVAL);
1481 
1482           percent = args->lhsPercent ? strchr(rhs.str, '%') : NULL;
1483 
1484           if (percent != NULL)
1485                     SepBuf_AddRange(buf, rhs.str, percent);
1486           if (percent != NULL || !args->lhsPercent)
1487                     SepBuf_AddRange(buf,
1488                         word.start + Substring_Length(args->lhsPrefix),
1489                         word.end - Substring_Length(args->lhsSuffix));
1490           SepBuf_AddStr(buf, percent != NULL ? percent + 1 : rhs.str);
1491 
1492           FStr_Done(&rhs);
1493 }
1494 
1495 static const char *
Substring_Find(Substring haystack,Substring needle)1496 Substring_Find(Substring haystack, Substring needle)
1497 {
1498           size_t len, needleLen, i;
1499 
1500           len = Substring_Length(haystack);
1501           needleLen = Substring_Length(needle);
1502           for (i = 0; i + needleLen <= len; i++)
1503                     if (memcmp(haystack.start + i, needle.start, needleLen) == 0)
1504                               return haystack.start + i;
1505           return NULL;
1506 }
1507 
1508 struct ModifyWord_SubstArgs {
1509           Substring lhs;
1510           Substring rhs;
1511           PatternFlags pflags;
1512           bool matched;
1513 };
1514 
1515 static void
ModifyWord_Subst(Substring word,SepBuf * buf,void * data)1516 ModifyWord_Subst(Substring word, SepBuf *buf, void *data)
1517 {
1518           struct ModifyWord_SubstArgs *args = data;
1519           size_t wordLen, lhsLen;
1520           const char *match;
1521 
1522           wordLen = Substring_Length(word);
1523           if (args->pflags.subOnce && args->matched)
1524                     goto nosub;
1525 
1526           lhsLen = Substring_Length(args->lhs);
1527           if (args->pflags.anchorStart) {
1528                     if (wordLen < lhsLen ||
1529                         memcmp(word.start, args->lhs.start, lhsLen) != 0)
1530                               goto nosub;
1531 
1532                     if (args->pflags.anchorEnd && wordLen != lhsLen)
1533                               goto nosub;
1534 
1535                     /* :S,^prefix,replacement, or :S,^whole$,replacement, */
1536                     SepBuf_AddSubstring(buf, args->rhs);
1537                     SepBuf_AddRange(buf, word.start + lhsLen, word.end);
1538                     args->matched = true;
1539                     return;
1540           }
1541 
1542           if (args->pflags.anchorEnd) {
1543                     if (wordLen < lhsLen)
1544                               goto nosub;
1545                     if (memcmp(word.end - lhsLen, args->lhs.start, lhsLen) != 0)
1546                               goto nosub;
1547 
1548                     /* :S,suffix$,replacement, */
1549                     SepBuf_AddRange(buf, word.start, word.end - lhsLen);
1550                     SepBuf_AddSubstring(buf, args->rhs);
1551                     args->matched = true;
1552                     return;
1553           }
1554 
1555           if (Substring_IsEmpty(args->lhs))
1556                     goto nosub;
1557 
1558           /* unanchored case, may match more than once */
1559           while ((match = Substring_Find(word, args->lhs)) != NULL) {
1560                     SepBuf_AddRange(buf, word.start, match);
1561                     SepBuf_AddSubstring(buf, args->rhs);
1562                     args->matched = true;
1563                     word.start = match + lhsLen;
1564                     if (Substring_IsEmpty(word) || !args->pflags.subGlobal)
1565                               break;
1566           }
1567 nosub:
1568           SepBuf_AddSubstring(buf, word);
1569 }
1570 
1571 /* Print the error caused by a regcomp or regexec call. */
1572 static void
RegexError(int reerr,const regex_t * pat,const char * str)1573 RegexError(int reerr, const regex_t *pat, const char *str)
1574 {
1575           size_t errlen = regerror(reerr, pat, NULL, 0);
1576           char *errbuf = bmake_malloc(errlen);
1577           regerror(reerr, pat, errbuf, errlen);
1578           Parse_Error(PARSE_FATAL, "%s: %s", str, errbuf);
1579           free(errbuf);
1580 }
1581 
1582 /* In the modifier ':C', replace a backreference from \0 to \9. */
1583 static void
RegexReplaceBackref(char ref,SepBuf * buf,const char * wp,const regmatch_t * m,size_t nsub)1584 RegexReplaceBackref(char ref, SepBuf *buf, const char *wp,
1585                         const regmatch_t *m, size_t nsub)
1586 {
1587           unsigned n = (unsigned)ref - '0';
1588 
1589           if (n >= nsub)
1590                     Parse_Error(PARSE_FATAL, "No subexpression \\%u", n);
1591           else if (m[n].rm_so == -1) {
1592                     if (opts.strict)
1593                               Error("No match for subexpression \\%u", n);
1594           } else {
1595                     SepBuf_AddRange(buf,
1596                         wp + (size_t)m[n].rm_so,
1597                         wp + (size_t)m[n].rm_eo);
1598           }
1599 }
1600 
1601 /*
1602  * The regular expression matches the word; now add the replacement to the
1603  * buffer, taking back-references from 'wp'.
1604  */
1605 static void
RegexReplace(Substring replace,SepBuf * buf,const char * wp,const regmatch_t * m,size_t nsub)1606 RegexReplace(Substring replace, SepBuf *buf, const char *wp,
1607                const regmatch_t *m, size_t nsub)
1608 {
1609           const char *rp;
1610 
1611           for (rp = replace.start; rp != replace.end; rp++) {
1612                     if (*rp == '\\' && rp + 1 != replace.end &&
1613                         (rp[1] == '&' || rp[1] == '\\'))
1614                               SepBuf_AddBytes(buf, ++rp, 1);
1615                     else if (*rp == '\\' && rp + 1 != replace.end &&
1616                                ch_isdigit(rp[1]))
1617                               RegexReplaceBackref(*++rp, buf, wp, m, nsub);
1618                     else if (*rp == '&') {
1619                               SepBuf_AddRange(buf,
1620                                   wp + (size_t)m[0].rm_so,
1621                                   wp + (size_t)m[0].rm_eo);
1622                     } else
1623                               SepBuf_AddBytes(buf, rp, 1);
1624           }
1625 }
1626 
1627 struct ModifyWord_SubstRegexArgs {
1628           regex_t re;
1629           size_t nsub;
1630           Substring replace;
1631           PatternFlags pflags;
1632           bool matched;
1633 };
1634 
1635 static void
ModifyWord_SubstRegex(Substring word,SepBuf * buf,void * data)1636 ModifyWord_SubstRegex(Substring word, SepBuf *buf, void *data)
1637 {
1638           struct ModifyWord_SubstRegexArgs *args = data;
1639           int xrv;
1640           const char *wp;
1641           int flags = 0;
1642           regmatch_t m[10];
1643 
1644           assert(word.end[0] == '\0');  /* assume null-terminated word */
1645           wp = word.start;
1646           if (args->pflags.subOnce && args->matched)
1647                     goto no_match;
1648 
1649 again:
1650           xrv = regexec(&args->re, wp, args->nsub, m, flags);
1651           if (xrv == 0)
1652                     goto ok;
1653           if (xrv != REG_NOMATCH)
1654                     RegexError(xrv, &args->re, "Unexpected regex error");
1655 no_match:
1656           SepBuf_AddRange(buf, wp, word.end);
1657           return;
1658 
1659 ok:
1660           args->matched = true;
1661           SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so);
1662 
1663           RegexReplace(args->replace, buf, wp, m, args->nsub);
1664 
1665           wp += (size_t)m[0].rm_eo;
1666           if (args->pflags.subGlobal) {
1667                     flags |= REG_NOTBOL;
1668                     if (m[0].rm_so == 0 && m[0].rm_eo == 0 && *wp != '\0') {
1669                               SepBuf_AddBytes(buf, wp, 1);
1670                               wp++;
1671                     }
1672                     if (*wp != '\0')
1673                               goto again;
1674           }
1675           if (*wp != '\0')
1676                     SepBuf_AddStr(buf, wp);
1677 }
1678 
1679 
1680 struct ModifyWord_LoopArgs {
1681           GNode *scope;
1682           const char *var;    /* name of the temporary variable */
1683           const char *body;   /* string to expand */
1684           VarEvalMode emode;
1685 };
1686 
1687 static void
ModifyWord_Loop(Substring word,SepBuf * buf,void * data)1688 ModifyWord_Loop(Substring word, SepBuf *buf, void *data)
1689 {
1690           const struct ModifyWord_LoopArgs *args;
1691           char *s;
1692 
1693           if (Substring_IsEmpty(word))
1694                     return;
1695 
1696           args = data;
1697           assert(word.end[0] == '\0');  /* assume null-terminated word */
1698           Var_SetWithFlags(args->scope, args->var, word.start,
1699               VAR_SET_NO_EXPORT);
1700           s = Var_Subst(args->body, args->scope, args->emode);
1701           /* TODO: handle errors */
1702 
1703           DEBUG2(VAR, "ModifyWord_Loop: expand \"%s\" to \"%s\"\n",
1704               args->body, s);
1705 
1706           if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n'))
1707                     buf->needSep = false;
1708           SepBuf_AddStr(buf, s);
1709           free(s);
1710 }
1711 
1712 
1713 /*
1714  * The :[first..last] modifier selects words from the expression.
1715  * It can also reverse the words.
1716  */
1717 static char *
VarSelectWords(const char * str,int first,int last,char sep,bool oneBigWord)1718 VarSelectWords(const char *str, int first, int last,
1719                  char sep, bool oneBigWord)
1720 {
1721           SubstringWords words;
1722           int len, start, end, step;
1723           int i;
1724 
1725           SepBuf buf;
1726           SepBuf_Init(&buf, sep);
1727 
1728           if (oneBigWord) {
1729                     /* fake what Substring_Words() would do */
1730                     words.len = 1;
1731                     words.words = bmake_malloc(sizeof(words.words[0]));
1732                     words.freeIt = NULL;
1733                     words.words[0] = Substring_InitStr(str); /* no need to copy */
1734           } else {
1735                     words = Substring_Words(str, false);
1736           }
1737 
1738           /* Convert -1 to len, -2 to (len - 1), etc. */
1739           len = (int)words.len;
1740           if (first < 0)
1741                     first += len + 1;
1742           if (last < 0)
1743                     last += len + 1;
1744 
1745           if (first > last) {
1746                     start = (first > len ? len : first) - 1;
1747                     end = last < 1 ? 0 : last - 1;
1748                     step = -1;
1749           } else {
1750                     start = first < 1 ? 0 : first - 1;
1751                     end = last > len ? len : last;
1752                     step = 1;
1753           }
1754 
1755           for (i = start; (step < 0) == (i >= end); i += step) {
1756                     SepBuf_AddSubstring(&buf, words.words[i]);
1757                     SepBuf_Sep(&buf);
1758           }
1759 
1760           SubstringWords_Free(words);
1761 
1762           return SepBuf_DoneData(&buf);
1763 }
1764 
1765 
1766 static void
ModifyWord_Realpath(Substring word,SepBuf * buf,void * data MAKE_ATTR_UNUSED)1767 ModifyWord_Realpath(Substring word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
1768 {
1769           struct stat st;
1770           char rbuf[MAXPATHLEN];
1771           const char *rp;
1772 
1773           assert(word.end[0] == '\0');  /* assume null-terminated word */
1774           rp = cached_realpath(word.start, rbuf);
1775           if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1776                     SepBuf_AddStr(buf, rp);
1777           else
1778                     SepBuf_AddSubstring(buf, word);
1779 }
1780 
1781 
1782 static char *
SubstringWords_JoinFree(SubstringWords words)1783 SubstringWords_JoinFree(SubstringWords words)
1784 {
1785           Buffer buf;
1786           size_t i;
1787 
1788           Buf_Init(&buf);
1789 
1790           for (i = 0; i < words.len; i++) {
1791                     if (i != 0) {
1792                               /*
1793                                * XXX: Use ch->sep instead of ' ', for consistency.
1794                                */
1795                               Buf_AddByte(&buf, ' ');
1796                     }
1797                     Buf_AddRange(&buf, words.words[i].start, words.words[i].end);
1798           }
1799 
1800           SubstringWords_Free(words);
1801 
1802           return Buf_DoneData(&buf);
1803 }
1804 
1805 
1806 /*
1807  * Quote shell meta-characters and space characters in the string.
1808  * If quoteDollar is set, also quote and double any '$' characters.
1809  */
1810 static void
QuoteShell(const char * str,bool quoteDollar,LazyBuf * buf)1811 QuoteShell(const char *str, bool quoteDollar, LazyBuf *buf)
1812 {
1813           const char *p;
1814 
1815           LazyBuf_Init(buf, str);
1816           for (p = str; *p != '\0'; p++) {
1817                     if (*p == '\n') {
1818                               const char *newline = Shell_GetNewline();
1819                               if (newline == NULL)
1820                                         newline = "\\\n";
1821                               LazyBuf_AddStr(buf, newline);
1822                               continue;
1823                     }
1824                     if (ch_isspace(*p) || ch_is_shell_meta(*p))
1825                               LazyBuf_Add(buf, '\\');
1826                     LazyBuf_Add(buf, *p);
1827                     if (quoteDollar && *p == '$')
1828                               LazyBuf_AddStr(buf, "\\$");
1829           }
1830 }
1831 
1832 /*
1833  * Compute the 32-bit hash of the given string, using the MurmurHash3
1834  * algorithm. Output is encoded as 8 hex digits, in Little Endian order.
1835  */
1836 static char *
Hash(const char * str)1837 Hash(const char *str)
1838 {
1839           static const char hexdigits[16] = "0123456789abcdef";
1840           const unsigned char *ustr = (const unsigned char *)str;
1841 
1842           uint32_t h = 0x971e137bU;
1843           uint32_t c1 = 0x95543787U;
1844           uint32_t c2 = 0x2ad7eb25U;
1845           size_t len2 = strlen(str);
1846 
1847           char *buf;
1848           size_t i;
1849 
1850           size_t len;
1851           for (len = len2; len != 0;) {
1852                     uint32_t k = 0;
1853                     switch (len) {
1854                     default:
1855                               k = ((uint32_t)ustr[3] << 24) |
1856                                   ((uint32_t)ustr[2] << 16) |
1857                                   ((uint32_t)ustr[1] << 8) |
1858                                   (uint32_t)ustr[0];
1859                               len -= 4;
1860                               ustr += 4;
1861                               break;
1862                     case 3:
1863                               k |= (uint32_t)ustr[2] << 16;
1864                               /* FALLTHROUGH */
1865                     case 2:
1866                               k |= (uint32_t)ustr[1] << 8;
1867                               /* FALLTHROUGH */
1868                     case 1:
1869                               k |= (uint32_t)ustr[0];
1870                               len = 0;
1871                     }
1872                     c1 = c1 * 5 + 0x7b7d159cU;
1873                     c2 = c2 * 5 + 0x6bce6396U;
1874                     k *= c1;
1875                     k = (k << 11) ^ (k >> 21);
1876                     k *= c2;
1877                     h = (h << 13) ^ (h >> 19);
1878                     h = h * 5 + 0x52dce729U;
1879                     h ^= k;
1880           }
1881           h ^= (uint32_t)len2;
1882           h *= 0x85ebca6b;
1883           h ^= h >> 13;
1884           h *= 0xc2b2ae35;
1885           h ^= h >> 16;
1886 
1887           buf = bmake_malloc(9);
1888           for (i = 0; i < 8; i++) {
1889                     buf[i] = hexdigits[h & 0x0f];
1890                     h >>= 4;
1891           }
1892           buf[8] = '\0';
1893           return buf;
1894 }
1895 
1896 static char *
FormatTime(const char * fmt,time_t t,bool gmt)1897 FormatTime(const char *fmt, time_t t, bool gmt)
1898 {
1899           char buf[BUFSIZ];
1900 
1901           if (t == 0)
1902                     time(&t);
1903           if (*fmt == '\0')
1904                     fmt = "%c";
1905           if (gmt && strchr(fmt, 's') != NULL) {
1906                     /* strftime "%s" only works with localtime, not with gmtime. */
1907                     const char *prev_tz_env = getenv("TZ");
1908                     char *prev_tz = prev_tz_env != NULL
1909                         ? bmake_strdup(prev_tz_env) : NULL;
1910                     setenv("TZ", "UTC", 1);
1911                     strftime(buf, sizeof buf, fmt, localtime(&t));
1912                     if (prev_tz != NULL) {
1913                               setenv("TZ", prev_tz, 1);
1914                               free(prev_tz);
1915                     } else
1916                               unsetenv("TZ");
1917           } else
1918                     strftime(buf, sizeof buf, fmt, (gmt ? gmtime : localtime)(&t));
1919 
1920           buf[sizeof buf - 1] = '\0';
1921           return bmake_strdup(buf);
1922 }
1923 
1924 /*
1925  * The ApplyModifier functions take an expression that is being evaluated.
1926  * Their task is to apply a single modifier to the expression.  This involves
1927  * parsing the modifier, evaluating it and finally updating the value of the
1928  * expression.
1929  *
1930  * Parsing the modifier
1931  *
1932  * If parsing succeeds, the parsing position *pp is updated to point to the
1933  * first character following the modifier, which typically is either ':' or
1934  * ch->endc.  The modifier doesn't have to check for this delimiter character,
1935  * this is done by ApplyModifiers.
1936  *
1937  * XXX: As of 2020-11-15, some modifiers such as :S, :C, :P, :L do not
1938  * need to be followed by a ':' or endc; this was an unintended mistake.
1939  *
1940  * If parsing fails because of a missing delimiter after a modifier part (as
1941  * in the :S, :C or :@ modifiers), return AMR_CLEANUP.
1942  *
1943  * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to
1944  * try the SysV modifier ':from=to' as fallback.  This should only be
1945  * done as long as there have been no side effects from evaluating nested
1946  * variables, to avoid evaluating them more than once.  In this case, the
1947  * parsing position may or may not be updated.  (XXX: Why not? The original
1948  * parsing position is well-known in ApplyModifiers.)
1949  *
1950  * If parsing fails and the SysV modifier ${VAR:from=to} should not be used
1951  * as a fallback, issue an error message using Parse_Error (preferred over
1952  * Error) and then return AMR_CLEANUP, which stops processing the expression.
1953  * (XXX: As of 2020-08-23, evaluation of the string continues nevertheless
1954  * after skipping a few bytes, which results in garbage.)
1955  *
1956  * Evaluating the modifier
1957  *
1958  * After parsing, the modifier is evaluated.  The side effects from evaluating
1959  * nested expressions in the modifier text often already happen
1960  * during parsing though.  For most modifiers this doesn't matter since their
1961  * only noticeable effect is that they update the value of the expression.
1962  * Some modifiers such as ':sh' or '::=' have noticeable side effects though.
1963  *
1964  * Evaluating the modifier usually takes the current value of the
1965  * expression from ch->expr->value, or the variable name from ch->var->name,
1966  * and stores the result back in ch->expr->value via Expr_SetValueOwn or
1967  * Expr_SetValueRefer.
1968  *
1969  * Some modifiers such as :D and :U turn undefined expressions into defined
1970  * expressions using Expr_Define.
1971  */
1972 
1973 typedef enum ExprDefined {
1974           /* The expression is based on a regular, defined variable. */
1975           DEF_REGULAR,
1976           /* The expression is based on an undefined variable. */
1977           DEF_UNDEF,
1978           /*
1979            * The expression started as an undefined expression, but one
1980            * of the modifiers (such as ':D' or ':U') has turned the expression
1981            * from undefined to defined.
1982            */
1983           DEF_DEFINED
1984 } ExprDefined;
1985 
1986 static const char ExprDefined_Name[][10] = {
1987           "regular",
1988           "undefined",
1989           "defined"
1990 };
1991 
1992 #if __STDC_VERSION__ >= 199901L
1993 #define const_member                    const
1994 #else
1995 #define const_member                    /* no const possible */
1996 #endif
1997 
1998 /* An expression based on a variable, such as $@ or ${VAR:Mpattern:Q}. */
1999 typedef struct Expr {
2000           const char *name;
2001           FStr value;
2002           VarEvalMode const_member emode;
2003           GNode *const_member scope;
2004           ExprDefined defined;
2005 } Expr;
2006 
2007 /*
2008  * The status of applying a chain of modifiers to an expression.
2009  *
2010  * The modifiers of an expression are broken into chains of modifiers,
2011  * starting a new nested chain whenever an indirect modifier starts.  There
2012  * are at most 2 nesting levels: the outer one for the direct modifiers, and
2013  * the inner one for the indirect modifiers.
2014  *
2015  * For example, the expression ${VAR:M*:${IND1}:${IND2}:O:u} has 3 chains of
2016  * modifiers:
2017  *
2018  *        Chain 1 starts with the single modifier ':M*'.
2019  *          Chain 2 starts with all modifiers from ${IND1}.
2020  *          Chain 2 ends at the ':' between ${IND1} and ${IND2}.
2021  *          Chain 3 starts with all modifiers from ${IND2}.
2022  *          Chain 3 ends at the ':' after ${IND2}.
2023  *        Chain 1 continues with the 2 modifiers ':O' and ':u'.
2024  *        Chain 1 ends at the final '}' of the expression.
2025  *
2026  * After such a chain ends, its properties no longer have any effect.
2027  *
2028  * See varmod-indirect.mk.
2029  */
2030 typedef struct ModChain {
2031           Expr *expr;
2032           /* '\0' or '{' or '(' */
2033           char const_member startc;
2034           /* '\0' or '}' or ')' */
2035           char const_member endc;
2036           /* Separator when joining words (see the :ts modifier). */
2037           char sep;
2038           /*
2039            * Whether some modifiers that otherwise split the variable value
2040            * into words, like :S and :C, treat the variable value as a single
2041            * big word, possibly containing spaces.
2042            */
2043           bool oneBigWord;
2044 } ModChain;
2045 
2046 static void
Expr_Define(Expr * expr)2047 Expr_Define(Expr *expr)
2048 {
2049           if (expr->defined == DEF_UNDEF)
2050                     expr->defined = DEF_DEFINED;
2051 }
2052 
2053 static const char *
Expr_Str(const Expr * expr)2054 Expr_Str(const Expr *expr)
2055 {
2056           return expr->value.str;
2057 }
2058 
2059 static SubstringWords
Expr_Words(const Expr * expr)2060 Expr_Words(const Expr *expr)
2061 {
2062           return Substring_Words(Expr_Str(expr), false);
2063 }
2064 
2065 static void
Expr_SetValue(Expr * expr,FStr value)2066 Expr_SetValue(Expr *expr, FStr value)
2067 {
2068           FStr_Done(&expr->value);
2069           expr->value = value;
2070 }
2071 
2072 static void
Expr_SetValueOwn(Expr * expr,char * value)2073 Expr_SetValueOwn(Expr *expr, char *value)
2074 {
2075           Expr_SetValue(expr, FStr_InitOwn(value));
2076 }
2077 
2078 static void
Expr_SetValueRefer(Expr * expr,const char * value)2079 Expr_SetValueRefer(Expr *expr, const char *value)
2080 {
2081           Expr_SetValue(expr, FStr_InitRefer(value));
2082 }
2083 
2084 static bool
Expr_ShouldEval(const Expr * expr)2085 Expr_ShouldEval(const Expr *expr)
2086 {
2087           return VarEvalMode_ShouldEval(expr->emode);
2088 }
2089 
2090 static bool
ModChain_ShouldEval(const ModChain * ch)2091 ModChain_ShouldEval(const ModChain *ch)
2092 {
2093           return Expr_ShouldEval(ch->expr);
2094 }
2095 
2096 
2097 typedef enum ApplyModifierResult {
2098           /* Continue parsing */
2099           AMR_OK,
2100           /* Not a match, try the ':from=to' modifier as well. */
2101           AMR_UNKNOWN,
2102           /* Error out without further error message. */
2103           AMR_CLEANUP
2104 } ApplyModifierResult;
2105 
2106 /*
2107  * Allow backslashes to escape the delimiter, $, and \, but don't touch other
2108  * backslashes.
2109  */
2110 static bool
IsEscapedModifierPart(const char * p,char delim,struct ModifyWord_SubstArgs * subst)2111 IsEscapedModifierPart(const char *p, char delim,
2112                           struct ModifyWord_SubstArgs *subst)
2113 {
2114           if (p[0] != '\\' || p[1] == '\0')
2115                     return false;
2116           if (p[1] == delim || p[1] == '\\' || p[1] == '$')
2117                     return true;
2118           return p[1] == '&' && subst != NULL;
2119 }
2120 
2121 /*
2122  * In a part of a modifier, parse a subexpression and evaluate it.
2123  */
2124 static void
ParseModifierPartExpr(const char ** pp,LazyBuf * part,const ModChain * ch,VarEvalMode emode)2125 ParseModifierPartExpr(const char **pp, LazyBuf *part, const ModChain *ch,
2126                           VarEvalMode emode)
2127 {
2128           const char *p = *pp;
2129           FStr nested_val = Var_Parse(&p, ch->expr->scope,
2130               VarEvalMode_WithoutKeepDollar(emode));
2131           /* TODO: handle errors */
2132           if (VarEvalMode_ShouldEval(emode))
2133                     LazyBuf_AddStr(part, nested_val.str);
2134           else
2135                     LazyBuf_AddSubstring(part, Substring_Init(*pp, p));
2136           FStr_Done(&nested_val);
2137           *pp = p;
2138 }
2139 
2140 /*
2141  * In a part of a modifier, parse some text that looks like a subexpression.
2142  * If the text starts with '$(', any '(' and ')' must be balanced.
2143  * If the text starts with '${', any '{' and '}' must be balanced.
2144  * If the text starts with '$', that '$' is copied verbatim, it is not parsed
2145  * as a short-name expression.
2146  */
2147 static void
ParseModifierPartBalanced(const char ** pp,LazyBuf * part)2148 ParseModifierPartBalanced(const char **pp, LazyBuf *part)
2149 {
2150           const char *p = *pp;
2151 
2152           if (p[1] == '(' || p[1] == '{') {
2153                     char startc = p[1];
2154                     int endc = startc == '(' ? ')' : '}';
2155                     int depth = 1;
2156 
2157                     for (p += 2; *p != '\0' && depth > 0; p++) {
2158                               if (p[-1] != '\\') {
2159                                         if (*p == startc)
2160                                                   depth++;
2161                                         if (*p == endc)
2162                                                   depth--;
2163                               }
2164                     }
2165                     LazyBuf_AddSubstring(part, Substring_Init(*pp, p));
2166                     *pp = p;
2167           } else {
2168                     LazyBuf_Add(part, *p);
2169                     *pp = p + 1;
2170           }
2171 }
2172 
2173 /*
2174  * Parse a part of a modifier such as the "from" and "to" in :S/from/to/ or
2175  * the "var" or "replacement ${var}" in :@var@replacement ${var}@, up to and
2176  * including the next unescaped delimiter.  The delimiter, as well as the
2177  * backslash or the dollar, can be escaped with a backslash.
2178  *
2179  * Return true if parsing succeeded, together with the parsed (and possibly
2180  * expanded) part.  In that case, pp points right after the delimiter.  The
2181  * delimiter is not included in the part though.
2182  */
2183 static bool
ParseModifierPart(const char ** pp,char end1,char end2,VarEvalMode emode,ModChain * ch,LazyBuf * part,PatternFlags * out_pflags,struct ModifyWord_SubstArgs * subst)2184 ParseModifierPart(
2185     /* The parsing position, updated upon return */
2186     const char **pp,
2187     char end1,
2188     char end2,
2189     /* Mode for evaluating nested expressions. */
2190     VarEvalMode emode,
2191     ModChain *ch,
2192     LazyBuf *part,
2193     /*
2194      * For the first part of the ':S' modifier, set anchorEnd if the last
2195      * character of the pattern is a $.
2196      */
2197     PatternFlags *out_pflags,
2198     /*
2199      * For the second part of the ':S' modifier, allow ampersands to be
2200      * escaped and replace unescaped ampersands with subst->lhs.
2201      */
2202     struct ModifyWord_SubstArgs *subst
2203 )
2204 {
2205           const char *p = *pp;
2206 
2207           LazyBuf_Init(part, p);
2208           while (*p != '\0' && *p != end1 && *p != end2) {
2209                     if (IsEscapedModifierPart(p, end2, subst)) {
2210                               LazyBuf_Add(part, p[1]);
2211                               p += 2;
2212                     } else if (*p != '$') {       /* Unescaped, simple text */
2213                               if (subst != NULL && *p == '&')
2214                                         LazyBuf_AddSubstring(part, subst->lhs);
2215                               else
2216                                         LazyBuf_Add(part, *p);
2217                               p++;
2218                     } else if (p[1] == end2) {    /* Unescaped '$' at end */
2219                               if (out_pflags != NULL)
2220                                         out_pflags->anchorEnd = true;
2221                               else
2222                                         LazyBuf_Add(part, *p);
2223                               p++;
2224                     } else if (emode == VARE_PARSE_BALANCED)
2225                               ParseModifierPartBalanced(&p, part);
2226                     else
2227                               ParseModifierPartExpr(&p, part, ch, emode);
2228           }
2229 
2230           if (*p != end1 && *p != end2) {
2231                     Parse_Error(PARSE_FATAL,
2232                         "Unfinished modifier after \"%.*s\", expecting \"%c\"",
2233                         (int)(p - *pp), *pp, end2);
2234                     LazyBuf_Done(part);
2235                     *pp = p;
2236                     return false;
2237           }
2238           *pp = p;
2239           if (end1 == end2)
2240                     (*pp)++;
2241 
2242           {
2243                     Substring sub = LazyBuf_Get(part);
2244                     DEBUG2(VAR, "Modifier part: \"%.*s\"\n",
2245                         (int)Substring_Length(sub), sub.start);
2246           }
2247 
2248           return true;
2249 }
2250 
2251 MAKE_INLINE bool
IsDelimiter(char c,const ModChain * ch)2252 IsDelimiter(char c, const ModChain *ch)
2253 {
2254           return c == ':' || c == ch->endc || c == '\0';
2255 }
2256 
2257 /* Test whether mod starts with modname, followed by a delimiter. */
2258 MAKE_INLINE bool
ModMatch(const char * mod,const char * modname,const ModChain * ch)2259 ModMatch(const char *mod, const char *modname, const ModChain *ch)
2260 {
2261           size_t n = strlen(modname);
2262           return strncmp(mod, modname, n) == 0 && IsDelimiter(mod[n], ch);
2263 }
2264 
2265 /* Test whether mod starts with modname, followed by a delimiter or '='. */
2266 MAKE_INLINE bool
ModMatchEq(const char * mod,const char * modname,const ModChain * ch)2267 ModMatchEq(const char *mod, const char *modname, const ModChain *ch)
2268 {
2269           size_t n = strlen(modname);
2270           return strncmp(mod, modname, n) == 0 &&
2271                  (IsDelimiter(mod[n], ch) || mod[n] == '=');
2272 }
2273 
2274 static bool
TryParseIntBase0(const char ** pp,int * out_num)2275 TryParseIntBase0(const char **pp, int *out_num)
2276 {
2277           char *end;
2278           long n;
2279 
2280           errno = 0;
2281           n = strtol(*pp, &end, 0);
2282 
2283           if (end == *pp)
2284                     return false;
2285           if ((n == LONG_MIN || n == LONG_MAX) && errno == ERANGE)
2286                     return false;
2287           if (n < INT_MIN || n > INT_MAX)
2288                     return false;
2289 
2290           *pp = end;
2291           *out_num = (int)n;
2292           return true;
2293 }
2294 
2295 static bool
TryParseSize(const char ** pp,size_t * out_num)2296 TryParseSize(const char **pp, size_t *out_num)
2297 {
2298           char *end;
2299           unsigned long n;
2300 
2301           if (!ch_isdigit(**pp))
2302                     return false;
2303 
2304           errno = 0;
2305           n = strtoul(*pp, &end, 10);
2306           if (n == ULONG_MAX && errno == ERANGE)
2307                     return false;
2308           if (n > SIZE_MAX)
2309                     return false;
2310 
2311           *pp = end;
2312           *out_num = (size_t)n;
2313           return true;
2314 }
2315 
2316 static bool
TryParseChar(const char ** pp,int base,char * out_ch)2317 TryParseChar(const char **pp, int base, char *out_ch)
2318 {
2319           char *end;
2320           unsigned long n;
2321 
2322           if (!ch_isalnum(**pp))
2323                     return false;
2324 
2325           errno = 0;
2326           n = strtoul(*pp, &end, base);
2327           if (n == ULONG_MAX && errno == ERANGE)
2328                     return false;
2329           if (n > UCHAR_MAX)
2330                     return false;
2331 
2332           *pp = end;
2333           *out_ch = (char)n;
2334           return true;
2335 }
2336 
2337 /*
2338  * Modify each word of the expression using the given function and place the
2339  * result back in the expression.
2340  */
2341 static void
ModifyWords(ModChain * ch,ModifyWordProc modifyWord,void * modifyWord_args,bool oneBigWord)2342 ModifyWords(ModChain *ch,
2343               ModifyWordProc modifyWord, void *modifyWord_args,
2344               bool oneBigWord)
2345 {
2346           Expr *expr = ch->expr;
2347           const char *val = Expr_Str(expr);
2348           SepBuf result;
2349           SubstringWords words;
2350           size_t i;
2351           Substring word;
2352 
2353           if (!ModChain_ShouldEval(ch))
2354                     return;
2355 
2356           if (oneBigWord) {
2357                     SepBuf_Init(&result, ch->sep);
2358                     /* XXX: performance: Substring_InitStr calls strlen */
2359                     word = Substring_InitStr(val);
2360                     modifyWord(word, &result, modifyWord_args);
2361                     goto done;
2362           }
2363 
2364           words = Substring_Words(val, false);
2365 
2366           DEBUG3(VAR, "ModifyWords: split \"%s\" into %u %s\n",
2367               val, (unsigned)words.len, words.len != 1 ? "words" : "word");
2368 
2369           SepBuf_Init(&result, ch->sep);
2370           for (i = 0; i < words.len; i++) {
2371                     modifyWord(words.words[i], &result, modifyWord_args);
2372                     if (result.buf.len > 0)
2373                               SepBuf_Sep(&result);
2374           }
2375 
2376           SubstringWords_Free(words);
2377 
2378 done:
2379           Expr_SetValueOwn(expr, SepBuf_DoneData(&result));
2380 }
2381 
2382 /* :@var@...${var}...@ */
2383 static ApplyModifierResult
ApplyModifier_Loop(const char ** pp,ModChain * ch)2384 ApplyModifier_Loop(const char **pp, ModChain *ch)
2385 {
2386           Expr *expr = ch->expr;
2387           struct ModifyWord_LoopArgs args;
2388           char prev_sep;
2389           LazyBuf tvarBuf, strBuf;
2390           FStr tvar, str;
2391 
2392           args.scope = expr->scope;
2393 
2394           (*pp)++;            /* Skip the first '@' */
2395           if (!ParseModifierPart(pp, '@', '@', VARE_PARSE,
2396               ch, &tvarBuf, NULL, NULL))
2397                     return AMR_CLEANUP;
2398           tvar = LazyBuf_DoneGet(&tvarBuf);
2399           args.var = tvar.str;
2400           if (strchr(args.var, '$') != NULL) {
2401                     Parse_Error(PARSE_FATAL,
2402                         "In the :@ modifier, the variable name \"%s\" "
2403                         "must not contain a dollar",
2404                         args.var);
2405                     goto cleanup_tvar;
2406           }
2407 
2408           if (!ParseModifierPart(pp, '@', '@', VARE_PARSE_BALANCED,
2409               ch, &strBuf, NULL, NULL))
2410                     goto cleanup_tvar;
2411           str = LazyBuf_DoneGet(&strBuf);
2412           args.body = str.str;
2413 
2414           if (!Expr_ShouldEval(expr))
2415                     goto done;
2416 
2417           args.emode = VarEvalMode_WithoutKeepDollar(expr->emode);
2418           prev_sep = ch->sep;
2419           ch->sep = ' ';                /* XXX: should be ch->sep for consistency */
2420           ModifyWords(ch, ModifyWord_Loop, &args, ch->oneBigWord);
2421           ch->sep = prev_sep;
2422           /* XXX: Consider restoring the previous value instead of deleting. */
2423           Var_Delete(expr->scope, args.var);
2424 
2425 done:
2426           FStr_Done(&tvar);
2427           FStr_Done(&str);
2428           return AMR_OK;
2429 
2430 cleanup_tvar:
2431           FStr_Done(&tvar);
2432           return AMR_CLEANUP;
2433 }
2434 
2435 static void
ParseModifier_Defined(const char ** pp,ModChain * ch,bool shouldEval,LazyBuf * buf)2436 ParseModifier_Defined(const char **pp, ModChain *ch, bool shouldEval,
2437                           LazyBuf *buf)
2438 {
2439           const char *p;
2440 
2441           p = *pp + 1;
2442           LazyBuf_Init(buf, p);
2443           while (!IsDelimiter(*p, ch)) {
2444 
2445                     /*
2446                      * XXX: This code is similar to the one in Var_Parse. See if
2447                      * the code can be merged. See also ParseModifier_Match and
2448                      * ParseModifierPart.
2449                      */
2450 
2451                     /* See Buf_AddEscaped in for.c for the counterpart. */
2452                     if (*p == '\\') {
2453                               char c = p[1];
2454                               if ((IsDelimiter(c, ch) && c != '\0') ||
2455                                   c == '$' || c == '\\') {
2456                                         if (shouldEval)
2457                                                   LazyBuf_Add(buf, c);
2458                                         p += 2;
2459                                         continue;
2460                               }
2461                     }
2462 
2463                     if (*p == '$') {
2464                               FStr val = Var_Parse(&p, ch->expr->scope,
2465                                   shouldEval ? ch->expr->emode : VARE_PARSE);
2466                               /* TODO: handle errors */
2467                               if (shouldEval)
2468                                         LazyBuf_AddStr(buf, val.str);
2469                               FStr_Done(&val);
2470                               continue;
2471                     }
2472 
2473                     if (shouldEval)
2474                               LazyBuf_Add(buf, *p);
2475                     p++;
2476           }
2477           *pp = p;
2478 }
2479 
2480 /* :Ddefined or :Uundefined */
2481 static ApplyModifierResult
ApplyModifier_Defined(const char ** pp,ModChain * ch)2482 ApplyModifier_Defined(const char **pp, ModChain *ch)
2483 {
2484           Expr *expr = ch->expr;
2485           LazyBuf buf;
2486           bool shouldEval =
2487               Expr_ShouldEval(expr) &&
2488               (**pp == 'D') == (expr->defined == DEF_REGULAR);
2489 
2490           ParseModifier_Defined(pp, ch, shouldEval, &buf);
2491 
2492           Expr_Define(expr);
2493           if (shouldEval)
2494                     Expr_SetValue(expr, Substring_Str(LazyBuf_Get(&buf)));
2495           LazyBuf_Done(&buf);
2496 
2497           return AMR_OK;
2498 }
2499 
2500 /* :L */
2501 static ApplyModifierResult
ApplyModifier_Literal(const char ** pp,ModChain * ch)2502 ApplyModifier_Literal(const char **pp, ModChain *ch)
2503 {
2504           Expr *expr = ch->expr;
2505 
2506           (*pp)++;
2507 
2508           if (Expr_ShouldEval(expr)) {
2509                     Expr_Define(expr);
2510                     Expr_SetValueOwn(expr, bmake_strdup(expr->name));
2511           }
2512 
2513           return AMR_OK;
2514 }
2515 
2516 static bool
TryParseTime(const char ** pp,time_t * out_time)2517 TryParseTime(const char **pp, time_t *out_time)
2518 {
2519           char *end;
2520           unsigned long n;
2521 
2522           if (!ch_isdigit(**pp))
2523                     return false;
2524 
2525           errno = 0;
2526           n = strtoul(*pp, &end, 10);
2527           if (n == ULONG_MAX && errno == ERANGE)
2528                     return false;
2529 
2530           *pp = end;
2531           *out_time = (time_t)n;        /* ignore possible truncation for now */
2532           return true;
2533 }
2534 
2535 /* :gmtime and :localtime */
2536 static ApplyModifierResult
ApplyModifier_Time(const char ** pp,ModChain * ch)2537 ApplyModifier_Time(const char **pp, ModChain *ch)
2538 {
2539           Expr *expr;
2540           time_t t;
2541           const char *args;
2542           const char *mod = *pp;
2543           bool gmt = mod[0] == 'g';
2544 
2545           if (!ModMatchEq(mod, gmt ? "gmtime" : "localtime", ch))
2546                     return AMR_UNKNOWN;
2547           args = mod + (gmt ? 6 : 9);
2548 
2549           if (args[0] == '=') {
2550                     const char *p = args + 1;
2551                     LazyBuf buf;
2552                     FStr arg;
2553                     if (!ParseModifierPart(&p, ':', ch->endc, ch->expr->emode,
2554                         ch, &buf, NULL, NULL))
2555                               return AMR_CLEANUP;
2556                     arg = LazyBuf_DoneGet(&buf);
2557                     if (ModChain_ShouldEval(ch)) {
2558                               const char *arg_p = arg.str;
2559                               if (!TryParseTime(&arg_p, &t) || *arg_p != '\0') {
2560                                         Parse_Error(PARSE_FATAL,
2561                                             "Invalid time value \"%s\"", arg.str);
2562                                         FStr_Done(&arg);
2563                                         return AMR_CLEANUP;
2564                               }
2565                     } else
2566                               t = 0;
2567                     FStr_Done(&arg);
2568                     *pp = p;
2569           } else {
2570                     t = 0;
2571                     *pp = args;
2572           }
2573 
2574           expr = ch->expr;
2575           if (Expr_ShouldEval(expr))
2576                     Expr_SetValueOwn(expr, FormatTime(Expr_Str(expr), t, gmt));
2577 
2578           return AMR_OK;
2579 }
2580 
2581 /* :hash */
2582 static ApplyModifierResult
ApplyModifier_Hash(const char ** pp,ModChain * ch)2583 ApplyModifier_Hash(const char **pp, ModChain *ch)
2584 {
2585           if (!ModMatch(*pp, "hash", ch))
2586                     return AMR_UNKNOWN;
2587           *pp += 4;
2588 
2589           if (ModChain_ShouldEval(ch))
2590                     Expr_SetValueOwn(ch->expr, Hash(Expr_Str(ch->expr)));
2591 
2592           return AMR_OK;
2593 }
2594 
2595 /* :P */
2596 static ApplyModifierResult
ApplyModifier_Path(const char ** pp,ModChain * ch)2597 ApplyModifier_Path(const char **pp, ModChain *ch)
2598 {
2599           Expr *expr = ch->expr;
2600           GNode *gn;
2601           char *path;
2602 
2603           (*pp)++;
2604 
2605           if (!Expr_ShouldEval(expr))
2606                     return AMR_OK;
2607 
2608           Expr_Define(expr);
2609 
2610           gn = Targ_FindNode(expr->name);
2611           if (gn == NULL || gn->type & OP_NOPATH)
2612                     path = NULL;
2613           else if (gn->path != NULL)
2614                     path = bmake_strdup(gn->path);
2615           else {
2616                     SearchPath *searchPath = Suff_FindPath(gn);
2617                     path = Dir_FindFile(expr->name, searchPath);
2618           }
2619           if (path == NULL)
2620                     path = bmake_strdup(expr->name);
2621           Expr_SetValueOwn(expr, path);
2622 
2623           return AMR_OK;
2624 }
2625 
2626 /* :!cmd! */
2627 static ApplyModifierResult
ApplyModifier_ShellCommand(const char ** pp,ModChain * ch)2628 ApplyModifier_ShellCommand(const char **pp, ModChain *ch)
2629 {
2630           Expr *expr = ch->expr;
2631           LazyBuf cmdBuf;
2632           FStr cmd;
2633 
2634           (*pp)++;
2635           if (!ParseModifierPart(pp, '!', '!', expr->emode,
2636               ch, &cmdBuf, NULL, NULL))
2637                     return AMR_CLEANUP;
2638           cmd = LazyBuf_DoneGet(&cmdBuf);
2639 
2640           if (Expr_ShouldEval(expr)) {
2641                     char *output, *error;
2642                     output = Cmd_Exec(cmd.str, &error);
2643                     Expr_SetValueOwn(expr, output);
2644                     if (error != NULL) {
2645                               Parse_Error(PARSE_WARNING, "%s", error);
2646                               free(error);
2647                     }
2648           } else
2649                     Expr_SetValueRefer(expr, "");
2650 
2651           FStr_Done(&cmd);
2652           Expr_Define(expr);
2653 
2654           return AMR_OK;
2655 }
2656 
2657 /*
2658  * The :range modifier generates an integer sequence as long as the words.
2659  * The :range=7 modifier generates an integer sequence from 1 to 7.
2660  */
2661 static ApplyModifierResult
ApplyModifier_Range(const char ** pp,ModChain * ch)2662 ApplyModifier_Range(const char **pp, ModChain *ch)
2663 {
2664           size_t n;
2665           Buffer buf;
2666           size_t i;
2667 
2668           const char *mod = *pp;
2669           if (!ModMatchEq(mod, "range", ch))
2670                     return AMR_UNKNOWN;
2671 
2672           if (mod[5] == '=') {
2673                     const char *p = mod + 6;
2674                     if (!TryParseSize(&p, &n)) {
2675                               Parse_Error(PARSE_FATAL,
2676                                   "Invalid number \"%s\" for ':range' modifier",
2677                                   mod + 6);
2678                               return AMR_CLEANUP;
2679                     }
2680                     *pp = p;
2681           } else {
2682                     n = 0;
2683                     *pp = mod + 5;
2684           }
2685 
2686           if (!ModChain_ShouldEval(ch))
2687                     return AMR_OK;
2688 
2689           if (n == 0) {
2690                     SubstringWords words = Expr_Words(ch->expr);
2691                     n = words.len;
2692                     SubstringWords_Free(words);
2693           }
2694 
2695           Buf_Init(&buf);
2696 
2697           for (i = 0; i < n; i++) {
2698                     if (i != 0) {
2699                               /*
2700                                * XXX: Use ch->sep instead of ' ', for consistency.
2701                                */
2702                               Buf_AddByte(&buf, ' ');
2703                     }
2704                     Buf_AddInt(&buf, 1 + (int)i);
2705           }
2706 
2707           Expr_SetValueOwn(ch->expr, Buf_DoneData(&buf));
2708           return AMR_OK;
2709 }
2710 
2711 /* Parse a ':M' or ':N' modifier. */
2712 static char *
ParseModifier_Match(const char ** pp,const ModChain * ch)2713 ParseModifier_Match(const char **pp, const ModChain *ch)
2714 {
2715           const char *mod = *pp;
2716           Expr *expr = ch->expr;
2717           bool copy = false;  /* pattern should be, or has been, copied */
2718           bool needSubst = false;
2719           const char *endpat;
2720           char *pattern;
2721 
2722           /*
2723            * In the loop below, ignore ':' unless we are at (or back to) the
2724            * original brace level.
2725            * XXX: This will likely not work right if $() and ${} are intermixed.
2726            */
2727           /*
2728            * XXX: This code is similar to the one in Var_Parse.
2729            * See if the code can be merged.
2730            * See also ApplyModifier_Defined.
2731            */
2732           int depth = 0;
2733           const char *p;
2734           for (p = mod + 1; *p != '\0' && !(*p == ':' && depth == 0); p++) {
2735                     if (*p == '\\' && p[1] != '\0' &&
2736                         (IsDelimiter(p[1], ch) || p[1] == ch->startc)) {
2737                               if (!needSubst)
2738                                         copy = true;
2739                               p++;
2740                               continue;
2741                     }
2742                     if (*p == '$')
2743                               needSubst = true;
2744                     if (*p == '(' || *p == '{')
2745                               depth++;
2746                     if (*p == ')' || *p == '}') {
2747                               depth--;
2748                               if (depth < 0)
2749                                         break;
2750                     }
2751           }
2752           *pp = p;
2753           endpat = p;
2754 
2755           if (copy) {
2756                     char *dst;
2757                     const char *src;
2758 
2759                     /* Compress the \:'s out of the pattern. */
2760                     pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1);
2761                     dst = pattern;
2762                     src = mod + 1;
2763                     for (; src < endpat; src++, dst++) {
2764                               if (src[0] == '\\' && src + 1 < endpat &&
2765                                   /* XXX: ch->startc is missing here; see above */
2766                                   IsDelimiter(src[1], ch))
2767                                         src++;
2768                               *dst = *src;
2769                     }
2770                     *dst = '\0';
2771           } else {
2772                     pattern = bmake_strsedup(mod + 1, endpat);
2773           }
2774 
2775           if (needSubst) {
2776                     char *old_pattern = pattern;
2777                     /*
2778                      * XXX: Contrary to ParseModifierPart, a dollar in a ':M' or
2779                      * ':N' modifier must be escaped as '$$', not as '\$'.
2780                      */
2781                     pattern = Var_Subst(pattern, expr->scope, expr->emode);
2782                     /* TODO: handle errors */
2783                     free(old_pattern);
2784           }
2785 
2786           DEBUG2(VAR, "Pattern for ':%c' is \"%s\"\n", mod[0], pattern);
2787 
2788           return pattern;
2789 }
2790 
2791 struct ModifyWord_MatchArgs {
2792           const char *pattern;
2793           bool neg;
2794           bool error_reported;
2795 };
2796 
2797 static void
ModifyWord_Match(Substring word,SepBuf * buf,void * data)2798 ModifyWord_Match(Substring word, SepBuf *buf, void *data)
2799 {
2800           struct ModifyWord_MatchArgs *args = data;
2801           StrMatchResult res;
2802           assert(word.end[0] == '\0');  /* assume null-terminated word */
2803           res = Str_Match(word.start, args->pattern);
2804           if (res.error != NULL && !args->error_reported) {
2805                     args->error_reported = true;
2806                     Parse_Error(PARSE_FATAL,
2807                         "%s in pattern '%s' of modifier '%s'",
2808                         res.error, args->pattern, args->neg ? ":N" : ":M");
2809           }
2810           if (res.matched != args->neg)
2811                     SepBuf_AddSubstring(buf, word);
2812 }
2813 
2814 /* :Mpattern or :Npattern */
2815 static ApplyModifierResult
ApplyModifier_Match(const char ** pp,ModChain * ch)2816 ApplyModifier_Match(const char **pp, ModChain *ch)
2817 {
2818           char mod = **pp;
2819           char *pattern;
2820 
2821           pattern = ParseModifier_Match(pp, ch);
2822 
2823           if (ModChain_ShouldEval(ch)) {
2824                     struct ModifyWord_MatchArgs args;
2825                     args.pattern = pattern;
2826                     args.neg = mod == 'N';
2827                     args.error_reported = false;
2828                     ModifyWords(ch, ModifyWord_Match, &args, ch->oneBigWord);
2829           }
2830 
2831           free(pattern);
2832           return AMR_OK;
2833 }
2834 
2835 struct ModifyWord_MtimeArgs {
2836           bool error;
2837           bool use_fallback;
2838           ApplyModifierResult rc;
2839           time_t fallback;
2840 };
2841 
2842 static void
ModifyWord_Mtime(Substring word,SepBuf * buf,void * data)2843 ModifyWord_Mtime(Substring word, SepBuf *buf, void *data)
2844 {
2845           struct ModifyWord_MtimeArgs *args = data;
2846           struct stat st;
2847           char tbuf[21];
2848 
2849           if (Substring_IsEmpty(word))
2850                     return;
2851           assert(word.end[0] == '\0');  /* assume null-terminated word */
2852           if (stat(word.start, &st) < 0) {
2853                     if (args->error) {
2854                               Parse_Error(PARSE_FATAL,
2855                                   "Cannot determine mtime for '%s': %s",
2856                                   word.start, strerror(errno));
2857                               args->rc = AMR_CLEANUP;
2858                               return;
2859                     }
2860                     if (args->use_fallback)
2861                               st.st_mtime = args->fallback;
2862                     else
2863                               time(&st.st_mtime);
2864           }
2865           snprintf(tbuf, sizeof(tbuf), "%u", (unsigned)st.st_mtime);
2866           SepBuf_AddStr(buf, tbuf);
2867 }
2868 
2869 /* :mtime */
2870 static ApplyModifierResult
ApplyModifier_Mtime(const char ** pp,ModChain * ch)2871 ApplyModifier_Mtime(const char **pp, ModChain *ch)
2872 {
2873           const char *p, *mod = *pp;
2874           struct ModifyWord_MtimeArgs args;
2875 
2876           if (!ModMatchEq(mod, "mtime", ch))
2877                     return AMR_UNKNOWN;
2878           *pp += 5;
2879           p = *pp;
2880           args.error = false;
2881           args.use_fallback = p[0] == '=';
2882           args.rc = AMR_OK;
2883           if (args.use_fallback) {
2884                     p++;
2885                     if (TryParseTime(&p, &args.fallback)) {
2886                     } else if (strncmp(p, "error", 5) == 0) {
2887                               p += 5;
2888                               args.error = true;
2889                     } else
2890                               goto invalid_argument;
2891                     if (!IsDelimiter(*p, ch))
2892                               goto invalid_argument;
2893                     *pp = p;
2894           }
2895           ModifyWords(ch, ModifyWord_Mtime, &args, ch->oneBigWord);
2896           return args.rc;
2897 
2898 invalid_argument:
2899           Parse_Error(PARSE_FATAL,
2900               "Invalid argument '%.*s' for modifier ':mtime'",
2901               (int)strcspn(*pp + 1, ":{}()"), *pp + 1);
2902           return AMR_CLEANUP;
2903 }
2904 
2905 static void
ParsePatternFlags(const char ** pp,PatternFlags * pflags,bool * oneBigWord)2906 ParsePatternFlags(const char **pp, PatternFlags *pflags, bool *oneBigWord)
2907 {
2908           for (;; (*pp)++) {
2909                     if (**pp == 'g')
2910                               pflags->subGlobal = true;
2911                     else if (**pp == '1')
2912                               pflags->subOnce = true;
2913                     else if (**pp == 'W')
2914                               *oneBigWord = true;
2915                     else
2916                               break;
2917           }
2918 }
2919 
2920 MAKE_INLINE PatternFlags
PatternFlags_None(void)2921 PatternFlags_None(void)
2922 {
2923           PatternFlags pflags = { false, false, false, false };
2924           return pflags;
2925 }
2926 
2927 /* :S,from,to, */
2928 static ApplyModifierResult
ApplyModifier_Subst(const char ** pp,ModChain * ch)2929 ApplyModifier_Subst(const char **pp, ModChain *ch)
2930 {
2931           struct ModifyWord_SubstArgs args;
2932           bool oneBigWord;
2933           LazyBuf lhsBuf, rhsBuf;
2934 
2935           char delim = (*pp)[1];
2936           if (delim == '\0') {
2937                     Parse_Error(PARSE_FATAL,
2938                         "Missing delimiter for modifier ':S'");
2939                     (*pp)++;
2940                     return AMR_CLEANUP;
2941           }
2942 
2943           *pp += 2;
2944 
2945           args.pflags = PatternFlags_None();
2946           args.matched = false;
2947 
2948           if (**pp == '^') {
2949                     args.pflags.anchorStart = true;
2950                     (*pp)++;
2951           }
2952 
2953           if (!ParseModifierPart(pp, delim, delim, ch->expr->emode,
2954               ch, &lhsBuf, &args.pflags, NULL))
2955                     return AMR_CLEANUP;
2956           args.lhs = LazyBuf_Get(&lhsBuf);
2957 
2958           if (!ParseModifierPart(pp, delim, delim, ch->expr->emode,
2959               ch, &rhsBuf, NULL, &args)) {
2960                     LazyBuf_Done(&lhsBuf);
2961                     return AMR_CLEANUP;
2962           }
2963           args.rhs = LazyBuf_Get(&rhsBuf);
2964 
2965           oneBigWord = ch->oneBigWord;
2966           ParsePatternFlags(pp, &args.pflags, &oneBigWord);
2967 
2968           ModifyWords(ch, ModifyWord_Subst, &args, oneBigWord);
2969 
2970           LazyBuf_Done(&lhsBuf);
2971           LazyBuf_Done(&rhsBuf);
2972           return AMR_OK;
2973 }
2974 
2975 /* :C,from,to, */
2976 static ApplyModifierResult
ApplyModifier_Regex(const char ** pp,ModChain * ch)2977 ApplyModifier_Regex(const char **pp, ModChain *ch)
2978 {
2979           struct ModifyWord_SubstRegexArgs args;
2980           bool oneBigWord;
2981           int error;
2982           LazyBuf reBuf, replaceBuf;
2983           FStr re;
2984 
2985           char delim = (*pp)[1];
2986           if (delim == '\0') {
2987                     Parse_Error(PARSE_FATAL,
2988                         "Missing delimiter for modifier ':C'");
2989                     (*pp)++;
2990                     return AMR_CLEANUP;
2991           }
2992 
2993           *pp += 2;
2994 
2995           if (!ParseModifierPart(pp, delim, delim, ch->expr->emode,
2996               ch, &reBuf, NULL, NULL))
2997                     return AMR_CLEANUP;
2998           re = LazyBuf_DoneGet(&reBuf);
2999 
3000           if (!ParseModifierPart(pp, delim, delim, ch->expr->emode,
3001               ch, &replaceBuf, NULL, NULL)) {
3002                     FStr_Done(&re);
3003                     return AMR_CLEANUP;
3004           }
3005           args.replace = LazyBuf_Get(&replaceBuf);
3006 
3007           args.pflags = PatternFlags_None();
3008           args.matched = false;
3009           oneBigWord = ch->oneBigWord;
3010           ParsePatternFlags(pp, &args.pflags, &oneBigWord);
3011 
3012           if (!ModChain_ShouldEval(ch))
3013                     goto done;
3014 
3015           error = regcomp(&args.re, re.str, REG_EXTENDED);
3016           if (error != 0) {
3017                     RegexError(error, &args.re, "Regex compilation error");
3018                     LazyBuf_Done(&replaceBuf);
3019                     FStr_Done(&re);
3020                     return AMR_CLEANUP;
3021           }
3022 
3023           args.nsub = args.re.re_nsub + 1;
3024           if (args.nsub > 10)
3025                     args.nsub = 10;
3026 
3027           ModifyWords(ch, ModifyWord_SubstRegex, &args, oneBigWord);
3028 
3029           regfree(&args.re);
3030 done:
3031           LazyBuf_Done(&replaceBuf);
3032           FStr_Done(&re);
3033           return AMR_OK;
3034 }
3035 
3036 /* :Q, :q */
3037 static ApplyModifierResult
ApplyModifier_Quote(const char ** pp,ModChain * ch)3038 ApplyModifier_Quote(const char **pp, ModChain *ch)
3039 {
3040           LazyBuf buf;
3041           bool quoteDollar;
3042 
3043           quoteDollar = **pp == 'q';
3044           if (!IsDelimiter((*pp)[1], ch))
3045                     return AMR_UNKNOWN;
3046           (*pp)++;
3047 
3048           if (!ModChain_ShouldEval(ch))
3049                     return AMR_OK;
3050 
3051           QuoteShell(Expr_Str(ch->expr), quoteDollar, &buf);
3052           if (buf.data != NULL)
3053                     Expr_SetValue(ch->expr, LazyBuf_DoneGet(&buf));
3054           else
3055                     LazyBuf_Done(&buf);
3056 
3057           return AMR_OK;
3058 }
3059 
3060 static void
ModifyWord_Copy(Substring word,SepBuf * buf,void * data MAKE_ATTR_UNUSED)3061 ModifyWord_Copy(Substring word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
3062 {
3063           SepBuf_AddSubstring(buf, word);
3064 }
3065 
3066 /* :ts<separator> */
3067 static ApplyModifierResult
ApplyModifier_ToSep(const char ** pp,ModChain * ch)3068 ApplyModifier_ToSep(const char **pp, ModChain *ch)
3069 {
3070           const char *sep = *pp + 2;
3071 
3072           /*
3073            * Even in parse-only mode, apply the side effects, since the side
3074            * effects are neither observable nor is there a performance penalty.
3075            * Checking for VARE_EVAL for every single piece of code in here
3076            * would make the code in this function too hard to read.
3077            */
3078 
3079           /* ":ts<any><endc>" or ":ts<any>:" */
3080           if (sep[0] != ch->endc && IsDelimiter(sep[1], ch)) {
3081                     *pp = sep + 1;
3082                     ch->sep = sep[0];
3083                     goto ok;
3084           }
3085 
3086           /* ":ts<endc>" or ":ts:" */
3087           if (IsDelimiter(sep[0], ch)) {
3088                     *pp = sep;
3089                     ch->sep = '\0';     /* no separator */
3090                     goto ok;
3091           }
3092 
3093           if (sep[0] != '\\')
3094                     return AMR_UNKNOWN;
3095 
3096           /* ":ts\n" */
3097           if (sep[1] == 'n') {
3098                     *pp = sep + 2;
3099                     ch->sep = '\n';
3100                     goto ok;
3101           }
3102 
3103           /* ":ts\t" */
3104           if (sep[1] == 't') {
3105                     *pp = sep + 2;
3106                     ch->sep = '\t';
3107                     goto ok;
3108           }
3109 
3110           /* ":ts\x40" or ":ts\100" */
3111           {
3112                     const char *p = sep + 1;
3113                     int base = 8;       /* assume octal */
3114 
3115                     if (sep[1] == 'x') {
3116                               base = 16;
3117                               p++;
3118                     } else if (!ch_isdigit(sep[1]))
3119                               return AMR_UNKNOWN; /* ":ts\..." */
3120 
3121                     if (!TryParseChar(&p, base, &ch->sep)) {
3122                               Parse_Error(PARSE_FATAL,
3123                                   "Invalid character number at \"%s\"", p);
3124                               return AMR_CLEANUP;
3125                     }
3126                     if (!IsDelimiter(*p, ch))
3127                               return AMR_UNKNOWN;
3128 
3129                     *pp = p;
3130           }
3131 
3132 ok:
3133           ModifyWords(ch, ModifyWord_Copy, NULL, ch->oneBigWord);
3134           return AMR_OK;
3135 }
3136 
3137 static char *
str_totitle(const char * str)3138 str_totitle(const char *str)
3139 {
3140           size_t i, n = strlen(str) + 1;
3141           char *res = bmake_malloc(n);
3142           for (i = 0; i < n; i++) {
3143                     if (i == 0 || ch_isspace(res[i - 1]))
3144                               res[i] = ch_toupper(str[i]);
3145                     else
3146                               res[i] = ch_tolower(str[i]);
3147           }
3148           return res;
3149 }
3150 
3151 
3152 static char *
str_toupper(const char * str)3153 str_toupper(const char *str)
3154 {
3155           size_t i, n = strlen(str) + 1;
3156           char *res = bmake_malloc(n);
3157           for (i = 0; i < n; i++)
3158                     res[i] = ch_toupper(str[i]);
3159           return res;
3160 }
3161 
3162 static char *
str_tolower(const char * str)3163 str_tolower(const char *str)
3164 {
3165           size_t i, n = strlen(str) + 1;
3166           char *res = bmake_malloc(n);
3167           for (i = 0; i < n; i++)
3168                     res[i] = ch_tolower(str[i]);
3169           return res;
3170 }
3171 
3172 /* :tA, :tu, :tl, :ts<separator>, etc. */
3173 static ApplyModifierResult
ApplyModifier_To(const char ** pp,ModChain * ch)3174 ApplyModifier_To(const char **pp, ModChain *ch)
3175 {
3176           Expr *expr = ch->expr;
3177           const char *mod = *pp;
3178           assert(mod[0] == 't');
3179 
3180           if (IsDelimiter(mod[1], ch))
3181                     return AMR_UNKNOWN;           /* ":t<endc>" or ":t:" */
3182 
3183           if (mod[1] == 's')
3184                     return ApplyModifier_ToSep(pp, ch);
3185 
3186           if (!IsDelimiter(mod[2], ch))
3187                     return AMR_UNKNOWN;
3188 
3189           if (mod[1] == 'A') {                                        /* :tA */
3190                     *pp = mod + 2;
3191                     ModifyWords(ch, ModifyWord_Realpath, NULL, ch->oneBigWord);
3192                     return AMR_OK;
3193           }
3194 
3195           if (mod[1] == 't') {                                        /* :tt */
3196                     *pp = mod + 2;
3197                     if (Expr_ShouldEval(expr))
3198                               Expr_SetValueOwn(expr, str_totitle(Expr_Str(expr)));
3199                     return AMR_OK;
3200           }
3201 
3202           if (mod[1] == 'u') {                                        /* :tu */
3203                     *pp = mod + 2;
3204                     if (Expr_ShouldEval(expr))
3205                               Expr_SetValueOwn(expr, str_toupper(Expr_Str(expr)));
3206                     return AMR_OK;
3207           }
3208 
3209           if (mod[1] == 'l') {                                        /* :tl */
3210                     *pp = mod + 2;
3211                     if (Expr_ShouldEval(expr))
3212                               Expr_SetValueOwn(expr, str_tolower(Expr_Str(expr)));
3213                     return AMR_OK;
3214           }
3215 
3216           if (mod[1] == 'W' || mod[1] == 'w') {             /* :tW, :tw */
3217                     *pp = mod + 2;
3218                     ch->oneBigWord = mod[1] == 'W';
3219                     return AMR_OK;
3220           }
3221 
3222           return AMR_UNKNOWN;           /* ":t<any>:" or ":t<any><endc>" */
3223 }
3224 
3225 /* :[#], :[1], :[-1..1], etc. */
3226 static ApplyModifierResult
ApplyModifier_Words(const char ** pp,ModChain * ch)3227 ApplyModifier_Words(const char **pp, ModChain *ch)
3228 {
3229           Expr *expr = ch->expr;
3230           int first, last;
3231           const char *p;
3232           LazyBuf argBuf;
3233           FStr arg;
3234 
3235           (*pp)++;            /* skip the '[' */
3236           if (!ParseModifierPart(pp, ']', ']', expr->emode,
3237               ch, &argBuf, NULL, NULL))
3238                     return AMR_CLEANUP;
3239           arg = LazyBuf_DoneGet(&argBuf);
3240           p = arg.str;
3241 
3242           if (!IsDelimiter(**pp, ch)) {
3243                     Parse_Error(PARSE_FATAL,
3244                         "Extra text after \"[%s]\"", arg.str);
3245                     FStr_Done(&arg);
3246                     return AMR_CLEANUP;
3247           }
3248 
3249           if (!ModChain_ShouldEval(ch))
3250                     goto ok;
3251 
3252           if (p[0] == '\0')
3253                     goto bad_modifier;            /* Found ":[]". */
3254 
3255           if (strcmp(p, "#") == 0) {              /* Found ":[#]" */
3256                     if (ch->oneBigWord)
3257                               Expr_SetValueRefer(expr, "1");
3258                     else {
3259                               Buffer buf;
3260 
3261                               SubstringWords words = Expr_Words(expr);
3262                               size_t ac = words.len;
3263                               SubstringWords_Free(words);
3264 
3265                               Buf_Init(&buf);
3266                               Buf_AddInt(&buf, (int)ac);
3267                               Expr_SetValueOwn(expr, Buf_DoneData(&buf));
3268                     }
3269                     goto ok;
3270           }
3271 
3272           if (strcmp(p, "*") == 0) {              /* ":[*]" */
3273                     ch->oneBigWord = true;
3274                     goto ok;
3275           }
3276 
3277           if (strcmp(p, "@") == 0) {              /* ":[@]" */
3278                     ch->oneBigWord = false;
3279                     goto ok;
3280           }
3281 
3282           /* Expect ":[N]" or ":[start..end]" */
3283           if (!TryParseIntBase0(&p, &first))
3284                     goto bad_modifier;
3285 
3286           if (p[0] == '\0')                       /* ":[N]" */
3287                     last = first;
3288           else if (strncmp(p, "..", 2) == 0) {
3289                     p += 2;
3290                     if (!TryParseIntBase0(&p, &last) || *p != '\0')
3291                               goto bad_modifier;
3292           } else
3293                     goto bad_modifier;
3294 
3295           if (first == 0 && last == 0) {                    /* ":[0]" or ":[0..0]" */
3296                     ch->oneBigWord = true;
3297                     goto ok;
3298           }
3299 
3300           if (first == 0 || last == 0)            /* ":[0..N]" or ":[N..0]" */
3301                     goto bad_modifier;
3302 
3303           Expr_SetValueOwn(expr,
3304               VarSelectWords(Expr_Str(expr), first, last,
3305                     ch->sep, ch->oneBigWord));
3306 
3307 ok:
3308           FStr_Done(&arg);
3309           return AMR_OK;
3310 
3311 bad_modifier:
3312           Parse_Error(PARSE_FATAL, "Invalid modifier \":[%s]\"", arg.str);
3313           FStr_Done(&arg);
3314           return AMR_CLEANUP;
3315 }
3316 
3317 #if __STDC_VERSION__ >= 199901L
3318 # define NUM_TYPE long long
3319 # define PARSE_NUM_TYPE strtoll
3320 #else
3321 # define NUM_TYPE long
3322 # define PARSE_NUM_TYPE strtol
3323 #endif
3324 
3325 static NUM_TYPE
num_val(Substring s)3326 num_val(Substring s)
3327 {
3328           NUM_TYPE val;
3329           char *ep;
3330 
3331           val = PARSE_NUM_TYPE(s.start, &ep, 0);
3332           if (ep != s.start) {
3333                     switch (*ep) {
3334                     case 'K':
3335                     case 'k':
3336                               val <<= 10;
3337                               break;
3338                     case 'M':
3339                     case 'm':
3340                               val <<= 20;
3341                               break;
3342                     case 'G':
3343                     case 'g':
3344                               val <<= 30;
3345                               break;
3346                     }
3347           }
3348           return val;
3349 }
3350 
3351 static int
SubNumAsc(const void * sa,const void * sb)3352 SubNumAsc(const void *sa, const void *sb)
3353 {
3354           NUM_TYPE a, b;
3355 
3356           a = num_val(*((const Substring *)sa));
3357           b = num_val(*((const Substring *)sb));
3358           return a > b ? 1 : b > a ? -1 : 0;
3359 }
3360 
3361 static int
SubNumDesc(const void * sa,const void * sb)3362 SubNumDesc(const void *sa, const void *sb)
3363 {
3364           return SubNumAsc(sb, sa);
3365 }
3366 
3367 static int
Substring_Cmp(Substring a,Substring b)3368 Substring_Cmp(Substring a, Substring b)
3369 {
3370           for (; a.start < a.end && b.start < b.end; a.start++, b.start++)
3371                     if (a.start[0] != b.start[0])
3372                               return (unsigned char)a.start[0]
3373                                   - (unsigned char)b.start[0];
3374           return (int)((a.end - a.start) - (b.end - b.start));
3375 }
3376 
3377 static int
SubStrAsc(const void * sa,const void * sb)3378 SubStrAsc(const void *sa, const void *sb)
3379 {
3380           return Substring_Cmp(*(const Substring *)sa, *(const Substring *)sb);
3381 }
3382 
3383 static int
SubStrDesc(const void * sa,const void * sb)3384 SubStrDesc(const void *sa, const void *sb)
3385 {
3386           return SubStrAsc(sb, sa);
3387 }
3388 
3389 static void
ShuffleSubstrings(Substring * strs,size_t n)3390 ShuffleSubstrings(Substring *strs, size_t n)
3391 {
3392           size_t i;
3393 
3394           for (i = n - 1; i > 0; i--) {
3395                     size_t rndidx = (size_t)random() % (i + 1);
3396                     Substring t = strs[i];
3397                     strs[i] = strs[rndidx];
3398                     strs[rndidx] = t;
3399           }
3400 }
3401 
3402 /*
3403  * :O               order ascending
3404  * :Or              order descending
3405  * :Ox              shuffle
3406  * :On              numeric ascending
3407  * :Onr, :Orn       numeric descending
3408  */
3409 static ApplyModifierResult
ApplyModifier_Order(const char ** pp,ModChain * ch)3410 ApplyModifier_Order(const char **pp, ModChain *ch)
3411 {
3412           const char *mod = *pp;
3413           SubstringWords words;
3414           int (*cmp)(const void *, const void *);
3415 
3416           if (IsDelimiter(mod[1], ch)) {
3417                     cmp = SubStrAsc;
3418                     (*pp)++;
3419           } else if (IsDelimiter(mod[2], ch)) {
3420                     if (mod[1] == 'n')
3421                               cmp = SubNumAsc;
3422                     else if (mod[1] == 'r')
3423                               cmp = SubStrDesc;
3424                     else if (mod[1] == 'x')
3425                               cmp = NULL;
3426                     else
3427                               return AMR_UNKNOWN;
3428                     *pp += 2;
3429           } else if (IsDelimiter(mod[3], ch)) {
3430                     if ((mod[1] == 'n' && mod[2] == 'r') ||
3431                         (mod[1] == 'r' && mod[2] == 'n'))
3432                               cmp = SubNumDesc;
3433                     else
3434                               return AMR_UNKNOWN;
3435                     *pp += 3;
3436           } else
3437                     return AMR_UNKNOWN;
3438 
3439           if (!ModChain_ShouldEval(ch))
3440                     return AMR_OK;
3441 
3442           words = Expr_Words(ch->expr);
3443           if (cmp == NULL)
3444                     ShuffleSubstrings(words.words, words.len);
3445           else {
3446                     assert(words.words[0].end[0] == '\0');
3447                     qsort(words.words, words.len, sizeof(words.words[0]), cmp);
3448           }
3449           Expr_SetValueOwn(ch->expr, SubstringWords_JoinFree(words));
3450 
3451           return AMR_OK;
3452 }
3453 
3454 /* :? then : else */
3455 static ApplyModifierResult
ApplyModifier_IfElse(const char ** pp,ModChain * ch)3456 ApplyModifier_IfElse(const char **pp, ModChain *ch)
3457 {
3458           Expr *expr = ch->expr;
3459           LazyBuf thenBuf;
3460           LazyBuf elseBuf;
3461 
3462           VarEvalMode then_emode = VARE_PARSE;
3463           VarEvalMode else_emode = VARE_PARSE;
3464           int parseErrorsBefore = parseErrors;
3465 
3466           CondResult cond_rc = CR_TRUE; /* anything other than CR_ERROR */
3467           if (Expr_ShouldEval(expr)) {
3468                     evalStack.elems[evalStack.len - 1].kind = VSK_COND;
3469                     cond_rc = Cond_EvalCondition(expr->name);
3470                     if (cond_rc == CR_TRUE)
3471                               then_emode = expr->emode;
3472                     else if (cond_rc == CR_FALSE)
3473                               else_emode = expr->emode;
3474                     else if (parseErrors == parseErrorsBefore)
3475                               Parse_Error(PARSE_FATAL, "Bad condition");
3476           }
3477 
3478           evalStack.elems[evalStack.len - 1].kind = VSK_COND_THEN;
3479           (*pp)++;            /* skip past the '?' */
3480           if (!ParseModifierPart(pp, ':', ':', then_emode,
3481               ch, &thenBuf, NULL, NULL))
3482                     return AMR_CLEANUP;
3483 
3484           evalStack.elems[evalStack.len - 1].kind = VSK_COND_ELSE;
3485           if (!ParseModifierPart(pp, ch->endc, ch->endc, else_emode,
3486               ch, &elseBuf, NULL, NULL)) {
3487                     LazyBuf_Done(&thenBuf);
3488                     return AMR_CLEANUP;
3489           }
3490 
3491           (*pp)--;            /* Go back to the ch->endc. */
3492 
3493           if (cond_rc == CR_ERROR) {
3494                     LazyBuf_Done(&thenBuf);
3495                     LazyBuf_Done(&elseBuf);
3496                     return AMR_CLEANUP;
3497           }
3498 
3499           if (!Expr_ShouldEval(expr)) {
3500                     LazyBuf_Done(&thenBuf);
3501                     LazyBuf_Done(&elseBuf);
3502           } else if (cond_rc == CR_TRUE) {
3503                     Expr_SetValue(expr, LazyBuf_DoneGet(&thenBuf));
3504                     LazyBuf_Done(&elseBuf);
3505           } else {
3506                     LazyBuf_Done(&thenBuf);
3507                     Expr_SetValue(expr, LazyBuf_DoneGet(&elseBuf));
3508           }
3509           Expr_Define(expr);
3510           return AMR_OK;
3511 }
3512 
3513 /*
3514  * The ::= modifiers are special in that they do not read the variable value
3515  * but instead assign to that variable.  They always expand to an empty
3516  * string.
3517  *
3518  * Their main purpose is in supporting .for loops that generate shell commands
3519  * since an ordinary variable assignment at that point would terminate the
3520  * dependency group for these targets.  For example:
3521  *
3522  * list-targets: .USE
3523  * .for i in ${.TARGET} ${.TARGET:R}.gz
3524  *        @${t::=$i}
3525  *        @echo 'The target is ${t:T}.'
3526  * .endfor
3527  *
3528  *          ::=<str>          Assigns <str> as the new value of variable.
3529  *          ::?=<str>         Assigns <str> as value of variable if
3530  *                            it was not already set.
3531  *          ::+=<str>         Appends <str> to variable.
3532  *          ::!=<cmd>         Assigns output of <cmd> as the new value of
3533  *                            variable.
3534  */
3535 static ApplyModifierResult
ApplyModifier_Assign(const char ** pp,ModChain * ch)3536 ApplyModifier_Assign(const char **pp, ModChain *ch)
3537 {
3538           Expr *expr = ch->expr;
3539           GNode *scope;
3540           FStr val;
3541           LazyBuf buf;
3542 
3543           const char *mod = *pp;
3544           const char *op = mod + 1;
3545 
3546           if (op[0] == '=')
3547                     goto found_op;
3548           if ((op[0] == '+' || op[0] == '?' || op[0] == '!') && op[1] == '=')
3549                     goto found_op;
3550           return AMR_UNKNOWN; /* "::<unrecognized>" */
3551 
3552 found_op:
3553           if (expr->name[0] == '\0') {
3554                     const char *value = op[0] == '=' ? op + 1 : op + 2;
3555                     *pp = mod + 1;
3556                     /* Take a guess at where the modifier ends. */
3557                     Parse_Error(PARSE_FATAL,
3558                         "Invalid attempt to assign \"%.*s\" to variable \"\" "
3559                         "via modifier \":%.*s\"",
3560                         (int)strcspn(value, ":)}"), value,
3561                         (int)(value - mod), mod);
3562                     return AMR_CLEANUP;
3563           }
3564 
3565           *pp = mod + (op[0] != '=' ? 3 : 2);
3566 
3567           if (!ParseModifierPart(pp, ch->endc, ch->endc, expr->emode,
3568               ch, &buf, NULL, NULL))
3569                     return AMR_CLEANUP;
3570           val = LazyBuf_DoneGet(&buf);
3571 
3572           (*pp)--;            /* Go back to the ch->endc. */
3573 
3574           if (!Expr_ShouldEval(expr))
3575                     goto done;
3576 
3577           scope = expr->scope;          /* scope where v belongs */
3578           if (expr->defined == DEF_REGULAR && expr->scope != SCOPE_GLOBAL
3579               && VarFind(expr->name, expr->scope, false) == NULL)
3580                     scope = SCOPE_GLOBAL;
3581 
3582           if (op[0] == '+')
3583                     Var_Append(scope, expr->name, val.str);
3584           else if (op[0] == '!') {
3585                     char *output, *error;
3586                     output = Cmd_Exec(val.str, &error);
3587                     if (error != NULL) {
3588                               Parse_Error(PARSE_WARNING, "%s", error);
3589                               free(error);
3590                     } else
3591                               Var_Set(scope, expr->name, output);
3592                     free(output);
3593           } else if (op[0] == '?' && expr->defined == DEF_REGULAR) {
3594                     /* Do nothing. */
3595           } else
3596                     Var_Set(scope, expr->name, val.str);
3597 
3598           Expr_SetValueRefer(expr, "");
3599 
3600 done:
3601           FStr_Done(&val);
3602           return AMR_OK;
3603 }
3604 
3605 /*
3606  * :_=...
3607  * remember current value
3608  */
3609 static ApplyModifierResult
ApplyModifier_Remember(const char ** pp,ModChain * ch)3610 ApplyModifier_Remember(const char **pp, ModChain *ch)
3611 {
3612           Expr *expr = ch->expr;
3613           const char *mod = *pp;
3614           FStr name;
3615 
3616           if (!ModMatchEq(mod, "_", ch))
3617                     return AMR_UNKNOWN;
3618 
3619           name = FStr_InitRefer("_");
3620           if (mod[1] == '=') {
3621                     /*
3622                      * XXX: This ad-hoc call to strcspn deviates from the usual
3623                      * behavior defined in ParseModifierPart.  This creates an
3624                      * unnecessary and undocumented inconsistency in make.
3625                      */
3626                     const char *arg = mod + 2;
3627                     size_t argLen = strcspn(arg, ":)}");
3628                     *pp = arg + argLen;
3629                     name = FStr_InitOwn(bmake_strldup(arg, argLen));
3630           } else
3631                     *pp = mod + 1;
3632 
3633           if (Expr_ShouldEval(expr))
3634                     Var_Set(SCOPE_GLOBAL, name.str, Expr_Str(expr));
3635           FStr_Done(&name);
3636 
3637           return AMR_OK;
3638 }
3639 
3640 /*
3641  * Apply the given function to each word of the variable value,
3642  * for a single-letter modifier such as :H, :T.
3643  */
3644 static ApplyModifierResult
ApplyModifier_WordFunc(const char ** pp,ModChain * ch,ModifyWordProc modifyWord)3645 ApplyModifier_WordFunc(const char **pp, ModChain *ch,
3646                            ModifyWordProc modifyWord)
3647 {
3648           if (!IsDelimiter((*pp)[1], ch))
3649                     return AMR_UNKNOWN;
3650           (*pp)++;
3651 
3652           ModifyWords(ch, modifyWord, NULL, ch->oneBigWord);
3653 
3654           return AMR_OK;
3655 }
3656 
3657 /* Remove adjacent duplicate words. */
3658 static ApplyModifierResult
ApplyModifier_Unique(const char ** pp,ModChain * ch)3659 ApplyModifier_Unique(const char **pp, ModChain *ch)
3660 {
3661           SubstringWords words;
3662 
3663           if (!IsDelimiter((*pp)[1], ch))
3664                     return AMR_UNKNOWN;
3665           (*pp)++;
3666 
3667           if (!ModChain_ShouldEval(ch))
3668                     return AMR_OK;
3669 
3670           words = Expr_Words(ch->expr);
3671 
3672           if (words.len > 1) {
3673                     size_t di, si;
3674                     for (di = 0, si = 1; si < words.len; si++)
3675                               if (!Substring_Eq(words.words[di], words.words[si]))
3676                                         words.words[++di] = words.words[si];
3677                     words.len = di + 1;
3678           }
3679 
3680           Expr_SetValueOwn(ch->expr, SubstringWords_JoinFree(words));
3681 
3682           return AMR_OK;
3683 }
3684 
3685 /* Test whether the modifier has the form '<lhs>=<rhs>'. */
3686 static bool
IsSysVModifier(const char * p,char startc,char endc)3687 IsSysVModifier(const char *p, char startc, char endc)
3688 {
3689           bool eqFound = false;
3690 
3691           int depth = 1;
3692           while (*p != '\0') {
3693                     if (*p == '=')      /* XXX: should also test depth == 1 */
3694                               eqFound = true;
3695                     else if (*p == endc) {
3696                               if (--depth == 0)
3697                                         break;
3698                     } else if (*p == startc)
3699                               depth++;
3700                     p++;
3701           }
3702           return eqFound;
3703 }
3704 
3705 /* :from=to */
3706 static ApplyModifierResult
ApplyModifier_SysV(const char ** pp,ModChain * ch)3707 ApplyModifier_SysV(const char **pp, ModChain *ch)
3708 {
3709           Expr *expr = ch->expr;
3710           LazyBuf lhsBuf, rhsBuf;
3711           FStr rhs;
3712           struct ModifyWord_SysVSubstArgs args;
3713           Substring lhs;
3714           const char *lhsSuffix;
3715 
3716           const char *mod = *pp;
3717 
3718           if (!IsSysVModifier(mod, ch->startc, ch->endc))
3719                     return AMR_UNKNOWN;
3720 
3721           if (!ParseModifierPart(pp, '=', '=', expr->emode,
3722               ch, &lhsBuf, NULL, NULL))
3723                     return AMR_CLEANUP;
3724 
3725           if (!ParseModifierPart(pp, ch->endc, ch->endc, expr->emode,
3726               ch, &rhsBuf, NULL, NULL)) {
3727                     LazyBuf_Done(&lhsBuf);
3728                     return AMR_CLEANUP;
3729           }
3730           rhs = LazyBuf_DoneGet(&rhsBuf);
3731 
3732           (*pp)--;            /* Go back to the ch->endc. */
3733 
3734           /* Do not turn an empty expression into non-empty. */
3735           if (lhsBuf.len == 0 && Expr_Str(expr)[0] == '\0')
3736                     goto done;
3737 
3738           lhs = LazyBuf_Get(&lhsBuf);
3739           lhsSuffix = Substring_SkipFirst(lhs, '%');
3740 
3741           args.scope = expr->scope;
3742           args.lhsPrefix = Substring_Init(lhs.start,
3743               lhsSuffix != lhs.start ? lhsSuffix - 1 : lhs.start);
3744           args.lhsPercent = lhsSuffix != lhs.start;
3745           args.lhsSuffix = Substring_Init(lhsSuffix, lhs.end);
3746           args.rhs = rhs.str;
3747 
3748           ModifyWords(ch, ModifyWord_SysVSubst, &args, ch->oneBigWord);
3749 
3750 done:
3751           LazyBuf_Done(&lhsBuf);
3752           FStr_Done(&rhs);
3753           return AMR_OK;
3754 }
3755 
3756 /* :sh */
3757 static ApplyModifierResult
ApplyModifier_SunShell(const char ** pp,ModChain * ch)3758 ApplyModifier_SunShell(const char **pp, ModChain *ch)
3759 {
3760           Expr *expr = ch->expr;
3761           const char *p = *pp;
3762           if (!(p[1] == 'h' && IsDelimiter(p[2], ch)))
3763                     return AMR_UNKNOWN;
3764           *pp = p + 2;
3765 
3766           if (Expr_ShouldEval(expr)) {
3767                     char *output, *error;
3768                     output = Cmd_Exec(Expr_Str(expr), &error);
3769                     if (error != NULL) {
3770                               Parse_Error(PARSE_WARNING, "%s", error);
3771                               free(error);
3772                     }
3773                     Expr_SetValueOwn(expr, output);
3774           }
3775 
3776           return AMR_OK;
3777 }
3778 
3779 /*
3780  * In cases where the evaluation mode and the definedness are the "standard"
3781  * ones, don't log them, to keep the logs readable.
3782  */
3783 static bool
ShouldLogInSimpleFormat(const Expr * expr)3784 ShouldLogInSimpleFormat(const Expr *expr)
3785 {
3786           return (expr->emode == VARE_EVAL
3787                     || expr->emode == VARE_EVAL_DEFINED
3788                     || expr->emode == VARE_EVAL_DEFINED_LOUD)
3789               && expr->defined == DEF_REGULAR;
3790 }
3791 
3792 static void
LogBeforeApply(const ModChain * ch,const char * mod)3793 LogBeforeApply(const ModChain *ch, const char *mod)
3794 {
3795           const Expr *expr = ch->expr;
3796           bool is_single_char = mod[0] != '\0' && IsDelimiter(mod[1], ch);
3797 
3798           /*
3799            * At this point, only the first character of the modifier can
3800            * be used since the end of the modifier is not yet known.
3801            */
3802 
3803           if (!Expr_ShouldEval(expr)) {
3804                     debug_printf("Parsing modifier ${%s:%c%s}\n",
3805                         expr->name, mod[0], is_single_char ? "" : "...");
3806                     return;
3807           }
3808 
3809           if (ShouldLogInSimpleFormat(expr)) {
3810                     debug_printf(
3811                         "Evaluating modifier ${%s:%c%s} on value \"%s\"\n",
3812                         expr->name, mod[0], is_single_char ? "" : "...",
3813                         Expr_Str(expr));
3814                     return;
3815           }
3816 
3817           debug_printf(
3818               "Evaluating modifier ${%s:%c%s} on value \"%s\" (%s, %s)\n",
3819               expr->name, mod[0], is_single_char ? "" : "...", Expr_Str(expr),
3820               VarEvalMode_Name[expr->emode], ExprDefined_Name[expr->defined]);
3821 }
3822 
3823 static void
LogAfterApply(const ModChain * ch,const char * p,const char * mod)3824 LogAfterApply(const ModChain *ch, const char *p, const char *mod)
3825 {
3826           const Expr *expr = ch->expr;
3827           const char *value = Expr_Str(expr);
3828 
3829           if (ShouldLogInSimpleFormat(expr)) {
3830                     debug_printf("Result of ${%s:%.*s} is \"%s\"\n",
3831                         expr->name, (int)(p - mod), mod, value);
3832                     return;
3833           }
3834 
3835           debug_printf("Result of ${%s:%.*s} is \"%s\" (%s, %s)\n",
3836               expr->name, (int)(p - mod), mod, value,
3837               VarEvalMode_Name[expr->emode],
3838               ExprDefined_Name[expr->defined]);
3839 }
3840 
3841 static ApplyModifierResult
ApplyModifier(const char ** pp,ModChain * ch)3842 ApplyModifier(const char **pp, ModChain *ch)
3843 {
3844           switch (**pp) {
3845           case '!':
3846                     return ApplyModifier_ShellCommand(pp, ch);
3847           case ':':
3848                     return ApplyModifier_Assign(pp, ch);
3849           case '?':
3850                     return ApplyModifier_IfElse(pp, ch);
3851           case '@':
3852                     return ApplyModifier_Loop(pp, ch);
3853           case '[':
3854                     return ApplyModifier_Words(pp, ch);
3855           case '_':
3856                     return ApplyModifier_Remember(pp, ch);
3857           case 'C':
3858                     return ApplyModifier_Regex(pp, ch);
3859           case 'D':
3860           case 'U':
3861                     return ApplyModifier_Defined(pp, ch);
3862           case 'E':
3863                     return ApplyModifier_WordFunc(pp, ch, ModifyWord_Suffix);
3864           case 'g':
3865           case 'l':
3866                     return ApplyModifier_Time(pp, ch);
3867           case 'H':
3868                     return ApplyModifier_WordFunc(pp, ch, ModifyWord_Head);
3869           case 'h':
3870                     return ApplyModifier_Hash(pp, ch);
3871           case 'L':
3872                     return ApplyModifier_Literal(pp, ch);
3873           case 'M':
3874           case 'N':
3875                     return ApplyModifier_Match(pp, ch);
3876           case 'm':
3877                     return ApplyModifier_Mtime(pp, ch);
3878           case 'O':
3879                     return ApplyModifier_Order(pp, ch);
3880           case 'P':
3881                     return ApplyModifier_Path(pp, ch);
3882           case 'Q':
3883           case 'q':
3884                     return ApplyModifier_Quote(pp, ch);
3885           case 'R':
3886                     return ApplyModifier_WordFunc(pp, ch, ModifyWord_Root);
3887           case 'r':
3888                     return ApplyModifier_Range(pp, ch);
3889           case 'S':
3890                     return ApplyModifier_Subst(pp, ch);
3891           case 's':
3892                     return ApplyModifier_SunShell(pp, ch);
3893           case 'T':
3894                     return ApplyModifier_WordFunc(pp, ch, ModifyWord_Tail);
3895           case 't':
3896                     return ApplyModifier_To(pp, ch);
3897           case 'u':
3898                     return ApplyModifier_Unique(pp, ch);
3899           default:
3900                     return AMR_UNKNOWN;
3901           }
3902 }
3903 
3904 static void ApplyModifiers(Expr *, const char **, char, char);
3905 
3906 typedef enum ApplyModifiersIndirectResult {
3907           /* The indirect modifiers have been applied successfully. */
3908           AMIR_CONTINUE,
3909           /* Fall back to the SysV modifier. */
3910           AMIR_SYSV,
3911           /* Error out. */
3912           AMIR_OUT
3913 } ApplyModifiersIndirectResult;
3914 
3915 /*
3916  * While expanding an expression, expand and apply indirect modifiers,
3917  * such as in ${VAR:${M_indirect}}.
3918  *
3919  * All indirect modifiers of a group must come from a single
3920  * expression.  ${VAR:${M1}} is valid but ${VAR:${M1}${M2}} is not.
3921  *
3922  * Multiple groups of indirect modifiers can be chained by separating them
3923  * with colons.  ${VAR:${M1}:${M2}} contains 2 indirect modifiers.
3924  *
3925  * If the expression is not followed by ch->endc or ':', fall
3926  * back to trying the SysV modifier, such as in ${VAR:${FROM}=${TO}}.
3927  */
3928 static ApplyModifiersIndirectResult
ApplyModifiersIndirect(ModChain * ch,const char ** pp)3929 ApplyModifiersIndirect(ModChain *ch, const char **pp)
3930 {
3931           Expr *expr = ch->expr;
3932           const char *p = *pp;
3933           FStr mods = Var_Parse(&p, expr->scope, expr->emode);
3934           /* TODO: handle errors */
3935 
3936           if (mods.str[0] != '\0' && !IsDelimiter(*p, ch)) {
3937                     FStr_Done(&mods);
3938                     return AMIR_SYSV;
3939           }
3940 
3941           DEBUG3(VAR, "Indirect modifier \"%s\" from \"%.*s\"\n",
3942               mods.str, (int)(p - *pp), *pp);
3943 
3944           if (ModChain_ShouldEval(ch) && mods.str[0] != '\0') {
3945                     const char *modsp = mods.str;
3946                     EvalStack_Push(VSK_INDIRECT_MODIFIERS, mods.str, NULL);
3947                     ApplyModifiers(expr, &modsp, '\0', '\0');
3948                     EvalStack_Pop();
3949                     if (Expr_Str(expr) == var_Error || *modsp != '\0') {
3950                               FStr_Done(&mods);
3951                               *pp = p;
3952                               return AMIR_OUT;    /* error already reported */
3953                     }
3954           }
3955           FStr_Done(&mods);
3956 
3957           if (*p == ':')
3958                     p++;
3959           else if (*p == '\0' && ch->endc != '\0') {
3960                     Parse_Error(PARSE_FATAL,
3961                         "Unclosed expression after indirect modifier, "
3962                         "expecting '%c'",
3963                         ch->endc);
3964                     *pp = p;
3965                     return AMIR_OUT;
3966           }
3967 
3968           *pp = p;
3969           return AMIR_CONTINUE;
3970 }
3971 
3972 static ApplyModifierResult
ApplySingleModifier(const char ** pp,ModChain * ch)3973 ApplySingleModifier(const char **pp, ModChain *ch)
3974 {
3975           ApplyModifierResult res;
3976           const char *mod = *pp;
3977           const char *p = *pp;
3978 
3979           if (DEBUG(VAR))
3980                     LogBeforeApply(ch, mod);
3981 
3982           if (posix_state == PS_SET)
3983                     res = ApplyModifier_SysV(&p, ch);
3984           else
3985                     res = AMR_UNKNOWN;
3986           if (res == AMR_UNKNOWN)
3987                     res = ApplyModifier(&p, ch);
3988 
3989           if (res == AMR_UNKNOWN && posix_state != PS_SET) {
3990                     assert(p == mod);
3991                     res = ApplyModifier_SysV(&p, ch);
3992           }
3993 
3994           if (res == AMR_UNKNOWN) {
3995                     /*
3996                      * Guess the end of the current modifier.
3997                      * XXX: Skipping the rest of the modifier hides
3998                      * errors and leads to wrong results.
3999                      * Parsing should rather stop here.
4000                      */
4001                     for (p++; !IsDelimiter(*p, ch); p++)
4002                               continue;
4003                     Parse_Error(PARSE_FATAL, "Unknown modifier \":%.*s\"",
4004                         (int)(p - mod), mod);
4005                     Expr_SetValueRefer(ch->expr, var_Error);
4006                     res = AMR_CLEANUP;
4007           }
4008           if (res != AMR_OK) {
4009                     *pp = p;
4010                     return res;
4011           }
4012 
4013           if (DEBUG(VAR))
4014                     LogAfterApply(ch, p, mod);
4015 
4016           if (*p == '\0' && ch->endc != '\0') {
4017                     Parse_Error(PARSE_FATAL,
4018                         "Unclosed expression, expecting '%c' for "
4019                         "modifier \"%.*s\"",
4020                         ch->endc, (int)(p - mod), mod);
4021           } else if (*p == ':') {
4022                     p++;
4023           } else if (opts.strict && *p != '\0' && *p != ch->endc) {
4024                     Parse_Error(PARSE_FATAL,
4025                         "Missing delimiter ':' after modifier \"%.*s\"",
4026                         (int)(p - mod), mod);
4027                     /*
4028                      * TODO: propagate parse error to the enclosing
4029                      * expression
4030                      */
4031           }
4032           *pp = p;
4033           return AMR_OK;
4034 }
4035 
4036 #if __STDC_VERSION__ >= 199901L
4037 #define ModChain_Init(expr, startc, endc, sep, oneBigWord) \
4038           (ModChain) { expr, startc, endc, sep, oneBigWord }
4039 #else
4040 MAKE_INLINE ModChain
ModChain_Init(Expr * expr,char startc,char endc,char sep,bool oneBigWord)4041 ModChain_Init(Expr *expr, char startc, char endc, char sep, bool oneBigWord)
4042 {
4043           ModChain ch;
4044           ch.expr = expr;
4045           ch.startc = startc;
4046           ch.endc = endc;
4047           ch.sep = sep;
4048           ch.oneBigWord = oneBigWord;
4049           return ch;
4050 }
4051 #endif
4052 
4053 /* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */
4054 static void
ApplyModifiers(Expr * expr,const char ** pp,char startc,char endc)4055 ApplyModifiers(
4056     Expr *expr,
4057     const char **pp,          /* the parsing position, updated upon return */
4058     char startc,    /* '(' or '{'; or '\0' for indirect modifiers */
4059     char endc                 /* ')' or '}'; or '\0' for indirect modifiers */
4060 )
4061 {
4062           ModChain ch = ModChain_Init(expr, startc, endc, ' ', false);
4063           const char *p;
4064 
4065           assert(startc == '(' || startc == '{' || startc == '\0');
4066           assert(endc == ')' || endc == '}' || endc == '\0');
4067           assert(Expr_Str(expr) != NULL);
4068 
4069           p = *pp;
4070 
4071           if (*p == '\0' && endc != '\0') {
4072                     Parse_Error(PARSE_FATAL,
4073                         "Unclosed expression, expecting '%c'", ch.endc);
4074                     goto cleanup;
4075           }
4076 
4077           while (*p != '\0' && *p != endc) {
4078                     ApplyModifierResult res;
4079 
4080                     if (*p == '$') {
4081                               /*
4082                                * TODO: Only evaluate the expression once, no matter
4083                                * whether it's an indirect modifier or the initial
4084                                * part of a SysV modifier.
4085                                */
4086                               ApplyModifiersIndirectResult amir =
4087                                   ApplyModifiersIndirect(&ch, &p);
4088                               if (amir == AMIR_CONTINUE)
4089                                         continue;
4090                               if (amir == AMIR_OUT)
4091                                         break;
4092                     }
4093 
4094                     res = ApplySingleModifier(&p, &ch);
4095                     if (res == AMR_CLEANUP)
4096                               goto cleanup;
4097           }
4098 
4099           *pp = p;
4100           assert(Expr_Str(expr) != NULL);         /* Use var_Error or varUndefined. */
4101           return;
4102 
4103 cleanup:
4104           /*
4105            * TODO: Use p + strlen(p) instead, to stop parsing immediately.
4106            *
4107            * In the unit tests, this generates a few shell commands with
4108            * unbalanced quotes.  Instead of producing these incomplete strings,
4109            * commands with evaluation errors should not be run at all.
4110            *
4111            * To make that happen, Var_Subst must report the actual errors
4112            * instead of returning the resulting string unconditionally.
4113            */
4114           *pp = p;
4115           Expr_SetValueRefer(expr, var_Error);
4116 }
4117 
4118 /*
4119  * Only 4 of the 7 built-in local variables are treated specially as they are
4120  * the only ones that will be set when dynamic sources are expanded.
4121  */
4122 static bool
VarnameIsDynamic(Substring varname)4123 VarnameIsDynamic(Substring varname)
4124 {
4125           const char *name;
4126           size_t len;
4127 
4128           name = varname.start;
4129           len = Substring_Length(varname);
4130           if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) {
4131                     switch (name[0]) {
4132                     case '@':
4133                     case '%':
4134                     case '*':
4135                     case '!':
4136                               return true;
4137                     }
4138                     return false;
4139           }
4140 
4141           if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) {
4142                     return Substring_Equals(varname, ".TARGET") ||
4143                            Substring_Equals(varname, ".ARCHIVE") ||
4144                            Substring_Equals(varname, ".PREFIX") ||
4145                            Substring_Equals(varname, ".MEMBER");
4146           }
4147 
4148           return false;
4149 }
4150 
4151 static const char *
UndefinedShortVarValue(char varname,const GNode * scope)4152 UndefinedShortVarValue(char varname, const GNode *scope)
4153 {
4154           if (scope == SCOPE_CMDLINE || scope == SCOPE_GLOBAL) {
4155                     /*
4156                      * If substituting a local variable in a non-local scope,
4157                      * assume it's for dynamic source stuff. We have to handle
4158                      * this specially and return the longhand for the variable
4159                      * with the dollar sign escaped so it makes it back to the
4160                      * caller. Only four of the local variables are treated
4161                      * specially as they are the only four that will be set
4162                      * when dynamic sources are expanded.
4163                      */
4164                     switch (varname) {
4165                     case '@':
4166                               return "$(.TARGET)";
4167                     case '%':
4168                               return "$(.MEMBER)";
4169                     case '*':
4170                               return "$(.PREFIX)";
4171                     case '!':
4172                               return "$(.ARCHIVE)";
4173                     }
4174           }
4175           return NULL;
4176 }
4177 
4178 /*
4179  * Parse a variable name, until the end character or a colon, whichever
4180  * comes first.
4181  */
4182 static void
ParseVarname(const char ** pp,char startc,char endc,GNode * scope,VarEvalMode emode,LazyBuf * buf)4183 ParseVarname(const char **pp, char startc, char endc,
4184                GNode *scope, VarEvalMode emode,
4185                LazyBuf *buf)
4186 {
4187           const char *p = *pp;
4188           int depth = 0;
4189 
4190           LazyBuf_Init(buf, p);
4191 
4192           while (*p != '\0') {
4193                     if ((*p == endc || *p == ':') && depth == 0)
4194                               break;
4195                     if (*p == startc)
4196                               depth++;
4197                     if (*p == endc)
4198                               depth--;
4199 
4200                     if (*p == '$') {
4201                               FStr nested_val = Var_Parse(&p, scope, emode);
4202                               /* TODO: handle errors */
4203                               LazyBuf_AddStr(buf, nested_val.str);
4204                               FStr_Done(&nested_val);
4205                     } else {
4206                               LazyBuf_Add(buf, *p);
4207                               p++;
4208                     }
4209           }
4210           *pp = p;
4211 }
4212 
4213 static bool
IsShortVarnameValid(char varname,const char * start)4214 IsShortVarnameValid(char varname, const char *start)
4215 {
4216           if (varname != '$' && varname != ':' && varname != '}' &&
4217               varname != ')' && varname != '\0')
4218                     return true;
4219 
4220           if (!opts.strict)
4221                     return false;       /* XXX: Missing error message */
4222 
4223           if (varname == '$' && save_dollars)
4224                     Parse_Error(PARSE_FATAL,
4225                         "To escape a dollar, use \\$, not $$, at \"%s\"", start);
4226           else if (varname == '\0')
4227                     Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
4228           else if (save_dollars)
4229                     Parse_Error(PARSE_FATAL,
4230                         "Invalid variable name '%c', at \"%s\"", varname, start);
4231 
4232           return false;
4233 }
4234 
4235 /*
4236  * Parse a single-character variable name such as in $V or $@.
4237  * Return whether to continue parsing.
4238  */
4239 static bool
ParseVarnameShort(char varname,const char ** pp,GNode * scope,VarEvalMode emode,const char ** out_false_val,Var ** out_true_var)4240 ParseVarnameShort(char varname, const char **pp, GNode *scope,
4241                       VarEvalMode emode,
4242                       const char **out_false_val,
4243                       Var **out_true_var)
4244 {
4245           char name[2];
4246           Var *v;
4247           const char *val;
4248 
4249           if (!IsShortVarnameValid(varname, *pp)) {
4250                     (*pp)++;  /* only skip the '$' */
4251                     *out_false_val = var_Error;
4252                     return false;
4253           }
4254 
4255           name[0] = varname;
4256           name[1] = '\0';
4257           v = VarFind(name, scope, true);
4258           if (v != NULL) {
4259                     /* No need to advance *pp, the calling code handles this. */
4260                     *out_true_var = v;
4261                     return true;
4262           }
4263 
4264           *pp += 2;
4265 
4266           val = UndefinedShortVarValue(varname, scope);
4267           if (val == NULL)
4268                     val = emode == VARE_EVAL_DEFINED
4269                         || emode == VARE_EVAL_DEFINED_LOUD
4270                         ? var_Error : varUndefined;
4271 
4272           if ((opts.strict || emode == VARE_EVAL_DEFINED_LOUD)
4273               && val == var_Error) {
4274                     Parse_Error(PARSE_FATAL,
4275                         "Variable \"%s\" is undefined", name);
4276           }
4277 
4278           *out_false_val = val;
4279           return false;
4280 }
4281 
4282 /* Find variables like @F or <D. */
4283 static Var *
FindLocalLegacyVar(Substring varname,GNode * scope,const char ** out_extraModifiers)4284 FindLocalLegacyVar(Substring varname, GNode *scope,
4285                        const char **out_extraModifiers)
4286 {
4287           Var *v;
4288 
4289           /* Only resolve these variables if scope is a "real" target. */
4290           if (scope == SCOPE_CMDLINE || scope == SCOPE_GLOBAL)
4291                     return NULL;
4292 
4293           if (Substring_Length(varname) != 2)
4294                     return NULL;
4295           if (varname.start[1] != 'F' && varname.start[1] != 'D')
4296                     return NULL;
4297           if (strchr("@%?*!<>", varname.start[0]) == NULL)
4298                     return NULL;
4299 
4300           v = VarFindSubstring(Substring_Init(varname.start, varname.start + 1),
4301               scope, false);
4302           if (v == NULL)
4303                     return NULL;
4304 
4305           *out_extraModifiers = varname.start[1] == 'D' ? "H:" : "T:";
4306           return v;
4307 }
4308 
4309 static FStr
EvalUndefined(bool dynamic,const char * start,const char * p,Substring varname,VarEvalMode emode,int parseErrorsBefore)4310 EvalUndefined(bool dynamic, const char *start, const char *p,
4311                 Substring varname, VarEvalMode emode, int parseErrorsBefore)
4312 {
4313           if (dynamic)
4314                     return FStr_InitOwn(bmake_strsedup(start, p));
4315 
4316           if (emode == VARE_EVAL_DEFINED_LOUD
4317               || (emode == VARE_EVAL_DEFINED && opts.strict)) {
4318                     if (parseErrors == parseErrorsBefore) {
4319                               Parse_Error(PARSE_FATAL,
4320                                   "Variable \"%.*s\" is undefined",
4321                                   (int) Substring_Length(varname), varname.start);
4322                     }
4323                     return FStr_InitRefer(var_Error);
4324           }
4325 
4326           return FStr_InitRefer(
4327               emode == VARE_EVAL_DEFINED_LOUD || emode == VARE_EVAL_DEFINED
4328                     ? var_Error : varUndefined);
4329 }
4330 
4331 /*
4332  * Parse a long variable name enclosed in braces or parentheses such as $(VAR)
4333  * or ${VAR}, up to the closing brace or parenthesis, or in the case of
4334  * ${VAR:Modifiers}, up to the ':' that starts the modifiers.
4335  * Return whether to continue parsing.
4336  */
4337 static bool
ParseVarnameLong(const char ** pp,char startc,GNode * scope,VarEvalMode emode,VarEvalMode nested_emode,int parseErrorsBefore,const char ** out_false_pp,FStr * out_false_val,char * out_true_endc,Var ** out_true_v,bool * out_true_haveModifier,const char ** out_true_extraModifiers,bool * out_true_dynamic,ExprDefined * out_true_exprDefined)4338 ParseVarnameLong(
4339           const char **pp,
4340           char startc,
4341           GNode *scope,
4342           VarEvalMode emode,
4343           VarEvalMode nested_emode,
4344           int parseErrorsBefore,
4345 
4346           const char **out_false_pp,
4347           FStr *out_false_val,
4348 
4349           char *out_true_endc,
4350           Var **out_true_v,
4351           bool *out_true_haveModifier,
4352           const char **out_true_extraModifiers,
4353           bool *out_true_dynamic,
4354           ExprDefined *out_true_exprDefined
4355 )
4356 {
4357           LazyBuf varname;
4358           Substring name;
4359           Var *v;
4360           bool haveModifier;
4361           bool dynamic = false;
4362 
4363           const char *p = *pp;
4364           const char *start = p;
4365           char endc = startc == '(' ? ')' : '}';
4366 
4367           p += 2;                       /* skip "${" or "$(" or "y(" */
4368           ParseVarname(&p, startc, endc, scope, nested_emode, &varname);
4369           name = LazyBuf_Get(&varname);
4370 
4371           if (*p == ':')
4372                     haveModifier = true;
4373           else if (*p == endc)
4374                     haveModifier = false;
4375           else {
4376                     Parse_Error(PARSE_FATAL, "Unclosed variable \"%.*s\"",
4377                         (int)Substring_Length(name), name.start);
4378                     LazyBuf_Done(&varname);
4379                     *out_false_pp = p;
4380                     *out_false_val = FStr_InitRefer(var_Error);
4381                     return false;
4382           }
4383 
4384           v = VarFindSubstring(name, scope, true);
4385 
4386           /*
4387            * At this point, p points just after the variable name, either at
4388            * ':' or at endc.
4389            */
4390 
4391           if (v == NULL && Substring_Equals(name, ".SUFFIXES")) {
4392                     char *suffixes = Suff_NamesStr();
4393                     v = VarNew(FStr_InitRefer(".SUFFIXES"), suffixes,
4394                         true, false, true);
4395                     free(suffixes);
4396           } else if (v == NULL)
4397                     v = FindLocalLegacyVar(name, scope, out_true_extraModifiers);
4398 
4399           if (v == NULL) {
4400                     /*
4401                      * Defer expansion of dynamic variables if they appear in
4402                      * non-local scope since they are not defined there.
4403                      */
4404                     dynamic = VarnameIsDynamic(name) &&
4405                                 (scope == SCOPE_CMDLINE || scope == SCOPE_GLOBAL);
4406 
4407                     if (!haveModifier) {
4408                               p++;      /* skip endc */
4409                               *out_false_pp = p;
4410                               *out_false_val = EvalUndefined(dynamic, start, p,
4411                                   name, emode, parseErrorsBefore);
4412                               LazyBuf_Done(&varname);
4413                               return false;
4414                     }
4415 
4416                     /*
4417                      * The expression is based on an undefined variable.
4418                      * Nevertheless it needs a Var, for modifiers that access the
4419                      * variable name, such as :L or :?.
4420                      *
4421                      * Most modifiers leave this expression in the "undefined"
4422                      * state (DEF_UNDEF), only a few modifiers like :D, :U, :L,
4423                      * :P turn this undefined expression into a defined
4424                      * expression (DEF_DEFINED).
4425                      *
4426                      * In the end, after applying all modifiers, if the expression
4427                      * is still undefined, Var_Parse will return an empty string
4428                      * instead of the actually computed value.
4429                      */
4430                     v = VarNew(LazyBuf_DoneGet(&varname), "",
4431                         true, false, false);
4432                     *out_true_exprDefined = DEF_UNDEF;
4433           } else
4434                     LazyBuf_Done(&varname);
4435 
4436           *pp = p;
4437           *out_true_endc = endc;
4438           *out_true_v = v;
4439           *out_true_haveModifier = haveModifier;
4440           *out_true_dynamic = dynamic;
4441           return true;
4442 }
4443 
4444 #if __STDC_VERSION__ >= 199901L
4445 #define Expr_Init(name, value, emode, scope, defined) \
4446           (Expr) { name, value, emode, scope, defined }
4447 #else
4448 MAKE_INLINE Expr
Expr_Init(const char * name,FStr value,VarEvalMode emode,GNode * scope,ExprDefined defined)4449 Expr_Init(const char *name, FStr value,
4450             VarEvalMode emode, GNode *scope, ExprDefined defined)
4451 {
4452           Expr expr;
4453 
4454           expr.name = name;
4455           expr.value = value;
4456           expr.emode = emode;
4457           expr.scope = scope;
4458           expr.defined = defined;
4459           return expr;
4460 }
4461 #endif
4462 
4463 /*
4464  * Expressions of the form ${:U...} with a trivial value are often generated
4465  * by .for loops and are boring, so evaluate them without debug logging.
4466  */
4467 static bool
Var_Parse_U(const char ** pp,VarEvalMode emode,FStr * out_value)4468 Var_Parse_U(const char **pp, VarEvalMode emode, FStr *out_value)
4469 {
4470           const char *p;
4471 
4472           p = *pp;
4473           if (!(p[0] == '$' && p[1] == '{' && p[2] == ':' && p[3] == 'U'))
4474                     return false;
4475 
4476           p += 4;
4477           while (*p != '$' && *p != '{' && *p != ':' && *p != '\\' &&
4478                  *p != '}' && *p != '\0')
4479                     p++;
4480           if (*p != '}')
4481                     return false;
4482 
4483           *out_value = emode == VARE_PARSE
4484               ? FStr_InitRefer("")
4485               : FStr_InitOwn(bmake_strsedup(*pp + 4, p));
4486           *pp = p + 1;
4487           return true;
4488 }
4489 
4490 /*
4491  * Given the start of an expression (such as $v, $(VAR), ${VAR:Mpattern}),
4492  * extract the variable name and the modifiers, if any.  While parsing, apply
4493  * the modifiers to the value of the expression.
4494  *
4495  * Input:
4496  *        *pp                 The string to parse.
4497  *                            When called from CondParser_FuncCallEmpty, it can
4498  *                            also point to the "y" of "empty(VARNAME:Modifiers)".
4499  *        scope               The scope for finding variables.
4500  *        emode               Controls the exact details of parsing and evaluation.
4501  *
4502  * Output:
4503  *        *pp                 The position where to continue parsing.
4504  *                            TODO: After a parse error, the value of *pp is
4505  *                            unspecified.  It may not have been updated at all,
4506  *                            point to some random character in the string, to the
4507  *                            location of the parse error, or at the end of the
4508  *                            string.
4509  *        return              The value of the expression, never NULL.
4510  *        return              var_Error if there was a parse error.
4511  *        return              var_Error if the base variable of the expression was
4512  *                            undefined, emode is VARE_EVAL_DEFINED, and none of
4513  *                            the modifiers turned the undefined expression into a
4514  *                            defined expression.
4515  *                            XXX: It is not guaranteed that an error message has
4516  *                            been printed.
4517  *        return              varUndefined if the base variable of the expression
4518  *                            was undefined, emode was not VARE_EVAL_DEFINED,
4519  *                            and none of the modifiers turned the undefined
4520  *                            expression into a defined expression.
4521  */
4522 FStr
Var_Parse(const char ** pp,GNode * scope,VarEvalMode emode)4523 Var_Parse(const char **pp, GNode *scope, VarEvalMode emode)
4524 {
4525           const char *start, *p;
4526           bool haveModifier;  /* true for ${VAR:...}, false for ${VAR} */
4527           char startc;                  /* the actual '{' or '(' or '\0' */
4528           char endc;                    /* the expected '}' or ')' or '\0' */
4529           /*
4530            * true if the expression is based on one of the 7 predefined
4531            * variables that are local to a target, and the expression is
4532            * expanded in a non-local scope.  The result is the text of the
4533            * expression, unaltered.  This is needed to support dynamic sources.
4534            */
4535           bool dynamic;
4536           const char *extramodifiers;
4537           Var *v;
4538           Expr expr = Expr_Init(NULL, FStr_InitRefer(NULL),
4539               emode == VARE_EVAL_DEFINED || emode == VARE_EVAL_DEFINED_LOUD
4540                     ? VARE_EVAL : emode,
4541               scope, DEF_REGULAR);
4542           FStr val;
4543           int parseErrorsBefore = parseErrors;
4544 
4545           if (Var_Parse_U(pp, emode, &val))
4546                     return val;
4547 
4548           p = *pp;
4549           start = p;
4550           DEBUG2(VAR, "Var_Parse: %s (%s)\n", start, VarEvalMode_Name[emode]);
4551 
4552           val = FStr_InitRefer(NULL);
4553           extramodifiers = NULL;        /* extra modifiers to apply first */
4554           dynamic = false;
4555 
4556           endc = '\0';                  /* Appease GCC. */
4557 
4558           startc = p[1];
4559           if (startc != '(' && startc != '{') {
4560                     if (!ParseVarnameShort(startc, pp, scope, emode, &val.str, &v))
4561                               return val;
4562                     haveModifier = false;
4563                     p++;
4564           } else {
4565                     if (!ParseVarnameLong(&p, startc, scope, emode, expr.emode,
4566                         parseErrorsBefore,
4567                         pp, &val,
4568                         &endc, &v, &haveModifier, &extramodifiers,
4569                         &dynamic, &expr.defined))
4570                               return val;
4571           }
4572 
4573           expr.name = v->name.str;
4574           if (v->inUse && VarEvalMode_ShouldEval(emode)) {
4575                     Parse_Error(PARSE_FATAL, "Variable %s is recursive.",
4576                         v->name.str);
4577                     FStr_Done(&val);
4578                     if (*p != '\0')
4579                               p++;
4580                     *pp = p;
4581                     return FStr_InitRefer(var_Error);
4582           }
4583 
4584           /*
4585            * FIXME: This assignment creates an alias to the current value of the
4586            * variable.  This means that as long as the value of the expression
4587            * stays the same, the value of the variable must not change, and the
4588            * variable must not be deleted.  Using the ':@' modifier, it is
4589            * possible (since var.c 1.212 from 2017-02-01) to delete the variable
4590            * while its value is still being used:
4591            *
4592            *        VAR=      value
4593            *        _:=       ${VAR:${:U:@VAR@@}:S,^,prefix,}
4594            *
4595            * The same effect might be achievable using the '::=' or the ':_'
4596            * modifiers.
4597            *
4598            * At the bottom of this function, the resulting value is compared to
4599            * the then-current value of the variable.  This might also invoke
4600            * undefined behavior.
4601            */
4602           expr.value = FStr_InitRefer(v->val.data);
4603 
4604           if (!VarEvalMode_ShouldEval(emode))
4605                     EvalStack_Push(VSK_EXPR_PARSE, start, NULL);
4606           else if (expr.name[0] != '\0')
4607                     EvalStack_Push(VSK_VARNAME, expr.name, &expr.value);
4608           else
4609                     EvalStack_Push(VSK_EXPR, start, &expr.value);
4610 
4611           /*
4612            * Before applying any modifiers, expand any nested expressions from
4613            * the variable value.
4614            */
4615           if (VarEvalMode_ShouldEval(emode) &&
4616               strchr(Expr_Str(&expr), '$') != NULL) {
4617                     char *expanded;
4618                     v->inUse = true;
4619                     expanded = Var_Subst(Expr_Str(&expr), scope, expr.emode);
4620                     v->inUse = false;
4621                     /* TODO: handle errors */
4622                     Expr_SetValueOwn(&expr, expanded);
4623           }
4624 
4625           if (extramodifiers != NULL) {
4626                     const char *em = extramodifiers;
4627                     ApplyModifiers(&expr, &em, '\0', '\0');
4628           }
4629 
4630           if (haveModifier) {
4631                     p++;                /* Skip initial colon. */
4632                     ApplyModifiers(&expr, &p, startc, endc);
4633           }
4634 
4635           if (*p != '\0')               /* Skip past endc if possible. */
4636                     p++;
4637 
4638           *pp = p;
4639 
4640           if (expr.defined == DEF_UNDEF) {
4641                     Substring varname = Substring_InitStr(expr.name);
4642                     FStr value = EvalUndefined(dynamic, start, p, varname, emode,
4643                         parseErrorsBefore);
4644                     Expr_SetValue(&expr, value);
4645           }
4646 
4647           EvalStack_Pop();
4648 
4649           if (v->shortLived) {
4650                     if (expr.value.str == v->val.data) {
4651                               /* move ownership */
4652                               expr.value.freeIt = v->val.data;
4653                               v->val.data = NULL;
4654                     }
4655                     VarFreeShortLived(v);
4656           }
4657 
4658           return expr.value;
4659 }
4660 
4661 static void
VarSubstDollarDollar(const char ** pp,Buffer * res,VarEvalMode emode)4662 VarSubstDollarDollar(const char **pp, Buffer *res, VarEvalMode emode)
4663 {
4664           /* A dollar sign may be escaped with another dollar sign. */
4665           if (save_dollars && VarEvalMode_ShouldKeepDollar(emode))
4666                     Buf_AddByte(res, '$');
4667           Buf_AddByte(res, '$');
4668           *pp += 2;
4669 }
4670 
4671 static void
VarSubstExpr(const char ** pp,Buffer * buf,GNode * scope,VarEvalMode emode)4672 VarSubstExpr(const char **pp, Buffer *buf, GNode *scope, VarEvalMode emode)
4673 {
4674           const char *p = *pp;
4675           const char *nested_p = p;
4676           FStr val = Var_Parse(&nested_p, scope, emode);
4677           /* TODO: handle errors */
4678 
4679           if (val.str == var_Error || val.str == varUndefined) {
4680                     if (!VarEvalMode_ShouldKeepUndef(emode)
4681                         || val.str == var_Error) {
4682                               p = nested_p;
4683                     } else {
4684                               /*
4685                                * Copy the initial '$' of the undefined expression,
4686                                * thereby deferring expansion of the expression, but
4687                                * expand nested expressions if already possible. See
4688                                * unit-tests/varparse-undef-partial.mk.
4689                                */
4690                               Buf_AddByte(buf, *p);
4691                               p++;
4692                     }
4693           } else {
4694                     p = nested_p;
4695                     Buf_AddStr(buf, val.str);
4696           }
4697 
4698           FStr_Done(&val);
4699 
4700           *pp = p;
4701 }
4702 
4703 /*
4704  * Skip as many characters as possible -- either to the end of the string,
4705  * or to the next dollar sign, which may start an expression.
4706  */
4707 static void
VarSubstPlain(const char ** pp,Buffer * res)4708 VarSubstPlain(const char **pp, Buffer *res)
4709 {
4710           const char *p = *pp;
4711           const char *start = p;
4712 
4713           for (p++; *p != '$' && *p != '\0'; p++)
4714                     continue;
4715           Buf_AddRange(res, start, p);
4716           *pp = p;
4717 }
4718 
4719 /*
4720  * Expand all expressions like $V, ${VAR}, $(VAR:Modifiers) in the
4721  * given string.
4722  *
4723  * Input:
4724  *        str                 The string in which the expressions are expanded.
4725  *        scope               The scope in which to start searching for variables.
4726  *                            The other scopes are searched as well.
4727  *        emode               The mode for parsing or evaluating subexpressions.
4728  */
4729 char *
Var_Subst(const char * str,GNode * scope,VarEvalMode emode)4730 Var_Subst(const char *str, GNode *scope, VarEvalMode emode)
4731 {
4732           const char *p = str;
4733           Buffer res;
4734 
4735           Buf_Init(&res);
4736 
4737           while (*p != '\0') {
4738                     if (p[0] == '$' && p[1] == '$')
4739                               VarSubstDollarDollar(&p, &res, emode);
4740                     else if (p[0] == '$')
4741                               VarSubstExpr(&p, &res, scope, emode);
4742                     else
4743                               VarSubstPlain(&p, &res);
4744           }
4745 
4746           return Buf_DoneData(&res);
4747 }
4748 
4749 char *
Var_SubstInTarget(const char * str,GNode * scope)4750 Var_SubstInTarget(const char *str, GNode *scope)
4751 {
4752           char *res;
4753           EvalStack_Push(VSK_TARGET, scope->name, NULL);
4754           EvalStack_Push(VSK_COMMAND, str, NULL);
4755           res = Var_Subst(str, scope, VARE_EVAL);
4756           EvalStack_Pop();
4757           EvalStack_Pop();
4758           return res;
4759 }
4760 
4761 void
Var_Expand(FStr * str,GNode * scope,VarEvalMode emode)4762 Var_Expand(FStr *str, GNode *scope, VarEvalMode emode)
4763 {
4764           char *expanded;
4765 
4766           if (strchr(str->str, '$') == NULL)
4767                     return;
4768           expanded = Var_Subst(str->str, scope, emode);
4769           /* TODO: handle errors */
4770           FStr_Done(str);
4771           *str = FStr_InitOwn(expanded);
4772 }
4773 
4774 void
Var_Stats(void)4775 Var_Stats(void)
4776 {
4777           HashTable_DebugStats(&SCOPE_GLOBAL->vars, "Global variables");
4778 }
4779 
4780 static int
StrAsc(const void * sa,const void * sb)4781 StrAsc(const void *sa, const void *sb)
4782 {
4783           return strcmp(
4784               *((const char *const *)sa), *((const char *const *)sb));
4785 }
4786 
4787 
4788 /* Print all variables in a scope, sorted by name. */
4789 void
Var_Dump(GNode * scope)4790 Var_Dump(GNode *scope)
4791 {
4792           Vector /* of const char * */ vec;
4793           HashIter hi;
4794           size_t i;
4795           const char **varnames;
4796 
4797           Vector_Init(&vec, sizeof(const char *));
4798 
4799           HashIter_Init(&hi, &scope->vars);
4800           while (HashIter_Next(&hi))
4801                     *(const char **)Vector_Push(&vec) = hi.entry->key;
4802           varnames = vec.items;
4803 
4804           qsort(varnames, vec.len, sizeof varnames[0], StrAsc);
4805 
4806           for (i = 0; i < vec.len; i++) {
4807                     const char *varname = varnames[i];
4808                     const Var *var = HashTable_FindValue(&scope->vars, varname);
4809                     debug_printf("%-16s = %s%s\n", varname,
4810                         var->val.data, ValueDescription(var->val.data));
4811           }
4812 
4813           Vector_Done(&vec);
4814 }
4815