Annotation of src/usr.bin/make/var.c, Revision 1.790
1.790 ! rillig 1: /* $NetBSD: var.c,v 1.789 2021/02/02 16:18:16 rillig Exp $ */
1.11 christos 2:
1.1 cgd 3: /*
1.15 christos 4: * Copyright (c) 1988, 1989, 1990, 1993
5: * The Regents of the University of California. All rights reserved.
1.80 agc 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: /*
1.1 cgd 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:
1.592 rillig 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}}.
1.1 cgd 77: *
78: * Interface:
1.592 rillig 79: * Var_Init Initialize this module.
80: *
81: * Var_End Clean up the module.
82: *
83: * Var_Set Set the value of the variable, creating it if
84: * necessary.
85: *
86: * Var_Append Append more characters to the variable, creating it if
87: * necessary. A space is placed between the old value and
88: * the new one.
1.1 cgd 89: *
1.546 rillig 90: * Var_Exists See if a variable exists.
1.1 cgd 91: *
1.592 rillig 92: * Var_Value Return the unexpanded value of a variable, or NULL if
93: * the variable is undefined.
94: *
95: * Var_Subst Substitute all variable expressions in a string.
96: *
97: * Var_Parse Parse a variable expression such as ${VAR:Mpattern}.
1.1 cgd 98: *
1.592 rillig 99: * Var_Delete Delete a variable.
1.1 cgd 100: *
1.725 rillig 101: * Var_ReexportVars
102: * Export some or even all variables to the environment
1.592 rillig 103: * of this process and its child processes.
1.1 cgd 104: *
1.592 rillig 105: * Var_Export Export the variable to the environment of this process
106: * and its child processes.
1.1 cgd 107: *
1.592 rillig 108: * Var_UnExport Don't export the variable anymore.
1.1 cgd 109: *
110: * Debugging:
1.592 rillig 111: * Var_Stats Print out hashing statistics if in -dh mode.
112: *
113: * Var_Dump Print out all variables defined in the given context.
1.1 cgd 114: *
115: * XXX: There's a lot of duplication in these functions.
116: */
117:
1.630 rillig 118: #include <sys/stat.h>
1.31 gwr 119: #ifndef NO_REGEX
1.630 rillig 120: #include <sys/types.h>
121: #include <regex.h>
1.17 christos 122: #endif
1.631 rillig 123: #include <errno.h>
1.630 rillig 124: #include <inttypes.h>
125: #include <limits.h>
126: #include <time.h>
127:
128: #include "make.h"
129: #include "dir.h"
130: #include "job.h"
131: #include "metachar.h"
1.1 cgd 132:
1.512 rillig 133: /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
1.790 ! rillig 134: MAKE_RCSID("$NetBSD: var.c,v 1.789 2021/02/02 16:18:16 rillig Exp $");
1.240 rillig 135:
1.578 rillig 136: typedef enum VarFlags {
1.707 rillig 137: VAR_NONE = 0,
1.601 rillig 138:
1.703 rillig 139: /*
140: * The variable's value is currently being used by Var_Parse or
141: * Var_Subst. This marker is used to avoid endless recursion.
142: */
143: VAR_IN_USE = 0x01,
144:
145: /*
146: * The variable comes from the environment.
147: * These variables are not registered in any GNode, therefore they
148: * must be freed as soon as they are not used anymore.
149: */
150: VAR_FROM_ENV = 0x02,
151:
152: /*
153: * The variable is exported to the environment, to be used by child
154: * processes.
155: */
156: VAR_EXPORTED = 0x10,
157:
158: /*
159: * At the point where this variable was exported, it contained an
160: * unresolved reference to another variable. Before any child
161: * process is started, it needs to be exported again, in the hope
162: * that the referenced variable can then be resolved.
163: */
164: VAR_REEXPORT = 0x20,
165:
166: /* The variable came from the command line. */
167: VAR_FROM_CMD = 0x40,
168:
169: /*
170: * The variable value cannot be changed anymore, and the variable
171: * cannot be deleted. Any attempts to do so are silently ignored,
172: * they are logged with -dv though.
173: */
174: VAR_READONLY = 0x80
1.414 rillig 175: } VarFlags;
1.228 rillig 176:
1.778 rillig 177: /*
178: * Variables are defined using one of the VAR=value assignments. Their
1.570 rillig 179: * value can be queried by expressions such as $V, ${VAR}, or with modifiers
180: * such as ${VAR:S,from,to,g:Q}.
181: *
182: * There are 3 kinds of variables: context variables, environment variables,
183: * undefined variables.
184: *
185: * Context variables are stored in a GNode.context. The only way to undefine
186: * a context variable is using the .undef directive. In particular, it must
187: * not be possible to undefine a variable during the evaluation of an
188: * expression, or Var.name might point nowhere.
189: *
190: * Environment variables are temporary. They are returned by VarFind, and
191: * after using them, they must be freed using VarFreeEnv.
192: *
193: * Undefined variables occur during evaluation of variable expressions such
194: * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers.
195: */
1.1 cgd 196: typedef struct Var {
1.703 rillig 197: /*
198: * The name of the variable, once set, doesn't change anymore.
199: * For context variables, it aliases the corresponding HashEntry name.
200: * For environment and undefined variables, it is allocated.
201: */
1.711 rillig 202: FStr name;
1.570 rillig 203:
1.703 rillig 204: /* The unexpanded value of the variable. */
205: Buffer val;
206: /* Miscellaneous status flags. */
207: VarFlags flags;
1.417 rillig 208: } Var;
1.1 cgd 209:
1.710 rillig 210: /*
211: * Exporting vars is expensive so skip it if we can
212: */
213: typedef enum VarExportedMode {
214: VAR_EXPORTED_NONE,
215: VAR_EXPORTED_SOME,
216: VAR_EXPORTED_ALL
217: } VarExportedMode;
218:
1.713 rillig 219: typedef enum UnexportWhat {
220: UNEXPORT_NAMED,
221: UNEXPORT_ALL,
222: UNEXPORT_ENV
223: } UnexportWhat;
224:
1.261 rillig 225: /* Flags for pattern matching in the :S and :C modifiers */
1.788 rillig 226: typedef struct VarPatternFlags {
227:
1.703 rillig 228: /* Replace as often as possible ('g') */
1.788 rillig 229: Boolean subGlobal: 1;
1.703 rillig 230: /* Replace only once ('1') */
1.788 rillig 231: Boolean subOnce: 1;
1.703 rillig 232: /* Match at start of word ('^') */
1.788 rillig 233: Boolean anchorStart: 1;
1.703 rillig 234: /* Match at end of word ('$') */
1.788 rillig 235: Boolean anchorEnd: 1;
1.261 rillig 236: } VarPatternFlags;
1.16 christos 237:
1.710 rillig 238: /* SepBuf is a string being built from words, interleaved with separators. */
239: typedef struct SepBuf {
240: Buffer buf;
241: Boolean needSep;
242: /* Usually ' ', but see the ':ts' modifier. */
243: char sep;
244: } SepBuf;
245:
246:
1.774 rillig 247: ENUM_FLAGS_RTTI_4(VarEvalFlags,
248: VARE_UNDEFERR, VARE_WANTRES, VARE_KEEP_DOLLAR,
249: VARE_KEEP_UNDEF);
1.710 rillig 250:
251: /*
252: * This lets us tell if we have replaced the original environ
253: * (which we cannot free).
254: */
255: char **savedEnv = NULL;
256:
1.778 rillig 257: /*
258: * Special return value for Var_Parse, indicating a parse error. It may be
1.710 rillig 259: * caused by an undefined variable, a syntax error in a modifier or
1.778 rillig 260: * something entirely different.
261: */
1.710 rillig 262: char var_Error[] = "";
263:
1.778 rillig 264: /*
265: * Special return value for Var_Parse, indicating an undefined variable in
1.710 rillig 266: * a case where VARE_UNDEFERR is not set. This undefined variable is
267: * typically a dynamic variable such as ${.TARGET}, whose expansion needs to
1.778 rillig 268: * be deferred until it is defined in an actual target.
269: */
1.710 rillig 270: static char varUndefined[] = "";
271:
272: /*
273: * Traditionally this make consumed $$ during := like any other expansion.
274: * Other make's do not, and this make follows straight since 2016-01-09.
275: *
276: * This knob allows controlling the behavior.
277: * FALSE to consume $$ during := assignment.
278: * TRUE to preserve $$ during := assignment.
279: */
280: #define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
281: static Boolean save_dollars = TRUE;
282:
283: /*
284: * Internally, variables are contained in four different contexts.
285: * 1) the environment. They cannot be changed. If an environment
286: * variable is appended to, the result is placed in the global
287: * context.
288: * 2) the global context. Variables set in the makefiles are located
289: * here.
290: * 3) the command-line context. All variables set on the command line
291: * are placed in this context.
292: * 4) the local context. Each target has associated with it a context
293: * list. On this list are located the structures describing such
294: * local variables as $(@) and $(*)
295: * The four contexts are searched in the reverse order from which they are
296: * listed (but see opts.checkEnvFirst).
297: */
298: GNode *VAR_INTERNAL; /* variables from make itself */
299: GNode *VAR_GLOBAL; /* variables from the makefile */
300: GNode *VAR_CMDLINE; /* variables defined on the command-line */
301:
302: ENUM_FLAGS_RTTI_6(VarFlags,
303: VAR_IN_USE, VAR_FROM_ENV,
304: VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY);
305:
306: static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
307:
1.711 rillig 308:
1.569 rillig 309: static Var *
1.744 rillig 310: VarNew(FStr name, const char *value, VarFlags flags)
1.569 rillig 311: {
1.703 rillig 312: size_t value_len = strlen(value);
313: Var *var = bmake_malloc(sizeof *var);
1.744 rillig 314: var->name = name;
1.703 rillig 315: Buf_InitSize(&var->val, value_len + 1);
316: Buf_AddBytes(&var->val, value, value_len);
317: var->flags = flags;
318: return var;
1.569 rillig 319: }
320:
1.580 rillig 321: static const char *
322: CanonicalVarname(const char *name)
1.1 cgd 323: {
1.703 rillig 324: if (*name == '.' && ch_isupper(name[1])) {
325: switch (name[1]) {
326: case 'A':
327: if (strcmp(name, ".ALLSRC") == 0)
328: name = ALLSRC;
329: if (strcmp(name, ".ARCHIVE") == 0)
330: name = ARCHIVE;
331: break;
332: case 'I':
333: if (strcmp(name, ".IMPSRC") == 0)
334: name = IMPSRC;
335: break;
336: case 'M':
337: if (strcmp(name, ".MEMBER") == 0)
338: name = MEMBER;
339: break;
340: case 'O':
341: if (strcmp(name, ".OODATE") == 0)
342: name = OODATE;
343: break;
344: case 'P':
345: if (strcmp(name, ".PREFIX") == 0)
346: name = PREFIX;
347: break;
348: case 'S':
349: if (strcmp(name, ".SHELL") == 0) {
1.780 rillig 350: if (shellPath == NULL)
1.703 rillig 351: Shell_Init();
352: }
353: break;
354: case 'T':
355: if (strcmp(name, ".TARGET") == 0)
356: name = TARGET;
357: break;
358: }
1.242 rillig 359: }
360:
1.703 rillig 361: /* GNU make has an additional alias $^ == ${.ALLSRC}. */
1.580 rillig 362:
1.703 rillig 363: return name;
1.580 rillig 364: }
365:
1.587 rillig 366: static Var *
367: GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash)
368: {
1.703 rillig 369: return HashTable_FindValueHash(&ctxt->vars, varname, hash);
1.587 rillig 370: }
371:
1.778 rillig 372: /*
373: * Find the variable in the context, and maybe in other contexts as well.
1.580 rillig 374: *
375: * Input:
1.607 rillig 376: * name name to find, is not expanded any further
1.605 rillig 377: * ctxt context in which to look first
378: * elsewhere TRUE to look in other contexts as well
1.580 rillig 379: *
380: * Results:
1.605 rillig 381: * The found variable, or NULL if the variable does not exist.
382: * If the variable is an environment variable, it must be freed using
383: * VarFreeEnv after use.
1.580 rillig 384: */
385: static Var *
1.596 rillig 386: VarFind(const char *name, GNode *ctxt, Boolean elsewhere)
1.580 rillig 387: {
1.703 rillig 388: Var *var;
389: unsigned int nameHash;
390:
391: /*
392: * If the variable name begins with a '.', it could very well be
393: * one of the local ones. We check the name against all the local
394: * variables and substitute the short version in for 'name' if it
395: * matches one of them.
396: */
397: name = CanonicalVarname(name);
398: nameHash = Hash_Hash(name);
1.580 rillig 399:
1.703 rillig 400: /* First look for the variable in the given context. */
401: var = GNode_FindVar(ctxt, name, nameHash);
402: if (!elsewhere)
403: return var;
1.160 christos 404:
1.703 rillig 405: /*
406: * The variable was not found in the given context.
407: * Now look for it in the other contexts as well.
408: */
409: if (var == NULL && ctxt != VAR_CMDLINE)
410: var = GNode_FindVar(VAR_CMDLINE, name, nameHash);
1.1 cgd 411:
1.703 rillig 412: if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) {
413: var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
414: if (var == NULL && ctxt != VAR_INTERNAL) {
415: /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
416: var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
417: }
1.184 sjg 418: }
1.399 rillig 419:
1.703 rillig 420: if (var == NULL) {
421: char *env;
422:
423: if ((env = getenv(name)) != NULL) {
424: char *varname = bmake_strdup(name);
1.744 rillig 425: return VarNew(FStr_InitOwn(varname), env, VAR_FROM_ENV);
1.703 rillig 426: }
1.1 cgd 427:
1.703 rillig 428: if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) {
429: var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
430: if (var == NULL && ctxt != VAR_INTERNAL)
431: var = GNode_FindVar(VAR_INTERNAL, name,
432: nameHash);
433: return var;
434: }
1.399 rillig 435:
1.703 rillig 436: return NULL;
1.1 cgd 437: }
1.399 rillig 438:
1.703 rillig 439: return var;
1.1 cgd 440: }
441:
1.778 rillig 442: /*
443: * If the variable is an environment variable, free it.
1.105 christos 444: *
445: * Input:
446: * v the variable
1.605 rillig 447: * freeValue true if the variable value should be freed as well
1.105 christos 448: *
449: * Results:
1.400 rillig 450: * TRUE if it is an environment variable, FALSE otherwise.
1.105 christos 451: */
452: static Boolean
1.605 rillig 453: VarFreeEnv(Var *v, Boolean freeValue)
1.105 christos 454: {
1.703 rillig 455: if (!(v->flags & VAR_FROM_ENV))
456: return FALSE;
1.605 rillig 457:
1.711 rillig 458: FStr_Done(&v->name);
1.784 rillig 459: if (freeValue)
460: Buf_Done(&v->val);
461: else
462: Buf_DoneData(&v->val);
1.703 rillig 463: free(v);
464: return TRUE;
1.105 christos 465: }
466:
1.778 rillig 467: /*
468: * Add a new variable of the given name and value to the given context.
469: * The name and val arguments are duplicated so they may safely be freed.
470: */
1.5 cgd 471: static void
1.670 rillig 472: VarAdd(const char *name, const char *val, GNode *ctxt, VarSetFlags flags)
1.1 cgd 473: {
1.703 rillig 474: HashEntry *he = HashTable_CreateEntry(&ctxt->vars, name, NULL);
1.744 rillig 475: Var *v = VarNew(FStr_InitRefer(/* aliased to */ he->key), val,
1.707 rillig 476: flags & VAR_SET_READONLY ? VAR_READONLY : VAR_NONE);
1.703 rillig 477: HashEntry_Set(he, v);
1.790 ! rillig 478: DEBUG3(VAR, "%s:%s = %s\n", ctxt->name, name, val);
1.1 cgd 479: }
480:
1.736 rillig 481: /*
482: * Remove a variable from a context, freeing all related memory as well.
483: * The variable name is kept as-is, it is not expanded.
484: */
485: void
486: Var_DeleteVar(const char *varname, GNode *ctxt)
487: {
488: HashEntry *he = HashTable_FindEntry(&ctxt->vars, varname);
489: Var *v;
490:
491: if (he == NULL) {
492: DEBUG2(VAR, "%s:delete %s (not found)\n", ctxt->name, varname);
493: return;
494: }
495:
496: DEBUG2(VAR, "%s:delete %s\n", ctxt->name, varname);
497: v = HashEntry_Get(he);
498: if (v->flags & VAR_EXPORTED)
499: unsetenv(v->name.str);
500: if (strcmp(v->name.str, MAKE_EXPORTED) == 0)
501: var_exportedVars = VAR_EXPORTED_NONE;
502: assert(v->name.freeIt == NULL);
503: HashTable_DeleteEntry(&ctxt->vars, he);
1.784 rillig 504: Buf_Done(&v->val);
1.736 rillig 505: free(v);
506: }
507:
1.778 rillig 508: /*
509: * Remove a variable from a context, freeing all related memory as well.
510: * The variable name is expanded once.
511: */
1.1 cgd 512: void
1.73 christos 513: Var_Delete(const char *name, GNode *ctxt)
1.1 cgd 514: {
1.746 rillig 515: FStr varname = FStr_InitRefer(name);
1.412 rillig 516:
1.746 rillig 517: if (strchr(varname.str, '$') != NULL) {
518: char *expanded;
519: (void)Var_Subst(varname.str, VAR_GLOBAL, VARE_WANTRES,
520: &expanded);
1.703 rillig 521: /* TODO: handle errors */
1.746 rillig 522: varname = FStr_InitOwn(expanded);
1.703 rillig 523: }
1.397 rillig 524:
1.746 rillig 525: Var_DeleteVar(varname.str, ctxt);
526: FStr_Done(&varname);
1.1 cgd 527: }
528:
1.737 rillig 529: /*
1.762 rillig 530: * Undefine one or more variables from the global scope.
531: * The argument is expanded exactly once and then split into words.
1.737 rillig 532: */
1.735 rillig 533: void
1.762 rillig 534: Var_Undef(const char *arg)
1.735 rillig 535: {
1.762 rillig 536: VarParseResult vpr;
537: char *expanded;
538: Words varnames;
539: size_t i;
540:
541: if (arg[0] == '\0') {
542: Parse_Error(PARSE_FATAL,
543: "The .undef directive requires an argument");
544: return;
545: }
1.735 rillig 546:
1.762 rillig 547: vpr = Var_Subst(arg, VAR_GLOBAL, VARE_WANTRES, &expanded);
548: if (vpr != VPR_OK) {
1.737 rillig 549: Parse_Error(PARSE_FATAL,
1.762 rillig 550: "Error in variable names to be undefined");
551: return;
552: }
553:
554: varnames = Str_Words(expanded, FALSE);
555: if (varnames.len == 1 && varnames.words[0][0] == '\0')
556: varnames.len = 0;
557:
558: for (i = 0; i < varnames.len; i++) {
559: const char *varname = varnames.words[i];
560: Var_DeleteVar(varname, VAR_GLOBAL);
1.737 rillig 561: }
1.735 rillig 562:
1.762 rillig 563: Words_Free(varnames);
1.763 rillig 564: free(expanded);
1.735 rillig 565: }
566:
1.421 rillig 567: static Boolean
1.598 rillig 568: MayExport(const char *name)
1.118 sjg 569: {
1.703 rillig 570: if (name[0] == '.')
571: return FALSE; /* skip internals */
572: if (name[0] == '-')
573: return FALSE; /* skip misnamed variables */
574: if (name[1] == '\0') {
575: /*
576: * A single char.
577: * If it is one of the vars that should only appear in
578: * local context, skip it, else we can get Var_Subst
579: * into a loop.
580: */
581: switch (name[0]) {
582: case '@':
583: case '%':
584: case '*':
585: case '!':
586: return FALSE;
587: }
1.118 sjg 588: }
1.703 rillig 589: return TRUE;
1.598 rillig 590: }
591:
592: static Boolean
1.776 rillig 593: ExportVarEnv(Var *v)
594: {
595: const char *name = v->name.str;
1.777 rillig 596: char *val = v->val.data;
597: char *expr;
1.776 rillig 598:
1.777 rillig 599: if ((v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
1.776 rillig 600: return FALSE; /* nothing to do */
601:
1.777 rillig 602: if (strchr(val, '$') == NULL) {
603: if (!(v->flags & VAR_EXPORTED))
1.776 rillig 604: setenv(name, val, 1);
1.777 rillig 605: return TRUE;
1.776 rillig 606: }
607:
1.777 rillig 608: if (v->flags & VAR_IN_USE) {
609: /*
610: * We recursed while exporting in a child.
611: * This isn't going to end well, just skip it.
612: */
613: return FALSE;
614: }
1.776 rillig 615:
1.777 rillig 616: /* XXX: name is injected without escaping it */
617: expr = str_concat3("${", name, "}");
618: (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val);
619: /* TODO: handle errors */
620: setenv(name, val, 1);
621: free(val);
622: free(expr);
1.776 rillig 623: return TRUE;
624: }
625:
626: static Boolean
627: ExportVarPlain(Var *v)
1.598 rillig 628: {
1.777 rillig 629: if (strchr(v->val.data, '$') == NULL) {
630: setenv(v->name.str, v->val.data, 1);
631: v->flags |= VAR_EXPORTED;
632: v->flags &= ~(unsigned)VAR_REEXPORT;
633: return TRUE;
1.776 rillig 634: }
635:
1.777 rillig 636: /*
637: * Flag the variable as something we need to re-export.
638: * No point actually exporting it now though,
639: * the child process can do it at the last minute.
640: */
641: v->flags |= VAR_EXPORTED | VAR_REEXPORT;
1.776 rillig 642: return TRUE;
643: }
1.401 rillig 644:
1.776 rillig 645: static Boolean
646: ExportVarLiteral(Var *v)
647: {
1.777 rillig 648: if ((v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
649: return FALSE;
1.401 rillig 650:
1.777 rillig 651: if (!(v->flags & VAR_EXPORTED))
652: setenv(v->name.str, v->val.data, 1);
1.605 rillig 653:
1.703 rillig 654: return TRUE;
1.118 sjg 655: }
656:
657: /*
1.776 rillig 658: * Export a single variable.
659: *
660: * We ignore make internal variables (those which start with '.').
661: * Also we jump through some hoops to avoid calling setenv
662: * more than necessary since it can leak.
663: * We only manipulate flags of vars if 'parent' is set.
664: */
665: static Boolean
666: ExportVar(const char *name, VarExportMode mode)
667: {
668: Var *v;
669:
670: if (!MayExport(name))
671: return FALSE;
672:
673: v = VarFind(name, VAR_GLOBAL, FALSE);
674: if (v == NULL)
675: return FALSE;
676:
677: if (mode == VEM_ENV)
678: return ExportVarEnv(v);
679: else if (mode == VEM_PLAIN)
680: return ExportVarPlain(v);
681: else
682: return ExportVarLiteral(v);
683: }
684:
685: /*
1.765 rillig 686: * Actually export the variables that have been marked as needing to be
687: * re-exported.
1.118 sjg 688: */
689: void
1.725 rillig 690: Var_ReexportVars(void)
1.118 sjg 691: {
1.775 rillig 692: char *xvarnames;
1.412 rillig 693:
1.703 rillig 694: /*
695: * Several make implementations support this sort of mechanism for
696: * tracking recursion - but each uses a different name.
697: * We allow the makefiles to update MAKELEVEL and ensure
698: * children see a correctly incremented value.
699: */
700: char tmp[BUFSIZ];
701: snprintf(tmp, sizeof tmp, "%d", makelevel + 1);
702: setenv(MAKE_LEVEL_ENV, tmp, 1);
1.182 christos 703:
1.703 rillig 704: if (var_exportedVars == VAR_EXPORTED_NONE)
705: return;
1.118 sjg 706:
1.703 rillig 707: if (var_exportedVars == VAR_EXPORTED_ALL) {
708: HashIter hi;
1.575 rillig 709:
1.703 rillig 710: /* Ouch! Exporting all variables at once is crazy... */
711: HashIter_Init(&hi, &VAR_GLOBAL->vars);
712: while (HashIter_Next(&hi) != NULL) {
713: Var *var = hi.entry->value;
1.765 rillig 714: ExportVar(var->name.str, VEM_ENV);
1.703 rillig 715: }
716: return;
1.575 rillig 717: }
1.369 rillig 718:
1.703 rillig 719: (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES,
1.775 rillig 720: &xvarnames);
1.703 rillig 721: /* TODO: handle errors */
1.775 rillig 722: if (xvarnames[0] != '\0') {
723: Words varnames = Str_Words(xvarnames, FALSE);
1.703 rillig 724: size_t i;
725:
1.775 rillig 726: for (i = 0; i < varnames.len; i++)
727: ExportVar(varnames.words[i], VEM_ENV);
728: Words_Free(varnames);
1.703 rillig 729: }
1.775 rillig 730: free(xvarnames);
1.118 sjg 731: }
732:
1.726 rillig 733: static void
1.730 rillig 734: ExportVars(const char *varnames, Boolean isExport, VarExportMode mode)
1.726 rillig 735: {
1.727 rillig 736: Words words = Str_Words(varnames, FALSE);
737: size_t i;
738:
739: if (words.len == 1 && words.words[0][0] == '\0')
740: words.len = 0;
741:
742: for (i = 0; i < words.len; i++) {
743: const char *varname = words.words[i];
1.730 rillig 744: if (!ExportVar(varname, mode))
1.727 rillig 745: continue;
746:
747: if (var_exportedVars == VAR_EXPORTED_NONE)
748: var_exportedVars = VAR_EXPORTED_SOME;
1.726 rillig 749:
1.765 rillig 750: if (isExport && mode == VEM_PLAIN)
1.727 rillig 751: Var_Append(MAKE_EXPORTED, varname, VAR_GLOBAL);
1.726 rillig 752: }
1.727 rillig 753: Words_Free(words);
1.726 rillig 754: }
755:
1.728 rillig 756: static void
1.730 rillig 757: ExportVarsExpand(const char *uvarnames, Boolean isExport, VarExportMode mode)
1.728 rillig 758: {
759: char *xvarnames;
760:
761: (void)Var_Subst(uvarnames, VAR_GLOBAL, VARE_WANTRES, &xvarnames);
762: /* TODO: handle errors */
1.730 rillig 763: ExportVars(xvarnames, isExport, mode);
1.728 rillig 764: free(xvarnames);
765: }
766:
1.731 rillig 767: /* Export the named variables, or all variables. */
1.118 sjg 768: void
1.731 rillig 769: Var_Export(VarExportMode mode, const char *varnames)
1.118 sjg 770: {
1.765 rillig 771: if (mode == VEM_PLAIN && varnames[0] == '\0') {
1.703 rillig 772: var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
773: return;
774: }
1.118 sjg 775:
1.731 rillig 776: ExportVarsExpand(varnames, TRUE, mode);
1.729 rillig 777: }
778:
779: void
780: Var_ExportVars(const char *varnames)
781: {
1.765 rillig 782: ExportVarsExpand(varnames, FALSE, VEM_PLAIN);
1.118 sjg 783: }
784:
1.155 sjg 785:
1.257 rillig 786: extern char **environ;
787:
1.700 rillig 788: static void
1.714 rillig 789: ClearEnv(void)
1.701 rillig 790: {
791: const char *cp;
792: char **newenv;
793:
794: cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
795: if (environ == savedEnv) {
796: /* we have been here before! */
797: newenv = bmake_realloc(environ, 2 * sizeof(char *));
798: } else {
799: if (savedEnv != NULL) {
800: free(savedEnv);
801: savedEnv = NULL;
802: }
803: newenv = bmake_malloc(2 * sizeof(char *));
804: }
805:
806: /* Note: we cannot safely free() the original environ. */
807: environ = savedEnv = newenv;
808: newenv[0] = NULL;
809: newenv[1] = NULL;
1.780 rillig 810: if (cp != NULL && *cp != '\0')
1.701 rillig 811: setenv(MAKE_LEVEL_ENV, cp, 1);
812: }
813:
814: static void
1.732 rillig 815: GetVarnamesToUnexport(Boolean isEnv, const char *arg,
1.715 rillig 816: FStr *out_varnames, UnexportWhat *out_what)
1.714 rillig 817: {
818: UnexportWhat what;
1.739 rillig 819: FStr varnames = FStr_InitRefer("");
1.714 rillig 820:
1.732 rillig 821: if (isEnv) {
822: if (arg[0] != '\0') {
1.723 rillig 823: Parse_Error(PARSE_FATAL,
824: "The directive .unexport-env does not take "
825: "arguments");
826: }
1.714 rillig 827: what = UNEXPORT_ENV;
1.723 rillig 828:
1.732 rillig 829: } else {
830: what = arg[0] != '\0' ? UNEXPORT_NAMED : UNEXPORT_ALL;
1.714 rillig 831: if (what == UNEXPORT_NAMED)
1.739 rillig 832: varnames = FStr_InitRefer(arg);
1.714 rillig 833: }
834:
835: if (what != UNEXPORT_NAMED) {
836: char *expanded;
837: /* Using .MAKE.EXPORTED */
838: (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL,
839: VARE_WANTRES, &expanded);
840: /* TODO: handle errors */
1.739 rillig 841: varnames = FStr_InitOwn(expanded);
1.714 rillig 842: }
843:
844: *out_varnames = varnames;
845: *out_what = what;
846: }
847:
848: static void
1.713 rillig 849: UnexportVar(const char *varname, UnexportWhat what)
1.700 rillig 850: {
851: Var *v = VarFind(varname, VAR_GLOBAL, FALSE);
852: if (v == NULL) {
1.708 rillig 853: DEBUG1(VAR, "Not unexporting \"%s\" (not found)\n", varname);
1.700 rillig 854: return;
855: }
856:
1.708 rillig 857: DEBUG1(VAR, "Unexporting \"%s\"\n", varname);
1.713 rillig 858: if (what != UNEXPORT_ENV &&
859: (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
1.711 rillig 860: unsetenv(v->name.str);
1.700 rillig 861: v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT);
862:
1.713 rillig 863: if (what == UNEXPORT_NAMED) {
864: /* Remove the variable names from .MAKE.EXPORTED. */
1.700 rillig 865: /* XXX: v->name is injected without escaping it */
1.711 rillig 866: char *expr = str_concat3("${" MAKE_EXPORTED ":N",
867: v->name.str, "}");
1.700 rillig 868: char *cp;
869: (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp);
870: /* TODO: handle errors */
871: Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
872: free(cp);
873: free(expr);
874: }
875: }
876:
1.716 rillig 877: static void
878: UnexportVars(FStr *varnames, UnexportWhat what)
879: {
880: size_t i;
1.717 rillig 881: Words words;
882:
883: if (what == UNEXPORT_ENV)
884: ClearEnv();
1.716 rillig 885:
1.717 rillig 886: words = Str_Words(varnames->str, FALSE);
1.716 rillig 887: for (i = 0; i < words.len; i++) {
888: const char *varname = words.words[i];
889: UnexportVar(varname, what);
890: }
891: Words_Free(words);
892:
893: if (what != UNEXPORT_NAMED)
894: Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
895: }
896:
1.155 sjg 897: /*
898: * This is called when .unexport[-env] is seen.
1.338 rillig 899: *
900: * str must have the form "unexport[-env] varname...".
1.155 sjg 901: */
902: void
1.732 rillig 903: Var_UnExport(Boolean isEnv, const char *arg)
1.155 sjg 904: {
1.713 rillig 905: UnexportWhat what;
1.714 rillig 906: FStr varnames;
1.155 sjg 907:
1.732 rillig 908: GetVarnamesToUnexport(isEnv, arg, &varnames, &what);
1.716 rillig 909: UnexportVars(&varnames, what);
1.712 rillig 910: FStr_Done(&varnames);
1.155 sjg 911: }
912:
1.747 rillig 913: /* Set the variable to the value; the name is not expanded. */
914: static void
915: SetVar(const char *name, const char *val, GNode *ctxt, VarSetFlags flags)
1.1 cgd 916: {
1.704 rillig 917: Var *v;
1.142 dsl 918:
1.704 rillig 919: if (ctxt == VAR_GLOBAL) {
920: v = VarFind(name, VAR_CMDLINE, FALSE);
921: if (v != NULL) {
922: if (v->flags & VAR_FROM_CMD) {
1.708 rillig 923: DEBUG3(VAR, "%s:%s = %s ignored!\n",
1.704 rillig 924: ctxt->name, name, val);
1.747 rillig 925: return;
1.704 rillig 926: }
927: VarFreeEnv(v, TRUE);
928: }
1.129 sjg 929: }
1.400 rillig 930:
1.704 rillig 931: /*
932: * We only look for a variable in the given context since anything set
933: * here will override anything in a lower context, so there's not much
934: * point in searching them all just to save a bit of memory...
935: */
936: v = VarFind(name, ctxt, FALSE);
937: if (v == NULL) {
938: if (ctxt == VAR_CMDLINE && !(flags & VAR_SET_NO_EXPORT)) {
939: /*
940: * This var would normally prevent the same name being
941: * added to VAR_GLOBAL, so delete it from there if
942: * needed. Otherwise -V name may show the wrong value.
943: */
944: /* XXX: name is expanded for the second time */
945: Var_Delete(name, VAR_GLOBAL);
946: }
947: VarAdd(name, val, ctxt, flags);
948: } else {
949: if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) {
1.708 rillig 950: DEBUG3(VAR, "%s:%s = %s ignored (read-only)\n",
1.704 rillig 951: ctxt->name, name, val);
1.747 rillig 952: return;
1.704 rillig 953: }
954: Buf_Empty(&v->val);
955: Buf_AddStr(&v->val, val);
956:
1.708 rillig 957: DEBUG3(VAR, "%s:%s = %s\n", ctxt->name, name, val);
1.704 rillig 958: if (v->flags & VAR_EXPORTED)
1.765 rillig 959: ExportVar(name, VEM_PLAIN);
1.183 sjg 960: }
1.71 thorpej 961: /*
1.704 rillig 962: * Any variables given on the command line are automatically exported
963: * to the environment (as per POSIX standard)
964: * Other than internals.
1.71 thorpej 965: */
1.704 rillig 966: if (ctxt == VAR_CMDLINE && !(flags & VAR_SET_NO_EXPORT) &&
967: name[0] != '.') {
968: if (v == NULL)
969: v = VarFind(name, ctxt, FALSE); /* we just added it */
970: v->flags |= VAR_FROM_CMD;
971:
972: /*
973: * If requested, don't export these in the environment
974: * individually. We still put them in MAKEOVERRIDES so
975: * that the command-line settings continue to override
976: * Makefile settings.
977: */
978: if (!opts.varNoExportEnv)
979: setenv(name, val, 1);
1.62 sjg 980:
1.704 rillig 981: Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
982: }
983: if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0)
984: save_dollars = ParseBoolean(val, save_dollars);
1.205 sjg 985:
1.704 rillig 986: if (v != NULL)
987: VarFreeEnv(v, TRUE);
1.1 cgd 988: }
989:
1.747 rillig 990: /* See Var_Set for documentation. */
991: void
992: Var_SetWithFlags(const char *name, const char *val, GNode *ctxt,
993: VarSetFlags flags)
994: {
995: const char *unexpanded_name = name;
1.748 rillig 996: FStr varname = FStr_InitRefer(name);
1.747 rillig 997:
998: assert(val != NULL);
999:
1.748 rillig 1000: if (strchr(varname.str, '$') != NULL) {
1001: char *expanded;
1002: (void)Var_Subst(varname.str, ctxt, VARE_WANTRES, &expanded);
1.747 rillig 1003: /* TODO: handle errors */
1.748 rillig 1004: varname = FStr_InitOwn(expanded);
1.747 rillig 1005: }
1006:
1.748 rillig 1007: if (varname.str[0] == '\0') {
1.747 rillig 1008: DEBUG2(VAR, "Var_Set(\"%s\", \"%s\", ...) "
1009: "name expands to empty string - ignored\n",
1010: unexpanded_name, val);
1.748 rillig 1011: } else
1012: SetVar(varname.str, val, ctxt, flags);
1.747 rillig 1013:
1.748 rillig 1014: FStr_Done(&varname);
1.747 rillig 1015: }
1016:
1.718 rillig 1017: /*
1018: * Set the variable name to the value val in the given context.
1.230 rillig 1019: *
1.718 rillig 1020: * If the variable doesn't yet exist, it is created.
1021: * Otherwise the new value overwrites and replaces the old value.
1.483 rillig 1022: *
1.230 rillig 1023: * Input:
1.607 rillig 1024: * name name of the variable to set, is expanded once
1.230 rillig 1025: * val value to give to the variable
1026: * ctxt context in which to set it
1027: */
1028: void
1029: Var_Set(const char *name, const char *val, GNode *ctxt)
1030: {
1.703 rillig 1031: Var_SetWithFlags(name, val, ctxt, VAR_SET_NONE);
1.230 rillig 1032: }
1033:
1.718 rillig 1034: /*
1035: * The variable of the given name has the given value appended to it in the
1036: * given context.
1.1 cgd 1037: *
1.718 rillig 1038: * If the variable doesn't exist, it is created. Otherwise the strings are
1039: * concatenated, with a space in between.
1.483 rillig 1040: *
1.70 wiz 1041: * Input:
1.607 rillig 1042: * name name of the variable to modify, is expanded once
1.400 rillig 1043: * val string to append to it
1044: * ctxt context in which this should occur
1.70 wiz 1045: *
1.1 cgd 1046: * Notes:
1047: * Only if the variable is being sought in the global context is the
1048: * environment searched.
1049: * XXX: Knows its calling circumstances in that if called with ctxt
1050: * an actual target, it will only search that context since only
1051: * a local variable could be being appended to. This is actually
1052: * a big win and must be tolerated.
1053: */
1054: void
1.73 christos 1055: Var_Append(const char *name, const char *val, GNode *ctxt)
1.1 cgd 1056: {
1.704 rillig 1057: char *name_freeIt = NULL;
1058: Var *v;
1.1 cgd 1059:
1.704 rillig 1060: assert(val != NULL);
1.460 rillig 1061:
1.704 rillig 1062: if (strchr(name, '$') != NULL) {
1063: const char *unexpanded_name = name;
1064: (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
1065: /* TODO: handle errors */
1066: name = name_freeIt;
1067: if (name[0] == '\0') {
1.708 rillig 1068: DEBUG2(VAR, "Var_Append(\"%s\", \"%s\", ...) "
1069: "name expands to empty string - ignored\n",
1.704 rillig 1070: unexpanded_name, val);
1071: free(name_freeIt);
1072: return;
1073: }
1.139 dsl 1074: }
1.142 dsl 1075:
1.704 rillig 1076: v = VarFind(name, ctxt, ctxt == VAR_GLOBAL);
1.1 cgd 1077:
1.704 rillig 1078: if (v == NULL) {
1079: /* XXX: name is expanded for the second time */
1080: Var_Set(name, val, ctxt);
1081: } else if (v->flags & VAR_READONLY) {
1.708 rillig 1082: DEBUG1(VAR, "Ignoring append to %s since it is read-only\n",
1.704 rillig 1083: name);
1084: } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) {
1085: Buf_AddByte(&v->val, ' ');
1086: Buf_AddStr(&v->val, val);
1.1 cgd 1087:
1.785 rillig 1088: DEBUG3(VAR, "%s:%s = %s\n", ctxt->name, name, v->val.data);
1.1 cgd 1089:
1.704 rillig 1090: if (v->flags & VAR_FROM_ENV) {
1091: /*
1092: * If the original variable came from the environment,
1093: * we have to install it in the global context (we
1094: * could place it in the environment, but then we
1095: * should provide a way to export other variables...)
1096: */
1097: v->flags &= ~(unsigned)VAR_FROM_ENV;
1098: /*
1099: * This is the only place where a variable is
1100: * created whose v->name is not the same as
1101: * ctxt->context->key.
1102: */
1103: HashTable_Set(&ctxt->vars, name, v);
1104: }
1.1 cgd 1105: }
1.704 rillig 1106: free(name_freeIt);
1.1 cgd 1107: }
1108:
1.778 rillig 1109: /*
1110: * See if the given variable exists, in the given context or in other
1.483 rillig 1111: * fallback contexts.
1.1 cgd 1112: *
1.70 wiz 1113: * Input:
1.607 rillig 1114: * name Variable to find, is expanded once
1.70 wiz 1115: * ctxt Context in which to start search
1.1 cgd 1116: */
1117: Boolean
1.73 christos 1118: Var_Exists(const char *name, GNode *ctxt)
1.1 cgd 1119: {
1.747 rillig 1120: FStr varname = FStr_InitRefer(name);
1.703 rillig 1121: Var *v;
1.412 rillig 1122:
1.747 rillig 1123: if (strchr(varname.str, '$') != NULL) {
1124: char *expanded;
1125: (void)Var_Subst(varname.str, ctxt, VARE_WANTRES, &expanded);
1.703 rillig 1126: /* TODO: handle errors */
1.747 rillig 1127: varname = FStr_InitOwn(expanded);
1.703 rillig 1128: }
1.1 cgd 1129:
1.747 rillig 1130: v = VarFind(varname.str, ctxt, TRUE);
1131: FStr_Done(&varname);
1.703 rillig 1132: if (v == NULL)
1133: return FALSE;
1.231 rillig 1134:
1.703 rillig 1135: (void)VarFreeEnv(v, TRUE);
1136: return TRUE;
1.1 cgd 1137: }
1138:
1.718 rillig 1139: /*
1140: * Return the unexpanded value of the given variable in the given context,
1141: * or the usual contexts.
1.1 cgd 1142: *
1.70 wiz 1143: * Input:
1.607 rillig 1144: * name name to find, is not expanded any further
1.70 wiz 1145: * ctxt context in which to search for it
1146: *
1.1 cgd 1147: * Results:
1.337 rillig 1148: * The value if the variable exists, NULL if it doesn't.
1.632 rillig 1149: * If the returned value is not NULL, the caller must free
1150: * out_freeIt when the returned value is no longer needed.
1.1 cgd 1151: */
1.745 rillig 1152: FStr
1153: Var_Value(const char *name, GNode *ctxt)
1.1 cgd 1154: {
1.703 rillig 1155: Var *v = VarFind(name, ctxt, TRUE);
1156: char *value;
1157:
1158: if (v == NULL)
1.745 rillig 1159: return FStr_InitRefer(NULL);
1.412 rillig 1160:
1.785 rillig 1161: value = v->val.data;
1.745 rillig 1162: return VarFreeEnv(v, FALSE)
1163: ? FStr_InitOwn(value)
1164: : FStr_InitRefer(value);
1.1 cgd 1165: }
1166:
1.778 rillig 1167: /*
1168: * Return the unexpanded variable value from this node, without trying to look
1169: * up the variable in any other context.
1170: */
1.616 rillig 1171: const char *
1172: Var_ValueDirect(const char *name, GNode *ctxt)
1173: {
1.703 rillig 1174: Var *v = VarFind(name, ctxt, FALSE);
1.785 rillig 1175: return v != NULL ? v->val.data : NULL;
1.616 rillig 1176: }
1177:
1.244 rillig 1178:
1.278 rillig 1179: static void
1180: SepBuf_Init(SepBuf *buf, char sep)
1181: {
1.703 rillig 1182: Buf_InitSize(&buf->buf, 32);
1183: buf->needSep = FALSE;
1184: buf->sep = sep;
1.278 rillig 1185: }
1186:
1187: static void
1188: SepBuf_Sep(SepBuf *buf)
1189: {
1.703 rillig 1190: buf->needSep = TRUE;
1.278 rillig 1191: }
1192:
1193: static void
1.314 rillig 1194: SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1.278 rillig 1195: {
1.703 rillig 1196: if (mem_size == 0)
1197: return;
1198: if (buf->needSep && buf->sep != '\0') {
1199: Buf_AddByte(&buf->buf, buf->sep);
1200: buf->needSep = FALSE;
1201: }
1202: Buf_AddBytes(&buf->buf, mem, mem_size);
1.278 rillig 1203: }
1204:
1.314 rillig 1205: static void
1206: SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1207: {
1.703 rillig 1208: SepBuf_AddBytes(buf, start, (size_t)(end - start));
1.314 rillig 1209: }
1210:
1211: static void
1212: SepBuf_AddStr(SepBuf *buf, const char *str)
1213: {
1.703 rillig 1214: SepBuf_AddBytes(buf, str, strlen(str));
1.314 rillig 1215: }
1216:
1.278 rillig 1217: static char *
1.784 rillig 1218: SepBuf_DoneData(SepBuf *buf)
1.278 rillig 1219: {
1.784 rillig 1220: return Buf_DoneData(&buf->buf);
1.278 rillig 1221: }
1222:
1223:
1.778 rillig 1224: /*
1225: * This callback for ModifyWords gets a single word from a variable expression
1.609 rillig 1226: * and typically adds a modification of this word to the buffer. It may also
1227: * do nothing or add several words.
1228: *
1229: * For example, in ${:Ua b c:M*2}, the callback is called 3 times, once for
1.778 rillig 1230: * each word of "a b c".
1231: */
1.295 rillig 1232: typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data);
1.244 rillig 1233:
1234:
1.778 rillig 1235: /*
1236: * Callback for ModifyWords to implement the :H modifier.
1237: * Add the dirname of the given word to the buffer.
1238: */
1.779 rillig 1239: /*ARGSUSED*/
1.278 rillig 1240: static void
1.295 rillig 1241: ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1.1 cgd 1242: {
1.703 rillig 1243: const char *slash = strrchr(word, '/');
1244: if (slash != NULL)
1245: SepBuf_AddBytesBetween(buf, word, slash);
1246: else
1247: SepBuf_AddStr(buf, ".");
1.1 cgd 1248: }
1249:
1.778 rillig 1250: /*
1251: * Callback for ModifyWords to implement the :T modifier.
1252: * Add the basename of the given word to the buffer.
1253: */
1.779 rillig 1254: /*ARGSUSED*/
1.278 rillig 1255: static void
1.295 rillig 1256: ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1.1 cgd 1257: {
1.733 rillig 1258: SepBuf_AddStr(buf, str_basename(word));
1.1 cgd 1259: }
1260:
1.778 rillig 1261: /*
1262: * Callback for ModifyWords to implement the :E modifier.
1263: * Add the filename suffix of the given word to the buffer, if it exists.
1264: */
1.779 rillig 1265: /*ARGSUSED*/
1.278 rillig 1266: static void
1.295 rillig 1267: ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1.1 cgd 1268: {
1.703 rillig 1269: const char *lastDot = strrchr(word, '.');
1270: if (lastDot != NULL)
1271: SepBuf_AddStr(buf, lastDot + 1);
1.1 cgd 1272: }
1273:
1.778 rillig 1274: /*
1275: * Callback for ModifyWords to implement the :R modifier.
1276: * Add the basename of the given word to the buffer.
1277: */
1.779 rillig 1278: /*ARGSUSED*/
1.278 rillig 1279: static void
1.295 rillig 1280: ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1.1 cgd 1281: {
1.703 rillig 1282: const char *lastDot = strrchr(word, '.');
1283: size_t len = lastDot != NULL ? (size_t)(lastDot - word) : strlen(word);
1284: SepBuf_AddBytes(buf, word, len);
1.1 cgd 1285: }
1286:
1.778 rillig 1287: /*
1288: * Callback for ModifyWords to implement the :M modifier.
1289: * Place the word in the buffer if it matches the given pattern.
1290: */
1.278 rillig 1291: static void
1.295 rillig 1292: ModifyWord_Match(const char *word, SepBuf *buf, void *data)
1.1 cgd 1293: {
1.703 rillig 1294: const char *pattern = data;
1.708 rillig 1295: DEBUG2(VAR, "VarMatch [%s] [%s]\n", word, pattern);
1.703 rillig 1296: if (Str_Match(word, pattern))
1297: SepBuf_AddStr(buf, word);
1.1 cgd 1298: }
1299:
1.778 rillig 1300: /*
1301: * Callback for ModifyWords to implement the :N modifier.
1302: * Place the word in the buffer if it doesn't match the given pattern.
1303: */
1.291 rillig 1304: static void
1.295 rillig 1305: ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data)
1.291 rillig 1306: {
1.703 rillig 1307: const char *pattern = data;
1308: if (!Str_Match(word, pattern))
1309: SepBuf_AddStr(buf, word);
1.291 rillig 1310: }
1311:
1.13 christos 1312: #ifdef SYSVVARSUB
1.703 rillig 1313:
1.778 rillig 1314: /*
1315: * Check word against pattern for a match (% is a wildcard).
1.256 rillig 1316: *
1317: * Input:
1318: * word Word to examine
1319: * pattern Pattern to examine against
1320: *
1321: * Results:
1.377 rillig 1322: * Returns the start of the match, or NULL.
1.610 rillig 1323: * out_match_len returns the length of the match, if any.
1324: * out_hasPercent returns whether the pattern contains a percent.
1.256 rillig 1325: */
1.277 rillig 1326: static const char *
1.610 rillig 1327: SysVMatch(const char *word, const char *pattern,
1.703 rillig 1328: size_t *out_match_len, Boolean *out_hasPercent)
1.256 rillig 1329: {
1.703 rillig 1330: const char *p = pattern;
1331: const char *w = word;
1332: const char *percent;
1333: size_t w_len;
1334: size_t p_len;
1335: const char *w_tail;
1336:
1337: *out_hasPercent = FALSE;
1338: percent = strchr(p, '%');
1339: if (percent != NULL) { /* ${VAR:...%...=...} */
1340: *out_hasPercent = TRUE;
1341: if (w[0] == '\0')
1342: return NULL; /* empty word does not match pattern */
1343:
1344: /* check that the prefix matches */
1345: for (; p != percent && *w != '\0' && *w == *p; w++, p++)
1346: continue;
1347: if (p != percent)
1348: return NULL; /* No match */
1349:
1350: p++; /* Skip the percent */
1351: if (*p == '\0') {
1352: /* No more pattern, return the rest of the string */
1353: *out_match_len = strlen(w);
1354: return w;
1355: }
1.256 rillig 1356: }
1357:
1.703 rillig 1358: /* Test whether the tail matches */
1359: w_len = strlen(w);
1360: p_len = strlen(p);
1361: if (w_len < p_len)
1362: return NULL;
1363:
1364: w_tail = w + w_len - p_len;
1365: if (memcmp(p, w_tail, p_len) != 0)
1366: return NULL;
1.256 rillig 1367:
1.703 rillig 1368: *out_match_len = (size_t)(w_tail - w);
1369: return w;
1.256 rillig 1370: }
1371:
1.541 rillig 1372: struct ModifyWord_SYSVSubstArgs {
1.703 rillig 1373: GNode *ctx;
1374: const char *lhs;
1375: const char *rhs;
1.541 rillig 1376: };
1.276 rillig 1377:
1.291 rillig 1378: /* Callback for ModifyWords to implement the :%.from=%.to modifier. */
1.278 rillig 1379: static void
1.295 rillig 1380: ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data)
1.5 cgd 1381: {
1.703 rillig 1382: const struct ModifyWord_SYSVSubstArgs *args = data;
1383: char *rhs_expanded;
1384: const char *rhs;
1385: const char *percent;
1386:
1387: size_t match_len;
1388: Boolean lhsPercent;
1389: const char *match = SysVMatch(word, args->lhs, &match_len, &lhsPercent);
1390: if (match == NULL) {
1391: SepBuf_AddStr(buf, word);
1392: return;
1393: }
1.379 rillig 1394:
1.703 rillig 1395: /*
1396: * Append rhs to the buffer, substituting the first '%' with the
1397: * match, but only if the lhs had a '%' as well.
1398: */
1.379 rillig 1399:
1.703 rillig 1400: (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded);
1401: /* TODO: handle errors */
1.379 rillig 1402:
1.703 rillig 1403: rhs = rhs_expanded;
1404: percent = strchr(rhs, '%');
1.379 rillig 1405:
1.703 rillig 1406: if (percent != NULL && lhsPercent) {
1407: /* Copy the prefix of the replacement pattern */
1408: SepBuf_AddBytesBetween(buf, rhs, percent);
1409: rhs = percent + 1;
1410: }
1411: if (percent != NULL || !lhsPercent)
1412: SepBuf_AddBytes(buf, match, match_len);
1.379 rillig 1413:
1.703 rillig 1414: /* Append the suffix of the replacement pattern */
1415: SepBuf_AddStr(buf, rhs);
1.379 rillig 1416:
1.703 rillig 1417: free(rhs_expanded);
1.5 cgd 1418: }
1.13 christos 1419: #endif
1.5 cgd 1420:
1.1 cgd 1421:
1.541 rillig 1422: struct ModifyWord_SubstArgs {
1.703 rillig 1423: const char *lhs;
1424: size_t lhsLen;
1425: const char *rhs;
1426: size_t rhsLen;
1427: VarPatternFlags pflags;
1428: Boolean matched;
1.541 rillig 1429: };
1.291 rillig 1430:
1.778 rillig 1431: /*
1432: * Callback for ModifyWords to implement the :S,from,to, modifier.
1433: * Perform a string substitution on the given word.
1434: */
1.278 rillig 1435: static void
1.295 rillig 1436: ModifyWord_Subst(const char *word, SepBuf *buf, void *data)
1.1 cgd 1437: {
1.703 rillig 1438: size_t wordLen = strlen(word);
1439: struct ModifyWord_SubstArgs *args = data;
1440: const char *match;
1441:
1.788 rillig 1442: if (args->pflags.subOnce && args->matched)
1.703 rillig 1443: goto nosub;
1444:
1.788 rillig 1445: if (args->pflags.anchorStart) {
1.703 rillig 1446: if (wordLen < args->lhsLen ||
1447: memcmp(word, args->lhs, args->lhsLen) != 0)
1448: goto nosub;
1449:
1.788 rillig 1450: if ((args->pflags.anchorEnd) && wordLen != args->lhsLen)
1.703 rillig 1451: goto nosub;
1452:
1453: /* :S,^prefix,replacement, or :S,^whole$,replacement, */
1454: SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1455: SepBuf_AddBytes(buf, word + args->lhsLen,
1456: wordLen - args->lhsLen);
1457: args->matched = TRUE;
1458: return;
1459: }
1.1 cgd 1460:
1.788 rillig 1461: if (args->pflags.anchorEnd) {
1.703 rillig 1462: const char *start;
1.279 rillig 1463:
1.703 rillig 1464: if (wordLen < args->lhsLen)
1465: goto nosub;
1.412 rillig 1466:
1.703 rillig 1467: start = word + (wordLen - args->lhsLen);
1468: if (memcmp(start, args->lhs, args->lhsLen) != 0)
1469: goto nosub;
1470:
1471: /* :S,suffix$,replacement, */
1472: SepBuf_AddBytesBetween(buf, word, start);
1473: SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1474: args->matched = TRUE;
1475: return;
1476: }
1.315 rillig 1477:
1.703 rillig 1478: if (args->lhs[0] == '\0')
1479: goto nosub;
1.279 rillig 1480:
1.703 rillig 1481: /* unanchored case, may match more than once */
1482: while ((match = strstr(word, args->lhs)) != NULL) {
1483: SepBuf_AddBytesBetween(buf, word, match);
1484: SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1485: args->matched = TRUE;
1486: wordLen -= (size_t)(match - word) + args->lhsLen;
1487: word += (size_t)(match - word) + args->lhsLen;
1.788 rillig 1488: if (wordLen == 0 || !args->pflags.subGlobal)
1.703 rillig 1489: break;
1490: }
1.242 rillig 1491: nosub:
1.703 rillig 1492: SepBuf_AddBytes(buf, word, wordLen);
1.1 cgd 1493: }
1494:
1.31 gwr 1495: #ifndef NO_REGEX
1.400 rillig 1496: /* Print the error caused by a regcomp or regexec call. */
1.16 christos 1497: static void
1.672 rillig 1498: VarREError(int reerr, const regex_t *pat, const char *str)
1.16 christos 1499: {
1.703 rillig 1500: size_t errlen = regerror(reerr, pat, NULL, 0);
1501: char *errbuf = bmake_malloc(errlen);
1502: regerror(reerr, pat, errbuf, errlen);
1503: Error("%s: %s", str, errbuf);
1504: free(errbuf);
1.16 christos 1505: }
1506:
1.541 rillig 1507: struct ModifyWord_SubstRegexArgs {
1.703 rillig 1508: regex_t re;
1509: size_t nsub;
1510: char *replace;
1511: VarPatternFlags pflags;
1512: Boolean matched;
1.541 rillig 1513: };
1.291 rillig 1514:
1.778 rillig 1515: /*
1516: * Callback for ModifyWords to implement the :C/from/to/ modifier.
1517: * Perform a regex substitution on the given word.
1518: */
1.278 rillig 1519: static void
1.295 rillig 1520: ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data)
1.16 christos 1521: {
1.704 rillig 1522: struct ModifyWord_SubstRegexArgs *args = data;
1523: int xrv;
1524: const char *wp = word;
1525: char *rp;
1526: int flags = 0;
1527: regmatch_t m[10];
1.16 christos 1528:
1.788 rillig 1529: if (args->pflags.subOnce && args->matched)
1.704 rillig 1530: goto nosub;
1.307 rillig 1531:
1532: tryagain:
1.704 rillig 1533: xrv = regexec(&args->re, wp, args->nsub, m, flags);
1.16 christos 1534:
1.704 rillig 1535: switch (xrv) {
1536: case 0:
1537: args->matched = TRUE;
1538: SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so);
1539:
1.781 rillig 1540: for (rp = args->replace; *rp != '\0'; rp++) {
1.704 rillig 1541: if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
1542: SepBuf_AddBytes(buf, rp + 1, 1);
1543: rp++;
1544: continue;
1545: }
1.445 rillig 1546:
1.704 rillig 1547: if (*rp == '&') {
1548: SepBuf_AddBytesBetween(buf,
1549: wp + m[0].rm_so, wp + m[0].rm_eo);
1550: continue;
1551: }
1.445 rillig 1552:
1.704 rillig 1553: if (*rp != '\\' || !ch_isdigit(rp[1])) {
1554: SepBuf_AddBytes(buf, rp, 1);
1555: continue;
1556: }
1.445 rillig 1557:
1.704 rillig 1558: { /* \0 to \9 backreference */
1559: size_t n = (size_t)(rp[1] - '0');
1560: rp++;
1561:
1562: if (n >= args->nsub) {
1.734 rillig 1563: Error("No subexpression \\%u",
1564: (unsigned)n);
1.704 rillig 1565: } else if (m[n].rm_so == -1) {
1566: Error(
1.734 rillig 1567: "No match for subexpression \\%u",
1568: (unsigned)n);
1.704 rillig 1569: } else {
1570: SepBuf_AddBytesBetween(buf,
1571: wp + m[n].rm_so, wp + m[n].rm_eo);
1572: }
1573: }
1.16 christos 1574: }
1.445 rillig 1575:
1.704 rillig 1576: wp += m[0].rm_eo;
1.788 rillig 1577: if (args->pflags.subGlobal) {
1.704 rillig 1578: flags |= REG_NOTBOL;
1579: if (m[0].rm_so == 0 && m[0].rm_eo == 0) {
1580: SepBuf_AddBytes(buf, wp, 1);
1581: wp++;
1582: }
1583: if (*wp != '\0')
1584: goto tryagain;
1585: }
1586: if (*wp != '\0')
1587: SepBuf_AddStr(buf, wp);
1588: break;
1589: default:
1590: VarREError(xrv, &args->re, "Unexpected regex error");
1591: /* FALLTHROUGH */
1592: case REG_NOMATCH:
1593: nosub:
1594: SepBuf_AddStr(buf, wp);
1595: break;
1.20 christos 1596: }
1.16 christos 1597: }
1.17 christos 1598: #endif
1.16 christos 1599:
1600:
1.541 rillig 1601: struct ModifyWord_LoopArgs {
1.703 rillig 1602: GNode *ctx;
1603: char *tvar; /* name of temporary variable */
1604: char *str; /* string to expand */
1605: VarEvalFlags eflags;
1.541 rillig 1606: };
1.291 rillig 1607:
1608: /* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */
1.278 rillig 1609: static void
1.295 rillig 1610: ModifyWord_Loop(const char *word, SepBuf *buf, void *data)
1.40 sjg 1611: {
1.703 rillig 1612: const struct ModifyWord_LoopArgs *args;
1613: char *s;
1.412 rillig 1614:
1.703 rillig 1615: if (word[0] == '\0')
1616: return;
1.278 rillig 1617:
1.703 rillig 1618: args = data;
1619: Var_SetWithFlags(args->tvar, word, args->ctx, VAR_SET_NO_EXPORT);
1620: (void)Var_Subst(args->str, args->ctx, args->eflags, &s);
1621: /* TODO: handle errors */
1.64 sjg 1622:
1.708 rillig 1623: DEBUG4(VAR, "ModifyWord_Loop: "
1624: "in \"%s\", replace \"%s\" with \"%s\" to \"%s\"\n",
1.703 rillig 1625: word, args->tvar, args->str, s);
1626:
1627: if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n'))
1628: buf->needSep = FALSE;
1629: SepBuf_AddStr(buf, s);
1630: free(s);
1.40 sjg 1631: }
1632:
1.81 sjg 1633:
1.778 rillig 1634: /*
1635: * The :[first..last] modifier selects words from the expression.
1636: * It can also reverse the words.
1637: */
1.81 sjg 1638: static char *
1.449 rillig 1639: VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first,
1.301 rillig 1640: int last)
1.81 sjg 1641: {
1.703 rillig 1642: Words words;
1643: int len, start, end, step;
1644: int i;
1645:
1646: SepBuf buf;
1647: SepBuf_Init(&buf, sep);
1648:
1649: if (oneBigWord) {
1650: /* fake what Str_Words() would do if there were only one word */
1651: words.len = 1;
1652: words.words = bmake_malloc(
1653: (words.len + 1) * sizeof(words.words[0]));
1654: words.freeIt = bmake_strdup(str);
1655: words.words[0] = words.freeIt;
1656: words.words[1] = NULL;
1657: } else {
1658: words = Str_Words(str, FALSE);
1659: }
1.81 sjg 1660:
1.703 rillig 1661: /*
1662: * Now sanitize the given range. If first or last are negative,
1663: * convert them to the positive equivalents (-1 gets converted to len,
1664: * -2 gets converted to (len - 1), etc.).
1665: */
1666: len = (int)words.len;
1667: if (first < 0)
1668: first += len + 1;
1669: if (last < 0)
1670: last += len + 1;
1671:
1672: /* We avoid scanning more of the list than we need to. */
1673: if (first > last) {
1674: start = (first > len ? len : first) - 1;
1675: end = last < 1 ? 0 : last - 1;
1676: step = -1;
1677: } else {
1678: start = first < 1 ? 0 : first - 1;
1679: end = last > len ? len : last;
1680: step = 1;
1681: }
1.81 sjg 1682:
1.703 rillig 1683: for (i = start; (step < 0) == (i >= end); i += step) {
1684: SepBuf_AddStr(&buf, words.words[i]);
1685: SepBuf_Sep(&buf);
1686: }
1.81 sjg 1687:
1.703 rillig 1688: Words_Free(words);
1.81 sjg 1689:
1.784 rillig 1690: return SepBuf_DoneData(&buf);
1.81 sjg 1691: }
1692:
1.156 sjg 1693:
1.778 rillig 1694: /*
1695: * Callback for ModifyWords to implement the :tA modifier.
1696: * Replace each word with the result of realpath() if successful.
1697: */
1.779 rillig 1698: /*ARGSUSED*/
1.278 rillig 1699: static void
1.295 rillig 1700: ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
1.156 sjg 1701: {
1.703 rillig 1702: struct stat st;
1703: char rbuf[MAXPATHLEN];
1.231 rillig 1704:
1.703 rillig 1705: const char *rp = cached_realpath(word, rbuf);
1706: if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1707: word = rp;
1.231 rillig 1708:
1.703 rillig 1709: SepBuf_AddStr(buf, word);
1.156 sjg 1710: }
1711:
1.718 rillig 1712: /*
1713: * Modify each of the words of the passed string using the given function.
1.1 cgd 1714: *
1.70 wiz 1715: * Input:
1.278 rillig 1716: * str String whose words should be modified
1.291 rillig 1717: * modifyWord Function that modifies a single word
1.453 rillig 1718: * modifyWord_args Custom arguments for modifyWord
1.70 wiz 1719: *
1.1 cgd 1720: * Results:
1721: * A string of all the words modified appropriately.
1722: */
1723: static char *
1.619 rillig 1724: ModifyWords(const char *str,
1725: ModifyWordsCallback modifyWord, void *modifyWord_args,
1726: Boolean oneBigWord, char sep)
1.1 cgd 1727: {
1.703 rillig 1728: SepBuf result;
1729: Words words;
1730: size_t i;
1731:
1732: if (oneBigWord) {
1733: SepBuf_Init(&result, sep);
1734: modifyWord(str, &result, modifyWord_args);
1.784 rillig 1735: return SepBuf_DoneData(&result);
1.703 rillig 1736: }
1.412 rillig 1737:
1.316 rillig 1738: SepBuf_Init(&result, sep);
1739:
1.703 rillig 1740: words = Str_Words(str, FALSE);
1.401 rillig 1741:
1.734 rillig 1742: DEBUG2(VAR, "ModifyWords: split \"%s\" into %u words\n",
1743: str, (unsigned)words.len);
1.1 cgd 1744:
1.703 rillig 1745: for (i = 0; i < words.len; i++) {
1746: modifyWord(words.words[i], &result, modifyWord_args);
1.786 rillig 1747: if (result.buf.len > 0)
1.703 rillig 1748: SepBuf_Sep(&result);
1749: }
1.255 rillig 1750:
1.703 rillig 1751: Words_Free(words);
1.24 christos 1752:
1.784 rillig 1753: return SepBuf_DoneData(&result);
1.1 cgd 1754: }
1755:
1.35 christos 1756:
1.403 rillig 1757: static char *
1.479 rillig 1758: Words_JoinFree(Words words)
1.403 rillig 1759: {
1.703 rillig 1760: Buffer buf;
1761: size_t i;
1.412 rillig 1762:
1.703 rillig 1763: Buf_Init(&buf);
1.403 rillig 1764:
1.703 rillig 1765: for (i = 0; i < words.len; i++) {
1766: if (i != 0) {
1767: /* XXX: Use st->sep instead of ' ', for consistency. */
1768: Buf_AddByte(&buf, ' ');
1769: }
1770: Buf_AddStr(&buf, words.words[i]);
1771: }
1.403 rillig 1772:
1.703 rillig 1773: Words_Free(words);
1.403 rillig 1774:
1.784 rillig 1775: return Buf_DoneData(&buf);
1.403 rillig 1776: }
1777:
1.319 rillig 1778: /* Remove adjacent duplicate words. */
1.55 christos 1779: static char *
1.73 christos 1780: VarUniq(const char *str)
1.55 christos 1781: {
1.703 rillig 1782: Words words = Str_Words(str, FALSE);
1.55 christos 1783:
1.703 rillig 1784: if (words.len > 1) {
1785: size_t i, j;
1786: for (j = 0, i = 1; i < words.len; i++)
1787: if (strcmp(words.words[i], words.words[j]) != 0 &&
1788: (++j != i))
1789: words.words[j] = words.words[i];
1790: words.len = j + 1;
1791: }
1.55 christos 1792:
1.703 rillig 1793: return Words_JoinFree(words);
1.55 christos 1794: }
1795:
1796:
1.778 rillig 1797: /*
1798: * Quote shell meta-characters and space characters in the string.
1799: * If quoteDollar is set, also quote and double any '$' characters.
1800: */
1.16 christos 1801: static char *
1.483 rillig 1802: VarQuote(const char *str, Boolean quoteDollar)
1.16 christos 1803: {
1.703 rillig 1804: Buffer buf;
1805: Buf_Init(&buf);
1.193 christos 1806:
1.703 rillig 1807: for (; *str != '\0'; str++) {
1808: if (*str == '\n') {
1809: const char *newline = Shell_GetNewline();
1810: if (newline == NULL)
1811: newline = "\\\n";
1812: Buf_AddStr(&buf, newline);
1813: continue;
1814: }
1815: if (ch_isspace(*str) || is_shell_metachar((unsigned char)*str))
1816: Buf_AddByte(&buf, '\\');
1817: Buf_AddByte(&buf, *str);
1818: if (quoteDollar && *str == '$')
1819: Buf_AddStr(&buf, "\\$");
1.193 christos 1820: }
1821:
1.784 rillig 1822: return Buf_DoneData(&buf);
1.16 christos 1823: }
1824:
1.778 rillig 1825: /*
1826: * Compute the 32-bit hash of the given string, using the MurmurHash3
1827: * algorithm. Output is encoded as 8 hex digits, in Little Endian order.
1828: */
1.163 joerg 1829: static char *
1.252 rillig 1830: VarHash(const char *str)
1.163 joerg 1831: {
1.703 rillig 1832: static const char hexdigits[16] = "0123456789abcdef";
1833: const unsigned char *ustr = (const unsigned char *)str;
1834:
1835: uint32_t h = 0x971e137bU;
1836: uint32_t c1 = 0x95543787U;
1837: uint32_t c2 = 0x2ad7eb25U;
1838: size_t len2 = strlen(str);
1.163 joerg 1839:
1.703 rillig 1840: char *buf;
1841: size_t i;
1842:
1843: size_t len;
1.781 rillig 1844: for (len = len2; len != 0;) {
1.703 rillig 1845: uint32_t k = 0;
1846: switch (len) {
1847: default:
1848: k = ((uint32_t)ustr[3] << 24) |
1849: ((uint32_t)ustr[2] << 16) |
1850: ((uint32_t)ustr[1] << 8) |
1851: (uint32_t)ustr[0];
1852: len -= 4;
1853: ustr += 4;
1854: break;
1855: case 3:
1856: k |= (uint32_t)ustr[2] << 16;
1857: /* FALLTHROUGH */
1858: case 2:
1859: k |= (uint32_t)ustr[1] << 8;
1860: /* FALLTHROUGH */
1861: case 1:
1862: k |= (uint32_t)ustr[0];
1863: len = 0;
1864: }
1865: c1 = c1 * 5 + 0x7b7d159cU;
1866: c2 = c2 * 5 + 0x6bce6396U;
1867: k *= c1;
1868: k = (k << 11) ^ (k >> 21);
1869: k *= c2;
1870: h = (h << 13) ^ (h >> 19);
1871: h = h * 5 + 0x52dce729U;
1872: h ^= k;
1873: }
1874: h ^= (uint32_t)len2;
1875: h *= 0x85ebca6b;
1876: h ^= h >> 13;
1877: h *= 0xc2b2ae35;
1878: h ^= h >> 16;
1879:
1880: buf = bmake_malloc(9);
1881: for (i = 0; i < 8; i++) {
1882: buf[i] = hexdigits[h & 0x0f];
1883: h >>= 4;
1884: }
1885: buf[8] = '\0';
1886: return buf;
1.163 joerg 1887: }
1888:
1.164 sjg 1889: static char *
1.425 rillig 1890: VarStrftime(const char *fmt, Boolean zulu, time_t tim)
1.164 sjg 1891: {
1.703 rillig 1892: char buf[BUFSIZ];
1.164 sjg 1893:
1.703 rillig 1894: if (tim == 0)
1895: time(&tim);
1896: if (*fmt == '\0')
1897: fmt = "%c";
1898: strftime(buf, sizeof buf, fmt, zulu ? gmtime(&tim) : localtime(&tim));
1.235 rillig 1899:
1.703 rillig 1900: buf[sizeof buf - 1] = '\0';
1901: return bmake_strdup(buf);
1.164 sjg 1902: }
1903:
1.687 rillig 1904: /*
1905: * The ApplyModifier functions take an expression that is being evaluated.
1906: * Their task is to apply a single modifier to the expression.
1907: * To do this, they parse the modifier and its parameters from pp and apply
1908: * the parsed modifier to the current value of the expression, generating a
1909: * new value from it.
1910: *
1911: * The modifier typically lasts until the next ':', or a closing '}' or ')'
1.409 rillig 1912: * (taken from st->endc), or the end of the string (parse error).
1913: *
1.467 rillig 1914: * The high-level behavior of these functions is:
1915: *
1916: * 1. parse the modifier
1917: * 2. evaluate the modifier
1918: * 3. housekeeping
1919: *
1920: * Parsing the modifier
1921: *
1922: * If parsing succeeds, the parsing position *pp is updated to point to the
1923: * first character following the modifier, which typically is either ':' or
1.687 rillig 1924: * st->endc. The modifier doesn't have to check for this delimiter character,
1925: * this is done by ApplyModifiers.
1926: *
1927: * XXX: As of 2020-11-15, some modifiers such as :S, :C, :P, :L do not
1928: * need to be followed by a ':' or endc; this was an unintended mistake.
1.467 rillig 1929: *
1930: * If parsing fails because of a missing delimiter (as in the :S, :C or :@
1.530 rillig 1931: * modifiers), return AMR_CLEANUP.
1.467 rillig 1932: *
1933: * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to
1934: * try the SysV modifier ${VAR:from=to} as fallback. This should only be
1935: * done as long as there have been no side effects from evaluating nested
1936: * variables, to avoid evaluating them more than once. In this case, the
1.687 rillig 1937: * parsing position may or may not be updated. (XXX: Why not? The original
1938: * parsing position is well-known in ApplyModifiers.)
1.467 rillig 1939: *
1940: * If parsing fails and the SysV modifier ${VAR:from=to} should not be used
1941: * as a fallback, either issue an error message using Error or Parse_Error
1942: * and then return AMR_CLEANUP, or return AMR_BAD for the default error
1943: * message. Both of these return values will stop processing the variable
1944: * expression. (XXX: As of 2020-08-23, evaluation of the whole string
1945: * continues nevertheless after skipping a few bytes, which essentially is
1946: * undefined behavior. Not in the sense of C, but still it's impossible to
1947: * predict what happens in the parser.)
1948: *
1949: * Evaluating the modifier
1950: *
1951: * After parsing, the modifier is evaluated. The side effects from evaluating
1952: * nested variable expressions in the modifier text often already happen
1953: * during parsing though.
1954: *
1955: * Evaluating the modifier usually takes the current value of the variable
1.686 rillig 1956: * expression from st->val, or the variable name from st->var->name and stores
1.467 rillig 1957: * the result in st->newVal.
1958: *
1959: * If evaluating fails (as of 2020-08-23), an error message is printed using
1960: * Error. This function has no side-effects, it really just prints the error
1961: * message. Processing the expression continues as if everything were ok.
1962: * XXX: This should be fixed by adding proper error handling to Var_Subst,
1963: * Var_Parse, ApplyModifiers and ModifyWords.
1964: *
1965: * Housekeeping
1966: *
1.528 rillig 1967: * Some modifiers such as :D and :U turn undefined expressions into defined
1968: * expressions (see VEF_UNDEF, VEF_DEF).
1.467 rillig 1969: *
1970: * Some modifiers need to free some memory.
1.350 rillig 1971: */
1.409 rillig 1972:
1.789 rillig 1973: typedef enum VarExprStatus {
1974: /* The variable expression is based in a regular, defined variable. */
1975: VES_NONE,
1.703 rillig 1976: /* The variable expression is based on an undefined variable. */
1.789 rillig 1977: VES_UNDEF,
1.703 rillig 1978: /*
1979: * The variable expression started as an undefined expression, but one
1980: * of the modifiers (such as :D or :U) has turned the expression from
1981: * undefined to defined.
1982: */
1.789 rillig 1983: VES_DEF
1984: } VarExprStatus;
1.527 rillig 1985:
1.789 rillig 1986: static const char * const VarExprStatus_Name[] = {
1987: "none",
1988: "VES_UNDEF",
1989: "VES_DEF"
1990: };
1.527 rillig 1991:
1.541 rillig 1992: typedef struct ApplyModifiersState {
1.703 rillig 1993: /* '\0' or '{' or '(' */
1994: const char startc;
1995: /* '\0' or '}' or ')' */
1996: const char endc;
1997: Var *const var;
1998: GNode *const ctxt;
1999: const VarEvalFlags eflags;
2000: /*
2001: * The new value of the expression, after applying the modifier,
2002: * never NULL.
2003: */
1.758 rillig 2004: FStr newVal;
1.703 rillig 2005: /* Word separator in expansions (see the :ts modifier). */
2006: char sep;
2007: /*
2008: * TRUE if some modifiers that otherwise split the variable value
2009: * into words, like :S and :C, treat the variable value as a single
2010: * big word, possibly containing spaces.
2011: */
2012: Boolean oneBigWord;
1.789 rillig 2013: VarExprStatus exprStatus;
1.236 rillig 2014: } ApplyModifiersState;
2015:
1.525 rillig 2016: static void
1.527 rillig 2017: ApplyModifiersState_Define(ApplyModifiersState *st)
1.525 rillig 2018: {
1.789 rillig 2019: if (st->exprStatus == VES_UNDEF)
2020: st->exprStatus = VES_DEF;
1.525 rillig 2021: }
2022:
1.578 rillig 2023: typedef enum ApplyModifierResult {
1.703 rillig 2024: /* Continue parsing */
2025: AMR_OK,
2026: /* Not a match, try other modifiers as well */
2027: AMR_UNKNOWN,
2028: /* Error out with "Bad modifier" message */
2029: AMR_BAD,
2030: /* Error out without error message */
2031: AMR_CLEANUP
1.356 rillig 2032: } ApplyModifierResult;
2033:
1.703 rillig 2034: /*
2035: * Allow backslashes to escape the delimiter, $, and \, but don't touch other
2036: * backslashes.
2037: */
1.620 rillig 2038: static Boolean
2039: IsEscapedModifierPart(const char *p, char delim,
2040: struct ModifyWord_SubstArgs *subst)
2041: {
1.703 rillig 2042: if (p[0] != '\\')
2043: return FALSE;
2044: if (p[1] == delim || p[1] == '\\' || p[1] == '$')
2045: return TRUE;
2046: return p[1] == '&' && subst != NULL;
1.620 rillig 2047: }
2048:
1.760 rillig 2049: /* See ParseModifierPart */
1.531 rillig 2050: static VarParseResult
1.760 rillig 2051: ParseModifierPartSubst(
1.703 rillig 2052: const char **pp,
2053: char delim,
2054: VarEvalFlags eflags,
1.529 rillig 2055: ApplyModifiersState *st,
1.531 rillig 2056: char **out_part,
1.703 rillig 2057: /* Optionally stores the length of the returned string, just to save
2058: * another strlen call. */
2059: size_t *out_length,
2060: /* For the first part of the :S modifier, sets the VARP_ANCHOR_END flag
2061: * if the last character of the pattern is a $. */
2062: VarPatternFlags *out_pflags,
2063: /* For the second part of the :S modifier, allow ampersands to be
2064: * escaped and replace unescaped ampersands with subst->lhs. */
1.541 rillig 2065: struct ModifyWord_SubstArgs *subst
1.704 rillig 2066: )
2067: {
2068: Buffer buf;
2069: const char *p;
2070:
2071: Buf_Init(&buf);
2072:
2073: /*
2074: * Skim through until the matching delimiter is found; pick up
2075: * variable expressions on the way.
2076: */
2077: p = *pp;
2078: while (*p != '\0' && *p != delim) {
2079: const char *varstart;
2080:
2081: if (IsEscapedModifierPart(p, delim, subst)) {
2082: Buf_AddByte(&buf, p[1]);
2083: p += 2;
2084: continue;
2085: }
2086:
2087: if (*p != '$') { /* Unescaped, simple text */
2088: if (subst != NULL && *p == '&')
2089: Buf_AddBytes(&buf, subst->lhs, subst->lhsLen);
2090: else
2091: Buf_AddByte(&buf, *p);
2092: p++;
2093: continue;
2094: }
1.529 rillig 2095:
1.704 rillig 2096: if (p[1] == delim) { /* Unescaped $ at end of pattern */
2097: if (out_pflags != NULL)
1.788 rillig 2098: out_pflags->anchorEnd = TRUE;
1.704 rillig 2099: else
2100: Buf_AddByte(&buf, *p);
2101: p++;
2102: continue;
2103: }
1.529 rillig 2104:
1.704 rillig 2105: if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */
2106: const char *nested_p = p;
1.743 rillig 2107: FStr nested_val;
1.704 rillig 2108: VarEvalFlags nested_eflags =
2109: eflags & ~(unsigned)VARE_KEEP_DOLLAR;
1.529 rillig 2110:
1.704 rillig 2111: (void)Var_Parse(&nested_p, st->ctxt, nested_eflags,
1.743 rillig 2112: &nested_val);
1.704 rillig 2113: /* TODO: handle errors */
1.743 rillig 2114: Buf_AddStr(&buf, nested_val.str);
2115: FStr_Done(&nested_val);
1.704 rillig 2116: p += nested_p - p;
2117: continue;
2118: }
2119:
1.705 rillig 2120: /*
2121: * XXX: This whole block is very similar to Var_Parse without
1.704 rillig 2122: * VARE_WANTRES. There may be subtle edge cases though that
2123: * are not yet covered in the unit tests and that are parsed
2124: * differently, depending on whether they are evaluated or
2125: * not.
2126: *
2127: * This subtle difference is not documented in the manual
2128: * page, neither is the difference between parsing :D and
2129: * :M documented. No code should ever depend on these
2130: * details, but who knows.
2131: */
2132:
1.705 rillig 2133: varstart = p; /* Nested variable, only parsed */
1.704 rillig 2134: if (p[1] == '(' || p[1] == '{') {
2135: /*
2136: * Find the end of this variable reference
2137: * and suck it in without further ado.
2138: * It will be interpreted later.
2139: */
2140: char startc = p[1];
2141: int endc = startc == '(' ? ')' : '}';
2142: int depth = 1;
2143:
2144: for (p += 2; *p != '\0' && depth > 0; p++) {
2145: if (p[-1] != '\\') {
2146: if (*p == startc)
2147: depth++;
2148: if (*p == endc)
2149: depth--;
2150: }
2151: }
2152: Buf_AddBytesBetween(&buf, varstart, p);
2153: } else {
2154: Buf_AddByte(&buf, *varstart);
2155: p++;
1.529 rillig 2156: }
2157: }
2158:
1.704 rillig 2159: if (*p != delim) {
2160: *pp = p;
2161: Error("Unfinished modifier for %s ('%c' missing)",
1.711 rillig 2162: st->var->name.str, delim);
1.704 rillig 2163: *out_part = NULL;
1.767 rillig 2164: return VPR_ERR;
1.704 rillig 2165: }
2166:
1.787 rillig 2167: *pp = p + 1;
1.704 rillig 2168: if (out_length != NULL)
1.786 rillig 2169: *out_length = buf.len;
1.529 rillig 2170:
1.784 rillig 2171: *out_part = Buf_DoneData(&buf);
1.708 rillig 2172: DEBUG1(VAR, "Modifier part: \"%s\"\n", *out_part);
1.704 rillig 2173: return VPR_OK;
1.529 rillig 2174: }
2175:
1.760 rillig 2176: /*
2177: * Parse a part of a modifier such as the "from" and "to" in :S/from/to/ or
2178: * the "var" or "replacement ${var}" in :@var@replacement ${var}@, up to and
2179: * including the next unescaped delimiter. The delimiter, as well as the
2180: * backslash or the dollar, can be escaped with a backslash.
2181: *
2182: * Return the parsed (and possibly expanded) string, or NULL if no delimiter
2183: * was found. On successful return, the parsing position pp points right
2184: * after the delimiter. The delimiter is not included in the returned
2185: * value though.
2186: */
2187: static VarParseResult
2188: ParseModifierPart(
2189: /* The parsing position, updated upon return */
2190: const char **pp,
2191: /* Parsing stops at this delimiter */
2192: char delim,
2193: /* Flags for evaluating nested variables; if VARE_WANTRES is not set,
2194: * the text is only parsed. */
2195: VarEvalFlags eflags,
2196: ApplyModifiersState *st,
2197: char **out_part
2198: )
2199: {
2200: return ParseModifierPartSubst(pp, delim, eflags, st, out_part,
2201: NULL, NULL, NULL);
2202: }
2203:
1.400 rillig 2204: /* Test whether mod starts with modname, followed by a delimiter. */
1.684 rillig 2205: MAKE_INLINE Boolean
1.340 rillig 2206: ModMatch(const char *mod, const char *modname, char endc)
2207: {
1.703 rillig 2208: size_t n = strlen(modname);
2209: return strncmp(mod, modname, n) == 0 &&
2210: (mod[n] == endc || mod[n] == ':');
1.340 rillig 2211: }
2212:
1.400 rillig 2213: /* Test whether mod starts with modname, followed by a delimiter or '='. */
1.684 rillig 2214: MAKE_INLINE Boolean
1.340 rillig 2215: ModMatchEq(const char *mod, const char *modname, char endc)
2216: {
1.703 rillig 2217: size_t n = strlen(modname);
2218: return strncmp(mod, modname, n) == 0 &&
2219: (mod[n] == endc || mod[n] == ':' || mod[n] == '=');
1.340 rillig 2220: }
1.236 rillig 2221:
1.635 rillig 2222: static Boolean
2223: TryParseIntBase0(const char **pp, int *out_num)
2224: {
1.703 rillig 2225: char *end;
2226: long n;
1.635 rillig 2227:
1.703 rillig 2228: errno = 0;
2229: n = strtol(*pp, &end, 0);
2230: if ((n == LONG_MIN || n == LONG_MAX) && errno == ERANGE)
2231: return FALSE;
2232: if (n < INT_MIN || n > INT_MAX)
2233: return FALSE;
1.635 rillig 2234:
1.703 rillig 2235: *pp = end;
2236: *out_num = (int)n;
2237: return TRUE;
1.635 rillig 2238: }
2239:
2240: static Boolean
2241: TryParseSize(const char **pp, size_t *out_num)
2242: {
1.703 rillig 2243: char *end;
2244: unsigned long n;
1.635 rillig 2245:
1.703 rillig 2246: if (!ch_isdigit(**pp))
2247: return FALSE;
1.635 rillig 2248:
1.703 rillig 2249: errno = 0;
2250: n = strtoul(*pp, &end, 10);
2251: if (n == ULONG_MAX && errno == ERANGE)
2252: return FALSE;
2253: if (n > SIZE_MAX)
2254: return FALSE;
1.635 rillig 2255:
1.703 rillig 2256: *pp = end;
2257: *out_num = (size_t)n;
2258: return TRUE;
1.635 rillig 2259: }
2260:
2261: static Boolean
2262: TryParseChar(const char **pp, int base, char *out_ch)
2263: {
1.703 rillig 2264: char *end;
2265: unsigned long n;
1.635 rillig 2266:
1.703 rillig 2267: if (!ch_isalnum(**pp))
2268: return FALSE;
1.635 rillig 2269:
1.703 rillig 2270: errno = 0;
2271: n = strtoul(*pp, &end, base);
2272: if (n == ULONG_MAX && errno == ERANGE)
2273: return FALSE;
2274: if (n > UCHAR_MAX)
2275: return FALSE;
1.635 rillig 2276:
1.703 rillig 2277: *pp = end;
2278: *out_ch = (char)n;
2279: return TRUE;
1.635 rillig 2280: }
2281:
1.236 rillig 2282: /* :@var@...${var}...@ */
1.356 rillig 2283: static ApplyModifierResult
1.749 rillig 2284: ApplyModifier_Loop(const char **pp, const char *val, ApplyModifiersState *st)
1.417 rillig 2285: {
1.703 rillig 2286: struct ModifyWord_LoopArgs args;
2287: char prev_sep;
2288: VarParseResult res;
2289:
2290: args.ctx = st->ctxt;
2291:
2292: (*pp)++; /* Skip the first '@' */
1.760 rillig 2293: res = ParseModifierPart(pp, '@', VARE_NONE, st, &args.tvar);
1.703 rillig 2294: if (res != VPR_OK)
2295: return AMR_CLEANUP;
1.764 rillig 2296: if (opts.strict && strchr(args.tvar, '$') != NULL) {
1.703 rillig 2297: Parse_Error(PARSE_FATAL,
1.410 rillig 2298: "In the :@ modifier of \"%s\", the variable name \"%s\" "
2299: "must not contain a dollar.",
1.711 rillig 2300: st->var->name.str, args.tvar);
1.703 rillig 2301: return AMR_CLEANUP;
2302: }
1.236 rillig 2303:
1.760 rillig 2304: res = ParseModifierPart(pp, '@', VARE_NONE, st, &args.str);
1.703 rillig 2305: if (res != VPR_OK)
2306: return AMR_CLEANUP;
2307:
2308: args.eflags = st->eflags & ~(unsigned)VARE_KEEP_DOLLAR;
2309: prev_sep = st->sep;
2310: st->sep = ' '; /* XXX: should be st->sep for consistency */
1.758 rillig 2311: st->newVal = FStr_InitOwn(
1.756 rillig 2312: ModifyWords(val, ModifyWord_Loop, &args, st->oneBigWord, st->sep));
1.703 rillig 2313: st->sep = prev_sep;
2314: /* XXX: Consider restoring the previous variable instead of deleting. */
2315: Var_Delete(args.tvar, st->ctxt);
2316: free(args.tvar);
2317: free(args.str);
2318: return AMR_OK;
1.236 rillig 2319: }
2320:
2321: /* :Ddefined or :Uundefined */
1.356 rillig 2322: static ApplyModifierResult
1.758 rillig 2323: ApplyModifier_Defined(const char **pp, const char *val, ApplyModifiersState *st)
1.236 rillig 2324: {
1.703 rillig 2325: Buffer buf;
2326: const char *p;
1.412 rillig 2327:
1.703 rillig 2328: VarEvalFlags eflags = VARE_NONE;
2329: if (st->eflags & VARE_WANTRES)
1.789 rillig 2330: if ((**pp == 'D') == (st->exprStatus == VES_NONE))
1.703 rillig 2331: eflags = st->eflags;
2332:
2333: Buf_Init(&buf);
2334: p = *pp + 1;
2335: while (*p != st->endc && *p != ':' && *p != '\0') {
2336:
2337: /* XXX: This code is similar to the one in Var_Parse.
2338: * See if the code can be merged.
2339: * See also ApplyModifier_Match. */
2340:
2341: /* Escaped delimiter or other special character */
2342: if (*p == '\\') {
2343: char c = p[1];
2344: if (c == st->endc || c == ':' || c == '$' ||
2345: c == '\\') {
2346: Buf_AddByte(&buf, c);
2347: p += 2;
2348: continue;
2349: }
2350: }
1.236 rillig 2351:
1.703 rillig 2352: /* Nested variable expression */
2353: if (*p == '$') {
1.743 rillig 2354: FStr nested_val;
1.466 rillig 2355:
1.743 rillig 2356: (void)Var_Parse(&p, st->ctxt, eflags, &nested_val);
1.703 rillig 2357: /* TODO: handle errors */
1.743 rillig 2358: Buf_AddStr(&buf, nested_val.str);
2359: FStr_Done(&nested_val);
1.703 rillig 2360: continue;
2361: }
1.687 rillig 2362:
1.703 rillig 2363: /* Ordinary text */
2364: Buf_AddByte(&buf, *p);
2365: p++;
1.466 rillig 2366: }
1.703 rillig 2367: *pp = p;
1.466 rillig 2368:
1.703 rillig 2369: ApplyModifiersState_Define(st);
1.236 rillig 2370:
1.703 rillig 2371: if (eflags & VARE_WANTRES) {
1.784 rillig 2372: st->newVal = FStr_InitOwn(Buf_DoneData(&buf));
1.703 rillig 2373: } else {
1.758 rillig 2374: st->newVal = FStr_InitRefer(val);
1.784 rillig 2375: Buf_Done(&buf);
1.236 rillig 2376: }
1.703 rillig 2377: return AMR_OK;
1.236 rillig 2378: }
2379:
1.567 rillig 2380: /* :L */
2381: static ApplyModifierResult
2382: ApplyModifier_Literal(const char **pp, ApplyModifiersState *st)
2383: {
1.703 rillig 2384: ApplyModifiersState_Define(st);
1.758 rillig 2385: st->newVal = FStr_InitOwn(bmake_strdup(st->var->name.str));
1.703 rillig 2386: (*pp)++;
2387: return AMR_OK;
1.567 rillig 2388: }
2389:
1.633 rillig 2390: static Boolean
2391: TryParseTime(const char **pp, time_t *out_time)
1.631 rillig 2392: {
1.703 rillig 2393: char *end;
2394: unsigned long n;
1.631 rillig 2395:
1.703 rillig 2396: if (!ch_isdigit(**pp))
2397: return FALSE;
1.631 rillig 2398:
1.703 rillig 2399: errno = 0;
2400: n = strtoul(*pp, &end, 10);
2401: if (n == ULONG_MAX && errno == ERANGE)
2402: return FALSE;
1.631 rillig 2403:
1.703 rillig 2404: *pp = end;
2405: *out_time = (time_t)n; /* ignore possible truncation for now */
2406: return TRUE;
1.631 rillig 2407: }
2408:
1.236 rillig 2409: /* :gmtime */
1.356 rillig 2410: static ApplyModifierResult
1.749 rillig 2411: ApplyModifier_Gmtime(const char **pp, const char *val, ApplyModifiersState *st)
1.236 rillig 2412: {
1.703 rillig 2413: time_t utc;
1.412 rillig 2414:
1.703 rillig 2415: const char *mod = *pp;
2416: if (!ModMatchEq(mod, "gmtime", st->endc))
2417: return AMR_UNKNOWN;
2418:
2419: if (mod[6] == '=') {
2420: const char *arg = mod + 7;
2421: if (!TryParseTime(&arg, &utc)) {
2422: Parse_Error(PARSE_FATAL,
1.761 rillig 2423: "Invalid time value: %s", mod + 7);
1.703 rillig 2424: return AMR_CLEANUP;
2425: }
2426: *pp = arg;
2427: } else {
2428: utc = 0;
2429: *pp = mod + 6;
1.631 rillig 2430: }
1.758 rillig 2431: st->newVal = FStr_InitOwn(VarStrftime(val, TRUE, utc));
1.703 rillig 2432: return AMR_OK;
1.236 rillig 2433: }
2434:
2435: /* :localtime */
1.505 rillig 2436: static ApplyModifierResult
1.749 rillig 2437: ApplyModifier_Localtime(const char **pp, const char *val,
2438: ApplyModifiersState *st)
1.236 rillig 2439: {
1.703 rillig 2440: time_t utc;
1.412 rillig 2441:
1.703 rillig 2442: const char *mod = *pp;
2443: if (!ModMatchEq(mod, "localtime", st->endc))
2444: return AMR_UNKNOWN;
2445:
2446: if (mod[9] == '=') {
2447: const char *arg = mod + 10;
2448: if (!TryParseTime(&arg, &utc)) {
2449: Parse_Error(PARSE_FATAL,
1.761 rillig 2450: "Invalid time value: %s", mod + 10);
1.703 rillig 2451: return AMR_CLEANUP;
2452: }
2453: *pp = arg;
2454: } else {
2455: utc = 0;
2456: *pp = mod + 9;
1.631 rillig 2457: }
1.758 rillig 2458: st->newVal = FStr_InitOwn(VarStrftime(val, FALSE, utc));
1.703 rillig 2459: return AMR_OK;
1.236 rillig 2460: }
2461:
2462: /* :hash */
1.356 rillig 2463: static ApplyModifierResult
1.749 rillig 2464: ApplyModifier_Hash(const char **pp, const char *val, ApplyModifiersState *st)
1.236 rillig 2465: {
1.703 rillig 2466: if (!ModMatch(*pp, "hash", st->endc))
2467: return AMR_UNKNOWN;
1.340 rillig 2468:
1.758 rillig 2469: st->newVal = FStr_InitOwn(VarHash(val));
1.703 rillig 2470: *pp += 4;
2471: return AMR_OK;
1.236 rillig 2472: }
2473:
2474: /* :P */
1.356 rillig 2475: static ApplyModifierResult
1.409 rillig 2476: ApplyModifier_Path(const char **pp, ApplyModifiersState *st)
1.236 rillig 2477: {
1.703 rillig 2478: GNode *gn;
2479: char *path;
1.412 rillig 2480:
1.703 rillig 2481: ApplyModifiersState_Define(st);
1.409 rillig 2482:
1.711 rillig 2483: gn = Targ_FindNode(st->var->name.str);
1.703 rillig 2484: if (gn == NULL || gn->type & OP_NOPATH) {
2485: path = NULL;
2486: } else if (gn->path != NULL) {
2487: path = bmake_strdup(gn->path);
2488: } else {
2489: SearchPath *searchPath = Suff_FindPath(gn);
1.711 rillig 2490: path = Dir_FindFile(st->var->name.str, searchPath);
1.703 rillig 2491: }
2492: if (path == NULL)
1.711 rillig 2493: path = bmake_strdup(st->var->name.str);
1.758 rillig 2494: st->newVal = FStr_InitOwn(path);
1.409 rillig 2495:
1.703 rillig 2496: (*pp)++;
2497: return AMR_OK;
1.236 rillig 2498: }
2499:
2500: /* :!cmd! */
1.356 rillig 2501: static ApplyModifierResult
1.509 rillig 2502: ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st)
1.236 rillig 2503: {
1.703 rillig 2504: char *cmd;
2505: const char *errfmt;
2506: VarParseResult res;
2507:
2508: (*pp)++;
1.760 rillig 2509: res = ParseModifierPart(pp, '!', st->eflags, st, &cmd);
1.703 rillig 2510: if (res != VPR_OK)
2511: return AMR_CLEANUP;
2512:
2513: errfmt = NULL;
2514: if (st->eflags & VARE_WANTRES)
1.758 rillig 2515: st->newVal = FStr_InitOwn(Cmd_Exec(cmd, &errfmt));
1.703 rillig 2516: else
1.759 rillig 2517: st->newVal = FStr_InitRefer("");
1.703 rillig 2518: if (errfmt != NULL)
2519: Error(errfmt, cmd); /* XXX: why still return AMR_OK? */
2520: free(cmd);
1.274 rillig 2521:
1.703 rillig 2522: ApplyModifiersState_Define(st);
2523: return AMR_OK;
1.236 rillig 2524: }
2525:
1.778 rillig 2526: /*
2527: * The :range modifier generates an integer sequence as long as the words.
2528: * The :range=7 modifier generates an integer sequence from 1 to 7.
2529: */
1.356 rillig 2530: static ApplyModifierResult
1.749 rillig 2531: ApplyModifier_Range(const char **pp, const char *val, ApplyModifiersState *st)
1.236 rillig 2532: {
1.703 rillig 2533: size_t n;
2534: Buffer buf;
2535: size_t i;
1.412 rillig 2536:
1.703 rillig 2537: const char *mod = *pp;
2538: if (!ModMatchEq(mod, "range", st->endc))
2539: return AMR_UNKNOWN;
2540:
2541: if (mod[5] == '=') {
2542: const char *p = mod + 6;
2543: if (!TryParseSize(&p, &n)) {
2544: Parse_Error(PARSE_FATAL,
1.761 rillig 2545: "Invalid number: %s", mod + 6);
1.703 rillig 2546: return AMR_CLEANUP;
2547: }
2548: *pp = p;
2549: } else {
2550: n = 0;
2551: *pp = mod + 5;
1.635 rillig 2552: }
1.386 rillig 2553:
1.703 rillig 2554: if (n == 0) {
1.749 rillig 2555: Words words = Str_Words(val, FALSE);
1.703 rillig 2556: n = words.len;
2557: Words_Free(words);
2558: }
1.386 rillig 2559:
1.703 rillig 2560: Buf_Init(&buf);
1.386 rillig 2561:
1.703 rillig 2562: for (i = 0; i < n; i++) {
2563: if (i != 0) {
2564: /* XXX: Use st->sep instead of ' ', for consistency. */
2565: Buf_AddByte(&buf, ' ');
2566: }
2567: Buf_AddInt(&buf, 1 + (int)i);
2568: }
1.386 rillig 2569:
1.784 rillig 2570: st->newVal = FStr_InitOwn(Buf_DoneData(&buf));
1.703 rillig 2571: return AMR_OK;
1.236 rillig 2572: }
2573:
2574: /* :Mpattern or :Npattern */
1.356 rillig 2575: static ApplyModifierResult
1.749 rillig 2576: ApplyModifier_Match(const char **pp, const char *val, ApplyModifiersState *st)
1.236 rillig 2577: {
1.703 rillig 2578: const char *mod = *pp;
2579: Boolean copy = FALSE; /* pattern should be, or has been, copied */
2580: Boolean needSubst = FALSE;
2581: const char *endpat;
2582: char *pattern;
2583: ModifyWordsCallback callback;
1.412 rillig 2584:
1.703 rillig 2585: /*
2586: * In the loop below, ignore ':' unless we are at (or back to) the
2587: * original brace level.
2588: * XXX: This will likely not work right if $() and ${} are intermixed.
2589: */
2590: /* XXX: This code is similar to the one in Var_Parse.
2591: * See if the code can be merged.
2592: * See also ApplyModifier_Defined. */
2593: int nest = 0;
2594: const char *p;
2595: for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) {
2596: if (*p == '\\' &&
2597: (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) {
2598: if (!needSubst)
2599: copy = TRUE;
2600: p++;
2601: continue;
2602: }
2603: if (*p == '$')
2604: needSubst = TRUE;
2605: if (*p == '(' || *p == '{')
2606: nest++;
2607: if (*p == ')' || *p == '}') {
2608: nest--;
2609: if (nest < 0)
2610: break;
2611: }
1.236 rillig 2612: }
1.703 rillig 2613: *pp = p;
2614: endpat = p;
2615:
2616: if (copy) {
2617: char *dst;
2618: const char *src;
2619:
2620: /* Compress the \:'s out of the pattern. */
2621: pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1);
2622: dst = pattern;
2623: src = mod + 1;
2624: for (; src < endpat; src++, dst++) {
2625: if (src[0] == '\\' && src + 1 < endpat &&
2626: /* XXX: st->startc is missing here; see above */
2627: (src[1] == ':' || src[1] == st->endc))
2628: src++;
2629: *dst = *src;
2630: }
2631: *dst = '\0';
2632: } else {
2633: pattern = bmake_strsedup(mod + 1, endpat);
1.236 rillig 2634: }
1.288 rillig 2635:
1.703 rillig 2636: if (needSubst) {
2637: char *old_pattern = pattern;
2638: (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern);
2639: /* TODO: handle errors */
2640: free(old_pattern);
1.236 rillig 2641: }
1.346 rillig 2642:
1.708 rillig 2643: DEBUG3(VAR, "Pattern[%s] for [%s] is [%s]\n",
1.749 rillig 2644: st->var->name.str, val, pattern);
1.346 rillig 2645:
1.703 rillig 2646: callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch;
1.758 rillig 2647: st->newVal = FStr_InitOwn(ModifyWords(val, callback, pattern,
1.756 rillig 2648: st->oneBigWord, st->sep));
1.703 rillig 2649: free(pattern);
2650: return AMR_OK;
1.236 rillig 2651: }
2652:
2653: /* :S,from,to, */
1.356 rillig 2654: static ApplyModifierResult
1.749 rillig 2655: ApplyModifier_Subst(const char **pp, const char *val, ApplyModifiersState *st)
1.236 rillig 2656: {
1.703 rillig 2657: struct ModifyWord_SubstArgs args;
2658: char *lhs, *rhs;
2659: Boolean oneBigWord;
2660: VarParseResult res;
1.299 rillig 2661:
1.703 rillig 2662: char delim = (*pp)[1];
2663: if (delim == '\0') {
2664: Error("Missing delimiter for :S modifier");
2665: (*pp)++;
2666: return AMR_CLEANUP;
2667: }
1.236 rillig 2668:
1.703 rillig 2669: *pp += 2;
1.236 rillig 2670:
1.788 rillig 2671: args.pflags = (VarPatternFlags){ FALSE, FALSE, FALSE, FALSE };
1.703 rillig 2672: args.matched = FALSE;
1.236 rillig 2673:
1.703 rillig 2674: /*
2675: * If pattern begins with '^', it is anchored to the
2676: * start of the word -- skip over it and flag pattern.
2677: */
2678: if (**pp == '^') {
1.788 rillig 2679: args.pflags.anchorStart = TRUE;
1.703 rillig 2680: (*pp)++;
2681: }
2682:
1.760 rillig 2683: res = ParseModifierPartSubst(pp, delim, st->eflags, st, &lhs,
2684: &args.lhsLen, &args.pflags, NULL);
1.703 rillig 2685: if (res != VPR_OK)
2686: return AMR_CLEANUP;
2687: args.lhs = lhs;
2688:
1.760 rillig 2689: res = ParseModifierPartSubst(pp, delim, st->eflags, st, &rhs,
2690: &args.rhsLen, NULL, &args);
1.703 rillig 2691: if (res != VPR_OK)
2692: return AMR_CLEANUP;
2693: args.rhs = rhs;
2694:
2695: oneBigWord = st->oneBigWord;
2696: for (;; (*pp)++) {
2697: switch (**pp) {
2698: case 'g':
1.788 rillig 2699: args.pflags.subGlobal = TRUE;
1.703 rillig 2700: continue;
2701: case '1':
1.788 rillig 2702: args.pflags.subOnce = TRUE;
1.703 rillig 2703: continue;
2704: case 'W':
2705: oneBigWord = TRUE;
2706: continue;
2707: }
2708: break;
1.236 rillig 2709: }
2710:
1.758 rillig 2711: st->newVal = FStr_InitOwn(ModifyWords(val, ModifyWord_Subst, &args,
1.756 rillig 2712: oneBigWord, st->sep));
1.236 rillig 2713:
1.703 rillig 2714: free(lhs);
2715: free(rhs);
2716: return AMR_OK;
1.236 rillig 2717: }
2718:
2719: #ifndef NO_REGEX
1.291 rillig 2720:
1.236 rillig 2721: /* :C,from,to, */
1.356 rillig 2722: static ApplyModifierResult
1.749 rillig 2723: ApplyModifier_Regex(const char **pp, const char *val, ApplyModifiersState *st)
1.236 rillig 2724: {
1.703 rillig 2725: char *re;
2726: struct ModifyWord_SubstRegexArgs args;
2727: Boolean oneBigWord;
2728: int error;
2729: VarParseResult res;
2730:
2731: char delim = (*pp)[1];
2732: if (delim == '\0') {
2733: Error("Missing delimiter for :C modifier");
2734: (*pp)++;
2735: return AMR_CLEANUP;
2736: }
2737:
2738: *pp += 2;
1.236 rillig 2739:
1.760 rillig 2740: res = ParseModifierPart(pp, delim, st->eflags, st, &re);
1.703 rillig 2741: if (res != VPR_OK)
2742: return AMR_CLEANUP;
2743:
1.760 rillig 2744: res = ParseModifierPart(pp, delim, st->eflags, st, &args.replace);
1.703 rillig 2745: if (args.replace == NULL) {
2746: free(re);
2747: return AMR_CLEANUP;
2748: }
2749:
1.788 rillig 2750: args.pflags = (VarPatternFlags){ FALSE, FALSE, FALSE, FALSE };
1.703 rillig 2751: args.matched = FALSE;
2752: oneBigWord = st->oneBigWord;
2753: for (;; (*pp)++) {
2754: switch (**pp) {
2755: case 'g':
1.788 rillig 2756: args.pflags.subGlobal = TRUE;
1.703 rillig 2757: continue;
2758: case '1':
1.788 rillig 2759: args.pflags.subOnce = TRUE;
1.703 rillig 2760: continue;
2761: case 'W':
2762: oneBigWord = TRUE;
2763: continue;
2764: }
2765: break;
2766: }
1.236 rillig 2767:
1.703 rillig 2768: error = regcomp(&args.re, re, REG_EXTENDED);
1.236 rillig 2769: free(re);
1.703 rillig 2770: if (error != 0) {
2771: VarREError(error, &args.re, "Regex compilation error");
2772: free(args.replace);
2773: return AMR_CLEANUP;
1.236 rillig 2774: }
2775:
1.703 rillig 2776: args.nsub = args.re.re_nsub + 1;
2777: if (args.nsub > 10)
2778: args.nsub = 10;
1.758 rillig 2779: st->newVal = FStr_InitOwn(
1.756 rillig 2780: ModifyWords(val, ModifyWord_SubstRegex, &args,
2781: oneBigWord, st->sep));
1.703 rillig 2782: regfree(&args.re);
1.291 rillig 2783: free(args.replace);
1.703 rillig 2784: return AMR_OK;
2785: }
1.236 rillig 2786:
2787: #endif
2788:
1.555 rillig 2789: /* :Q, :q */
2790: static ApplyModifierResult
1.749 rillig 2791: ApplyModifier_Quote(const char **pp, const char *val, ApplyModifiersState *st)
1.555 rillig 2792: {
1.703 rillig 2793: if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
1.758 rillig 2794: st->newVal = FStr_InitOwn(VarQuote(val, **pp == 'q'));
1.703 rillig 2795: (*pp)++;
2796: return AMR_OK;
2797: } else
2798: return AMR_UNKNOWN;
1.555 rillig 2799: }
2800:
1.779 rillig 2801: /*ARGSUSED*/
1.278 rillig 2802: static void
1.295 rillig 2803: ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
1.278 rillig 2804: {
1.703 rillig 2805: SepBuf_AddStr(buf, word);
1.275 rillig 2806: }
2807:
1.289 rillig 2808: /* :ts<separator> */
1.356 rillig 2809: static ApplyModifierResult
1.749 rillig 2810: ApplyModifier_ToSep(const char **pp, const char *val, ApplyModifiersState *st)
1.289 rillig 2811: {
1.703 rillig 2812: const char *sep = *pp + 2;
2813:
2814: /* ":ts<any><endc>" or ":ts<any>:" */
2815: if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
2816: st->sep = sep[0];
2817: *pp = sep + 1;
2818: goto ok;
2819: }
1.468 rillig 2820:
1.703 rillig 2821: /* ":ts<endc>" or ":ts:" */
2822: if (sep[0] == st->endc || sep[0] == ':') {
2823: st->sep = '\0'; /* no separator */
2824: *pp = sep;
2825: goto ok;
2826: }
1.468 rillig 2827:
1.703 rillig 2828: /* ":ts<unrecognised><unrecognised>". */
2829: if (sep[0] != '\\') {
2830: (*pp)++; /* just for backwards compatibility */
2831: return AMR_BAD;
2832: }
1.468 rillig 2833:
1.703 rillig 2834: /* ":ts\n" */
2835: if (sep[1] == 'n') {
2836: st->sep = '\n';
2837: *pp = sep + 2;
2838: goto ok;
2839: }
1.468 rillig 2840:
1.703 rillig 2841: /* ":ts\t" */
2842: if (sep[1] == 't') {
2843: st->sep = '\t';
2844: *pp = sep + 2;
2845: goto ok;
2846: }
1.468 rillig 2847:
1.703 rillig 2848: /* ":ts\x40" or ":ts\100" */
2849: {
2850: const char *p = sep + 1;
2851: int base = 8; /* assume octal */
1.468 rillig 2852:
1.703 rillig 2853: if (sep[1] == 'x') {
2854: base = 16;
2855: p++;
2856: } else if (!ch_isdigit(sep[1])) {
2857: (*pp)++; /* just for backwards compatibility */
2858: return AMR_BAD; /* ":ts<backslash><unrecognised>". */
2859: }
1.289 rillig 2860:
1.703 rillig 2861: if (!TryParseChar(&p, base, &st->sep)) {
2862: Parse_Error(PARSE_FATAL,
1.761 rillig 2863: "Invalid character number: %s", p);
1.703 rillig 2864: return AMR_CLEANUP;
2865: }
2866: if (*p != ':' && *p != st->endc) {
2867: (*pp)++; /* just for backwards compatibility */
2868: return AMR_BAD;
2869: }
1.468 rillig 2870:
1.703 rillig 2871: *pp = p;
1.556 rillig 2872: }
1.635 rillig 2873:
1.468 rillig 2874: ok:
1.758 rillig 2875: st->newVal = FStr_InitOwn(
1.756 rillig 2876: ModifyWords(val, ModifyWord_Copy, NULL, st->oneBigWord, st->sep));
1.703 rillig 2877: return AMR_OK;
1.289 rillig 2878: }
2879:
1.738 rillig 2880: static char *
2881: str_toupper(const char *str)
2882: {
2883: char *res;
2884: size_t i, len;
2885:
2886: len = strlen(str);
2887: res = bmake_malloc(len + 1);
2888: for (i = 0; i < len + 1; i++)
2889: res[i] = ch_toupper(str[i]);
2890:
2891: return res;
2892: }
2893:
2894: static char *
2895: str_tolower(const char *str)
2896: {
2897: char *res;
2898: size_t i, len;
2899:
2900: len = strlen(str);
2901: res = bmake_malloc(len + 1);
2902: for (i = 0; i < len + 1; i++)
2903: res[i] = ch_tolower(str[i]);
2904:
2905: return res;
2906: }
2907:
1.289 rillig 2908: /* :tA, :tu, :tl, :ts<separator>, etc. */
1.356 rillig 2909: static ApplyModifierResult
1.758 rillig 2910: ApplyModifier_To(const char **pp, const char *val, ApplyModifiersState *st)
1.236 rillig 2911: {
1.703 rillig 2912: const char *mod = *pp;
2913: assert(mod[0] == 't');
1.363 rillig 2914:
1.703 rillig 2915: if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') {
2916: *pp = mod + 1;
2917: return AMR_BAD; /* Found ":t<endc>" or ":t:". */
2918: }
1.289 rillig 2919:
1.703 rillig 2920: if (mod[1] == 's')
1.749 rillig 2921: return ApplyModifier_ToSep(pp, val, st);
1.289 rillig 2922:
1.703 rillig 2923: if (mod[2] != st->endc && mod[2] != ':') {
2924: *pp = mod + 1;
2925: return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */
2926: }
1.236 rillig 2927:
1.703 rillig 2928: /* Check for two-character options: ":tu", ":tl" */
2929: if (mod[1] == 'A') { /* absolute path */
1.758 rillig 2930: st->newVal = FStr_InitOwn(
1.756 rillig 2931: ModifyWords(val, ModifyWord_Realpath, NULL,
2932: st->oneBigWord, st->sep));
1.703 rillig 2933: *pp = mod + 2;
2934: return AMR_OK;
2935: }
1.475 rillig 2936:
1.703 rillig 2937: if (mod[1] == 'u') { /* :tu */
1.758 rillig 2938: st->newVal = FStr_InitOwn(str_toupper(val));
1.703 rillig 2939: *pp = mod + 2;
2940: return AMR_OK;
2941: }
1.475 rillig 2942:
1.703 rillig 2943: if (mod[1] == 'l') { /* :tl */
1.758 rillig 2944: st->newVal = FStr_InitOwn(str_tolower(val));
1.703 rillig 2945: *pp = mod + 2;
2946: return AMR_OK;
2947: }
1.475 rillig 2948:
1.703 rillig 2949: if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */
2950: st->oneBigWord = mod[1] == 'W';
1.758 rillig 2951: st->newVal = FStr_InitRefer(val);
1.703 rillig 2952: *pp = mod + 2;
2953: return AMR_OK;
2954: }
1.475 rillig 2955:
1.703 rillig 2956: /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2957: *pp = mod + 1;
2958: return AMR_BAD;
1.236 rillig 2959: }
2960:
1.634 rillig 2961: /* :[#], :[1], :[-1..1], etc. */
1.356 rillig 2962: static ApplyModifierResult
1.758 rillig 2963: ApplyModifier_Words(const char **pp, const char *val, ApplyModifiersState *st)
1.236 rillig 2964: {
1.703 rillig 2965: char *estr;
2966: int first, last;
2967: VarParseResult res;
2968: const char *p;
1.412 rillig 2969:
1.703 rillig 2970: (*pp)++; /* skip the '[' */
1.760 rillig 2971: res = ParseModifierPart(pp, ']', st->eflags, st, &estr);
1.703 rillig 2972: if (res != VPR_OK)
2973: return AMR_CLEANUP;
2974:
2975: /* now *pp points just after the closing ']' */
2976: if (**pp != ':' && **pp != st->endc)
2977: goto bad_modifier; /* Found junk after ']' */
2978:
2979: if (estr[0] == '\0')
2980: goto bad_modifier; /* empty square brackets in ":[]". */
2981:
2982: if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */
2983: if (st->oneBigWord) {
1.759 rillig 2984: st->newVal = FStr_InitRefer("1");
1.703 rillig 2985: } else {
2986: Buffer buf;
1.412 rillig 2987:
1.749 rillig 2988: Words words = Str_Words(val, FALSE);
1.703 rillig 2989: size_t ac = words.len;
2990: Words_Free(words);
2991:
2992: /* 3 digits + '\0' is usually enough */
2993: Buf_InitSize(&buf, 4);
2994: Buf_AddInt(&buf, (int)ac);
1.784 rillig 2995: st->newVal = FStr_InitOwn(Buf_DoneData(&buf));
1.703 rillig 2996: }
2997: goto ok;
2998: }
1.494 rillig 2999:
1.703 rillig 3000: if (estr[0] == '*' && estr[1] == '\0') {
3001: /* Found ":[*]" */
3002: st->oneBigWord = TRUE;
1.758 rillig 3003: st->newVal = FStr_InitRefer(val);
1.703 rillig 3004: goto ok;
1.236 rillig 3005: }
1.288 rillig 3006:
1.703 rillig 3007: if (estr[0] == '@' && estr[1] == '\0') {
3008: /* Found ":[@]" */
3009: st->oneBigWord = FALSE;
1.758 rillig 3010: st->newVal = FStr_InitRefer(val);
1.703 rillig 3011: goto ok;
3012: }
1.288 rillig 3013:
1.703 rillig 3014: /*
3015: * We expect estr to contain a single integer for :[N], or two
3016: * integers separated by ".." for :[start..end].
3017: */
3018: p = estr;
3019: if (!TryParseIntBase0(&p, &first))
3020: goto bad_modifier; /* Found junk instead of a number */
3021:
3022: if (p[0] == '\0') { /* Found only one integer in :[N] */
3023: last = first;
3024: } else if (p[0] == '.' && p[1] == '.' && p[2] != '\0') {
3025: /* Expecting another integer after ".." */
3026: p += 2;
3027: if (!TryParseIntBase0(&p, &last) || *p != '\0')
3028: goto bad_modifier; /* Found junk after ".." */
3029: } else
3030: goto bad_modifier; /* Found junk instead of ".." */
1.288 rillig 3031:
1.703 rillig 3032: /*
3033: * Now first and last are properly filled in, but we still have to
3034: * check for 0 as a special case.
3035: */
3036: if (first == 0 && last == 0) {
3037: /* ":[0]" or perhaps ":[0..0]" */
3038: st->oneBigWord = TRUE;
1.758 rillig 3039: st->newVal = FStr_InitRefer(val);
1.703 rillig 3040: goto ok;
3041: }
1.288 rillig 3042:
1.703 rillig 3043: /* ":[0..N]" or ":[N..0]" */
3044: if (first == 0 || last == 0)
3045: goto bad_modifier;
3046:
3047: /* Normal case: select the words described by first and last. */
1.758 rillig 3048: st->newVal = FStr_InitOwn(
1.756 rillig 3049: VarSelectWords(st->sep, st->oneBigWord, val, first, last));
1.288 rillig 3050:
3051: ok:
1.703 rillig 3052: free(estr);
3053: return AMR_OK;
1.288 rillig 3054:
3055: bad_modifier:
1.703 rillig 3056: free(estr);
3057: return AMR_BAD;
1.236 rillig 3058: }
3059:
1.404 rillig 3060: static int
3061: str_cmp_asc(const void *a, const void *b)
3062: {
1.703 rillig 3063: return strcmp(*(const char *const *)a, *(const char *const *)b);
1.404 rillig 3064: }
3065:
3066: static int
3067: str_cmp_desc(const void *a, const void *b)
3068: {
1.703 rillig 3069: return strcmp(*(const char *const *)b, *(const char *const *)a);
1.404 rillig 3070: }
3071:
1.705 rillig 3072: static void
3073: ShuffleStrings(char **strs, size_t n)
3074: {
3075: size_t i;
3076:
3077: for (i = n - 1; i > 0; i--) {
3078: size_t rndidx = (size_t)random() % (i + 1);
3079: char *t = strs[i];
3080: strs[i] = strs[rndidx];
3081: strs[rndidx] = t;
3082: }
3083: }
3084:
1.402 rillig 3085: /* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */
1.356 rillig 3086: static ApplyModifierResult
1.749 rillig 3087: ApplyModifier_Order(const char **pp, const char *val, ApplyModifiersState *st)
1.236 rillig 3088: {
1.705 rillig 3089: const char *mod = (*pp)++; /* skip past the 'O' in any case */
1.402 rillig 3090:
1.749 rillig 3091: Words words = Str_Words(val, FALSE);
1.401 rillig 3092:
1.705 rillig 3093: if (mod[1] == st->endc || mod[1] == ':') {
3094: /* :O sorts ascending */
3095: qsort(words.words, words.len, sizeof words.words[0],
3096: str_cmp_asc);
1.402 rillig 3097:
1.705 rillig 3098: } else if ((mod[1] == 'r' || mod[1] == 'x') &&
3099: (mod[2] == st->endc || mod[2] == ':')) {
3100: (*pp)++;
1.402 rillig 3101:
1.705 rillig 3102: if (mod[1] == 'r') { /* :Or sorts descending */
3103: qsort(words.words, words.len, sizeof words.words[0],
3104: str_cmp_desc);
3105: } else
3106: ShuffleStrings(words.words, words.len);
1.402 rillig 3107: } else {
1.705 rillig 3108: Words_Free(words);
3109: return AMR_BAD;
1.402 rillig 3110: }
3111:
1.758 rillig 3112: st->newVal = FStr_InitOwn(Words_JoinFree(words));
1.705 rillig 3113: return AMR_OK;
1.236 rillig 3114: }
3115:
3116: /* :? then : else */
1.356 rillig 3117: static ApplyModifierResult
1.779 rillig 3118: ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st)
1.236 rillig 3119: {
1.703 rillig 3120: char *then_expr, *else_expr;
3121: VarParseResult res;
1.412 rillig 3122:
1.703 rillig 3123: Boolean value = FALSE;
3124: VarEvalFlags then_eflags = VARE_NONE;
3125: VarEvalFlags else_eflags = VARE_NONE;
1.236 rillig 3126:
1.703 rillig 3127: int cond_rc = COND_PARSE; /* anything other than COND_INVALID */
3128: if (st->eflags & VARE_WANTRES) {
1.711 rillig 3129: cond_rc = Cond_EvalCondition(st->var->name.str, &value);
1.703 rillig 3130: if (cond_rc != COND_INVALID && value)
3131: then_eflags = st->eflags;
3132: if (cond_rc != COND_INVALID && !value)
3133: else_eflags = st->eflags;
3134: }
3135:
3136: (*pp)++; /* skip past the '?' */
1.760 rillig 3137: res = ParseModifierPart(pp, ':', then_eflags, st, &then_expr);
1.703 rillig 3138: if (res != VPR_OK)
3139: return AMR_CLEANUP;
3140:
1.760 rillig 3141: res = ParseModifierPart(pp, st->endc, else_eflags, st, &else_expr);
1.703 rillig 3142: if (res != VPR_OK)
3143: return AMR_CLEANUP;
3144:
3145: (*pp)--;
3146: if (cond_rc == COND_INVALID) {
3147: Error("Bad conditional expression `%s' in %s?%s:%s",
1.711 rillig 3148: st->var->name.str, st->var->name.str, then_expr, else_expr);
1.703 rillig 3149: return AMR_CLEANUP;
3150: }
3151:
3152: if (value) {
1.758 rillig 3153: st->newVal = FStr_InitOwn(then_expr);
1.703 rillig 3154: free(else_expr);
3155: } else {
1.758 rillig 3156: st->newVal = FStr_InitOwn(else_expr);
1.703 rillig 3157: free(then_expr);
3158: }
3159: ApplyModifiersState_Define(st);
3160: return AMR_OK;
1.236 rillig 3161: }
3162:
1.283 rillig 3163: /*
3164: * The ::= modifiers actually assign a value to the variable.
3165: * Their main purpose is in supporting modifiers of .for loop
3166: * iterators and other obscure uses. They always expand to
3167: * nothing. In a target rule that would otherwise expand to an
3168: * empty line they can be preceded with @: to keep make happy.
3169: * Eg.
3170: *
3171: * foo: .USE
3172: * .for i in ${.TARGET} ${.TARGET:R}.gz
1.546 rillig 3173: * @: ${t::=$i}
1.283 rillig 3174: * @echo blah ${t:T}
3175: * .endfor
3176: *
3177: * ::=<str> Assigns <str> as the new value of variable.
3178: * ::?=<str> Assigns <str> as value of variable if
3179: * it was not already set.
3180: * ::+=<str> Appends <str> to variable.
3181: * ::!=<cmd> Assigns output of <cmd> as the new value of
3182: * variable.
3183: */
1.356 rillig 3184: static ApplyModifierResult
1.409 rillig 3185: ApplyModifier_Assign(const char **pp, ApplyModifiersState *st)
1.236 rillig 3186: {
1.703 rillig 3187: GNode *ctxt;
3188: char delim;
3189: char *val;
3190: VarParseResult res;
1.272 rillig 3191:
1.703 rillig 3192: const char *mod = *pp;
3193: const char *op = mod + 1;
1.272 rillig 3194:
1.703 rillig 3195: if (op[0] == '=')
3196: goto ok;
3197: if ((op[0] == '!' || op[0] == '+' || op[0] == '?') && op[1] == '=')
3198: goto ok;
3199: return AMR_UNKNOWN; /* "::<unrecognised>" */
3200: ok:
1.272 rillig 3201:
1.711 rillig 3202: if (st->var->name.str[0] == '\0') {
1.703 rillig 3203: *pp = mod + 1;
3204: return AMR_BAD;
3205: }
1.272 rillig 3206:
1.703 rillig 3207: ctxt = st->ctxt; /* context where v belongs */
1.789 rillig 3208: if (st->exprStatus == VES_NONE && st->ctxt != VAR_GLOBAL) {
1.711 rillig 3209: Var *gv = VarFind(st->var->name.str, st->ctxt, FALSE);
1.703 rillig 3210: if (gv == NULL)
3211: ctxt = VAR_GLOBAL;
3212: else
3213: VarFreeEnv(gv, TRUE);
3214: }
1.236 rillig 3215:
1.273 rillig 3216: switch (op[0]) {
1.236 rillig 3217: case '+':
1.272 rillig 3218: case '?':
1.703 rillig 3219: case '!':
3220: *pp = mod + 3;
1.272 rillig 3221: break;
1.236 rillig 3222: default:
1.703 rillig 3223: *pp = mod + 2;
3224: break;
3225: }
3226:
3227: delim = st->startc == '(' ? ')' : '}';
1.760 rillig 3228: res = ParseModifierPart(pp, delim, st->eflags, st, &val);
1.703 rillig 3229: if (res != VPR_OK)
3230: return AMR_CLEANUP;
3231:
3232: (*pp)--;
3233:
3234: if (st->eflags & VARE_WANTRES) {
3235: switch (op[0]) {
3236: case '+':
1.711 rillig 3237: Var_Append(st->var->name.str, val, ctxt);
1.703 rillig 3238: break;
3239: case '!': {
3240: const char *errfmt;
3241: char *cmd_output = Cmd_Exec(val, &errfmt);
3242: if (errfmt != NULL)
3243: Error(errfmt, val);
3244: else
1.711 rillig 3245: Var_Set(st->var->name.str, cmd_output, ctxt);
1.703 rillig 3246: free(cmd_output);
3247: break;
3248: }
3249: case '?':
1.789 rillig 3250: if (st->exprStatus == VES_NONE)
1.703 rillig 3251: break;
3252: /* FALLTHROUGH */
3253: default:
1.711 rillig 3254: Var_Set(st->var->name.str, val, ctxt);
1.703 rillig 3255: break;
3256: }
1.236 rillig 3257: }
1.703 rillig 3258: free(val);
1.759 rillig 3259: st->newVal = FStr_InitRefer("");
1.703 rillig 3260: return AMR_OK;
1.236 rillig 3261: }
3262:
1.778 rillig 3263: /*
3264: * :_=...
3265: * remember current value
3266: */
1.356 rillig 3267: static ApplyModifierResult
1.758 rillig 3268: ApplyModifier_Remember(const char **pp, const char *val,
3269: ApplyModifiersState *st)
1.236 rillig 3270: {
1.703 rillig 3271: const char *mod = *pp;
3272: if (!ModMatchEq(mod, "_", st->endc))
3273: return AMR_UNKNOWN;
3274:
3275: if (mod[1] == '=') {
3276: size_t n = strcspn(mod + 2, ":)}");
3277: char *name = bmake_strldup(mod + 2, n);
1.749 rillig 3278: Var_Set(name, val, st->ctxt);
1.703 rillig 3279: free(name);
3280: *pp = mod + 2 + n;
3281: } else {
1.749 rillig 3282: Var_Set("_", val, st->ctxt);
1.703 rillig 3283: *pp = mod + 1;
3284: }
1.758 rillig 3285: st->newVal = FStr_InitRefer(val);
1.703 rillig 3286: return AMR_OK;
1.236 rillig 3287: }
3288:
1.778 rillig 3289: /*
3290: * Apply the given function to each word of the variable value,
3291: * for a single-letter modifier such as :H, :T.
3292: */
1.434 rillig 3293: static ApplyModifierResult
1.749 rillig 3294: ApplyModifier_WordFunc(const char **pp, const char *val,
3295: ApplyModifiersState *st, ModifyWordsCallback modifyWord)
1.434 rillig 3296: {
1.703 rillig 3297: char delim = (*pp)[1];
3298: if (delim != st->endc && delim != ':')
3299: return AMR_UNKNOWN;
3300:
1.758 rillig 3301: st->newVal = FStr_InitOwn(ModifyWords(val, modifyWord, NULL,
1.756 rillig 3302: st->oneBigWord, st->sep));
1.703 rillig 3303: (*pp)++;
3304: return AMR_OK;
1.434 rillig 3305: }
3306:
1.567 rillig 3307: static ApplyModifierResult
1.749 rillig 3308: ApplyModifier_Unique(const char **pp, const char *val, ApplyModifiersState *st)
1.567 rillig 3309: {
1.703 rillig 3310: if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
1.758 rillig 3311: st->newVal = FStr_InitOwn(VarUniq(val));
1.703 rillig 3312: (*pp)++;
3313: return AMR_OK;
3314: } else
3315: return AMR_UNKNOWN;
1.567 rillig 3316: }
3317:
1.236 rillig 3318: #ifdef SYSVVARSUB
3319: /* :from=to */
1.356 rillig 3320: static ApplyModifierResult
1.758 rillig 3321: ApplyModifier_SysV(const char **pp, const char *val, ApplyModifiersState *st)
1.236 rillig 3322: {
1.703 rillig 3323: char *lhs, *rhs;
3324: VarParseResult res;
1.412 rillig 3325:
1.703 rillig 3326: const char *mod = *pp;
3327: Boolean eqFound = FALSE;
1.245 rillig 3328:
1.703 rillig 3329: /*
3330: * First we make a pass through the string trying to verify it is a
3331: * SysV-make-style translation. It must be: <lhs>=<rhs>
3332: */
3333: int depth = 1;
3334: const char *p = mod;
3335: while (*p != '\0' && depth > 0) {
3336: if (*p == '=') { /* XXX: should also test depth == 1 */
3337: eqFound = TRUE;
3338: /* continue looking for st->endc */
3339: } else if (*p == st->endc)
3340: depth--;
3341: else if (*p == st->startc)
3342: depth++;
3343: if (depth > 0)
3344: p++;
3345: }
3346: if (*p != st->endc || !eqFound)
3347: return AMR_UNKNOWN;
1.236 rillig 3348:
1.760 rillig 3349: res = ParseModifierPart(pp, '=', st->eflags, st, &lhs);
1.703 rillig 3350: if (res != VPR_OK)
3351: return AMR_CLEANUP;
3352:
3353: /* The SysV modifier lasts until the end of the variable expression. */
1.760 rillig 3354: res = ParseModifierPart(pp, st->endc, st->eflags, st, &rhs);
1.703 rillig 3355: if (res != VPR_OK)
3356: return AMR_CLEANUP;
3357:
3358: (*pp)--;
1.749 rillig 3359: if (lhs[0] == '\0' && val[0] == '\0') {
1.758 rillig 3360: st->newVal = FStr_InitRefer(val); /* special case */
1.703 rillig 3361: } else {
3362: struct ModifyWord_SYSVSubstArgs args = { st->ctxt, lhs, rhs };
1.758 rillig 3363: st->newVal = FStr_InitOwn(
1.756 rillig 3364: ModifyWords(val, ModifyWord_SYSVSubst, &args,
3365: st->oneBigWord, st->sep));
1.703 rillig 3366: }
3367: free(lhs);
3368: free(rhs);
3369: return AMR_OK;
1.236 rillig 3370: }
3371: #endif
3372:
1.548 rillig 3373: #ifdef SUNSHCMD
3374: /* :sh */
3375: static ApplyModifierResult
1.749 rillig 3376: ApplyModifier_SunShell(const char **pp, const char *val,
3377: ApplyModifiersState *st)
1.548 rillig 3378: {
1.703 rillig 3379: const char *p = *pp;
3380: if (p[1] == 'h' && (p[2] == st->endc || p[2] == ':')) {
3381: if (st->eflags & VARE_WANTRES) {
3382: const char *errfmt;
1.758 rillig 3383: st->newVal = FStr_InitOwn(Cmd_Exec(val, &errfmt));
1.703 rillig 3384: if (errfmt != NULL)
1.749 rillig 3385: Error(errfmt, val);
1.703 rillig 3386: } else
1.759 rillig 3387: st->newVal = FStr_InitRefer("");
1.703 rillig 3388: *pp = p + 2;
3389: return AMR_OK;
1.548 rillig 3390: } else
1.703 rillig 3391: return AMR_UNKNOWN;
1.548 rillig 3392: }
3393: #endif
3394:
1.549 rillig 3395: static void
1.749 rillig 3396: LogBeforeApply(const ApplyModifiersState *st, const char *mod, char endc,
3397: const char *val)
1.549 rillig 3398: {
1.703 rillig 3399: char eflags_str[VarEvalFlags_ToStringSize];
3400: char vflags_str[VarFlags_ToStringSize];
3401: Boolean is_single_char = mod[0] != '\0' &&
3402: (mod[1] == endc || mod[1] == ':');
3403:
3404: /* At this point, only the first character of the modifier can
3405: * be used since the end of the modifier is not yet known. */
3406: debug_printf("Applying ${%s:%c%s} to \"%s\" (%s, %s, %s)\n",
1.749 rillig 3407: st->var->name.str, mod[0], is_single_char ? "" : "...", val,
1.783 rillig 3408: VarEvalFlags_ToString(eflags_str, st->eflags),
3409: VarFlags_ToString(vflags_str, st->var->flags),
1.789 rillig 3410: VarExprStatus_Name[st->exprStatus]);
1.549 rillig 3411: }
3412:
3413: static void
3414: LogAfterApply(ApplyModifiersState *st, const char *p, const char *mod)
3415: {
1.703 rillig 3416: char eflags_str[VarEvalFlags_ToStringSize];
3417: char vflags_str[VarFlags_ToStringSize];
1.756 rillig 3418: const char *quot = st->newVal.str == var_Error ? "" : "\"";
3419: const char *newVal =
3420: st->newVal.str == var_Error ? "error" : st->newVal.str;
1.703 rillig 3421:
3422: debug_printf("Result of ${%s:%.*s} is %s%s%s (%s, %s, %s)\n",
1.711 rillig 3423: st->var->name.str, (int)(p - mod), mod, quot, newVal, quot,
1.783 rillig 3424: VarEvalFlags_ToString(eflags_str, st->eflags),
3425: VarFlags_ToString(vflags_str, st->var->flags),
1.789 rillig 3426: VarExprStatus_Name[st->exprStatus]);
1.549 rillig 3427: }
3428:
1.551 rillig 3429: static ApplyModifierResult
1.758 rillig 3430: ApplyModifier(const char **pp, const char *val, ApplyModifiersState *st)
1.551 rillig 3431: {
1.703 rillig 3432: switch (**pp) {
3433: case ':':
3434: return ApplyModifier_Assign(pp, st);
3435: case '@':
1.749 rillig 3436: return ApplyModifier_Loop(pp, val, st);
1.703 rillig 3437: case '_':
1.749 rillig 3438: return ApplyModifier_Remember(pp, val, st);
1.703 rillig 3439: case 'D':
3440: case 'U':
1.749 rillig 3441: return ApplyModifier_Defined(pp, val, st);
1.703 rillig 3442: case 'L':
3443: return ApplyModifier_Literal(pp, st);
3444: case 'P':
3445: return ApplyModifier_Path(pp, st);
3446: case '!':
3447: return ApplyModifier_ShellCommand(pp, st);
3448: case '[':
1.749 rillig 3449: return ApplyModifier_Words(pp, val, st);
1.703 rillig 3450: case 'g':
1.749 rillig 3451: return ApplyModifier_Gmtime(pp, val, st);
1.703 rillig 3452: case 'h':
1.749 rillig 3453: return ApplyModifier_Hash(pp, val, st);
1.703 rillig 3454: case 'l':
1.749 rillig 3455: return ApplyModifier_Localtime(pp, val, st);
1.703 rillig 3456: case 't':
1.749 rillig 3457: return ApplyModifier_To(pp, val, st);
1.703 rillig 3458: case 'N':
3459: case 'M':
1.749 rillig 3460: return ApplyModifier_Match(pp, val, st);
1.703 rillig 3461: case 'S':
1.749 rillig 3462: return ApplyModifier_Subst(pp, val, st);
1.703 rillig 3463: case '?':
1.779 rillig 3464: return ApplyModifier_IfElse(pp, st);
1.551 rillig 3465: #ifndef NO_REGEX
1.703 rillig 3466: case 'C':
1.749 rillig 3467: return ApplyModifier_Regex(pp, val, st);
1.551 rillig 3468: #endif
1.703 rillig 3469: case 'q':
3470: case 'Q':
1.749 rillig 3471: return ApplyModifier_Quote(pp, val, st);
1.703 rillig 3472: case 'T':
1.749 rillig 3473: return ApplyModifier_WordFunc(pp, val, st, ModifyWord_Tail);
1.703 rillig 3474: case 'H':
1.749 rillig 3475: return ApplyModifier_WordFunc(pp, val, st, ModifyWord_Head);
1.703 rillig 3476: case 'E':
1.749 rillig 3477: return ApplyModifier_WordFunc(pp, val, st, ModifyWord_Suffix);
1.703 rillig 3478: case 'R':
1.749 rillig 3479: return ApplyModifier_WordFunc(pp, val, st, ModifyWord_Root);
1.703 rillig 3480: case 'r':
1.749 rillig 3481: return ApplyModifier_Range(pp, val, st);
1.703 rillig 3482: case 'O':
1.749 rillig 3483: return ApplyModifier_Order(pp, val, st);
1.703 rillig 3484: case 'u':
1.749 rillig 3485: return ApplyModifier_Unique(pp, val, st);
1.551 rillig 3486: #ifdef SUNSHCMD
1.703 rillig 3487: case 's':
1.749 rillig 3488: return ApplyModifier_SunShell(pp, val, st);
1.551 rillig 3489: #endif
1.703 rillig 3490: default:
3491: return AMR_UNKNOWN;
3492: }
1.551 rillig 3493: }
3494:
1.758 rillig 3495: static FStr ApplyModifiers(const char **, FStr, char, char, Var *,
1.789 rillig 3496: VarExprStatus *, GNode *, VarEvalFlags);
1.641 rillig 3497:
3498: typedef enum ApplyModifiersIndirectResult {
1.752 rillig 3499: /* The indirect modifiers have been applied successfully. */
1.703 rillig 3500: AMIR_CONTINUE,
1.752 rillig 3501: /* Fall back to the SysV modifier. */
1.703 rillig 3502: AMIR_APPLY_MODS,
1.752 rillig 3503: /* Error out. */
1.703 rillig 3504: AMIR_OUT
1.641 rillig 3505: } ApplyModifiersIndirectResult;
3506:
1.752 rillig 3507: /*
3508: * While expanding a variable expression, expand and apply indirect modifiers,
3509: * such as in ${VAR:${M_indirect}}.
3510: *
3511: * All indirect modifiers of a group must come from a single variable
3512: * expression. ${VAR:${M1}} is valid but ${VAR:${M1}${M2}} is not.
3513: *
3514: * Multiple groups of indirect modifiers can be chained by separating them
3515: * with colons. ${VAR:${M1}:${M2}} contains 2 indirect modifiers.
3516: *
3517: * If the variable expression is not followed by st->endc or ':', fall
3518: * back to trying the SysV modifier, such as in ${VAR:${FROM}=${TO}}.
3519: *
3520: * The expression ${VAR:${M1}${M2}} is not treated as an indirect
3521: * modifier, and it is neither a SysV modifier but a parse error.
3522: */
1.641 rillig 3523: static ApplyModifiersIndirectResult
1.721 rillig 3524: ApplyModifiersIndirect(ApplyModifiersState *st, const char **pp,
1.758 rillig 3525: FStr *inout_value)
1.703 rillig 3526: {
1.721 rillig 3527: const char *p = *pp;
1.743 rillig 3528: FStr mods;
1.641 rillig 3529:
1.743 rillig 3530: (void)Var_Parse(&p, st->ctxt, st->eflags, &mods);
1.703 rillig 3531: /* TODO: handle errors */
1.641 rillig 3532:
1.743 rillig 3533: if (mods.str[0] != '\0' && *p != '\0' && *p != ':' && *p != st->endc) {
3534: FStr_Done(&mods);
1.703 rillig 3535: return AMIR_APPLY_MODS;
3536: }
3537:
1.708 rillig 3538: DEBUG3(VAR, "Indirect modifier \"%s\" from \"%.*s\"\n",
1.743 rillig 3539: mods.str, (int)(p - *pp), *pp);
1.703 rillig 3540:
1.743 rillig 3541: if (mods.str[0] != '\0') {
3542: const char *modsp = mods.str;
1.758 rillig 3543: FStr newVal = ApplyModifiers(&modsp, *inout_value, '\0', '\0',
1.789 rillig 3544: st->var, &st->exprStatus, st->ctxt, st->eflags);
1.757 rillig 3545: *inout_value = newVal;
1.773 rillig 3546: if (newVal.str == var_Error || *modsp != '\0') {
1.743 rillig 3547: FStr_Done(&mods);
1.721 rillig 3548: *pp = p;
1.703 rillig 3549: return AMIR_OUT; /* error already reported */
3550: }
3551: }
1.743 rillig 3552: FStr_Done(&mods);
1.641 rillig 3553:
1.703 rillig 3554: if (*p == ':')
3555: p++;
3556: else if (*p == '\0' && st->endc != '\0') {
3557: Error("Unclosed variable specification after complex "
3558: "modifier (expecting '%c') for %s",
1.711 rillig 3559: st->endc, st->var->name.str);
1.721 rillig 3560: *pp = p;
1.703 rillig 3561: return AMIR_OUT;
1.641 rillig 3562: }
3563:
1.721 rillig 3564: *pp = p;
1.703 rillig 3565: return AMIR_CONTINUE;
1.641 rillig 3566: }
3567:
1.750 rillig 3568: static ApplyModifierResult
1.751 rillig 3569: ApplySingleModifier(ApplyModifiersState *st, const char *mod, char endc,
1.758 rillig 3570: const char **pp, FStr *inout_value)
1.750 rillig 3571: {
3572: ApplyModifierResult res;
3573: const char *p = *pp;
1.758 rillig 3574: const char *const val = inout_value->str;
1.750 rillig 3575:
3576: if (DEBUG(VAR))
3577: LogBeforeApply(st, mod, endc, val);
3578:
3579: res = ApplyModifier(&p, val, st);
3580:
3581: #ifdef SYSVVARSUB
3582: if (res == AMR_UNKNOWN) {
3583: assert(p == mod);
3584: res = ApplyModifier_SysV(&p, val, st);
3585: }
3586: #endif
3587:
3588: if (res == AMR_UNKNOWN) {
1.754 rillig 3589: Parse_Error(PARSE_FATAL, "Unknown modifier '%c'", *mod);
1.750 rillig 3590: /*
3591: * Guess the end of the current modifier.
3592: * XXX: Skipping the rest of the modifier hides
3593: * errors and leads to wrong results.
3594: * Parsing should rather stop here.
3595: */
3596: for (p++; *p != ':' && *p != st->endc && *p != '\0'; p++)
3597: continue;
1.758 rillig 3598: st->newVal = FStr_InitRefer(var_Error);
1.750 rillig 3599: }
3600: if (res == AMR_CLEANUP || res == AMR_BAD) {
3601: *pp = p;
3602: return res;
3603: }
3604:
3605: if (DEBUG(VAR))
3606: LogAfterApply(st, p, mod);
3607:
1.756 rillig 3608: if (st->newVal.str != val) {
1.758 rillig 3609: FStr_Done(inout_value);
1.757 rillig 3610: *inout_value = st->newVal;
1.750 rillig 3611: }
3612: if (*p == '\0' && st->endc != '\0') {
3613: Error(
3614: "Unclosed variable specification (expecting '%c') "
3615: "for \"%s\" (value \"%s\") modifier %c",
1.757 rillig 3616: st->endc, st->var->name.str, inout_value->str, *mod);
1.750 rillig 3617: } else if (*p == ':') {
3618: p++;
1.764 rillig 3619: } else if (opts.strict && *p != '\0' && *p != endc) {
1.750 rillig 3620: Parse_Error(PARSE_FATAL,
3621: "Missing delimiter ':' after modifier \"%.*s\"",
3622: (int)(p - mod), mod);
3623: /*
3624: * TODO: propagate parse error to the enclosing
3625: * expression
3626: */
3627: }
3628: *pp = p;
3629: return AMR_OK;
3630: }
3631:
1.419 rillig 3632: /* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */
1.758 rillig 3633: static FStr
1.357 rillig 3634: ApplyModifiers(
1.720 rillig 3635: const char **pp, /* the parsing position, updated upon return */
1.758 rillig 3636: FStr value, /* the current value of the expression */
1.720 rillig 3637: char startc, /* '(' or '{', or '\0' for indirect modifiers */
3638: char endc, /* ')' or '}', or '\0' for indirect modifiers */
3639: Var *v,
1.789 rillig 3640: VarExprStatus *exprStatus,
1.720 rillig 3641: GNode *ctxt, /* for looking up and modifying variables */
1.757 rillig 3642: VarEvalFlags eflags
1.703 rillig 3643: )
3644: {
3645: ApplyModifiersState st = {
3646: startc, endc, v, ctxt, eflags,
1.782 rillig 3647: #if defined(lint)
3648: /* lint cannot parse C99 struct initializers yet. */
3649: { var_Error, NULL },
3650: #else
1.758 rillig 3651: FStr_InitRefer(var_Error), /* .newVal */
1.782 rillig 3652: #endif
1.703 rillig 3653: ' ', /* .sep */
3654: FALSE, /* .oneBigWord */
1.789 rillig 3655: *exprStatus /* .exprStatus */
1.703 rillig 3656: };
3657: const char *p;
3658: const char *mod;
3659:
3660: assert(startc == '(' || startc == '{' || startc == '\0');
3661: assert(endc == ')' || endc == '}' || endc == '\0');
1.757 rillig 3662: assert(value.str != NULL);
1.703 rillig 3663:
3664: p = *pp;
3665:
3666: if (*p == '\0' && endc != '\0') {
3667: Error(
3668: "Unclosed variable expression (expecting '%c') for \"%s\"",
1.711 rillig 3669: st.endc, st.var->name.str);
1.703 rillig 3670: goto cleanup;
3671: }
3672:
3673: while (*p != '\0' && *p != endc) {
1.750 rillig 3674: ApplyModifierResult res;
1.703 rillig 3675:
3676: if (*p == '$') {
3677: ApplyModifiersIndirectResult amir;
1.757 rillig 3678: amir = ApplyModifiersIndirect(&st, &p, &value);
1.703 rillig 3679: if (amir == AMIR_CONTINUE)
3680: continue;
3681: if (amir == AMIR_OUT)
1.752 rillig 3682: break;
1.703 rillig 3683: }
1.752 rillig 3684:
1.756 rillig 3685: /* default value, in case of errors */
1.758 rillig 3686: st.newVal = FStr_InitRefer(var_Error);
1.703 rillig 3687: mod = p;
1.649 rillig 3688:
1.757 rillig 3689: res = ApplySingleModifier(&st, mod, endc, &p, &value);
1.703 rillig 3690: if (res == AMR_CLEANUP)
3691: goto cleanup;
3692: if (res == AMR_BAD)
3693: goto bad_modifier;
1.356 rillig 3694: }
1.752 rillig 3695:
1.703 rillig 3696: *pp = p;
1.757 rillig 3697: assert(value.str != NULL); /* Use var_Error or varUndefined instead. */
1.789 rillig 3698: *exprStatus = st.exprStatus;
1.757 rillig 3699: return value;
1.25 christos 3700:
1.240 rillig 3701: bad_modifier:
1.703 rillig 3702: /* XXX: The modifier end is only guessed. */
3703: Error("Bad modifier `:%.*s' for %s",
1.711 rillig 3704: (int)strcspn(mod, ":)}"), mod, st.var->name.str);
1.25 christos 3705:
1.240 rillig 3706: cleanup:
1.703 rillig 3707: *pp = p;
1.758 rillig 3708: FStr_Done(&value);
1.789 rillig 3709: *exprStatus = st.exprStatus;
1.758 rillig 3710: return FStr_InitRefer(var_Error);
1.108 sjg 3711: }
1.25 christos 3712:
1.778 rillig 3713: /*
3714: * Only four of the local variables are treated specially as they are the
3715: * only four that will be set when dynamic sources are expanded.
3716: */
1.335 rillig 3717: static Boolean
1.626 rillig 3718: VarnameIsDynamic(const char *name, size_t len)
1.335 rillig 3719: {
1.703 rillig 3720: if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) {
3721: switch (name[0]) {
3722: case '@':
3723: case '%':
3724: case '*':
3725: case '!':
3726: return TRUE;
3727: }
3728: return FALSE;
1.335 rillig 3729: }
3730:
1.703 rillig 3731: if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) {
3732: return strcmp(name, ".TARGET") == 0 ||
3733: strcmp(name, ".ARCHIVE") == 0 ||
3734: strcmp(name, ".PREFIX") == 0 ||
3735: strcmp(name, ".MEMBER") == 0;
3736: }
1.335 rillig 3737:
1.703 rillig 3738: return FALSE;
1.335 rillig 3739: }
3740:
1.502 rillig 3741: static const char *
1.769 rillig 3742: UndefinedShortVarValue(char varname, const GNode *ctxt)
1.502 rillig 3743: {
1.703 rillig 3744: if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) {
3745: /*
3746: * If substituting a local variable in a non-local context,
3747: * assume it's for dynamic source stuff. We have to handle
3748: * this specially and return the longhand for the variable
3749: * with the dollar sign escaped so it makes it back to the
3750: * caller. Only four of the local variables are treated
3751: * specially as they are the only four that will be set
3752: * when dynamic sources are expanded.
3753: */
3754: switch (varname) {
3755: case '@':
3756: return "$(.TARGET)";
3757: case '%':
3758: return "$(.MEMBER)";
3759: case '*':
3760: return "$(.PREFIX)";
3761: case '!':
3762: return "$(.ARCHIVE)";
3763: }
1.502 rillig 3764: }
1.769 rillig 3765: return NULL;
1.502 rillig 3766: }
3767:
1.778 rillig 3768: /*
3769: * Parse a variable name, until the end character or a colon, whichever
3770: * comes first.
3771: */
1.504 rillig 3772: static char *
1.501 rillig 3773: ParseVarname(const char **pp, char startc, char endc,
1.504 rillig 3774: GNode *ctxt, VarEvalFlags eflags,
3775: size_t *out_varname_len)
1.501 rillig 3776: {
1.703 rillig 3777: Buffer buf;
3778: const char *p = *pp;
3779: int depth = 1;
3780:
3781: Buf_Init(&buf);
3782:
3783: while (*p != '\0') {
3784: /* Track depth so we can spot parse errors. */
3785: if (*p == startc)
3786: depth++;
3787: if (*p == endc) {
3788: if (--depth == 0)
3789: break;
3790: }
3791: if (*p == ':' && depth == 1)
3792: break;
1.501 rillig 3793:
1.703 rillig 3794: /* A variable inside a variable, expand. */
3795: if (*p == '$') {
1.743 rillig 3796: FStr nested_val;
3797: (void)Var_Parse(&p, ctxt, eflags, &nested_val);
1.703 rillig 3798: /* TODO: handle errors */
1.743 rillig 3799: Buf_AddStr(&buf, nested_val.str);
3800: FStr_Done(&nested_val);
1.703 rillig 3801: } else {
3802: Buf_AddByte(&buf, *p);
3803: p++;
3804: }
1.501 rillig 3805: }
1.703 rillig 3806: *pp = p;
1.786 rillig 3807: *out_varname_len = buf.len;
1.784 rillig 3808: return Buf_DoneData(&buf);
1.501 rillig 3809: }
3810:
1.652 rillig 3811: static VarParseResult
1.507 rillig 3812: ValidShortVarname(char varname, const char *start)
3813: {
1.703 rillig 3814: switch (varname) {
3815: case '\0':
3816: case ')':
3817: case '}':
3818: case ':':
3819: case '$':
3820: break; /* and continue below */
3821: default:
3822: return VPR_OK;
3823: }
1.507 rillig 3824:
1.771 rillig 3825: if (!opts.strict)
3826: return VPR_ERR; /* XXX: Missing error message */
1.507 rillig 3827:
1.703 rillig 3828: if (varname == '$')
3829: Parse_Error(PARSE_FATAL,
1.507 rillig 3830: "To escape a dollar, use \\$, not $$, at \"%s\"", start);
1.703 rillig 3831: else if (varname == '\0')
3832: Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
3833: else
3834: Parse_Error(PARSE_FATAL,
1.507 rillig 3835: "Invalid variable name '%c', at \"%s\"", varname, start);
3836:
1.767 rillig 3837: return VPR_ERR;
1.507 rillig 3838: }
3839:
1.778 rillig 3840: /*
3841: * Parse a single-character variable name such as $V or $@.
3842: * Return whether to continue parsing.
3843: */
1.622 rillig 3844: static Boolean
1.667 rillig 3845: ParseVarnameShort(char startc, const char **pp, GNode *ctxt,
3846: VarEvalFlags eflags,
3847: VarParseResult *out_FALSE_res, const char **out_FALSE_val,
3848: Var **out_TRUE_var)
3849: {
1.703 rillig 3850: char name[2];
3851: Var *v;
3852: VarParseResult vpr;
1.622 rillig 3853:
1.703 rillig 3854: /*
3855: * If it's not bounded by braces of some sort, life is much simpler.
3856: * We just need to check for the first character and return the
3857: * value if it exists.
3858: */
1.622 rillig 3859:
1.703 rillig 3860: vpr = ValidShortVarname(startc, *pp);
3861: if (vpr != VPR_OK) {
3862: (*pp)++;
3863: *out_FALSE_val = var_Error;
3864: *out_FALSE_res = vpr;
3865: return FALSE;
3866: }
1.622 rillig 3867:
1.703 rillig 3868: name[0] = startc;
3869: name[1] = '\0';
3870: v = VarFind(name, ctxt, TRUE);
3871: if (v == NULL) {
1.770 rillig 3872: const char *val;
1.703 rillig 3873: *pp += 2;
1.622 rillig 3874:
1.770 rillig 3875: val = UndefinedShortVarValue(startc, ctxt);
3876: if (val == NULL)
3877: val = eflags & VARE_UNDEFERR ? var_Error : varUndefined;
1.769 rillig 3878:
1.770 rillig 3879: if (opts.strict && val == var_Error) {
1.703 rillig 3880: Parse_Error(PARSE_FATAL,
3881: "Variable \"%s\" is undefined", name);
1.767 rillig 3882: *out_FALSE_res = VPR_ERR;
1.770 rillig 3883: *out_FALSE_val = val;
1.703 rillig 3884: return FALSE;
3885: }
1.767 rillig 3886:
3887: /*
3888: * XXX: This looks completely wrong.
3889: *
3890: * If undefined expressions are not allowed, this should
3891: * rather be VPR_ERR instead of VPR_UNDEF, together with an
3892: * error message.
3893: *
3894: * If undefined expressions are allowed, this should rather
3895: * be VPR_UNDEF instead of VPR_OK.
3896: */
3897: *out_FALSE_res = eflags & VARE_UNDEFERR ? VPR_UNDEF : VPR_OK;
1.770 rillig 3898: *out_FALSE_val = val;
1.703 rillig 3899: return FALSE;
1.622 rillig 3900: }
3901:
1.703 rillig 3902: *out_TRUE_var = v;
3903: return TRUE;
1.622 rillig 3904: }
3905:
1.662 rillig 3906: /* Find variables like @F or <D. */
3907: static Var *
3908: FindLocalLegacyVar(const char *varname, size_t namelen, GNode *ctxt,
3909: const char **out_extraModifiers)
3910: {
1.703 rillig 3911: /* Only resolve these variables if ctxt is a "real" target. */
3912: if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL)
3913: return NULL;
3914:
3915: if (namelen != 2)
3916: return NULL;
3917: if (varname[1] != 'F' && varname[1] != 'D')
3918: return NULL;
3919: if (strchr("@%?*!<>", varname[0]) == NULL)
3920: return NULL;
3921:
3922: {
3923: char name[] = { varname[0], '\0' };
3924: Var *v = VarFind(name, ctxt, FALSE);
3925:
3926: if (v != NULL) {
3927: if (varname[1] == 'D') {
3928: *out_extraModifiers = "H:";
3929: } else { /* F */
3930: *out_extraModifiers = "T:";
3931: }
3932: }
3933: return v;
1.662 rillig 3934: }
3935: }
3936:
1.663 rillig 3937: static VarParseResult
1.667 rillig 3938: EvalUndefined(Boolean dynamic, const char *start, const char *p, char *varname,
3939: VarEvalFlags eflags,
1.740 rillig 3940: FStr *out_val)
1.667 rillig 3941: {
1.703 rillig 3942: if (dynamic) {
1.740 rillig 3943: *out_val = FStr_InitOwn(bmake_strsedup(start, p));
1.703 rillig 3944: free(varname);
3945: return VPR_OK;
3946: }
3947:
1.764 rillig 3948: if ((eflags & VARE_UNDEFERR) && opts.strict) {
1.703 rillig 3949: Parse_Error(PARSE_FATAL,
3950: "Variable \"%s\" is undefined", varname);
3951: free(varname);
1.740 rillig 3952: *out_val = FStr_InitRefer(var_Error);
1.767 rillig 3953: return VPR_ERR;
1.703 rillig 3954: }
3955:
3956: if (eflags & VARE_UNDEFERR) {
3957: free(varname);
1.740 rillig 3958: *out_val = FStr_InitRefer(var_Error);
1.767 rillig 3959: return VPR_UNDEF; /* XXX: Should be VPR_ERR instead. */
1.703 rillig 3960: }
3961:
1.663 rillig 3962: free(varname);
1.740 rillig 3963: *out_val = FStr_InitRefer(varUndefined);
1.663 rillig 3964: return VPR_OK;
3965: }
3966:
1.778 rillig 3967: /*
3968: * Parse a long variable name enclosed in braces or parentheses such as $(VAR)
1.623 rillig 3969: * or ${VAR}, up to the closing brace or parenthesis, or in the case of
3970: * ${VAR:Modifiers}, up to the ':' that starts the modifiers.
1.778 rillig 3971: * Return whether to continue parsing.
3972: */
1.623 rillig 3973: static Boolean
3974: ParseVarnameLong(
1.664 rillig 3975: const char *p,
1.624 rillig 3976: char startc,
3977: GNode *ctxt,
3978: VarEvalFlags eflags,
3979:
1.664 rillig 3980: const char **out_FALSE_pp,
1.624 rillig 3981: VarParseResult *out_FALSE_res,
1.740 rillig 3982: FStr *out_FALSE_val,
1.624 rillig 3983:
3984: char *out_TRUE_endc,
3985: const char **out_TRUE_p,
3986: Var **out_TRUE_v,
3987: Boolean *out_TRUE_haveModifier,
3988: const char **out_TRUE_extraModifiers,
3989: Boolean *out_TRUE_dynamic,
1.789 rillig 3990: VarExprStatus *out_TRUE_exprStatus
1.703 rillig 3991: )
3992: {
3993: size_t namelen;
3994: char *varname;
3995: Var *v;
3996: Boolean haveModifier;
3997: Boolean dynamic = FALSE;
3998:
3999: const char *const start = p;
4000: char endc = startc == '(' ? ')' : '}';
4001:
4002: p += 2; /* skip "${" or "$(" or "y(" */
4003: varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen);
4004:
4005: if (*p == ':') {
4006: haveModifier = TRUE;
4007: } else if (*p == endc) {
4008: haveModifier = FALSE;
4009: } else {
4010: Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname);
4011: free(varname);
4012: *out_FALSE_pp = p;
1.740 rillig 4013: *out_FALSE_val = FStr_InitRefer(var_Error);
1.767 rillig 4014: *out_FALSE_res = VPR_ERR;
1.703 rillig 4015: return FALSE;
4016: }
1.623 rillig 4017:
1.703 rillig 4018: v = VarFind(varname, ctxt, TRUE);
1.623 rillig 4019:
1.703 rillig 4020: /* At this point, p points just after the variable name,
4021: * either at ':' or at endc. */
1.623 rillig 4022:
1.703 rillig 4023: if (v == NULL) {
4024: v = FindLocalLegacyVar(varname, namelen, ctxt,
4025: out_TRUE_extraModifiers);
4026: }
1.623 rillig 4027:
1.703 rillig 4028: if (v == NULL) {
4029: /*
4030: * Defer expansion of dynamic variables if they appear in
4031: * non-local context since they are not defined there.
4032: */
4033: dynamic = VarnameIsDynamic(varname, namelen) &&
4034: (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL);
4035:
4036: if (!haveModifier) {
4037: p++; /* skip endc */
4038: *out_FALSE_pp = p;
4039: *out_FALSE_res = EvalUndefined(dynamic, start, p,
1.740 rillig 4040: varname, eflags, out_FALSE_val);
1.703 rillig 4041: return FALSE;
4042: }
1.623 rillig 4043:
1.703 rillig 4044: /*
4045: * The variable expression is based on an undefined variable.
4046: * Nevertheless it needs a Var, for modifiers that access the
4047: * variable name, such as :L or :?.
4048: *
4049: * Most modifiers leave this expression in the "undefined"
4050: * state (VEF_UNDEF), only a few modifiers like :D, :U, :L,
4051: * :P turn this undefined expression into a defined
4052: * expression (VEF_DEF).
4053: *
4054: * At the end, after applying all modifiers, if the expression
4055: * is still undefined, Var_Parse will return an empty string
4056: * instead of the actually computed value.
4057: */
1.744 rillig 4058: v = VarNew(FStr_InitOwn(varname), "", VAR_NONE);
1.789 rillig 4059: *out_TRUE_exprStatus = VES_UNDEF;
1.703 rillig 4060: } else
4061: free(varname);
1.623 rillig 4062:
1.703 rillig 4063: *out_TRUE_endc = endc;
4064: *out_TRUE_p = p;
4065: *out_TRUE_v = v;
4066: *out_TRUE_haveModifier = haveModifier;
4067: *out_TRUE_dynamic = dynamic;
4068: return TRUE;
1.623 rillig 4069: }
4070:
1.709 rillig 4071: /* Free the environment variable now since we own it. */
4072: static void
4073: FreeEnvVar(void **out_val_freeIt, Var *v, const char *value)
4074: {
1.784 rillig 4075: char *varValue = Buf_DoneData(&v->val);
1.709 rillig 4076: if (value == varValue)
4077: *out_val_freeIt = varValue;
4078: else
4079: free(varValue);
4080:
1.711 rillig 4081: FStr_Done(&v->name);
1.709 rillig 4082: free(v);
4083: }
4084:
1.666 rillig 4085: /*
4086: * Given the start of a variable expression (such as $v, $(VAR),
4087: * ${VAR:Mpattern}), extract the variable name and value, and the modifiers,
4088: * if any. While doing that, apply the modifiers to the value of the
4089: * expression, forming its final value. A few of the modifiers such as :!cmd!
4090: * or ::= have side effects.
1.579 rillig 4091: *
1.108 sjg 4092: * Input:
1.666 rillig 4093: * *pp The string to parse.
4094: * When parsing a condition in ParseEmptyArg, it may also
4095: * point to the "y" of "empty(VARNAME:Modifiers)", which
4096: * is syntactically the same.
4097: * ctxt The context for finding variables
4098: * eflags Control the exact details of parsing
4099: *
4100: * Output:
4101: * *pp The position where to continue parsing.
4102: * TODO: After a parse error, the value of *pp is
4103: * unspecified. It may not have been updated at all,
4104: * point to some random character in the string, to the
4105: * location of the parse error, or at the end of the
4106: * string.
4107: * *out_val The value of the variable expression, never NULL.
4108: * *out_val var_Error if there was a parse error.
4109: * *out_val var_Error if the base variable of the expression was
4110: * undefined, eflags contains VARE_UNDEFERR, and none of
4111: * the modifiers turned the undefined expression into a
4112: * defined expression.
4113: * XXX: It is not guaranteed that an error message has
4114: * been printed.
4115: * *out_val varUndefined if the base variable of the expression
4116: * was undefined, eflags did not contain VARE_UNDEFERR,
4117: * and none of the modifiers turned the undefined
4118: * expression into a defined expression.
4119: * XXX: It is not guaranteed that an error message has
4120: * been printed.
4121: * *out_val_freeIt Must be freed by the caller after using *out_val.
1.108 sjg 4122: */
1.514 rillig 4123: /* coverity[+alloc : arg-*4] */
1.526 rillig 4124: VarParseResult
1.743 rillig 4125: Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags, FStr *out_val)
1.108 sjg 4126: {
1.703 rillig 4127: const char *p = *pp;
4128: const char *const start = p;
4129: /* TRUE if have modifiers for the variable. */
4130: Boolean haveModifier;
4131: /* Starting character if variable in parens or braces. */
4132: char startc;
4133: /* Ending character if variable in parens or braces. */
4134: char endc;
4135: /*
4136: * TRUE if the variable is local and we're expanding it in a
4137: * non-local context. This is done to support dynamic sources.
4138: * The result is just the expression, unaltered.
4139: */
4140: Boolean dynamic;
4141: const char *extramodifiers;
4142: Var *v;
1.758 rillig 4143: FStr value;
1.703 rillig 4144: char eflags_str[VarEvalFlags_ToStringSize];
1.789 rillig 4145: VarExprStatus exprStatus = VES_NONE;
1.703 rillig 4146:
1.708 rillig 4147: DEBUG2(VAR, "Var_Parse: %s with %s\n", start,
1.783 rillig 4148: VarEvalFlags_ToString(eflags_str, eflags));
1.703 rillig 4149:
1.743 rillig 4150: *out_val = FStr_InitRefer(NULL);
1.703 rillig 4151: extramodifiers = NULL; /* extra modifiers to apply first */
4152: dynamic = FALSE;
1.473 rillig 4153:
1.703 rillig 4154: /*
4155: * Appease GCC, which thinks that the variable might not be
4156: * initialized.
4157: */
4158: endc = '\0';
1.108 sjg 4159:
1.703 rillig 4160: startc = p[1];
4161: if (startc != '(' && startc != '{') {
4162: VarParseResult res;
4163: if (!ParseVarnameShort(startc, pp, ctxt, eflags, &res,
1.743 rillig 4164: &out_val->str, &v))
1.703 rillig 4165: return res;
4166: haveModifier = FALSE;
4167: p++;
4168: } else {
4169: VarParseResult res;
4170: if (!ParseVarnameLong(p, startc, ctxt, eflags,
1.743 rillig 4171: pp, &res, out_val,
1.703 rillig 4172: &endc, &p, &v, &haveModifier, &extramodifiers,
1.789 rillig 4173: &dynamic, &exprStatus))
1.703 rillig 4174: return res;
4175: }
1.401 rillig 4176:
1.703 rillig 4177: if (v->flags & VAR_IN_USE)
1.711 rillig 4178: Fatal("Variable %s is recursive.", v->name.str);
1.187 christos 4179:
1.703 rillig 4180: /*
4181: * XXX: This assignment creates an alias to the current value of the
4182: * variable. This means that as long as the value of the expression
4183: * stays the same, the value of the variable must not change.
4184: * Using the '::=' modifier, it could be possible to do exactly this.
4185: * At the bottom of this function, the resulting value is compared to
4186: * the then-current value of the variable. This might also invoke
4187: * undefined behavior.
4188: */
1.785 rillig 4189: value = FStr_InitRefer(v->val.data);
1.108 sjg 4190:
1.703 rillig 4191: /*
4192: * Before applying any modifiers, expand any nested expressions from
4193: * the variable value.
4194: */
1.743 rillig 4195: if (strchr(value.str, '$') != NULL && (eflags & VARE_WANTRES)) {
4196: char *expanded;
1.703 rillig 4197: VarEvalFlags nested_eflags = eflags;
1.764 rillig 4198: if (opts.strict)
1.703 rillig 4199: nested_eflags &= ~(unsigned)VARE_UNDEFERR;
4200: v->flags |= VAR_IN_USE;
1.743 rillig 4201: (void)Var_Subst(value.str, ctxt, nested_eflags, &expanded);
1.703 rillig 4202: v->flags &= ~(unsigned)VAR_IN_USE;
4203: /* TODO: handle errors */
1.758 rillig 4204: value = FStr_InitOwn(expanded);
1.191 dholland 4205: }
4206:
1.703 rillig 4207: if (haveModifier || extramodifiers != NULL) {
4208: if (extramodifiers != NULL) {
4209: const char *em = extramodifiers;
1.757 rillig 4210: value = ApplyModifiers(&em, value, '\0', '\0',
1.789 rillig 4211: v, &exprStatus, ctxt, eflags);
1.703 rillig 4212: }
1.191 dholland 4213:
1.703 rillig 4214: if (haveModifier) {
1.757 rillig 4215: p++; /* Skip initial colon. */
1.703 rillig 4216:
1.757 rillig 4217: value = ApplyModifiers(&p, value, startc, endc,
1.789 rillig 4218: v, &exprStatus, ctxt, eflags);
1.703 rillig 4219: }
1.191 dholland 4220: }
1.438 rillig 4221:
1.703 rillig 4222: if (*p != '\0') /* Skip past endc if possible. */
4223: p++;
1.519 rillig 4224:
1.703 rillig 4225: *pp = p;
1.15 christos 4226:
1.703 rillig 4227: if (v->flags & VAR_FROM_ENV) {
1.743 rillig 4228: FreeEnvVar(&value.freeIt, v, value.str);
1.703 rillig 4229:
1.789 rillig 4230: } else if (exprStatus != VES_NONE) {
4231: if (exprStatus != VES_DEF) {
1.758 rillig 4232: FStr_Done(&value);
1.703 rillig 4233: if (dynamic) {
1.758 rillig 4234: value = FStr_InitOwn(bmake_strsedup(start, p));
1.703 rillig 4235: } else {
4236: /*
4237: * The expression is still undefined,
4238: * therefore discard the actual value and
4239: * return an error marker instead.
4240: */
1.758 rillig 4241: value = FStr_InitRefer(eflags & VARE_UNDEFERR
1.743 rillig 4242: ? var_Error : varUndefined);
1.703 rillig 4243: }
4244: }
1.785 rillig 4245: if (value.str != v->val.data)
1.784 rillig 4246: Buf_Done(&v->val);
1.711 rillig 4247: FStr_Done(&v->name);
1.703 rillig 4248: free(v);
1.34 christos 4249: }
1.743 rillig 4250: *out_val = (FStr){ value.str, value.freeIt };
1.766 rillig 4251: return VPR_OK; /* XXX: Is not correct in all cases */
1.1 cgd 4252: }
4253:
1.678 rillig 4254: static void
1.768 rillig 4255: VarSubstDollarDollar(const char **pp, Buffer *res, VarEvalFlags eflags)
4256: {
4257: /*
4258: * A dollar sign may be escaped with another dollar
4259: * sign.
4260: */
4261: if (save_dollars && (eflags & VARE_KEEP_DOLLAR))
4262: Buf_AddByte(res, '$');
4263: Buf_AddByte(res, '$');
4264: *pp += 2;
4265: }
4266:
4267: static void
4268: VarSubstExpr(const char **pp, Buffer *buf, GNode *ctxt,
4269: VarEvalFlags eflags, Boolean *inout_errorReported)
1.678 rillig 4270: {
1.703 rillig 4271: const char *p = *pp;
4272: const char *nested_p = p;
1.743 rillig 4273: FStr val;
1.703 rillig 4274:
1.743 rillig 4275: (void)Var_Parse(&nested_p, ctxt, eflags, &val);
1.703 rillig 4276: /* TODO: handle errors */
1.678 rillig 4277:
1.743 rillig 4278: if (val.str == var_Error || val.str == varUndefined) {
1.774 rillig 4279: if (!(eflags & VARE_KEEP_UNDEF)) {
1.703 rillig 4280: p = nested_p;
1.743 rillig 4281: } else if ((eflags & VARE_UNDEFERR) || val.str == var_Error) {
1.703 rillig 4282:
4283: /*
4284: * XXX: This condition is wrong. If val == var_Error,
4285: * this doesn't necessarily mean there was an undefined
4286: * variable. It could equally well be a parse error;
4287: * see unit-tests/varmod-order.exp.
4288: */
4289:
4290: /*
4291: * If variable is undefined, complain and skip the
4292: * variable. The complaint will stop us from doing
4293: * anything when the file is parsed.
4294: */
4295: if (!*inout_errorReported) {
4296: Parse_Error(PARSE_FATAL,
4297: "Undefined variable \"%.*s\"",
4298: (int)(size_t)(nested_p - p), p);
4299: }
4300: p = nested_p;
4301: *inout_errorReported = TRUE;
4302: } else {
4303: /* Copy the initial '$' of the undefined expression,
4304: * thereby deferring expansion of the expression, but
4305: * expand nested expressions if already possible.
4306: * See unit-tests/varparse-undef-partial.mk. */
4307: Buf_AddByte(buf, *p);
4308: p++;
4309: }
1.678 rillig 4310: } else {
1.703 rillig 4311: p = nested_p;
1.743 rillig 4312: Buf_AddStr(buf, val.str);
1.678 rillig 4313: }
4314:
1.743 rillig 4315: FStr_Done(&val);
1.678 rillig 4316:
1.703 rillig 4317: *pp = p;
1.678 rillig 4318: }
4319:
1.768 rillig 4320: /*
4321: * Skip as many characters as possible -- either to the end of the string
4322: * or to the next dollar sign (variable expression).
4323: */
4324: static void
4325: VarSubstPlain(const char **pp, Buffer *res)
4326: {
4327: const char *p = *pp;
4328: const char *start = p;
4329:
4330: for (p++; *p != '$' && *p != '\0'; p++)
4331: continue;
4332: Buf_AddBytesBetween(res, start, p);
4333: *pp = p;
4334: }
4335:
1.778 rillig 4336: /*
4337: * Expand all variable expressions like $V, ${VAR}, $(VAR:Modifiers) in the
1.660 rillig 4338: * given string.
1.1 cgd 4339: *
1.70 wiz 4340: * Input:
1.660 rillig 4341: * str The string in which the variable expressions are
4342: * expanded.
4343: * ctxt The context in which to start searching for
4344: * variables. The other contexts are searched as well.
1.677 rillig 4345: * eflags Special effects during expansion.
1.1 cgd 4346: */
1.533 rillig 4347: VarParseResult
4348: Var_Subst(const char *str, GNode *ctxt, VarEvalFlags eflags, char **out_res)
1.1 cgd 4349: {
1.703 rillig 4350: const char *p = str;
4351: Buffer res;
1.1 cgd 4352:
1.703 rillig 4353: /* Set true if an error has already been reported,
4354: * to prevent a plethora of messages when recursing */
4355: /* XXX: Why is the 'static' necessary here? */
4356: static Boolean errorReported;
4357:
4358: Buf_Init(&res);
4359: errorReported = FALSE;
4360:
4361: while (*p != '\0') {
1.768 rillig 4362: if (p[0] == '$' && p[1] == '$')
4363: VarSubstDollarDollar(&p, &res, eflags);
4364: else if (p[0] == '$')
4365: VarSubstExpr(&p, &res, ctxt, eflags, &errorReported);
4366: else
4367: VarSubstPlain(&p, &res);
1.1 cgd 4368: }
1.15 christos 4369:
1.784 rillig 4370: *out_res = Buf_DoneDataCompact(&res);
1.703 rillig 4371: return VPR_OK;
1.1 cgd 4372: }
4373:
1.572 rillig 4374: /* Initialize the variables module. */
1.1 cgd 4375: void
1.70 wiz 4376: Var_Init(void)
1.1 cgd 4377: {
1.703 rillig 4378: VAR_INTERNAL = GNode_New("Internal");
4379: VAR_GLOBAL = GNode_New("Global");
4380: VAR_CMDLINE = GNode_New("Command");
1.6 jtc 4381: }
4382:
1.572 rillig 4383: /* Clean up the variables module. */
1.6 jtc 4384: void
1.70 wiz 4385: Var_End(void)
1.6 jtc 4386: {
1.703 rillig 4387: Var_Stats();
1.286 sjg 4388: }
4389:
4390: void
4391: Var_Stats(void)
4392: {
1.703 rillig 4393: HashTable_DebugStats(&VAR_GLOBAL->vars, "VAR_GLOBAL");
1.1 cgd 4394: }
1.15 christos 4395:
1.573 rillig 4396: /* Print all variables in a context, sorted by name. */
1.5 cgd 4397: void
1.70 wiz 4398: Var_Dump(GNode *ctxt)
1.1 cgd 4399: {
1.703 rillig 4400: Vector /* of const char * */ vec;
4401: HashIter hi;
4402: size_t i;
4403: const char **varnames;
4404:
4405: Vector_Init(&vec, sizeof(const char *));
4406:
4407: HashIter_Init(&hi, &ctxt->vars);
4408: while (HashIter_Next(&hi) != NULL)
4409: *(const char **)Vector_Push(&vec) = hi.entry->key;
4410: varnames = vec.items;
4411:
4412: qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc);
4413:
4414: for (i = 0; i < vec.len; i++) {
4415: const char *varname = varnames[i];
4416: Var *var = HashTable_FindValue(&ctxt->vars, varname);
1.785 rillig 4417: debug_printf("%-16s = %s\n", varname, var->val.data);
1.703 rillig 4418: }
1.573 rillig 4419:
1.703 rillig 4420: Vector_Done(&vec);
1.1 cgd 4421: }
CVSweb <webmaster@jp.NetBSD.org>