var.c revision 1.257 1 /* $NetBSD: var.c,v 1.257 2020/07/19 10:28:44 rillig Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 /*
36 * Copyright (c) 1989 by Berkeley Softworks
37 * All rights reserved.
38 *
39 * This code is derived from software contributed to Berkeley by
40 * Adam de Boor.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement:
52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE.
69 */
70
71 #ifndef MAKE_NATIVE
72 static char rcsid[] = "$NetBSD: var.c,v 1.257 2020/07/19 10:28:44 rillig Exp $";
73 #else
74 #include <sys/cdefs.h>
75 #ifndef lint
76 #if 0
77 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
78 #else
79 __RCSID("$NetBSD: var.c,v 1.257 2020/07/19 10:28:44 rillig Exp $");
80 #endif
81 #endif /* not lint */
82 #endif
83
84 /*-
85 * var.c --
86 * Variable-handling functions
87 *
88 * Interface:
89 * Var_Set Set the value of a variable in the given
90 * context. The variable is created if it doesn't
91 * yet exist. The value and variable name need not
92 * be preserved.
93 *
94 * Var_Append Append more characters to an existing variable
95 * in the given context. The variable needn't
96 * exist already -- it will be created if it doesn't.
97 * A space is placed between the old value and the
98 * new one.
99 *
100 * Var_Exists See if a variable exists.
101 *
102 * Var_Value Return the value of a variable in a context or
103 * NULL if the variable is undefined.
104 *
105 * Var_Subst Substitute either a single variable or all
106 * variables in a string, using the given context as
107 * the top-most one.
108 *
109 * Var_Parse Parse a variable expansion from a string and
110 * return the result and the number of characters
111 * consumed.
112 *
113 * Var_Delete Delete a variable in a context.
114 *
115 * Var_Init Initialize this module.
116 *
117 * Debugging:
118 * Var_Dump Print out all variables defined in the given
119 * context.
120 *
121 * XXX: There's a lot of duplication in these functions.
122 */
123
124 #include <sys/stat.h>
125 #ifndef NO_REGEX
126 #include <sys/types.h>
127 #include <regex.h>
128 #endif
129 #include <ctype.h>
130 #include <inttypes.h>
131 #include <stdlib.h>
132 #include <limits.h>
133 #include <time.h>
134
135 #include "make.h"
136 #include "buf.h"
137 #include "dir.h"
138 #include "job.h"
139 #include "metachar.h"
140
141 extern int makelevel;
142 /*
143 * This lets us tell if we have replaced the original environ
144 * (which we cannot free).
145 */
146 char **savedEnv = NULL;
147
148 /*
149 * This is a harmless return value for Var_Parse that can be used by Var_Subst
150 * to determine if there was an error in parsing -- easier than returning
151 * a flag, as things outside this module don't give a hoot.
152 */
153 char var_Error[] = "";
154
155 /*
156 * Similar to var_Error, but returned when the 'VARF_UNDEFERR' flag for
157 * Var_Parse is not set. Why not just use a constant? Well, gcc likes
158 * to condense identical string instances...
159 */
160 static char varNoError[] = "";
161
162 /*
163 * Traditionally we consume $$ during := like any other expansion.
164 * Other make's do not.
165 * This knob allows controlling the behavior.
166 * FALSE for old behavior.
167 * TRUE for new compatible.
168 */
169 #define SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
170 static Boolean save_dollars = TRUE;
171
172 /*
173 * Internally, variables are contained in four different contexts.
174 * 1) the environment. They may not be changed. If an environment
175 * variable is appended-to, the result is placed in the global
176 * context.
177 * 2) the global context. Variables set in the Makefile are located in
178 * the global context. It is the penultimate context searched when
179 * substituting.
180 * 3) the command-line context. All variables set on the command line
181 * are placed in this context. They are UNALTERABLE once placed here.
182 * 4) the local context. Each target has associated with it a context
183 * list. On this list are located the structures describing such
184 * local variables as $(@) and $(*)
185 * The four contexts are searched in the reverse order from which they are
186 * listed.
187 */
188 GNode *VAR_INTERNAL; /* variables from make itself */
189 GNode *VAR_GLOBAL; /* variables from the makefile */
190 GNode *VAR_CMD; /* variables defined on the command-line */
191
192 #define FIND_CMD 0x1 /* look in VAR_CMD when searching */
193 #define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */
194 #define FIND_ENV 0x4 /* look in the environment also */
195
196 typedef enum {
197 VAR_IN_USE = 0x01, /* Variable's value is currently being used.
198 * Used to avoid endless recursion */
199 VAR_FROM_ENV = 0x02, /* Variable comes from the environment */
200 VAR_JUNK = 0x04, /* Variable is a junk variable that
201 * should be destroyed when done with
202 * it. Used by Var_Parse for undefined,
203 * modified variables */
204 VAR_KEEP = 0x08, /* Variable is VAR_JUNK, but we found
205 * a use for it in some modifier and
206 * the value is therefore valid */
207 VAR_EXPORTED = 0x10, /* Variable is exported */
208 VAR_REEXPORT = 0x20, /* Indicate if var needs re-export.
209 * This would be true if it contains $'s */
210 VAR_FROM_CMD = 0x40 /* Variable came from command line */
211 } Var_Flags;
212
213 typedef struct Var {
214 char *name; /* the variable's name */
215 Buffer val; /* its value */
216 Var_Flags flags; /* miscellaneous status flags */
217 } Var;
218
219 /*
220 * Exporting vars is expensive so skip it if we can
221 */
222 #define VAR_EXPORTED_NONE 0
223 #define VAR_EXPORTED_YES 1
224 #define VAR_EXPORTED_ALL 2
225 static int var_exportedVars = VAR_EXPORTED_NONE;
226 /*
227 * We pass this to Var_Export when doing the initial export
228 * or after updating an exported var.
229 */
230 #define VAR_EXPORT_PARENT 1
231 /*
232 * We pass this to Var_Export1 to tell it to leave the value alone.
233 */
234 #define VAR_EXPORT_LITERAL 2
235
236 typedef enum {
237 VAR_SUB_GLOBAL = 0x01, /* Apply substitution globally */
238 VAR_SUB_ONE = 0x02, /* Apply substitution to one word */
239 VAR_SUB_MATCHED = 0x04, /* There was a match */
240 VAR_MATCH_START = 0x08, /* Match at start of word */
241 VAR_MATCH_END = 0x10, /* Match at end of word */
242 VAR_NOSUBST = 0x20 /* don't expand vars in VarGetPattern */
243 } VarPattern_Flags;
244
245 typedef enum {
246 VAR_NO_EXPORT = 0x01 /* do not export */
247 } VarSet_Flags;
248
249 typedef struct {
250 /*
251 * The following fields are set by Var_Parse() when it
252 * encounters modifiers that need to keep state for use by
253 * subsequent modifiers within the same variable expansion.
254 */
255 Byte varSpace; /* Word separator in expansions */
256 Boolean oneBigWord; /* TRUE if we will treat the variable as a
257 * single big word, even if it contains
258 * embedded spaces (as opposed to the
259 * usual behaviour of treating it as
260 * several space-separated words). */
261 } Var_Parse_State;
262
263 /* struct passed as 'void *' to VarSubstitute() for ":S/lhs/rhs/",
264 * to VarSYSVMatch() for ":lhs=rhs". */
265 typedef struct {
266 const char *lhs; /* String to match */
267 int leftLen; /* Length of string */
268 const char *rhs; /* Replacement string (w/ &'s removed) */
269 int rightLen; /* Length of replacement */
270 VarPattern_Flags flags;
271 } VarPattern;
272
273 /* struct passed as 'void *' to VarLoopExpand() for ":@tvar@str@" */
274 typedef struct {
275 GNode *ctxt; /* variable context */
276 char *tvar; /* name of temp var */
277 int tvarLen;
278 char *str; /* string to expand */
279 int strLen;
280 Varf_Flags flags;
281 } VarLoop;
282
283 #ifndef NO_REGEX
284 /* struct passed as 'void *' to VarRESubstitute() for ":C///" */
285 typedef struct {
286 regex_t re;
287 int nsub;
288 regmatch_t *matches;
289 char *replace;
290 int flags;
291 } VarREPattern;
292 #endif
293
294 /* struct passed to VarSelectWords() for ":[start..end]" */
295 typedef struct {
296 int start; /* first word to select */
297 int end; /* last word to select */
298 } VarSelectWords_t;
299
300 #define BROPEN '{'
301 #define BRCLOSE '}'
302 #define PROPEN '('
303 #define PRCLOSE ')'
304
305 /*-
306 *-----------------------------------------------------------------------
307 * VarFind --
308 * Find the given variable in the given context and any other contexts
309 * indicated.
310 *
311 * Input:
312 * name name to find
313 * ctxt context in which to find it
314 * flags FIND_GLOBAL set means to look in the
315 * VAR_GLOBAL context as well. FIND_CMD set means
316 * to look in the VAR_CMD context also. FIND_ENV
317 * set means to look in the environment
318 *
319 * Results:
320 * A pointer to the structure describing the desired variable or
321 * NULL if the variable does not exist.
322 *
323 * Side Effects:
324 * None
325 *-----------------------------------------------------------------------
326 */
327 static Var *
328 VarFind(const char *name, GNode *ctxt, int flags)
329 {
330 Hash_Entry *var;
331 Var *v;
332
333 /*
334 * If the variable name begins with a '.', it could very well be one of
335 * the local ones. We check the name against all the local variables
336 * and substitute the short version in for 'name' if it matches one of
337 * them.
338 */
339 if (*name == '.' && isupper((unsigned char) name[1])) {
340 switch (name[1]) {
341 case 'A':
342 if (strcmp(name, ".ALLSRC") == 0)
343 name = ALLSRC;
344 if (strcmp(name, ".ARCHIVE") == 0)
345 name = ARCHIVE;
346 break;
347 case 'I':
348 if (strcmp(name, ".IMPSRC") == 0)
349 name = IMPSRC;
350 break;
351 case 'M':
352 if (strcmp(name, ".MEMBER") == 0)
353 name = MEMBER;
354 break;
355 case 'O':
356 if (strcmp(name, ".OODATE") == 0)
357 name = OODATE;
358 break;
359 case 'P':
360 if (strcmp(name, ".PREFIX") == 0)
361 name = PREFIX;
362 break;
363 case 'T':
364 if (strcmp(name, ".TARGET") == 0)
365 name = TARGET;
366 break;
367 }
368 }
369
370 #ifdef notyet
371 /* for compatibility with gmake */
372 if (name[0] == '^' && name[1] == '\0')
373 name = ALLSRC;
374 #endif
375
376 /*
377 * First look for the variable in the given context. If it's not there,
378 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
379 * depending on the FIND_* flags in 'flags'
380 */
381 var = Hash_FindEntry(&ctxt->context, name);
382
383 if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMD) {
384 var = Hash_FindEntry(&VAR_CMD->context, name);
385 }
386 if (!checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) &&
387 ctxt != VAR_GLOBAL)
388 {
389 var = Hash_FindEntry(&VAR_GLOBAL->context, name);
390 if (var == NULL && ctxt != VAR_INTERNAL) {
391 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
392 var = Hash_FindEntry(&VAR_INTERNAL->context, name);
393 }
394 }
395 if (var == NULL && (flags & FIND_ENV)) {
396 char *env;
397
398 if ((env = getenv(name)) != NULL) {
399 int len;
400
401 v = bmake_malloc(sizeof(Var));
402 v->name = bmake_strdup(name);
403
404 len = strlen(env);
405
406 Buf_Init(&v->val, len + 1);
407 Buf_AddBytes(&v->val, len, env);
408
409 v->flags = VAR_FROM_ENV;
410 return v;
411 } else if (checkEnvFirst && (flags & FIND_GLOBAL) &&
412 ctxt != VAR_GLOBAL)
413 {
414 var = Hash_FindEntry(&VAR_GLOBAL->context, name);
415 if (var == NULL && ctxt != VAR_INTERNAL) {
416 var = Hash_FindEntry(&VAR_INTERNAL->context, name);
417 }
418 if (var == NULL) {
419 return NULL;
420 } else {
421 return (Var *)Hash_GetValue(var);
422 }
423 } else {
424 return NULL;
425 }
426 } else if (var == NULL) {
427 return NULL;
428 } else {
429 return (Var *)Hash_GetValue(var);
430 }
431 }
432
433 /*-
434 *-----------------------------------------------------------------------
435 * VarFreeEnv --
436 * If the variable is an environment variable, free it
437 *
438 * Input:
439 * v the variable
440 * destroy true if the value buffer should be destroyed.
441 *
442 * Results:
443 * 1 if it is an environment variable 0 ow.
444 *
445 * Side Effects:
446 * The variable is free'ed if it is an environent variable.
447 *-----------------------------------------------------------------------
448 */
449 static Boolean
450 VarFreeEnv(Var *v, Boolean destroy)
451 {
452 if (!(v->flags & VAR_FROM_ENV))
453 return FALSE;
454 free(v->name);
455 Buf_Destroy(&v->val, destroy);
456 free(v);
457 return TRUE;
458 }
459
460 /*-
461 *-----------------------------------------------------------------------
462 * VarAdd --
463 * Add a new variable of name name and value val to the given context
464 *
465 * Input:
466 * name name of variable to add
467 * val value to set it to
468 * ctxt context in which to set it
469 *
470 * Side Effects:
471 * The new variable is placed at the front of the given context
472 * The name and val arguments are duplicated so they may
473 * safely be freed.
474 *-----------------------------------------------------------------------
475 */
476 static void
477 VarAdd(const char *name, const char *val, GNode *ctxt)
478 {
479 Var *v;
480 int len;
481 Hash_Entry *h;
482
483 v = bmake_malloc(sizeof(Var));
484
485 len = val != NULL ? strlen(val) : 0;
486 Buf_Init(&v->val, len + 1);
487 Buf_AddBytes(&v->val, len, val);
488
489 v->flags = 0;
490
491 h = Hash_CreateEntry(&ctxt->context, name, NULL);
492 Hash_SetValue(h, v);
493 v->name = h->name;
494 if (DEBUG(VAR) && !(ctxt->flags & INTERNAL)) {
495 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
496 }
497 }
498
499 /*-
500 *-----------------------------------------------------------------------
501 * Var_Delete --
502 * Remove a variable from a context.
503 *
504 * Side Effects:
505 * The Var structure is removed and freed.
506 *
507 *-----------------------------------------------------------------------
508 */
509 void
510 Var_Delete(const char *name, GNode *ctxt)
511 {
512 Hash_Entry *ln;
513 char *cp;
514
515 if (strchr(name, '$') != NULL) {
516 cp = Var_Subst(NULL, name, VAR_GLOBAL, VARF_WANTRES);
517 } else {
518 cp = UNCONST(name);
519 }
520 ln = Hash_FindEntry(&ctxt->context, cp);
521 if (DEBUG(VAR)) {
522 fprintf(debug_file, "%s:delete %s%s\n",
523 ctxt->name, cp, ln ? "" : " (not found)");
524 }
525 if (cp != name)
526 free(cp);
527 if (ln != NULL) {
528 Var *v = (Var *)Hash_GetValue(ln);
529 if (v->flags & VAR_EXPORTED) {
530 unsetenv(v->name);
531 }
532 if (strcmp(MAKE_EXPORTED, v->name) == 0) {
533 var_exportedVars = VAR_EXPORTED_NONE;
534 }
535 if (v->name != ln->name)
536 free(v->name);
537 Hash_DeleteEntry(&ctxt->context, ln);
538 Buf_Destroy(&v->val, TRUE);
539 free(v);
540 }
541 }
542
543
544 /*
545 * Export a var.
546 * We ignore make internal variables (those which start with '.')
547 * Also we jump through some hoops to avoid calling setenv
548 * more than necessary since it can leak.
549 * We only manipulate flags of vars if 'parent' is set.
550 */
551 static int
552 Var_Export1(const char *name, int flags)
553 {
554 char tmp[BUFSIZ];
555 Var *v;
556 char *val = NULL;
557 int n;
558 int parent = (flags & VAR_EXPORT_PARENT);
559
560 if (*name == '.')
561 return 0; /* skip internals */
562 if (!name[1]) {
563 /*
564 * A single char.
565 * If it is one of the vars that should only appear in
566 * local context, skip it, else we can get Var_Subst
567 * into a loop.
568 */
569 switch (name[0]) {
570 case '@':
571 case '%':
572 case '*':
573 case '!':
574 return 0;
575 }
576 }
577 v = VarFind(name, VAR_GLOBAL, 0);
578 if (v == NULL)
579 return 0;
580 if (!parent &&
581 (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) {
582 return 0; /* nothing to do */
583 }
584 val = Buf_GetAll(&v->val, NULL);
585 if ((flags & VAR_EXPORT_LITERAL) == 0 && strchr(val, '$')) {
586 if (parent) {
587 /*
588 * Flag this as something we need to re-export.
589 * No point actually exporting it now though,
590 * the child can do it at the last minute.
591 */
592 v->flags |= (VAR_EXPORTED|VAR_REEXPORT);
593 return 1;
594 }
595 if (v->flags & VAR_IN_USE) {
596 /*
597 * We recursed while exporting in a child.
598 * This isn't going to end well, just skip it.
599 */
600 return 0;
601 }
602 n = snprintf(tmp, sizeof(tmp), "${%s}", name);
603 if (n < (int)sizeof(tmp)) {
604 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
605 setenv(name, val, 1);
606 free(val);
607 }
608 } else {
609 if (parent) {
610 v->flags &= ~VAR_REEXPORT; /* once will do */
611 }
612 if (parent || !(v->flags & VAR_EXPORTED)) {
613 setenv(name, val, 1);
614 }
615 }
616 /*
617 * This is so Var_Set knows to call Var_Export again...
618 */
619 if (parent) {
620 v->flags |= VAR_EXPORTED;
621 }
622 return 1;
623 }
624
625 static void
626 Var_ExportVars_callback(void *entry, void *unused MAKE_ATTR_UNUSED)
627 {
628 Var *var = entry;
629 Var_Export1(var->name, 0);
630 }
631
632 /*
633 * This gets called from our children.
634 */
635 void
636 Var_ExportVars(void)
637 {
638 char tmp[BUFSIZ];
639 char *val;
640 int n;
641
642 /*
643 * Several make's support this sort of mechanism for tracking
644 * recursion - but each uses a different name.
645 * We allow the makefiles to update MAKELEVEL and ensure
646 * children see a correctly incremented value.
647 */
648 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
649 setenv(MAKE_LEVEL_ENV, tmp, 1);
650
651 if (VAR_EXPORTED_NONE == var_exportedVars)
652 return;
653
654 if (VAR_EXPORTED_ALL == var_exportedVars) {
655 /* Ouch! This is crazy... */
656 Hash_ForEach(&VAR_GLOBAL->context, Var_ExportVars_callback, NULL);
657 return;
658 }
659 /*
660 * We have a number of exported vars,
661 */
662 n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}");
663 if (n < (int)sizeof(tmp)) {
664 char **av;
665 char *as;
666 int ac;
667 int i;
668
669 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
670 if (*val) {
671 av = brk_string(val, &ac, FALSE, &as);
672 for (i = 0; i < ac; i++)
673 Var_Export1(av[i], 0);
674 free(as);
675 free(av);
676 }
677 free(val);
678 }
679 }
680
681 /*
682 * This is called when .export is seen or
683 * .MAKE.EXPORTED is modified.
684 * It is also called when any exported var is modified.
685 */
686 void
687 Var_Export(char *str, int isExport)
688 {
689 char *name;
690 char *val;
691 char **av;
692 char *as;
693 int flags;
694 int ac;
695 int i;
696
697 if (isExport && (!str || !str[0])) {
698 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
699 return;
700 }
701
702 flags = 0;
703 if (strncmp(str, "-env", 4) == 0) {
704 str += 4;
705 } else if (strncmp(str, "-literal", 8) == 0) {
706 str += 8;
707 flags |= VAR_EXPORT_LITERAL;
708 } else {
709 flags |= VAR_EXPORT_PARENT;
710 }
711 val = Var_Subst(NULL, str, VAR_GLOBAL, VARF_WANTRES);
712 if (*val) {
713 av = brk_string(val, &ac, FALSE, &as);
714 for (i = 0; i < ac; i++) {
715 name = av[i];
716 if (!name[1]) {
717 /*
718 * A single char.
719 * If it is one of the vars that should only appear in
720 * local context, skip it, else we can get Var_Subst
721 * into a loop.
722 */
723 switch (name[0]) {
724 case '@':
725 case '%':
726 case '*':
727 case '!':
728 continue;
729 }
730 }
731 if (Var_Export1(name, flags)) {
732 if (VAR_EXPORTED_ALL != var_exportedVars)
733 var_exportedVars = VAR_EXPORTED_YES;
734 if (isExport && (flags & VAR_EXPORT_PARENT)) {
735 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
736 }
737 }
738 }
739 free(as);
740 free(av);
741 }
742 free(val);
743 }
744
745
746 extern char **environ;
747
748 /*
749 * This is called when .unexport[-env] is seen.
750 */
751 void
752 Var_UnExport(char *str)
753 {
754 char tmp[BUFSIZ];
755 char *vlist;
756 char *cp;
757 Boolean unexport_env;
758 int n;
759
760 if (str == NULL || str[0] == '\0')
761 return; /* assert? */
762
763 vlist = NULL;
764
765 str += 8;
766 unexport_env = (strncmp(str, "-env", 4) == 0);
767 if (unexport_env) {
768 char **newenv;
769
770 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
771 if (environ == savedEnv) {
772 /* we have been here before! */
773 newenv = bmake_realloc(environ, 2 * sizeof(char *));
774 } else {
775 if (savedEnv) {
776 free(savedEnv);
777 savedEnv = NULL;
778 }
779 newenv = bmake_malloc(2 * sizeof(char *));
780 }
781 if (!newenv)
782 return;
783 /* Note: we cannot safely free() the original environ. */
784 environ = savedEnv = newenv;
785 newenv[0] = NULL;
786 newenv[1] = NULL;
787 if (cp && *cp)
788 setenv(MAKE_LEVEL_ENV, cp, 1);
789 } else {
790 for (; *str != '\n' && isspace((unsigned char) *str); str++)
791 continue;
792 if (str[0] && str[0] != '\n') {
793 vlist = str;
794 }
795 }
796
797 if (!vlist) {
798 /* Using .MAKE.EXPORTED */
799 vlist = Var_Subst(NULL, "${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL,
800 VARF_WANTRES);
801 }
802 if (vlist) {
803 Var *v;
804 char **av;
805 char *as;
806 int ac;
807 int i;
808
809 av = brk_string(vlist, &ac, FALSE, &as);
810 for (i = 0; i < ac; i++) {
811 v = VarFind(av[i], VAR_GLOBAL, 0);
812 if (!v)
813 continue;
814 if (!unexport_env &&
815 (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED)
816 {
817 unsetenv(v->name);
818 }
819 v->flags &= ~(VAR_EXPORTED|VAR_REEXPORT);
820 /*
821 * If we are unexporting a list,
822 * remove each one from .MAKE.EXPORTED.
823 * If we are removing them all,
824 * just delete .MAKE.EXPORTED below.
825 */
826 if (vlist == str) {
827 n = snprintf(tmp, sizeof(tmp),
828 "${" MAKE_EXPORTED ":N%s}", v->name);
829 if (n < (int)sizeof(tmp)) {
830 cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
831 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
832 free(cp);
833 }
834 }
835 }
836 free(as);
837 free(av);
838 if (vlist != str) {
839 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
840 free(vlist);
841 }
842 }
843 }
844
845 static void
846 Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
847 VarSet_Flags flags)
848 {
849 Var *v;
850 char *expanded_name = NULL;
851
852 /*
853 * We only look for a variable in the given context since anything set
854 * here will override anything in a lower context, so there's not much
855 * point in searching them all just to save a bit of memory...
856 */
857 if (strchr(name, '$') != NULL) {
858 expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES);
859 if (expanded_name[0] == '\0') {
860 if (DEBUG(VAR)) {
861 fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) "
862 "name expands to empty string - ignored\n",
863 name, val);
864 }
865 free(expanded_name);
866 return;
867 }
868 name = expanded_name;
869 }
870 if (ctxt == VAR_GLOBAL) {
871 v = VarFind(name, VAR_CMD, 0);
872 if (v != NULL) {
873 if ((v->flags & VAR_FROM_CMD)) {
874 if (DEBUG(VAR)) {
875 fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val);
876 }
877 goto out;
878 }
879 VarFreeEnv(v, TRUE);
880 }
881 }
882 v = VarFind(name, ctxt, 0);
883 if (v == NULL) {
884 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
885 /*
886 * This var would normally prevent the same name being added
887 * to VAR_GLOBAL, so delete it from there if needed.
888 * Otherwise -V name may show the wrong value.
889 */
890 Var_Delete(name, VAR_GLOBAL);
891 }
892 VarAdd(name, val, ctxt);
893 } else {
894 Buf_Empty(&v->val);
895 if (val)
896 Buf_AddBytes(&v->val, strlen(val), val);
897
898 if (DEBUG(VAR)) {
899 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
900 }
901 if ((v->flags & VAR_EXPORTED)) {
902 Var_Export1(name, VAR_EXPORT_PARENT);
903 }
904 }
905 /*
906 * Any variables given on the command line are automatically exported
907 * to the environment (as per POSIX standard)
908 */
909 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
910 if (v == NULL) {
911 /* we just added it */
912 v = VarFind(name, ctxt, 0);
913 }
914 if (v != NULL)
915 v->flags |= VAR_FROM_CMD;
916 /*
917 * If requested, don't export these in the environment
918 * individually. We still put them in MAKEOVERRIDES so
919 * that the command-line settings continue to override
920 * Makefile settings.
921 */
922 if (varNoExportEnv != TRUE)
923 setenv(name, val ? val : "", 1);
924
925 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
926 }
927 if (*name == '.') {
928 if (strcmp(name, SAVE_DOLLARS) == 0)
929 save_dollars = s2Boolean(val, save_dollars);
930 }
931
932 out:
933 free(expanded_name);
934 if (v != NULL)
935 VarFreeEnv(v, TRUE);
936 }
937
938 /*-
939 *-----------------------------------------------------------------------
940 * Var_Set --
941 * Set the variable name to the value val in the given context.
942 *
943 * Input:
944 * name name of variable to set
945 * val value to give to the variable
946 * ctxt context in which to set it
947 *
948 * Side Effects:
949 * If the variable doesn't yet exist, a new record is created for it.
950 * Else the old value is freed and the new one stuck in its place
951 *
952 * Notes:
953 * The variable is searched for only in its context before being
954 * created in that context. I.e. if the context is VAR_GLOBAL,
955 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
956 * VAR_CMD->context is searched. This is done to avoid the literally
957 * thousands of unnecessary strcmp's that used to be done to
958 * set, say, $(@) or $(<).
959 * If the context is VAR_GLOBAL though, we check if the variable
960 * was set in VAR_CMD from the command line and skip it if so.
961 *-----------------------------------------------------------------------
962 */
963 void
964 Var_Set(const char *name, const char *val, GNode *ctxt)
965 {
966 Var_Set_with_flags(name, val, ctxt, 0);
967 }
968
969 /*-
970 *-----------------------------------------------------------------------
971 * Var_Append --
972 * The variable of the given name has the given value appended to it in
973 * the given context.
974 *
975 * Input:
976 * name name of variable to modify
977 * val String to append to it
978 * ctxt Context in which this should occur
979 *
980 * Side Effects:
981 * If the variable doesn't exist, it is created. Else the strings
982 * are concatenated (with a space in between).
983 *
984 * Notes:
985 * Only if the variable is being sought in the global context is the
986 * environment searched.
987 * XXX: Knows its calling circumstances in that if called with ctxt
988 * an actual target, it will only search that context since only
989 * a local variable could be being appended to. This is actually
990 * a big win and must be tolerated.
991 *-----------------------------------------------------------------------
992 */
993 void
994 Var_Append(const char *name, const char *val, GNode *ctxt)
995 {
996 Var *v;
997 Hash_Entry *h;
998 char *expanded_name = NULL;
999
1000 if (strchr(name, '$') != NULL) {
1001 expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES);
1002 if (expanded_name[0] == '\0') {
1003 if (DEBUG(VAR)) {
1004 fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) "
1005 "name expands to empty string - ignored\n",
1006 name, val);
1007 }
1008 free(expanded_name);
1009 return;
1010 }
1011 name = expanded_name;
1012 }
1013
1014 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD|FIND_ENV) : 0);
1015
1016 if (v == NULL) {
1017 Var_Set(name, val, ctxt);
1018 } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) {
1019 Buf_AddByte(&v->val, ' ');
1020 Buf_AddBytes(&v->val, strlen(val), val);
1021
1022 if (DEBUG(VAR)) {
1023 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name,
1024 Buf_GetAll(&v->val, NULL));
1025 }
1026
1027 if (v->flags & VAR_FROM_ENV) {
1028 /*
1029 * If the original variable came from the environment, we
1030 * have to install it in the global context (we could place
1031 * it in the environment, but then we should provide a way to
1032 * export other variables...)
1033 */
1034 v->flags &= ~VAR_FROM_ENV;
1035 h = Hash_CreateEntry(&ctxt->context, name, NULL);
1036 Hash_SetValue(h, v);
1037 }
1038 }
1039 free(expanded_name);
1040 }
1041
1042 /*-
1043 *-----------------------------------------------------------------------
1044 * Var_Exists --
1045 * See if the given variable exists.
1046 *
1047 * Input:
1048 * name Variable to find
1049 * ctxt Context in which to start search
1050 *
1051 * Results:
1052 * TRUE if it does, FALSE if it doesn't
1053 *
1054 * Side Effects:
1055 * None.
1056 *
1057 *-----------------------------------------------------------------------
1058 */
1059 Boolean
1060 Var_Exists(const char *name, GNode *ctxt)
1061 {
1062 Var *v;
1063 char *cp;
1064
1065 if ((cp = strchr(name, '$')) != NULL)
1066 cp = Var_Subst(NULL, name, ctxt, VARF_WANTRES);
1067 v = VarFind(cp ? cp : name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV);
1068 free(cp);
1069 if (v == NULL)
1070 return FALSE;
1071
1072 (void)VarFreeEnv(v, TRUE);
1073 return TRUE;
1074 }
1075
1076 /*-
1077 *-----------------------------------------------------------------------
1078 * Var_Value --
1079 * Return the value of the named variable in the given context
1080 *
1081 * Input:
1082 * name name to find
1083 * ctxt context in which to search for it
1084 *
1085 * Results:
1086 * The value if the variable exists, NULL if it doesn't
1087 *
1088 * Side Effects:
1089 * None
1090 *-----------------------------------------------------------------------
1091 */
1092 char *
1093 Var_Value(const char *name, GNode *ctxt, char **frp)
1094 {
1095 Var *v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1096 *frp = NULL;
1097 if (v == NULL)
1098 return NULL;
1099
1100 char *p = Buf_GetAll(&v->val, NULL);
1101 if (VarFreeEnv(v, FALSE))
1102 *frp = p;
1103 return p;
1104 }
1105
1106
1107 /* This callback for VarModify gets a single word from an expression and
1108 * typically adds a modification of this word to the buffer. It may also do
1109 * nothing or add several words.
1110 *
1111 * If addSpaces is TRUE, it must add a space before adding anything else to
1112 * the buffer.
1113 *
1114 * It returns the addSpace value for the next call of this callback. Typical
1115 * return values are the current addSpaces or TRUE. */
1116 typedef Boolean (*VarModifyCallback)(GNode *ctxt, Var_Parse_State *vpstate,
1117 const char *word, Boolean addSpace, Buffer *buf, void *data);
1118
1119
1120 /* Callback function for VarModify to implement the :H modifier.
1121 * Add the dirname of the given word to the buffer. */
1122 static Boolean
1123 VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1124 const char *word, Boolean addSpace, Buffer *buf,
1125 void *dummy MAKE_ATTR_UNUSED)
1126 {
1127 const char *slash = strrchr(word, '/');
1128
1129 if (addSpace && vpstate->varSpace)
1130 Buf_AddByte(buf, vpstate->varSpace);
1131 if (slash != NULL)
1132 Buf_AddBytes(buf, slash - word, word);
1133 else
1134 Buf_AddByte(buf, '.');
1135
1136 return TRUE;
1137 }
1138
1139 /* Callback function for VarModify to implement the :T modifier.
1140 * Add the basename of the given word to the buffer. */
1141 static Boolean
1142 VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1143 const char *word, Boolean addSpace, Buffer *buf,
1144 void *dummy MAKE_ATTR_UNUSED)
1145 {
1146 const char *slash = strrchr(word, '/');
1147 const char *base = slash != NULL ? slash + 1 : word;
1148
1149 if (addSpace && vpstate->varSpace != '\0')
1150 Buf_AddByte(buf, vpstate->varSpace);
1151 Buf_AddBytes(buf, strlen(base), base);
1152 return TRUE;
1153 }
1154
1155 /* Callback function for VarModify to implement the :E modifier.
1156 * Add the filename suffix of the given word to the buffer, if it exists. */
1157 static Boolean
1158 VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1159 const char *word, Boolean addSpace, Buffer *buf,
1160 void *dummy MAKE_ATTR_UNUSED)
1161 {
1162 const char *dot = strrchr(word, '.');
1163 if (dot == NULL)
1164 return addSpace;
1165
1166 if (addSpace && vpstate->varSpace != '\0')
1167 Buf_AddByte(buf, vpstate->varSpace);
1168 Buf_AddBytes(buf, strlen(dot + 1), dot + 1);
1169 return TRUE;
1170 }
1171
1172 /* Callback function for VarModify to implement the :R modifier.
1173 * Add the filename basename of the given word to the buffer. */
1174 static Boolean
1175 VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1176 const char *word, Boolean addSpace, Buffer *buf,
1177 void *dummy MAKE_ATTR_UNUSED)
1178 {
1179 char *dot = strrchr(word, '.');
1180 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word);
1181
1182 if (addSpace && vpstate->varSpace != '\0')
1183 Buf_AddByte(buf, vpstate->varSpace);
1184 Buf_AddBytes(buf, len, word);
1185 return TRUE;
1186 }
1187
1188 /* Callback function for VarModify to implement the :M modifier.
1189 * Place the word in the buffer if it matches the given pattern. */
1190 static Boolean
1191 VarMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1192 const char *word, Boolean addSpace, Buffer *buf,
1193 void *data)
1194 {
1195 const char *pattern = data;
1196 if (DEBUG(VAR))
1197 fprintf(debug_file, "VarMatch [%s] [%s]\n", word, pattern);
1198 if (!Str_Match(word, pattern))
1199 return addSpace;
1200 if (addSpace && vpstate->varSpace != '\0')
1201 Buf_AddByte(buf, vpstate->varSpace);
1202 Buf_AddBytes(buf, strlen(word), word);
1203 return TRUE;
1204 }
1205
1206 #ifdef SYSVVARSUB
1207 /*-
1208 *-----------------------------------------------------------------------
1209 * Str_SYSVMatch --
1210 * Check word against pattern for a match (% is wild),
1211 *
1212 * Input:
1213 * word Word to examine
1214 * pattern Pattern to examine against
1215 * len Number of characters to substitute
1216 *
1217 * Results:
1218 * Returns the beginning position of a match or null. The number
1219 * of characters matched is returned in len.
1220 *
1221 * Side Effects:
1222 * None
1223 *
1224 *-----------------------------------------------------------------------
1225 */
1226 static char *
1227 Str_SYSVMatch(const char *word, const char *pattern, size_t *len,
1228 Boolean *hasPercent)
1229 {
1230 const char *p = pattern;
1231 const char *w = word;
1232 const char *m;
1233
1234 *hasPercent = FALSE;
1235 if (*p == '\0') {
1236 /* Null pattern is the whole string */
1237 *len = strlen(w);
1238 return UNCONST(w);
1239 }
1240
1241 if ((m = strchr(p, '%')) != NULL) {
1242 *hasPercent = TRUE;
1243 if (*w == '\0') {
1244 /* empty word does not match pattern */
1245 return NULL;
1246 }
1247 /* check that the prefix matches */
1248 for (; p != m && *w && *w == *p; w++, p++)
1249 continue;
1250
1251 if (p != m)
1252 return NULL; /* No match */
1253
1254 if (*++p == '\0') {
1255 /* No more pattern, return the rest of the string */
1256 *len = strlen(w);
1257 return UNCONST(w);
1258 }
1259 }
1260
1261 m = w;
1262
1263 /* Find a matching tail */
1264 do
1265 if (strcmp(p, w) == 0) {
1266 *len = w - m;
1267 return UNCONST(m);
1268 }
1269 while (*w++ != '\0');
1270
1271 return NULL;
1272 }
1273
1274
1275 /*-
1276 *-----------------------------------------------------------------------
1277 * Str_SYSVSubst --
1278 * Substitute '%' on the pattern with len characters from src.
1279 * If the pattern does not contain a '%' prepend len characters
1280 * from src.
1281 *
1282 * Side Effects:
1283 * Places result on buf
1284 *
1285 *-----------------------------------------------------------------------
1286 */
1287 static void
1288 Str_SYSVSubst(Buffer *buf, const char *pat, const char *src, size_t len,
1289 Boolean lhsHasPercent)
1290 {
1291 const char *m;
1292
1293 if ((m = strchr(pat, '%')) != NULL && lhsHasPercent) {
1294 /* Copy the prefix */
1295 Buf_AddBytes(buf, m - pat, pat);
1296 /* skip the % */
1297 pat = m + 1;
1298 }
1299 if (m != NULL || !lhsHasPercent) {
1300 /* Copy the pattern */
1301 Buf_AddBytes(buf, len, src);
1302 }
1303
1304 /* append the rest */
1305 Buf_AddBytes(buf, strlen(pat), pat);
1306 }
1307
1308
1309 /* Callback function for VarModify to implement the :%.from=%.to modifier. */
1310 static Boolean
1311 VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate,
1312 const char *word, Boolean addSpace, Buffer *buf,
1313 void *data)
1314 {
1315 size_t len;
1316 const char *ptr;
1317 Boolean hasPercent;
1318 VarPattern *pat = data;
1319
1320 if (addSpace && vpstate->varSpace != '\0')
1321 Buf_AddByte(buf, vpstate->varSpace);
1322
1323 if ((ptr = Str_SYSVMatch(word, pat->lhs, &len, &hasPercent)) != NULL) {
1324 char *varexp = Var_Subst(NULL, pat->rhs, ctx, VARF_WANTRES);
1325 Str_SYSVSubst(buf, varexp, ptr, len, hasPercent);
1326 free(varexp);
1327 } else {
1328 Buf_AddBytes(buf, strlen(word), word);
1329 }
1330
1331 return TRUE;
1332 }
1333 #endif
1334
1335 /* Callback function for VarModify to implement the :N modifier.
1336 * Place the word in the buffer if it doesn't match the given pattern. */
1337 static Boolean
1338 VarNoMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1339 const char *word, Boolean addSpace, Buffer *buf,
1340 void *data)
1341 {
1342 const char *pattern = data;
1343 if (Str_Match(word, pattern))
1344 return addSpace;
1345 if (addSpace && vpstate->varSpace != '\0')
1346 Buf_AddByte(buf, vpstate->varSpace);
1347 Buf_AddBytes(buf, strlen(word), word);
1348 return TRUE;
1349 }
1350
1351 /* Callback function for VarModify to implement the :S,from,to, modifier.
1352 * Perform a string substitution on the given word. */
1353 static Boolean
1354 VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1355 const char *word, Boolean addSpace, Buffer *buf,
1356 void *data)
1357 {
1358 int wordLen = strlen(word);
1359 const char *cp; /* General pointer */
1360 VarPattern *pattern = data;
1361
1362 if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) !=
1363 (VAR_SUB_ONE|VAR_SUB_MATCHED)) {
1364 /*
1365 * Still substituting -- break it down into simple anchored cases
1366 * and if none of them fits, perform the general substitution case.
1367 */
1368 if ((pattern->flags & VAR_MATCH_START) &&
1369 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
1370 /*
1371 * Anchored at start and beginning of word matches pattern
1372 */
1373 if ((pattern->flags & VAR_MATCH_END) &&
1374 (wordLen == pattern->leftLen)) {
1375 /*
1376 * Also anchored at end and matches to the end (word
1377 * is same length as pattern) add space and rhs only
1378 * if rhs is non-null.
1379 */
1380 if (pattern->rightLen != 0) {
1381 if (addSpace && vpstate->varSpace != '\0') {
1382 Buf_AddByte(buf, vpstate->varSpace);
1383 }
1384 addSpace = TRUE;
1385 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1386 }
1387 pattern->flags |= VAR_SUB_MATCHED;
1388 } else if (pattern->flags & VAR_MATCH_END) {
1389 /*
1390 * Doesn't match to end -- copy word wholesale
1391 */
1392 goto nosub;
1393 } else {
1394 /*
1395 * Matches at start but need to copy in trailing characters
1396 */
1397 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0) {
1398 if (addSpace && vpstate->varSpace != '\0') {
1399 Buf_AddByte(buf, vpstate->varSpace);
1400 }
1401 addSpace = TRUE;
1402 }
1403 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1404 Buf_AddBytes(buf, wordLen - pattern->leftLen,
1405 (word + pattern->leftLen));
1406 pattern->flags |= VAR_SUB_MATCHED;
1407 }
1408 } else if (pattern->flags & VAR_MATCH_START) {
1409 /*
1410 * Had to match at start of word and didn't -- copy whole word.
1411 */
1412 goto nosub;
1413 } else if (pattern->flags & VAR_MATCH_END) {
1414 /*
1415 * Anchored at end, Find only place match could occur (leftLen
1416 * characters from the end of the word) and see if it does. Note
1417 * that because the $ will be left at the end of the lhs, we have
1418 * to use strncmp.
1419 */
1420 cp = word + (wordLen - pattern->leftLen);
1421 if ((cp >= word) &&
1422 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
1423 /*
1424 * Match found. If we will place characters in the buffer,
1425 * add a space before hand as indicated by addSpace, then
1426 * stuff in the initial, unmatched part of the word followed
1427 * by the right-hand-side.
1428 */
1429 if (((cp - word) + pattern->rightLen) != 0) {
1430 if (addSpace && vpstate->varSpace != '\0') {
1431 Buf_AddByte(buf, vpstate->varSpace);
1432 }
1433 addSpace = TRUE;
1434 }
1435 Buf_AddBytes(buf, cp - word, word);
1436 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1437 pattern->flags |= VAR_SUB_MATCHED;
1438 } else {
1439 /*
1440 * Had to match at end and didn't. Copy entire word.
1441 */
1442 goto nosub;
1443 }
1444 } else {
1445 /*
1446 * Pattern is unanchored: search for the pattern in the word using
1447 * String_FindSubstring, copying unmatched portions and the
1448 * right-hand-side for each match found, handling non-global
1449 * substitutions correctly, etc. When the loop is done, any
1450 * remaining part of the word (word and wordLen are adjusted
1451 * accordingly through the loop) is copied straight into the
1452 * buffer.
1453 * addSpace is set FALSE as soon as a space is added to the
1454 * buffer.
1455 */
1456 Boolean done;
1457 int origSize;
1458
1459 done = FALSE;
1460 origSize = Buf_Size(buf);
1461 while (!done) {
1462 cp = Str_FindSubstring(word, pattern->lhs);
1463 if (cp != NULL) {
1464 if (addSpace && (((cp - word) + pattern->rightLen) != 0)) {
1465 Buf_AddByte(buf, vpstate->varSpace);
1466 addSpace = FALSE;
1467 }
1468 Buf_AddBytes(buf, cp - word, word);
1469 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1470 wordLen -= (cp - word) + pattern->leftLen;
1471 word = cp + pattern->leftLen;
1472 if (wordLen == 0) {
1473 done = TRUE;
1474 }
1475 if ((pattern->flags & VAR_SUB_GLOBAL) == 0) {
1476 done = TRUE;
1477 }
1478 pattern->flags |= VAR_SUB_MATCHED;
1479 } else {
1480 done = TRUE;
1481 }
1482 }
1483 if (wordLen != 0) {
1484 if (addSpace && vpstate->varSpace != '\0') {
1485 Buf_AddByte(buf, vpstate->varSpace);
1486 }
1487 Buf_AddBytes(buf, wordLen, word);
1488 }
1489 /*
1490 * If added characters to the buffer, need to add a space
1491 * before we add any more. If we didn't add any, just return
1492 * the previous value of addSpace.
1493 */
1494 return (Buf_Size(buf) != origSize) || addSpace;
1495 }
1496 return addSpace;
1497 }
1498 nosub:
1499 if (addSpace && vpstate->varSpace != '\0') {
1500 Buf_AddByte(buf, vpstate->varSpace);
1501 }
1502 Buf_AddBytes(buf, wordLen, word);
1503 return TRUE;
1504 }
1505
1506 #ifndef NO_REGEX
1507 /*-
1508 *-----------------------------------------------------------------------
1509 * VarREError --
1510 * Print the error caused by a regcomp or regexec call.
1511 *
1512 * Side Effects:
1513 * An error gets printed.
1514 *
1515 *-----------------------------------------------------------------------
1516 */
1517 static void
1518 VarREError(int reerr, regex_t *pat, const char *str)
1519 {
1520 char *errbuf;
1521 int errlen;
1522
1523 errlen = regerror(reerr, pat, 0, 0);
1524 errbuf = bmake_malloc(errlen);
1525 regerror(reerr, pat, errbuf, errlen);
1526 Error("%s: %s", str, errbuf);
1527 free(errbuf);
1528 }
1529
1530 /* Callback function for VarModify to implement the :C/from/to/ modifier.
1531 * Perform a regex substitution on the given word. */
1532 static Boolean
1533 VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED,
1534 Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
1535 const char *word, Boolean addSpace, Buffer *buf,
1536 void *data)
1537 {
1538 VarREPattern *pat = data;
1539 int xrv;
1540 const char *wp = word;
1541 char *rp;
1542 int added = 0;
1543 int flags = 0;
1544
1545 #define MAYBE_ADD_SPACE() \
1546 if (addSpace && !added) \
1547 Buf_AddByte(buf, ' '); \
1548 added = 1
1549
1550 if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==
1551 (VAR_SUB_ONE|VAR_SUB_MATCHED))
1552 xrv = REG_NOMATCH;
1553 else {
1554 tryagain:
1555 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
1556 }
1557
1558 switch (xrv) {
1559 case 0:
1560 pat->flags |= VAR_SUB_MATCHED;
1561 if (pat->matches[0].rm_so > 0) {
1562 MAYBE_ADD_SPACE();
1563 Buf_AddBytes(buf, pat->matches[0].rm_so, wp);
1564 }
1565
1566 for (rp = pat->replace; *rp; rp++) {
1567 if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
1568 MAYBE_ADD_SPACE();
1569 Buf_AddByte(buf, rp[1]);
1570 rp++;
1571 } else if ((*rp == '&') ||
1572 ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
1573 int n;
1574 const char *subbuf;
1575 int sublen;
1576 char errstr[3];
1577
1578 if (*rp == '&') {
1579 n = 0;
1580 errstr[0] = '&';
1581 errstr[1] = '\0';
1582 } else {
1583 n = rp[1] - '0';
1584 errstr[0] = '\\';
1585 errstr[1] = rp[1];
1586 errstr[2] = '\0';
1587 rp++;
1588 }
1589
1590 if (n > pat->nsub) {
1591 Error("No subexpression %s", &errstr[0]);
1592 subbuf = "";
1593 sublen = 0;
1594 } else if ((pat->matches[n].rm_so == -1) &&
1595 (pat->matches[n].rm_eo == -1)) {
1596 Error("No match for subexpression %s", &errstr[0]);
1597 subbuf = "";
1598 sublen = 0;
1599 } else {
1600 subbuf = wp + pat->matches[n].rm_so;
1601 sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
1602 }
1603
1604 if (sublen > 0) {
1605 MAYBE_ADD_SPACE();
1606 Buf_AddBytes(buf, sublen, subbuf);
1607 }
1608 } else {
1609 MAYBE_ADD_SPACE();
1610 Buf_AddByte(buf, *rp);
1611 }
1612 }
1613 wp += pat->matches[0].rm_eo;
1614 if (pat->flags & VAR_SUB_GLOBAL) {
1615 flags |= REG_NOTBOL;
1616 if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {
1617 MAYBE_ADD_SPACE();
1618 Buf_AddByte(buf, *wp);
1619 wp++;
1620
1621 }
1622 if (*wp)
1623 goto tryagain;
1624 }
1625 if (*wp) {
1626 MAYBE_ADD_SPACE();
1627 Buf_AddBytes(buf, strlen(wp), wp);
1628 }
1629 break;
1630 default:
1631 VarREError(xrv, &pat->re, "Unexpected regex error");
1632 /* fall through */
1633 case REG_NOMATCH:
1634 if (*wp) {
1635 MAYBE_ADD_SPACE();
1636 Buf_AddBytes(buf, strlen(wp), wp);
1637 }
1638 break;
1639 }
1640 return addSpace || added;
1641 }
1642 #endif
1643
1644
1645 /* Callback function for VarModify to implement the :@var (at) ...@ modifier of
1646 * ODE make. We set the temp variable named in pattern.lhs to word and
1647 * expand pattern.rhs. */
1648 static Boolean
1649 VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED,
1650 Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
1651 const char *word, Boolean addSpace, Buffer *buf,
1652 void *data)
1653 {
1654 VarLoop *loop = data;
1655 char *s;
1656 int slen;
1657
1658 if (*word) {
1659 Var_Set_with_flags(loop->tvar, word, loop->ctxt, VAR_NO_EXPORT);
1660 s = Var_Subst(NULL, loop->str, loop->ctxt, loop->flags);
1661 if (DEBUG(VAR)) {
1662 fprintf(debug_file,
1663 "VarLoopExpand: in \"%s\", replace \"%s\" with \"%s\" "
1664 "to \"%s\"\n",
1665 word, loop->tvar, loop->str, s ? s : "(null)");
1666 }
1667 if (s != NULL && *s != '\0') {
1668 if (addSpace && *s != '\n')
1669 Buf_AddByte(buf, ' ');
1670 Buf_AddBytes(buf, (slen = strlen(s)), s);
1671 addSpace = (slen > 0 && s[slen - 1] != '\n');
1672 }
1673 free(s);
1674 }
1675 return addSpace;
1676 }
1677
1678
1679 /*-
1680 *-----------------------------------------------------------------------
1681 * VarSelectWords --
1682 * Implements the :[start..end] modifier.
1683 * This is a special case of VarModify since we want to be able
1684 * to scan the list backwards if start > end.
1685 *
1686 * Input:
1687 * str String whose words should be trimmed
1688 * seldata words to select
1689 *
1690 * Results:
1691 * A string of all the words selected.
1692 *
1693 * Side Effects:
1694 * None.
1695 *
1696 *-----------------------------------------------------------------------
1697 */
1698 static char *
1699 VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1700 const char *str, VarSelectWords_t *seldata)
1701 {
1702 Buffer buf; /* Buffer for the new string */
1703 Boolean addSpace; /* TRUE if need to add a space to the
1704 * buffer before adding the trimmed
1705 * word */
1706 char **av; /* word list */
1707 char *as; /* word list memory */
1708 int ac, i;
1709 int start, end, step;
1710
1711 Buf_Init(&buf, 0);
1712 addSpace = FALSE;
1713
1714 if (vpstate->oneBigWord) {
1715 /* fake what brk_string() would do if there were only one word */
1716 ac = 1;
1717 av = bmake_malloc((ac + 1) * sizeof(char *));
1718 as = bmake_strdup(str);
1719 av[0] = as;
1720 av[1] = NULL;
1721 } else {
1722 av = brk_string(str, &ac, FALSE, &as);
1723 }
1724
1725 /*
1726 * Now sanitize seldata.
1727 * If seldata->start or seldata->end are negative, convert them to
1728 * the positive equivalents (-1 gets converted to argc, -2 gets
1729 * converted to (argc-1), etc.).
1730 */
1731 if (seldata->start < 0)
1732 seldata->start = ac + seldata->start + 1;
1733 if (seldata->end < 0)
1734 seldata->end = ac + seldata->end + 1;
1735
1736 /*
1737 * We avoid scanning more of the list than we need to.
1738 */
1739 if (seldata->start > seldata->end) {
1740 start = MIN(ac, seldata->start) - 1;
1741 end = MAX(0, seldata->end - 1);
1742 step = -1;
1743 } else {
1744 start = MAX(0, seldata->start - 1);
1745 end = MIN(ac, seldata->end);
1746 step = 1;
1747 }
1748
1749 for (i = start;
1750 (step < 0 && i >= end) || (step > 0 && i < end);
1751 i += step) {
1752 if (av[i] && *av[i]) {
1753 if (addSpace && vpstate->varSpace != '\0') {
1754 Buf_AddByte(&buf, vpstate->varSpace);
1755 }
1756 Buf_AddBytes(&buf, strlen(av[i]), av[i]);
1757 addSpace = TRUE;
1758 }
1759 }
1760
1761 free(as);
1762 free(av);
1763
1764 return Buf_Destroy(&buf, FALSE);
1765 }
1766
1767
1768 /* Callback function for VarModify to implement the :tA modifier.
1769 * Replace each word with the result of realpath() if successful. */
1770 static Boolean
1771 VarRealpath(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1772 const char *word, Boolean addSpace, Buffer *buf,
1773 void *patternp MAKE_ATTR_UNUSED)
1774 {
1775 struct stat st;
1776 char rbuf[MAXPATHLEN];
1777 char *rp;
1778
1779 if (addSpace && vpstate->varSpace != '\0')
1780 Buf_AddByte(buf, vpstate->varSpace);
1781 rp = cached_realpath(word, rbuf);
1782 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1783 word = rp;
1784
1785 Buf_AddBytes(buf, strlen(word), word);
1786 return TRUE;
1787 }
1788
1789 /*-
1790 *-----------------------------------------------------------------------
1791 * Modify each of the words of the passed string using the given function.
1792 *
1793 * Input:
1794 * str String whose words should be trimmed
1795 * modProc Function to use to modify them
1796 * data Custom data for the modProc
1797 *
1798 * Results:
1799 * A string of all the words modified appropriately.
1800 *
1801 * Side Effects:
1802 * None.
1803 *
1804 *-----------------------------------------------------------------------
1805 */
1806 static char *
1807 VarModify(GNode *ctx, Var_Parse_State *vpstate,
1808 const char *str, VarModifyCallback modProc, void *datum)
1809 {
1810 Buffer buf; /* Buffer for the new string */
1811 Boolean addSpace; /* TRUE if need to add a space to the
1812 * buffer before adding the trimmed word */
1813 char **av; /* word list */
1814 char *as; /* word list memory */
1815 int ac, i;
1816
1817 Buf_Init(&buf, 0);
1818 addSpace = FALSE;
1819
1820 if (vpstate->oneBigWord) {
1821 /* fake what brk_string() would do if there were only one word */
1822 ac = 1;
1823 av = bmake_malloc((ac + 1) * sizeof(char *));
1824 as = bmake_strdup(str);
1825 av[0] = as;
1826 av[1] = NULL;
1827 } else {
1828 av = brk_string(str, &ac, FALSE, &as);
1829 }
1830
1831 if (DEBUG(VAR)) {
1832 fprintf(debug_file, "VarModify: split \"%s\" into %d words\n",
1833 str, ac);
1834 }
1835
1836 for (i = 0; i < ac; i++)
1837 addSpace = modProc(ctx, vpstate, av[i], addSpace, &buf, datum);
1838
1839 free(as);
1840 free(av);
1841
1842 return Buf_Destroy(&buf, FALSE);
1843 }
1844
1845
1846 static int
1847 VarWordCompare(const void *a, const void *b)
1848 {
1849 int r = strcmp(*(const char * const *)a, *(const char * const *)b);
1850 return r;
1851 }
1852
1853 static int
1854 VarWordCompareReverse(const void *a, const void *b)
1855 {
1856 int r = strcmp(*(const char * const *)b, *(const char * const *)a);
1857 return r;
1858 }
1859
1860 /*-
1861 *-----------------------------------------------------------------------
1862 * VarOrder --
1863 * Order the words in the string.
1864 *
1865 * Input:
1866 * str String whose words should be sorted.
1867 * otype How to order: s - sort, x - random.
1868 *
1869 * Results:
1870 * A string containing the words ordered.
1871 *
1872 * Side Effects:
1873 * None.
1874 *
1875 *-----------------------------------------------------------------------
1876 */
1877 static char *
1878 VarOrder(const char *str, const char otype)
1879 {
1880 Buffer buf; /* Buffer for the new string */
1881 char **av; /* word list [first word does not count] */
1882 char *as; /* word list memory */
1883 int ac, i;
1884
1885 Buf_Init(&buf, 0);
1886
1887 av = brk_string(str, &ac, FALSE, &as);
1888
1889 if (ac > 0) {
1890 switch (otype) {
1891 case 'r': /* reverse sort alphabetically */
1892 qsort(av, ac, sizeof(char *), VarWordCompareReverse);
1893 break;
1894 case 's': /* sort alphabetically */
1895 qsort(av, ac, sizeof(char *), VarWordCompare);
1896 break;
1897 case 'x': /* randomize */
1898 {
1899 /*
1900 * We will use [ac..2] range for mod factors. This will produce
1901 * random numbers in [(ac-1)..0] interval, and minimal
1902 * reasonable value for mod factor is 2 (the mod 1 will produce
1903 * 0 with probability 1).
1904 */
1905 for (i = ac - 1; i > 0; i--) {
1906 int rndidx = random() % (i + 1);
1907 char *t = av[i];
1908 av[i] = av[rndidx];
1909 av[rndidx] = t;
1910 }
1911 }
1912 }
1913 }
1914
1915 for (i = 0; i < ac; i++) {
1916 Buf_AddBytes(&buf, strlen(av[i]), av[i]);
1917 if (i != ac - 1)
1918 Buf_AddByte(&buf, ' ');
1919 }
1920
1921 free(as);
1922 free(av);
1923
1924 return Buf_Destroy(&buf, FALSE);
1925 }
1926
1927
1928 /*-
1929 *-----------------------------------------------------------------------
1930 * VarUniq --
1931 * Remove adjacent duplicate words.
1932 *
1933 * Input:
1934 * str String whose words should be sorted
1935 *
1936 * Results:
1937 * A string containing the resulting words.
1938 *
1939 * Side Effects:
1940 * None.
1941 *
1942 *-----------------------------------------------------------------------
1943 */
1944 static char *
1945 VarUniq(const char *str)
1946 {
1947 Buffer buf; /* Buffer for new string */
1948 char **av; /* List of words to affect */
1949 char *as; /* Word list memory */
1950 int ac, i, j;
1951
1952 Buf_Init(&buf, 0);
1953 av = brk_string(str, &ac, FALSE, &as);
1954
1955 if (ac > 1) {
1956 for (j = 0, i = 1; i < ac; i++)
1957 if (strcmp(av[i], av[j]) != 0 && (++j != i))
1958 av[j] = av[i];
1959 ac = j + 1;
1960 }
1961
1962 for (i = 0; i < ac; i++) {
1963 Buf_AddBytes(&buf, strlen(av[i]), av[i]);
1964 if (i != ac - 1)
1965 Buf_AddByte(&buf, ' ');
1966 }
1967
1968 free(as);
1969 free(av);
1970
1971 return Buf_Destroy(&buf, FALSE);
1972 }
1973
1974 /*-
1975 *-----------------------------------------------------------------------
1976 * VarRange --
1977 * Return an integer sequence
1978 *
1979 * Input:
1980 * str String whose words provide default range
1981 * ac range length, if 0 use str words
1982 *
1983 * Side Effects:
1984 * None.
1985 *
1986 *-----------------------------------------------------------------------
1987 */
1988 static char *
1989 VarRange(const char *str, int ac)
1990 {
1991 Buffer buf; /* Buffer for new string */
1992 char tmp[32]; /* each element */
1993 char **av; /* List of words to affect */
1994 char *as; /* Word list memory */
1995 int i, n;
1996
1997 Buf_Init(&buf, 0);
1998 if (ac > 0) {
1999 as = NULL;
2000 av = NULL;
2001 } else {
2002 av = brk_string(str, &ac, FALSE, &as);
2003 }
2004 for (i = 0; i < ac; i++) {
2005 n = snprintf(tmp, sizeof(tmp), "%d", 1 + i);
2006 if (n >= (int)sizeof(tmp))
2007 break;
2008 Buf_AddBytes(&buf, n, tmp);
2009 if (i != ac - 1)
2010 Buf_AddByte(&buf, ' ');
2011 }
2012
2013 free(as);
2014 free(av);
2015
2016 return Buf_Destroy(&buf, FALSE);
2017 }
2018
2019
2020 /*-
2021 *-----------------------------------------------------------------------
2022 * VarGetPattern --
2023 * During the parsing of a part of a modifier such as :S or :@,
2024 * pass through the tstr looking for 1) escaped delimiters,
2025 * '$'s and backslashes (place the escaped character in
2026 * uninterpreted) and 2) unescaped $'s that aren't before
2027 * the delimiter (expand the variable substitution unless flags
2028 * has VAR_NOSUBST set).
2029 * Return the expanded string or NULL if the delimiter was missing
2030 * If pattern is specified, handle escaped ampersands, and replace
2031 * unescaped ampersands with the lhs of the pattern.
2032 *
2033 * Results:
2034 * A string of all the words modified appropriately.
2035 * If length is specified, return the string length of the buffer
2036 * If flags is specified and the last character of the pattern is a
2037 * $ set the VAR_MATCH_END bit of flags.
2038 *
2039 * Side Effects:
2040 * None.
2041 *-----------------------------------------------------------------------
2042 */
2043 static char *
2044 VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
2045 VarPattern_Flags flags, const char **tstr, int delim,
2046 VarPattern_Flags *vflags, int *length, VarPattern *pattern)
2047 {
2048 const char *cp;
2049 char *rstr;
2050 Buffer buf;
2051 int junk;
2052 int errnum = flags & VARF_UNDEFERR;
2053
2054 Buf_Init(&buf, 0);
2055 if (length == NULL)
2056 length = &junk;
2057
2058 #define IS_A_MATCH(cp, delim) \
2059 ((cp[0] == '\\') && ((cp[1] == delim) || \
2060 (cp[1] == '\\') || (cp[1] == '$') || (pattern && (cp[1] == '&'))))
2061
2062 /*
2063 * Skim through until the matching delimiter is found;
2064 * pick up variable substitutions on the way. Also allow
2065 * backslashes to quote the delimiter, $, and \, but don't
2066 * touch other backslashes.
2067 */
2068 for (cp = *tstr; *cp && (*cp != delim); cp++) {
2069 if (IS_A_MATCH(cp, delim)) {
2070 Buf_AddByte(&buf, cp[1]);
2071 cp++;
2072 } else if (*cp == '$') {
2073 if (cp[1] == delim) {
2074 if (vflags == NULL)
2075 Buf_AddByte(&buf, *cp);
2076 else
2077 /*
2078 * Unescaped $ at end of pattern => anchor
2079 * pattern at end.
2080 */
2081 *vflags |= VAR_MATCH_END;
2082 } else {
2083 if (vflags == NULL || (*vflags & VAR_NOSUBST) == 0) {
2084 char *cp2;
2085 int len;
2086 void *freeIt;
2087
2088 /*
2089 * If unescaped dollar sign not before the
2090 * delimiter, assume it's a variable
2091 * substitution and recurse.
2092 */
2093 cp2 = Var_Parse(cp, ctxt, errnum | (flags & VARF_WANTRES),
2094 &len, &freeIt);
2095 Buf_AddBytes(&buf, strlen(cp2), cp2);
2096 free(freeIt);
2097 cp += len - 1;
2098 } else {
2099 const char *cp2 = &cp[1];
2100
2101 if (*cp2 == PROPEN || *cp2 == BROPEN) {
2102 /*
2103 * Find the end of this variable reference
2104 * and suck it in without further ado.
2105 * It will be interpreted later.
2106 */
2107 int have = *cp2;
2108 int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE;
2109 int depth = 1;
2110
2111 for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) {
2112 if (cp2[-1] != '\\') {
2113 if (*cp2 == have)
2114 ++depth;
2115 if (*cp2 == want)
2116 --depth;
2117 }
2118 }
2119 Buf_AddBytes(&buf, cp2 - cp, cp);
2120 cp = --cp2;
2121 } else
2122 Buf_AddByte(&buf, *cp);
2123 }
2124 }
2125 } else if (pattern && *cp == '&')
2126 Buf_AddBytes(&buf, pattern->leftLen, pattern->lhs);
2127 else
2128 Buf_AddByte(&buf, *cp);
2129 }
2130
2131 if (*cp != delim) {
2132 *tstr = cp;
2133 *length = 0;
2134 return NULL;
2135 }
2136
2137 *tstr = ++cp;
2138 *length = Buf_Size(&buf);
2139 rstr = Buf_Destroy(&buf, FALSE);
2140 if (DEBUG(VAR))
2141 fprintf(debug_file, "Modifier pattern: \"%s\"\n", rstr);
2142 return rstr;
2143 }
2144
2145 /*-
2146 *-----------------------------------------------------------------------
2147 * VarQuote --
2148 * Quote shell meta-characters and space characters in the string
2149 * if quoteDollar is set, also quote and double any '$' characters.
2150 *
2151 * Results:
2152 * The quoted string
2153 *
2154 * Side Effects:
2155 * None.
2156 *
2157 *-----------------------------------------------------------------------
2158 */
2159 static char *
2160 VarQuote(char *str, Boolean quoteDollar)
2161 {
2162
2163 Buffer buf;
2164 const char *newline;
2165 size_t nlen;
2166
2167 if ((newline = Shell_GetNewline()) == NULL)
2168 newline = "\\\n";
2169 nlen = strlen(newline);
2170
2171 Buf_Init(&buf, 0);
2172
2173 for (; *str != '\0'; str++) {
2174 if (*str == '\n') {
2175 Buf_AddBytes(&buf, nlen, newline);
2176 continue;
2177 }
2178 if (isspace((unsigned char)*str) || ismeta((unsigned char)*str))
2179 Buf_AddByte(&buf, '\\');
2180 Buf_AddByte(&buf, *str);
2181 if (quoteDollar && *str == '$')
2182 Buf_AddBytes(&buf, 2, "\\$");
2183 }
2184
2185 str = Buf_Destroy(&buf, FALSE);
2186 if (DEBUG(VAR))
2187 fprintf(debug_file, "QuoteMeta: [%s]\n", str);
2188 return str;
2189 }
2190
2191 /*-
2192 *-----------------------------------------------------------------------
2193 * VarHash --
2194 * Hash the string using the MurmurHash3 algorithm.
2195 * Output is computed using 32bit Little Endian arithmetic.
2196 *
2197 * Input:
2198 * str String to modify
2199 *
2200 * Results:
2201 * Hash value of str, encoded as 8 hex digits.
2202 *
2203 * Side Effects:
2204 * None.
2205 *
2206 *-----------------------------------------------------------------------
2207 */
2208 static char *
2209 VarHash(const char *str)
2210 {
2211 static const char hexdigits[16] = "0123456789abcdef";
2212 Buffer buf;
2213 size_t len, len2;
2214 const unsigned char *ustr = (const unsigned char *)str;
2215 uint32_t h, k, c1, c2;
2216
2217 h = 0x971e137bU;
2218 c1 = 0x95543787U;
2219 c2 = 0x2ad7eb25U;
2220 len2 = strlen(str);
2221
2222 for (len = len2; len; ) {
2223 k = 0;
2224 switch (len) {
2225 default:
2226 k = ((uint32_t)ustr[3] << 24) |
2227 ((uint32_t)ustr[2] << 16) |
2228 ((uint32_t)ustr[1] << 8) |
2229 (uint32_t)ustr[0];
2230 len -= 4;
2231 ustr += 4;
2232 break;
2233 case 3:
2234 k |= (uint32_t)ustr[2] << 16;
2235 /* FALLTHROUGH */
2236 case 2:
2237 k |= (uint32_t)ustr[1] << 8;
2238 /* FALLTHROUGH */
2239 case 1:
2240 k |= (uint32_t)ustr[0];
2241 len = 0;
2242 }
2243 c1 = c1 * 5 + 0x7b7d159cU;
2244 c2 = c2 * 5 + 0x6bce6396U;
2245 k *= c1;
2246 k = (k << 11) ^ (k >> 21);
2247 k *= c2;
2248 h = (h << 13) ^ (h >> 19);
2249 h = h * 5 + 0x52dce729U;
2250 h ^= k;
2251 }
2252 h ^= len2;
2253 h *= 0x85ebca6b;
2254 h ^= h >> 13;
2255 h *= 0xc2b2ae35;
2256 h ^= h >> 16;
2257
2258 Buf_Init(&buf, 0);
2259 for (len = 0; len < 8; ++len) {
2260 Buf_AddByte(&buf, hexdigits[h & 15]);
2261 h >>= 4;
2262 }
2263
2264 return Buf_Destroy(&buf, FALSE);
2265 }
2266
2267 static char *
2268 VarStrftime(const char *fmt, int zulu, time_t utc)
2269 {
2270 char buf[BUFSIZ];
2271
2272 if (!utc)
2273 time(&utc);
2274 if (!*fmt)
2275 fmt = "%c";
2276 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc));
2277
2278 buf[sizeof(buf) - 1] = '\0';
2279 return bmake_strdup(buf);
2280 }
2281
2282 typedef struct {
2283 /* const parameters */
2284 int startc;
2285 int endc;
2286 Var *v;
2287 GNode *ctxt;
2288 int flags;
2289 int *lengthPtr;
2290 void **freePtr;
2291
2292 /* read-write */
2293 char *nstr;
2294 const char *tstr;
2295 const char *start;
2296 const char *cp; /* Secondary pointer into str (place marker
2297 * for tstr) */
2298 char termc; /* Character which terminated scan */
2299 int cnt; /* Used to count brace pairs when variable in
2300 * in parens or braces */
2301 char delim;
2302 int modifier; /* that we are processing */
2303 Var_Parse_State parsestate; /* Flags passed to helper functions */
2304
2305 /* result */
2306 char *newStr; /* New value to return */
2307 } ApplyModifiersState;
2308
2309 /* we now have some modifiers with long names */
2310 #define STRMOD_MATCH(s, want, n) \
2311 (strncmp(s, want, n) == 0 && (s[n] == st->endc || s[n] == ':'))
2312 #define STRMOD_MATCHX(s, want, n) \
2313 (strncmp(s, want, n) == 0 && \
2314 (s[n] == st->endc || s[n] == ':' || s[n] == '='))
2315 #define CHARMOD_MATCH(c) (c == st->endc || c == ':')
2316
2317 /* :@var (at) ...${var}...@ */
2318 static Boolean
2319 ApplyModifier_At(ApplyModifiersState *st) {
2320 VarLoop loop;
2321 VarPattern_Flags vflags = VAR_NOSUBST;
2322
2323 st->cp = ++(st->tstr);
2324 st->delim = '@';
2325 loop.tvar = VarGetPattern(
2326 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2327 &vflags, &loop.tvarLen, NULL);
2328 if (loop.tvar == NULL)
2329 return FALSE;
2330
2331 loop.str = VarGetPattern(
2332 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2333 &vflags, &loop.strLen, NULL);
2334 if (loop.str == NULL)
2335 return FALSE;
2336
2337 st->termc = *st->cp;
2338 st->delim = '\0';
2339
2340 loop.flags = st->flags & (VARF_UNDEFERR | VARF_WANTRES);
2341 loop.ctxt = st->ctxt;
2342 st->newStr = VarModify(
2343 st->ctxt, &st->parsestate, st->nstr, VarLoopExpand, &loop);
2344 Var_Delete(loop.tvar, st->ctxt);
2345 free(loop.tvar);
2346 free(loop.str);
2347 return TRUE;
2348 }
2349
2350 /* :Ddefined or :Uundefined */
2351 static void
2352 ApplyModifier_Defined(ApplyModifiersState *st)
2353 {
2354 Buffer buf; /* Buffer for patterns */
2355 int nflags;
2356
2357 if (st->flags & VARF_WANTRES) {
2358 int wantres;
2359 if (*st->tstr == 'U')
2360 wantres = ((st->v->flags & VAR_JUNK) != 0);
2361 else
2362 wantres = ((st->v->flags & VAR_JUNK) == 0);
2363 nflags = st->flags & ~VARF_WANTRES;
2364 if (wantres)
2365 nflags |= VARF_WANTRES;
2366 } else
2367 nflags = st->flags;
2368
2369 /*
2370 * Pass through tstr looking for 1) escaped delimiters,
2371 * '$'s and backslashes (place the escaped character in
2372 * uninterpreted) and 2) unescaped $'s that aren't before
2373 * the delimiter (expand the variable substitution).
2374 * The result is left in the Buffer buf.
2375 */
2376 Buf_Init(&buf, 0);
2377 for (st->cp = st->tstr + 1;
2378 *st->cp != st->endc && *st->cp != ':' && *st->cp != '\0';
2379 st->cp++) {
2380 if (*st->cp == '\\' &&
2381 (st->cp[1] == ':' || st->cp[1] == '$' || st->cp[1] == st->endc ||
2382 st->cp[1] == '\\')) {
2383 Buf_AddByte(&buf, st->cp[1]);
2384 st->cp++;
2385 } else if (*st->cp == '$') {
2386 /*
2387 * If unescaped dollar sign, assume it's a
2388 * variable substitution and recurse.
2389 */
2390 char *cp2;
2391 int len;
2392 void *freeIt;
2393
2394 cp2 = Var_Parse(st->cp, st->ctxt, nflags, &len, &freeIt);
2395 Buf_AddBytes(&buf, strlen(cp2), cp2);
2396 free(freeIt);
2397 st->cp += len - 1;
2398 } else {
2399 Buf_AddByte(&buf, *st->cp);
2400 }
2401 }
2402
2403 st->termc = *st->cp;
2404
2405 if (st->v->flags & VAR_JUNK)
2406 st->v->flags |= VAR_KEEP;
2407 if (nflags & VARF_WANTRES) {
2408 st->newStr = Buf_Destroy(&buf, FALSE);
2409 } else {
2410 st->newStr = st->nstr;
2411 Buf_Destroy(&buf, TRUE);
2412 }
2413 }
2414
2415 /* :gmtime */
2416 static Boolean
2417 ApplyModifier_Gmtime(ApplyModifiersState *st)
2418 {
2419 time_t utc;
2420 char *ep;
2421
2422 st->cp = st->tstr + 1; /* make sure it is set */
2423 if (!STRMOD_MATCHX(st->tstr, "gmtime", 6))
2424 return FALSE;
2425 if (st->tstr[6] == '=') {
2426 utc = strtoul(&st->tstr[7], &ep, 10);
2427 st->cp = ep;
2428 } else {
2429 utc = 0;
2430 st->cp = st->tstr + 6;
2431 }
2432 st->newStr = VarStrftime(st->nstr, 1, utc);
2433 st->termc = *st->cp;
2434 return TRUE;
2435 }
2436
2437 /* :localtime */
2438 static Boolean
2439 ApplyModifier_Localtime(ApplyModifiersState *st)
2440 {
2441 time_t utc;
2442 char *ep;
2443
2444 st->cp = st->tstr + 1; /* make sure it is set */
2445 if (!STRMOD_MATCHX(st->tstr, "localtime", 9))
2446 return FALSE;
2447
2448 if (st->tstr[9] == '=') {
2449 utc = strtoul(&st->tstr[10], &ep, 10);
2450 st->cp = ep;
2451 } else {
2452 utc = 0;
2453 st->cp = st->tstr + 9;
2454 }
2455 st->newStr = VarStrftime(st->nstr, 0, utc);
2456 st->termc = *st->cp;
2457 return TRUE;
2458 }
2459
2460 /* :hash */
2461 static Boolean
2462 ApplyModifier_Hash(ApplyModifiersState *st)
2463 {
2464 st->cp = st->tstr + 1; /* make sure it is set */
2465 if (!STRMOD_MATCH(st->tstr, "hash", 4))
2466 return FALSE;
2467 st->newStr = VarHash(st->nstr);
2468 st->cp = st->tstr + 4;
2469 st->termc = *st->cp;
2470 return TRUE;
2471 }
2472
2473 /* :P */
2474 static void
2475 ApplyModifier_Path(ApplyModifiersState *st)
2476 {
2477 GNode *gn;
2478
2479 if ((st->v->flags & VAR_JUNK) != 0)
2480 st->v->flags |= VAR_KEEP;
2481 gn = Targ_FindNode(st->v->name, TARG_NOCREATE);
2482 if (gn == NULL || gn->type & OP_NOPATH) {
2483 st->newStr = NULL;
2484 } else if (gn->path) {
2485 st->newStr = bmake_strdup(gn->path);
2486 } else {
2487 st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn));
2488 }
2489 if (!st->newStr)
2490 st->newStr = bmake_strdup(st->v->name);
2491 st->cp = ++st->tstr;
2492 st->termc = *st->tstr;
2493 }
2494
2495 /* :!cmd! */
2496 static Boolean
2497 ApplyModifier_Exclam(ApplyModifiersState *st)
2498 {
2499 const char *emsg;
2500 VarPattern pattern;
2501
2502 pattern.flags = 0;
2503
2504 st->delim = '!';
2505 emsg = NULL;
2506 st->cp = ++st->tstr;
2507 pattern.rhs = VarGetPattern(
2508 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2509 NULL, &pattern.rightLen, NULL);
2510 if (pattern.rhs == NULL)
2511 return FALSE;
2512 if (st->flags & VARF_WANTRES)
2513 st->newStr = Cmd_Exec(pattern.rhs, &emsg);
2514 else
2515 st->newStr = varNoError;
2516 free(UNCONST(pattern.rhs));
2517 if (emsg)
2518 Error(emsg, st->nstr);
2519 st->termc = *st->cp;
2520 st->delim = '\0';
2521 if (st->v->flags & VAR_JUNK)
2522 st->v->flags |= VAR_KEEP;
2523 return TRUE;
2524 }
2525
2526 /* :range */
2527 static Boolean
2528 ApplyModifier_Range(ApplyModifiersState *st)
2529 {
2530 int n;
2531 char *ep;
2532
2533 st->cp = st->tstr + 1; /* make sure it is set */
2534 if (!STRMOD_MATCHX(st->tstr, "range", 5))
2535 return FALSE;
2536
2537 if (st->tstr[5] == '=') {
2538 n = strtoul(&st->tstr[6], &ep, 10);
2539 st->cp = ep;
2540 } else {
2541 n = 0;
2542 st->cp = st->tstr + 5;
2543 }
2544 st->newStr = VarRange(st->nstr, n);
2545 st->termc = *st->cp;
2546 return TRUE;
2547 }
2548
2549 /* :Mpattern or :Npattern */
2550 static void
2551 ApplyModifier_Match(ApplyModifiersState *st)
2552 {
2553 char *pattern;
2554 const char *endpat; /* points just after end of pattern */
2555 char *cp2;
2556 Boolean copy; /* pattern should be, or has been, copied */
2557 Boolean needSubst;
2558 int nest;
2559
2560 copy = FALSE;
2561 needSubst = FALSE;
2562 nest = 1;
2563 /*
2564 * In the loop below, ignore ':' unless we are at
2565 * (or back to) the original brace level.
2566 * XXX This will likely not work right if $() and ${}
2567 * are intermixed.
2568 */
2569 for (st->cp = st->tstr + 1;
2570 *st->cp != '\0' && !(*st->cp == ':' && nest == 1);
2571 st->cp++) {
2572 if (*st->cp == '\\' &&
2573 (st->cp[1] == ':' || st->cp[1] == st->endc ||
2574 st->cp[1] == st->startc)) {
2575 if (!needSubst)
2576 copy = TRUE;
2577 st->cp++;
2578 continue;
2579 }
2580 if (*st->cp == '$')
2581 needSubst = TRUE;
2582 if (*st->cp == '(' || *st->cp == '{')
2583 ++nest;
2584 if (*st->cp == ')' || *st->cp == '}') {
2585 --nest;
2586 if (nest == 0)
2587 break;
2588 }
2589 }
2590 st->termc = *st->cp;
2591 endpat = st->cp;
2592 if (copy) {
2593 /*
2594 * Need to compress the \:'s out of the pattern, so
2595 * allocate enough room to hold the uncompressed
2596 * pattern (note that st->cp started at st->tstr+1, so
2597 * st->cp - st->tstr takes the null byte into account) and
2598 * compress the pattern into the space.
2599 */
2600 pattern = bmake_malloc(st->cp - st->tstr);
2601 for (cp2 = pattern, st->cp = st->tstr + 1;
2602 st->cp < endpat;
2603 st->cp++, cp2++) {
2604 if ((*st->cp == '\\') && (st->cp+1 < endpat) &&
2605 (st->cp[1] == ':' || st->cp[1] == st->endc))
2606 st->cp++;
2607 *cp2 = *st->cp;
2608 }
2609 *cp2 = '\0';
2610 endpat = cp2;
2611 } else {
2612 /*
2613 * Either Var_Subst or VarModify will need a
2614 * nul-terminated string soon, so construct one now.
2615 */
2616 pattern = bmake_strndup(st->tstr+1, endpat - (st->tstr + 1));
2617 }
2618 if (needSubst) {
2619 /* pattern contains embedded '$', so use Var_Subst to expand it. */
2620 cp2 = pattern;
2621 pattern = Var_Subst(NULL, cp2, st->ctxt, st->flags);
2622 free(cp2);
2623 }
2624 if (DEBUG(VAR))
2625 fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n",
2626 st->v->name, st->nstr, pattern);
2627 if (*st->tstr == 'M') {
2628 st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr, VarMatch,
2629 pattern);
2630 } else {
2631 st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr, VarNoMatch,
2632 pattern);
2633 }
2634 free(pattern);
2635 }
2636
2637 /* :S,from,to, */
2638 static Boolean
2639 ApplyModifier_Subst(ApplyModifiersState *st)
2640 {
2641 VarPattern pattern;
2642 Var_Parse_State tmpparsestate;
2643
2644 pattern.flags = 0;
2645 tmpparsestate = st->parsestate;
2646 st->delim = st->tstr[1];
2647 st->tstr += 2;
2648
2649 /*
2650 * If pattern begins with '^', it is anchored to the
2651 * start of the word -- skip over it and flag pattern.
2652 */
2653 if (*st->tstr == '^') {
2654 pattern.flags |= VAR_MATCH_START;
2655 st->tstr += 1;
2656 }
2657
2658 st->cp = st->tstr;
2659 pattern.lhs = VarGetPattern(
2660 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2661 &pattern.flags, &pattern.leftLen, NULL);
2662 if (pattern.lhs == NULL)
2663 return FALSE;
2664
2665 pattern.rhs = VarGetPattern(
2666 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2667 NULL, &pattern.rightLen, &pattern);
2668 if (pattern.rhs == NULL)
2669 return FALSE;
2670
2671 /*
2672 * Check for global substitution. If 'g' after the final
2673 * delimiter, substitution is global and is marked that
2674 * way.
2675 */
2676 for (;; st->cp++) {
2677 switch (*st->cp) {
2678 case 'g':
2679 pattern.flags |= VAR_SUB_GLOBAL;
2680 continue;
2681 case '1':
2682 pattern.flags |= VAR_SUB_ONE;
2683 continue;
2684 case 'W':
2685 tmpparsestate.oneBigWord = TRUE;
2686 continue;
2687 }
2688 break;
2689 }
2690
2691 st->termc = *st->cp;
2692 st->newStr = VarModify(
2693 st->ctxt, &tmpparsestate, st->nstr, VarSubstitute, &pattern);
2694
2695 /* Free the two strings. */
2696 free(UNCONST(pattern.lhs));
2697 free(UNCONST(pattern.rhs));
2698 st->delim = '\0';
2699 return TRUE;
2700 }
2701
2702 #ifndef NO_REGEX
2703 /* :C,from,to, */
2704 static Boolean
2705 ApplyModifier_Regex(ApplyModifiersState *st)
2706 {
2707 VarREPattern pattern;
2708 char *re;
2709 int error;
2710 Var_Parse_State tmpparsestate;
2711
2712 pattern.flags = 0;
2713 tmpparsestate = st->parsestate;
2714 st->delim = st->tstr[1];
2715 st->tstr += 2;
2716
2717 st->cp = st->tstr;
2718
2719 re = VarGetPattern(
2720 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2721 NULL, NULL, NULL);
2722 if (re == NULL)
2723 return FALSE;
2724
2725 pattern.replace = VarGetPattern(
2726 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2727 NULL, NULL, NULL);
2728 if (pattern.replace == NULL) {
2729 free(re);
2730 return FALSE;
2731 }
2732
2733 for (;; st->cp++) {
2734 switch (*st->cp) {
2735 case 'g':
2736 pattern.flags |= VAR_SUB_GLOBAL;
2737 continue;
2738 case '1':
2739 pattern.flags |= VAR_SUB_ONE;
2740 continue;
2741 case 'W':
2742 tmpparsestate.oneBigWord = TRUE;
2743 continue;
2744 }
2745 break;
2746 }
2747
2748 st->termc = *st->cp;
2749
2750 error = regcomp(&pattern.re, re, REG_EXTENDED);
2751 free(re);
2752 if (error) {
2753 *st->lengthPtr = st->cp - st->start + 1;
2754 VarREError(error, &pattern.re, "RE substitution error");
2755 free(pattern.replace);
2756 return FALSE;
2757 }
2758
2759 pattern.nsub = pattern.re.re_nsub + 1;
2760 if (pattern.nsub < 1)
2761 pattern.nsub = 1;
2762 if (pattern.nsub > 10)
2763 pattern.nsub = 10;
2764 pattern.matches = bmake_malloc(pattern.nsub * sizeof(regmatch_t));
2765 st->newStr = VarModify(
2766 st->ctxt, &tmpparsestate, st->nstr, VarRESubstitute, &pattern);
2767 regfree(&pattern.re);
2768 free(pattern.replace);
2769 free(pattern.matches);
2770 st->delim = '\0';
2771 return TRUE;
2772 }
2773 #endif
2774
2775 /* :tA, :tu, :tl, etc. */
2776 static Boolean
2777 ApplyModifier_To(ApplyModifiersState *st)
2778 {
2779 st->cp = st->tstr + 1; /* make sure it is set */
2780 if (st->tstr[1] != st->endc && st->tstr[1] != ':') {
2781 if (st->tstr[1] == 's') {
2782 /* Use the char (if any) at st->tstr[2] as the word separator. */
2783 VarPattern pattern;
2784
2785 if (st->tstr[2] != st->endc &&
2786 (st->tstr[3] == st->endc || st->tstr[3] == ':')) {
2787 /* ":ts<unrecognised><endc>" or
2788 * ":ts<unrecognised>:" */
2789 st->parsestate.varSpace = st->tstr[2];
2790 st->cp = st->tstr + 3;
2791 } else if (st->tstr[2] == st->endc || st->tstr[2] == ':') {
2792 /* ":ts<endc>" or ":ts:" */
2793 st->parsestate.varSpace = 0; /* no separator */
2794 st->cp = st->tstr + 2;
2795 } else if (st->tstr[2] == '\\') {
2796 const char *xp = &st->tstr[3];
2797 int base = 8; /* assume octal */
2798
2799 switch (st->tstr[3]) {
2800 case 'n':
2801 st->parsestate.varSpace = '\n';
2802 st->cp = st->tstr + 4;
2803 break;
2804 case 't':
2805 st->parsestate.varSpace = '\t';
2806 st->cp = st->tstr + 4;
2807 break;
2808 case 'x':
2809 base = 16;
2810 xp++;
2811 goto get_numeric;
2812 case '0':
2813 base = 0;
2814 goto get_numeric;
2815 default:
2816 if (isdigit((unsigned char)st->tstr[3])) {
2817 char *ep;
2818 get_numeric:
2819 st->parsestate.varSpace = strtoul(xp, &ep, base);
2820 if (*ep != ':' && *ep != st->endc)
2821 return FALSE;
2822 st->cp = ep;
2823 } else {
2824 /* ":ts<backslash><unrecognised>". */
2825 return FALSE;
2826 }
2827 break;
2828 }
2829 } else {
2830 /* Found ":ts<unrecognised><unrecognised>". */
2831 return FALSE;
2832 }
2833
2834 st->termc = *st->cp;
2835
2836 /*
2837 * We cannot be certain that VarModify will be used - even if there
2838 * is a subsequent modifier, so do a no-op VarSubstitute now to for
2839 * str to be re-expanded without the spaces.
2840 */
2841 pattern.flags = VAR_SUB_ONE;
2842 pattern.lhs = pattern.rhs = "\032";
2843 pattern.leftLen = pattern.rightLen = 1;
2844
2845 st->newStr = VarModify(
2846 st->ctxt, &st->parsestate, st->nstr, VarSubstitute, &pattern);
2847 } else if (st->tstr[2] == st->endc || st->tstr[2] == ':') {
2848 /* Check for two-character options: ":tu", ":tl" */
2849 if (st->tstr[1] == 'A') { /* absolute path */
2850 st->newStr = VarModify(
2851 st->ctxt, &st->parsestate, st->nstr, VarRealpath, NULL);
2852 st->cp = st->tstr + 2;
2853 st->termc = *st->cp;
2854 } else if (st->tstr[1] == 'u') {
2855 char *dp = bmake_strdup(st->nstr);
2856 for (st->newStr = dp; *dp; dp++)
2857 *dp = toupper((unsigned char)*dp);
2858 st->cp = st->tstr + 2;
2859 st->termc = *st->cp;
2860 } else if (st->tstr[1] == 'l') {
2861 char *dp = bmake_strdup(st->nstr);
2862 for (st->newStr = dp; *dp; dp++)
2863 *dp = tolower((unsigned char)*dp);
2864 st->cp = st->tstr + 2;
2865 st->termc = *st->cp;
2866 } else if (st->tstr[1] == 'W' || st->tstr[1] == 'w') {
2867 st->parsestate.oneBigWord = (st->tstr[1] == 'W');
2868 st->newStr = st->nstr;
2869 st->cp = st->tstr + 2;
2870 st->termc = *st->cp;
2871 } else {
2872 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2873 return FALSE;
2874 }
2875 } else {
2876 /* Found ":t<unrecognised><unrecognised>". */
2877 return FALSE;
2878 }
2879 } else {
2880 /* Found ":t<endc>" or ":t:". */
2881 return FALSE;
2882 }
2883 return TRUE;
2884 }
2885
2886 /* :[#], :[1], etc. */
2887 static int
2888 ApplyModifier_Words(ApplyModifiersState *st)
2889 {
2890 /*
2891 * Look for the closing ']', recursively
2892 * expanding any embedded variables.
2893 *
2894 * estr is a pointer to the expanded result,
2895 * which we must free().
2896 */
2897 char *estr;
2898
2899 st->cp = st->tstr + 1; /* point to char after '[' */
2900 st->delim = ']'; /* look for closing ']' */
2901 estr = VarGetPattern(
2902 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2903 NULL, NULL, NULL);
2904 if (estr == NULL)
2905 return 'c'; /* report missing ']' */
2906 /* now st->cp points just after the closing ']' */
2907 st->delim = '\0';
2908 if (st->cp[0] != ':' && st->cp[0] != st->endc) {
2909 /* Found junk after ']' */
2910 free(estr);
2911 return 'b';
2912 }
2913 if (estr[0] == '\0') {
2914 /* Found empty square brackets in ":[]". */
2915 free(estr);
2916 return 'b';
2917 } else if (estr[0] == '#' && estr[1] == '\0') {
2918 /* Found ":[#]" */
2919
2920 /*
2921 * We will need enough space for the decimal
2922 * representation of an int. We calculate the
2923 * space needed for the octal representation,
2924 * and add enough slop to cope with a '-' sign
2925 * (which should never be needed) and a '\0'
2926 * string terminator.
2927 */
2928 int newStrSize = (sizeof(int) * CHAR_BIT + 2) / 3 + 2;
2929
2930 st->newStr = bmake_malloc(newStrSize);
2931 if (st->parsestate.oneBigWord) {
2932 strncpy(st->newStr, "1", newStrSize);
2933 } else {
2934 /* XXX: brk_string() is a rather expensive
2935 * way of counting words. */
2936 char **av;
2937 char *as;
2938 int ac;
2939
2940 av = brk_string(st->nstr, &ac, FALSE, &as);
2941 snprintf(st->newStr, newStrSize, "%d", ac);
2942 free(as);
2943 free(av);
2944 }
2945 st->termc = *st->cp;
2946 free(estr);
2947 return 0;
2948 } else if (estr[0] == '*' && estr[1] == '\0') {
2949 /* Found ":[*]" */
2950 st->parsestate.oneBigWord = TRUE;
2951 st->newStr = st->nstr;
2952 st->termc = *st->cp;
2953 free(estr);
2954 return 0;
2955 } else if (estr[0] == '@' && estr[1] == '\0') {
2956 /* Found ":[@]" */
2957 st->parsestate.oneBigWord = FALSE;
2958 st->newStr = st->nstr;
2959 st->termc = *st->cp;
2960 free(estr);
2961 return 0;
2962 } else {
2963 char *ep;
2964 /*
2965 * We expect estr to contain a single
2966 * integer for :[N], or two integers
2967 * separated by ".." for :[start..end].
2968 */
2969 VarSelectWords_t seldata = { 0, 0 };
2970
2971 seldata.start = strtol(estr, &ep, 0);
2972 if (ep == estr) {
2973 /* Found junk instead of a number */
2974 free(estr);
2975 return 'b';
2976 } else if (ep[0] == '\0') {
2977 /* Found only one integer in :[N] */
2978 seldata.end = seldata.start;
2979 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') {
2980 /* Expecting another integer after ".." */
2981 ep += 2;
2982 seldata.end = strtol(ep, &ep, 0);
2983 if (ep[0] != '\0') {
2984 /* Found junk after ".." */
2985 free(estr);
2986 return 'b';
2987 }
2988 } else {
2989 /* Found junk instead of ".." */
2990 free(estr);
2991 return 'b';
2992 }
2993 /*
2994 * Now seldata is properly filled in,
2995 * but we still have to check for 0 as
2996 * a special case.
2997 */
2998 if (seldata.start == 0 && seldata.end == 0) {
2999 /* ":[0]" or perhaps ":[0..0]" */
3000 st->parsestate.oneBigWord = TRUE;
3001 st->newStr = st->nstr;
3002 st->termc = *st->cp;
3003 free(estr);
3004 return 0;
3005 } else if (seldata.start == 0 || seldata.end == 0) {
3006 /* ":[0..N]" or ":[N..0]" */
3007 free(estr);
3008 return 'b';
3009 }
3010 /* Normal case: select the words described by seldata. */
3011 st->newStr = VarSelectWords(
3012 st->ctxt, &st->parsestate, st->nstr, &seldata);
3013
3014 st->termc = *st->cp;
3015 free(estr);
3016 return 0;
3017 }
3018 }
3019
3020 /* :O or :Ox */
3021 static Boolean
3022 ApplyModifier_Order(ApplyModifiersState *st)
3023 {
3024 char otype;
3025
3026 st->cp = st->tstr + 1; /* skip to the rest in any case */
3027 if (st->tstr[1] == st->endc || st->tstr[1] == ':') {
3028 otype = 's';
3029 st->termc = *st->cp;
3030 } else if ((st->tstr[1] == 'r' || st->tstr[1] == 'x') &&
3031 (st->tstr[2] == st->endc || st->tstr[2] == ':')) {
3032 otype = st->tstr[1];
3033 st->cp = st->tstr + 2;
3034 st->termc = *st->cp;
3035 } else {
3036 return FALSE;
3037 }
3038 st->newStr = VarOrder(st->nstr, otype);
3039 return TRUE;
3040 }
3041
3042 /* :? then : else */
3043 static Boolean
3044 ApplyModifier_IfElse(ApplyModifiersState *st)
3045 {
3046 VarPattern pattern;
3047 Boolean value;
3048 int cond_rc;
3049 VarPattern_Flags lhs_flags, rhs_flags;
3050
3051 /* find ':', and then substitute accordingly */
3052 if (st->flags & VARF_WANTRES) {
3053 cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE);
3054 if (cond_rc == COND_INVALID) {
3055 lhs_flags = rhs_flags = VAR_NOSUBST;
3056 } else if (value) {
3057 lhs_flags = 0;
3058 rhs_flags = VAR_NOSUBST;
3059 } else {
3060 lhs_flags = VAR_NOSUBST;
3061 rhs_flags = 0;
3062 }
3063 } else {
3064 /* we are just consuming and discarding */
3065 cond_rc = value = 0;
3066 lhs_flags = rhs_flags = VAR_NOSUBST;
3067 }
3068 pattern.flags = 0;
3069
3070 st->cp = ++st->tstr;
3071 st->delim = ':';
3072 pattern.lhs = VarGetPattern(
3073 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
3074 &lhs_flags, &pattern.leftLen, NULL);
3075 if (pattern.lhs == NULL)
3076 return FALSE;
3077
3078 /* BROPEN or PROPEN */
3079 st->delim = st->endc;
3080 pattern.rhs = VarGetPattern(
3081 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
3082 &rhs_flags, &pattern.rightLen, NULL);
3083 if (pattern.rhs == NULL)
3084 return FALSE;
3085
3086 st->termc = *--st->cp;
3087 st->delim = '\0';
3088 if (cond_rc == COND_INVALID) {
3089 Error("Bad conditional expression `%s' in %s?%s:%s",
3090 st->v->name, st->v->name, pattern.lhs, pattern.rhs);
3091 return FALSE;
3092 }
3093
3094 if (value) {
3095 st->newStr = UNCONST(pattern.lhs);
3096 free(UNCONST(pattern.rhs));
3097 } else {
3098 st->newStr = UNCONST(pattern.rhs);
3099 free(UNCONST(pattern.lhs));
3100 }
3101 if (st->v->flags & VAR_JUNK)
3102 st->v->flags |= VAR_KEEP;
3103 return TRUE;
3104 }
3105
3106 /* "::=", "::!=", "::+=", or "::?=" */
3107 static int
3108 ApplyModifier_Assign(ApplyModifiersState *st)
3109 {
3110 if (st->tstr[1] == '=' ||
3111 (st->tstr[2] == '=' &&
3112 (st->tstr[1] == '!' || st->tstr[1] == '+' || st->tstr[1] == '?'))) {
3113 GNode *v_ctxt; /* context where v belongs */
3114 const char *emsg;
3115 char *sv_name;
3116 VarPattern pattern;
3117 int how;
3118 VarPattern_Flags vflags;
3119
3120 if (st->v->name[0] == 0)
3121 return 'b';
3122
3123 v_ctxt = st->ctxt;
3124 sv_name = NULL;
3125 ++st->tstr;
3126 if (st->v->flags & VAR_JUNK) {
3127 /*
3128 * We need to bmake_strdup() it incase
3129 * VarGetPattern() recurses.
3130 */
3131 sv_name = st->v->name;
3132 st->v->name = bmake_strdup(st->v->name);
3133 } else if (st->ctxt != VAR_GLOBAL) {
3134 Var *gv = VarFind(st->v->name, st->ctxt, 0);
3135 if (gv == NULL)
3136 v_ctxt = VAR_GLOBAL;
3137 else
3138 VarFreeEnv(gv, TRUE);
3139 }
3140
3141 switch ((how = *st->tstr)) {
3142 case '+':
3143 case '?':
3144 case '!':
3145 st->cp = &st->tstr[2];
3146 break;
3147 default:
3148 st->cp = ++st->tstr;
3149 break;
3150 }
3151 st->delim = st->startc == PROPEN ? PRCLOSE : BRCLOSE;
3152 pattern.flags = 0;
3153
3154 vflags = (st->flags & VARF_WANTRES) ? 0 : VAR_NOSUBST;
3155 pattern.rhs = VarGetPattern(
3156 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
3157 &vflags, &pattern.rightLen, NULL);
3158 if (st->v->flags & VAR_JUNK) {
3159 /* restore original name */
3160 free(st->v->name);
3161 st->v->name = sv_name;
3162 }
3163 if (pattern.rhs == NULL)
3164 return 'c';
3165
3166 st->termc = *--st->cp;
3167 st->delim = '\0';
3168
3169 if (st->flags & VARF_WANTRES) {
3170 switch (how) {
3171 case '+':
3172 Var_Append(st->v->name, pattern.rhs, v_ctxt);
3173 break;
3174 case '!':
3175 st->newStr = Cmd_Exec(pattern.rhs, &emsg);
3176 if (emsg)
3177 Error(emsg, st->nstr);
3178 else
3179 Var_Set(st->v->name, st->newStr, v_ctxt);
3180 free(st->newStr);
3181 break;
3182 case '?':
3183 if ((st->v->flags & VAR_JUNK) == 0)
3184 break;
3185 /* FALLTHROUGH */
3186 default:
3187 Var_Set(st->v->name, pattern.rhs, v_ctxt);
3188 break;
3189 }
3190 }
3191 free(UNCONST(pattern.rhs));
3192 st->newStr = varNoError;
3193 return 0;
3194 }
3195 return 'd'; /* "::<unrecognised>" */
3196 }
3197
3198 /* remember current value */
3199 static Boolean
3200 ApplyModifier_Remember(ApplyModifiersState *st)
3201 {
3202 st->cp = st->tstr + 1; /* make sure it is set */
3203 if (!STRMOD_MATCHX(st->tstr, "_", 1))
3204 return FALSE;
3205
3206 if (st->tstr[1] == '=') {
3207 char *np;
3208 int n;
3209
3210 st->cp++;
3211 n = strcspn(st->cp, ":)}");
3212 np = bmake_strndup(st->cp, n + 1);
3213 np[n] = '\0';
3214 st->cp = st->tstr + 2 + n;
3215 Var_Set(np, st->nstr, st->ctxt);
3216 free(np);
3217 } else {
3218 Var_Set("_", st->nstr, st->ctxt);
3219 }
3220 st->newStr = st->nstr;
3221 st->termc = *st->cp;
3222 return TRUE;
3223 }
3224
3225 #ifdef SYSVVARSUB
3226 /* :from=to */
3227 static int
3228 ApplyModifier_SysV(ApplyModifiersState *st)
3229 {
3230 /*
3231 * This can either be a bogus modifier or a System-V
3232 * substitution command.
3233 */
3234 VarPattern pattern;
3235 Boolean eqFound = FALSE;
3236
3237 pattern.flags = 0;
3238
3239 /*
3240 * First we make a pass through the string trying
3241 * to verify it is a SYSV-make-style translation:
3242 * it must be: <string1>=<string2>)
3243 */
3244 st->cp = st->tstr;
3245 st->cnt = 1;
3246 while (*st->cp != '\0' && st->cnt) {
3247 if (*st->cp == '=') {
3248 eqFound = TRUE;
3249 /* continue looking for st->endc */
3250 } else if (*st->cp == st->endc)
3251 st->cnt--;
3252 else if (*st->cp == st->startc)
3253 st->cnt++;
3254 if (st->cnt)
3255 st->cp++;
3256 }
3257 if (*st->cp != st->endc || !eqFound)
3258 return 0;
3259
3260 st->delim = '=';
3261 st->cp = st->tstr;
3262 pattern.lhs = VarGetPattern(
3263 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
3264 &pattern.flags, &pattern.leftLen, NULL);
3265 if (pattern.lhs == NULL)
3266 return 'c';
3267
3268 st->delim = st->endc;
3269 pattern.rhs = VarGetPattern(
3270 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
3271 NULL, &pattern.rightLen, &pattern);
3272 if (pattern.rhs == NULL)
3273 return 'c';
3274
3275 /*
3276 * SYSV modifications happen through the whole
3277 * string. Note the pattern is anchored at the end.
3278 */
3279 st->termc = *--st->cp;
3280 st->delim = '\0';
3281 if (pattern.leftLen == 0 && *st->nstr == '\0') {
3282 st->newStr = st->nstr; /* special case */
3283 } else {
3284 st->newStr = VarModify(
3285 st->ctxt, &st->parsestate, st->nstr, VarSYSVMatch, &pattern);
3286 }
3287 free(UNCONST(pattern.lhs));
3288 free(UNCONST(pattern.rhs));
3289 return '=';
3290 }
3291 #endif
3292
3293 /*
3294 * Now we need to apply any modifiers the user wants applied.
3295 * These are:
3296 * :M<pattern> words which match the given <pattern>.
3297 * <pattern> is of the standard file
3298 * wildcarding form.
3299 * :N<pattern> words which do not match the given <pattern>.
3300 * :S<d><pat1><d><pat2><d>[1gW]
3301 * Substitute <pat2> for <pat1> in the value
3302 * :C<d><pat1><d><pat2><d>[1gW]
3303 * Substitute <pat2> for regex <pat1> in the value
3304 * :H Substitute the head of each word
3305 * :T Substitute the tail of each word
3306 * :E Substitute the extension (minus '.') of
3307 * each word
3308 * :R Substitute the root of each word
3309 * (pathname minus the suffix).
3310 * :O ("Order") Alphabeticaly sort words in variable.
3311 * :Ox ("intermiX") Randomize words in variable.
3312 * :u ("uniq") Remove adjacent duplicate words.
3313 * :tu Converts the variable contents to uppercase.
3314 * :tl Converts the variable contents to lowercase.
3315 * :ts[c] Sets varSpace - the char used to
3316 * separate words to 'c'. If 'c' is
3317 * omitted then no separation is used.
3318 * :tW Treat the variable contents as a single
3319 * word, even if it contains spaces.
3320 * (Mnemonic: one big 'W'ord.)
3321 * :tw Treat the variable contents as multiple
3322 * space-separated words.
3323 * (Mnemonic: many small 'w'ords.)
3324 * :[index] Select a single word from the value.
3325 * :[start..end] Select multiple words from the value.
3326 * :[*] or :[0] Select the entire value, as a single
3327 * word. Equivalent to :tW.
3328 * :[@] Select the entire value, as multiple
3329 * words. Undoes the effect of :[*].
3330 * Equivalent to :tw.
3331 * :[#] Returns the number of words in the value.
3332 *
3333 * :?<true-value>:<false-value>
3334 * If the variable evaluates to true, return
3335 * true value, else return the second value.
3336 * :lhs=rhs Like :S, but the rhs goes to the end of
3337 * the invocation.
3338 * :sh Treat the current value as a command
3339 * to be run, new value is its output.
3340 * The following added so we can handle ODE makefiles.
3341 * :@<tmpvar>@<newval>@
3342 * Assign a temporary local variable <tmpvar>
3343 * to the current value of each word in turn
3344 * and replace each word with the result of
3345 * evaluating <newval>
3346 * :D<newval> Use <newval> as value if variable defined
3347 * :U<newval> Use <newval> as value if variable undefined
3348 * :L Use the name of the variable as the value.
3349 * :P Use the path of the node that has the same
3350 * name as the variable as the value. This
3351 * basically includes an implied :L so that
3352 * the common method of refering to the path
3353 * of your dependent 'x' in a rule is to use
3354 * the form '${x:P}'.
3355 * :!<cmd>! Run cmd much the same as :sh run's the
3356 * current value of the variable.
3357 * The ::= modifiers, actually assign a value to the variable.
3358 * Their main purpose is in supporting modifiers of .for loop
3359 * iterators and other obscure uses. They always expand to
3360 * nothing. In a target rule that would otherwise expand to an
3361 * empty line they can be preceded with @: to keep make happy.
3362 * Eg.
3363 *
3364 * foo: .USE
3365 * .for i in ${.TARGET} ${.TARGET:R}.gz
3366 * @: ${t::=$i}
3367 * @echo blah ${t:T}
3368 * .endfor
3369 *
3370 * ::=<str> Assigns <str> as the new value of variable.
3371 * ::?=<str> Assigns <str> as value of variable if
3372 * it was not already set.
3373 * ::+=<str> Appends <str> to variable.
3374 * ::!=<cmd> Assigns output of <cmd> as the new value of
3375 * variable.
3376 */
3377 static char *
3378 ApplyModifiers(char *nstr, const char *tstr,
3379 int const startc, int const endc,
3380 Var * const v, GNode * const ctxt, int const flags,
3381 int * const lengthPtr, void ** const freePtr)
3382 {
3383 ApplyModifiersState st = {
3384 startc, endc, v, ctxt, flags, lengthPtr, freePtr,
3385 nstr, tstr, tstr, tstr,
3386 '\0', 0, '\0', 0, {' ', FALSE}, NULL
3387 };
3388
3389 while (*st.tstr && *st.tstr != st.endc) {
3390
3391 if (*st.tstr == '$') {
3392 /*
3393 * We may have some complex modifiers in a variable.
3394 */
3395 void *freeIt;
3396 char *rval;
3397 int rlen;
3398 int c;
3399
3400 rval = Var_Parse(st.tstr, st.ctxt, st.flags, &rlen, &freeIt);
3401
3402 /*
3403 * If we have not parsed up to st.endc or ':',
3404 * we are not interested.
3405 */
3406 if (rval != NULL && *rval &&
3407 (c = st.tstr[rlen]) != '\0' &&
3408 c != ':' &&
3409 c != st.endc) {
3410 free(freeIt);
3411 goto apply_mods;
3412 }
3413
3414 if (DEBUG(VAR)) {
3415 fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n",
3416 rval, rlen, st.tstr, rlen, st.tstr + rlen);
3417 }
3418
3419 st.tstr += rlen;
3420
3421 if (rval != NULL && *rval) {
3422 int used;
3423
3424 st.nstr = ApplyModifiers(st.nstr, rval, 0, 0, st.v,
3425 st.ctxt, st.flags, &used, st.freePtr);
3426 if (st.nstr == var_Error
3427 || (st.nstr == varNoError && (st.flags & VARF_UNDEFERR) == 0)
3428 || strlen(rval) != (size_t) used) {
3429 free(freeIt);
3430 goto out; /* error already reported */
3431 }
3432 }
3433 free(freeIt);
3434 if (*st.tstr == ':')
3435 st.tstr++;
3436 else if (!*st.tstr && st.endc) {
3437 Error("Unclosed variable specification after complex "
3438 "modifier (expecting '%c') for %s", st.endc, st.v->name);
3439 goto out;
3440 }
3441 continue;
3442 }
3443 apply_mods:
3444 if (DEBUG(VAR)) {
3445 fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name,
3446 *st.tstr, st.nstr);
3447 }
3448 st.newStr = var_Error;
3449 switch ((st.modifier = *st.tstr)) {
3450 case ':':
3451 {
3452 int res = ApplyModifier_Assign(&st);
3453 if (res == 'b')
3454 goto bad_modifier;
3455 if (res == 'c')
3456 goto cleanup;
3457 if (res == 'd')
3458 goto default_case;
3459 break;
3460 }
3461 case '@':
3462 ApplyModifier_At(&st);
3463 break;
3464 case '_':
3465 if (!ApplyModifier_Remember(&st))
3466 goto default_case;
3467 break;
3468 case 'D':
3469 case 'U':
3470 ApplyModifier_Defined(&st);
3471 break;
3472 case 'L':
3473 {
3474 if ((st.v->flags & VAR_JUNK) != 0)
3475 st.v->flags |= VAR_KEEP;
3476 st.newStr = bmake_strdup(st.v->name);
3477 st.cp = ++st.tstr;
3478 st.termc = *st.tstr;
3479 break;
3480 }
3481 case 'P':
3482 ApplyModifier_Path(&st);
3483 break;
3484 case '!':
3485 if (!ApplyModifier_Exclam(&st))
3486 goto cleanup;
3487 break;
3488 case '[':
3489 {
3490 int res = ApplyModifier_Words(&st);
3491 if (res == 'b')
3492 goto bad_modifier;
3493 if (res == 'c')
3494 goto cleanup;
3495 break;
3496 }
3497 case 'g':
3498 if (!ApplyModifier_Gmtime(&st))
3499 goto default_case;
3500 break;
3501 case 'h':
3502 if (!ApplyModifier_Hash(&st))
3503 goto default_case;
3504 break;
3505 case 'l':
3506 if (!ApplyModifier_Localtime(&st))
3507 goto default_case;
3508 break;
3509 case 't':
3510 if (!ApplyModifier_To(&st))
3511 goto bad_modifier;
3512 break;
3513 case 'N':
3514 case 'M':
3515 ApplyModifier_Match(&st);
3516 break;
3517 case 'S':
3518 if (!ApplyModifier_Subst(&st))
3519 goto cleanup;
3520 break;
3521 case '?':
3522 if (!ApplyModifier_IfElse(&st))
3523 goto cleanup;
3524 break;
3525 #ifndef NO_REGEX
3526 case 'C':
3527 if (!ApplyModifier_Regex(&st))
3528 goto cleanup;
3529 break;
3530 #endif
3531 case 'q':
3532 case 'Q':
3533 if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3534 st.newStr = VarQuote(st.nstr, st.modifier == 'q');
3535 st.cp = st.tstr + 1;
3536 st.termc = *st.cp;
3537 break;
3538 }
3539 goto default_case;
3540 case 'T':
3541 if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3542 st.newStr = VarModify(st.ctxt, &st.parsestate, st.nstr, VarTail,
3543 NULL);
3544 st.cp = st.tstr + 1;
3545 st.termc = *st.cp;
3546 break;
3547 }
3548 goto default_case;
3549 case 'H':
3550 if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3551 st.newStr = VarModify(st.ctxt, &st.parsestate, st.nstr, VarHead,
3552 NULL);
3553 st.cp = st.tstr + 1;
3554 st.termc = *st.cp;
3555 break;
3556 }
3557 goto default_case;
3558 case 'E':
3559 if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3560 st.newStr = VarModify(st.ctxt, &st.parsestate, st.nstr, VarSuffix,
3561 NULL);
3562 st.cp = st.tstr + 1;
3563 st.termc = *st.cp;
3564 break;
3565 }
3566 goto default_case;
3567 case 'R':
3568 if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3569 st.newStr = VarModify(st.ctxt, &st.parsestate, st.nstr, VarRoot,
3570 NULL);
3571 st.cp = st.tstr + 1;
3572 st.termc = *st.cp;
3573 break;
3574 }
3575 goto default_case;
3576 case 'r':
3577 if (!ApplyModifier_Range(&st))
3578 goto default_case;
3579 break;
3580 case 'O':
3581 if (!ApplyModifier_Order(&st))
3582 goto bad_modifier;
3583 break;
3584 case 'u':
3585 if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3586 st.newStr = VarUniq(st.nstr);
3587 st.cp = st.tstr + 1;
3588 st.termc = *st.cp;
3589 break;
3590 }
3591 goto default_case;
3592 #ifdef SUNSHCMD
3593 case 's':
3594 if (st.tstr[1] == 'h' && (st.tstr[2] == st.endc || st.tstr[2] == ':')) {
3595 const char *emsg;
3596 if (st.flags & VARF_WANTRES) {
3597 st.newStr = Cmd_Exec(st.nstr, &emsg);
3598 if (emsg)
3599 Error(emsg, st.nstr);
3600 } else
3601 st.newStr = varNoError;
3602 st.cp = st.tstr + 2;
3603 st.termc = *st.cp;
3604 break;
3605 }
3606 goto default_case;
3607 #endif
3608 default:
3609 default_case:
3610 {
3611 #ifdef SYSVVARSUB
3612 int res = ApplyModifier_SysV(&st);
3613 if (res == 'c')
3614 goto cleanup;
3615 if (res != '=')
3616 #endif
3617 {
3618 Error("Unknown modifier '%c'", *st.tstr);
3619 for (st.cp = st.tstr+1;
3620 *st.cp != ':' && *st.cp != st.endc && *st.cp != '\0';
3621 st.cp++)
3622 continue;
3623 st.termc = *st.cp;
3624 st.newStr = var_Error;
3625 }
3626 }
3627 }
3628 if (DEBUG(VAR)) {
3629 fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n",
3630 st.v->name, st.modifier, st.newStr);
3631 }
3632
3633 if (st.newStr != st.nstr) {
3634 if (*st.freePtr) {
3635 free(st.nstr);
3636 *st.freePtr = NULL;
3637 }
3638 st.nstr = st.newStr;
3639 if (st.nstr != var_Error && st.nstr != varNoError) {
3640 *st.freePtr = st.nstr;
3641 }
3642 }
3643 if (st.termc == '\0' && st.endc != '\0') {
3644 Error("Unclosed variable specification (expecting '%c') "
3645 "for \"%s\" (value \"%s\") modifier %c",
3646 st.endc, st.v->name, st.nstr, st.modifier);
3647 } else if (st.termc == ':') {
3648 st.cp++;
3649 }
3650 st.tstr = st.cp;
3651 }
3652 out:
3653 *st.lengthPtr = st.tstr - st.start;
3654 return st.nstr;
3655
3656 bad_modifier:
3657 /* "{(" */
3658 Error("Bad modifier `:%.*s' for %s", (int)strcspn(st.tstr, ":)}"), st.tstr,
3659 st.v->name);
3660
3661 cleanup:
3662 *st.lengthPtr = st.cp - st.start;
3663 if (st.delim != '\0')
3664 Error("Unclosed substitution for %s (%c missing)",
3665 st.v->name, st.delim);
3666 free(*st.freePtr);
3667 *st.freePtr = NULL;
3668 return var_Error;
3669 }
3670
3671 /*-
3672 *-----------------------------------------------------------------------
3673 * Var_Parse --
3674 * Given the start of a variable invocation, extract the variable
3675 * name and find its value, then modify it according to the
3676 * specification.
3677 *
3678 * Input:
3679 * str The string to parse
3680 * ctxt The context for the variable
3681 * flags VARF_UNDEFERR if undefineds are an error
3682 * VARF_WANTRES if we actually want the result
3683 * VARF_ASSIGN if we are in a := assignment
3684 * lengthPtr OUT: The length of the specification
3685 * freePtr OUT: Non-NULL if caller should free *freePtr
3686 *
3687 * Results:
3688 * The (possibly-modified) value of the variable or var_Error if the
3689 * specification is invalid. The length of the specification is
3690 * placed in *lengthPtr (for invalid specifications, this is just
3691 * 2...?).
3692 * If *freePtr is non-NULL then it's a pointer that the caller
3693 * should pass to free() to free memory used by the result.
3694 *
3695 * Side Effects:
3696 * None.
3697 *
3698 *-----------------------------------------------------------------------
3699 */
3700 /* coverity[+alloc : arg-*4] */
3701 char *
3702 Var_Parse(const char *str, GNode *ctxt, Varf_Flags flags,
3703 int *lengthPtr, void **freePtr)
3704 {
3705 const char *tstr; /* Pointer into str */
3706 Var *v; /* Variable in invocation */
3707 Boolean haveModifier; /* TRUE if have modifiers for the variable */
3708 char endc; /* Ending character when variable in parens
3709 * or braces */
3710 char startc; /* Starting character when variable in parens
3711 * or braces */
3712 int vlen; /* Length of variable name */
3713 const char *start; /* Points to original start of str */
3714 char *nstr; /* New string, used during expansion */
3715 Boolean dynamic; /* TRUE if the variable is local and we're
3716 * expanding it in a non-local context. This
3717 * is done to support dynamic sources. The
3718 * result is just the invocation, unaltered */
3719 const char *extramodifiers; /* extra modifiers to apply first */
3720 char name[2];
3721
3722 *freePtr = NULL;
3723 extramodifiers = NULL;
3724 dynamic = FALSE;
3725 start = str;
3726
3727 startc = str[1];
3728 if (startc != PROPEN && startc != BROPEN) {
3729 /*
3730 * If it's not bounded by braces of some sort, life is much simpler.
3731 * We just need to check for the first character and return the
3732 * value if it exists.
3733 */
3734
3735 /* Error out some really stupid names */
3736 if (startc == '\0' || strchr(")}:$", startc)) {
3737 *lengthPtr = 1;
3738 return var_Error;
3739 }
3740 name[0] = startc;
3741 name[1] = '\0';
3742
3743 v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
3744 if (v == NULL) {
3745 *lengthPtr = 2;
3746
3747 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
3748 /*
3749 * If substituting a local variable in a non-local context,
3750 * assume it's for dynamic source stuff. We have to handle
3751 * this specially and return the longhand for the variable
3752 * with the dollar sign escaped so it makes it back to the
3753 * caller. Only four of the local variables are treated
3754 * specially as they are the only four that will be set
3755 * when dynamic sources are expanded.
3756 */
3757 switch (str[1]) {
3758 case '@':
3759 return UNCONST("$(.TARGET)");
3760 case '%':
3761 return UNCONST("$(.MEMBER)");
3762 case '*':
3763 return UNCONST("$(.PREFIX)");
3764 case '!':
3765 return UNCONST("$(.ARCHIVE)");
3766 }
3767 }
3768 return (flags & VARF_UNDEFERR) ? var_Error : varNoError;
3769 } else {
3770 haveModifier = FALSE;
3771 tstr = &str[1];
3772 endc = str[1];
3773 }
3774 } else {
3775 Buffer buf; /* Holds the variable name */
3776 int depth = 1;
3777
3778 endc = startc == PROPEN ? PRCLOSE : BRCLOSE;
3779 Buf_Init(&buf, 0);
3780
3781 /*
3782 * Skip to the end character or a colon, whichever comes first.
3783 */
3784 for (tstr = str + 2; *tstr != '\0'; tstr++) {
3785 /* Track depth so we can spot parse errors. */
3786 if (*tstr == startc)
3787 depth++;
3788 if (*tstr == endc) {
3789 if (--depth == 0)
3790 break;
3791 }
3792 if (depth == 1 && *tstr == ':')
3793 break;
3794 /* A variable inside a variable, expand. */
3795 if (*tstr == '$') {
3796 int rlen;
3797 void *freeIt;
3798 char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt);
3799 if (rval != NULL)
3800 Buf_AddBytes(&buf, strlen(rval), rval);
3801 free(freeIt);
3802 tstr += rlen - 1;
3803 } else
3804 Buf_AddByte(&buf, *tstr);
3805 }
3806 if (*tstr == ':') {
3807 haveModifier = TRUE;
3808 } else if (*tstr == endc) {
3809 haveModifier = FALSE;
3810 } else {
3811 /*
3812 * If we never did find the end character, return NULL
3813 * right now, setting the length to be the distance to
3814 * the end of the string, since that's what make does.
3815 */
3816 *lengthPtr = tstr - str;
3817 Buf_Destroy(&buf, TRUE);
3818 return var_Error;
3819 }
3820 str = Buf_GetAll(&buf, &vlen);
3821
3822 /*
3823 * At this point, str points into newly allocated memory from
3824 * buf, containing only the name of the variable.
3825 *
3826 * start and tstr point into the const string that was pointed
3827 * to by the original value of the str parameter. start points
3828 * to the '$' at the beginning of the string, while tstr points
3829 * to the char just after the end of the variable name -- this
3830 * will be '\0', ':', PRCLOSE, or BRCLOSE.
3831 */
3832
3833 v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
3834 /*
3835 * Check also for bogus D and F forms of local variables since we're
3836 * in a local context and the name is the right length.
3837 */
3838 if ((v == NULL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
3839 (vlen == 2) && (str[1] == 'F' || str[1] == 'D') &&
3840 strchr("@%?*!<>", str[0]) != NULL) {
3841 /*
3842 * Well, it's local -- go look for it.
3843 */
3844 name[0] = *str;
3845 name[1] = '\0';
3846 v = VarFind(name, ctxt, 0);
3847
3848 if (v != NULL) {
3849 if (str[1] == 'D') {
3850 extramodifiers = "H:";
3851 } else { /* F */
3852 extramodifiers = "T:";
3853 }
3854 }
3855 }
3856
3857 if (v == NULL) {
3858 if (((vlen == 1) ||
3859 (((vlen == 2) && (str[1] == 'F' || str[1] == 'D')))) &&
3860 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
3861 {
3862 /*
3863 * If substituting a local variable in a non-local context,
3864 * assume it's for dynamic source stuff. We have to handle
3865 * this specially and return the longhand for the variable
3866 * with the dollar sign escaped so it makes it back to the
3867 * caller. Only four of the local variables are treated
3868 * specially as they are the only four that will be set
3869 * when dynamic sources are expanded.
3870 */
3871 switch (*str) {
3872 case '@':
3873 case '%':
3874 case '*':
3875 case '!':
3876 dynamic = TRUE;
3877 break;
3878 }
3879 } else if (vlen > 2 && *str == '.' &&
3880 isupper((unsigned char) str[1]) &&
3881 (ctxt == VAR_CMD || ctxt == VAR_GLOBAL))
3882 {
3883 int len = vlen - 1;
3884 if ((strncmp(str, ".TARGET", len) == 0) ||
3885 (strncmp(str, ".ARCHIVE", len) == 0) ||
3886 (strncmp(str, ".PREFIX", len) == 0) ||
3887 (strncmp(str, ".MEMBER", len) == 0))
3888 {
3889 dynamic = TRUE;
3890 }
3891 }
3892
3893 if (!haveModifier) {
3894 /*
3895 * No modifiers -- have specification length so we can return
3896 * now.
3897 */
3898 *lengthPtr = tstr - start + 1;
3899 if (dynamic) {
3900 char *pstr = bmake_strndup(start, *lengthPtr);
3901 *freePtr = pstr;
3902 Buf_Destroy(&buf, TRUE);
3903 return pstr;
3904 } else {
3905 Buf_Destroy(&buf, TRUE);
3906 return (flags & VARF_UNDEFERR) ? var_Error : varNoError;
3907 }
3908 } else {
3909 /*
3910 * Still need to get to the end of the variable specification,
3911 * so kludge up a Var structure for the modifications
3912 */
3913 v = bmake_malloc(sizeof(Var));
3914 v->name = UNCONST(str);
3915 Buf_Init(&v->val, 1);
3916 v->flags = VAR_JUNK;
3917 Buf_Destroy(&buf, FALSE);
3918 }
3919 } else
3920 Buf_Destroy(&buf, TRUE);
3921 }
3922
3923 if (v->flags & VAR_IN_USE) {
3924 Fatal("Variable %s is recursive.", v->name);
3925 /*NOTREACHED*/
3926 } else {
3927 v->flags |= VAR_IN_USE;
3928 }
3929 /*
3930 * Before doing any modification, we have to make sure the value
3931 * has been fully expanded. If it looks like recursion might be
3932 * necessary (there's a dollar sign somewhere in the variable's value)
3933 * we just call Var_Subst to do any other substitutions that are
3934 * necessary. Note that the value returned by Var_Subst will have
3935 * been dynamically-allocated, so it will need freeing when we
3936 * return.
3937 */
3938 nstr = Buf_GetAll(&v->val, NULL);
3939 if (strchr(nstr, '$') != NULL && (flags & VARF_WANTRES) != 0) {
3940 nstr = Var_Subst(NULL, nstr, ctxt, flags);
3941 *freePtr = nstr;
3942 }
3943
3944 v->flags &= ~VAR_IN_USE;
3945
3946 if (nstr != NULL && (haveModifier || extramodifiers != NULL)) {
3947 void *extraFree;
3948 int used;
3949
3950 extraFree = NULL;
3951 if (extramodifiers != NULL) {
3952 nstr = ApplyModifiers(nstr, extramodifiers, '(', ')',
3953 v, ctxt, flags, &used, &extraFree);
3954 }
3955
3956 if (haveModifier) {
3957 /* Skip initial colon. */
3958 tstr++;
3959
3960 nstr = ApplyModifiers(nstr, tstr, startc, endc,
3961 v, ctxt, flags, &used, freePtr);
3962 tstr += used;
3963 free(extraFree);
3964 } else {
3965 *freePtr = extraFree;
3966 }
3967 }
3968 *lengthPtr = tstr - start + (*tstr ? 1 : 0);
3969
3970 if (v->flags & VAR_FROM_ENV) {
3971 Boolean destroy = FALSE;
3972
3973 if (nstr != Buf_GetAll(&v->val, NULL)) {
3974 destroy = TRUE;
3975 } else {
3976 /*
3977 * Returning the value unmodified, so tell the caller to free
3978 * the thing.
3979 */
3980 *freePtr = nstr;
3981 }
3982 VarFreeEnv(v, destroy);
3983 } else if (v->flags & VAR_JUNK) {
3984 /*
3985 * Perform any free'ing needed and set *freePtr to NULL so the caller
3986 * doesn't try to free a static pointer.
3987 * If VAR_KEEP is also set then we want to keep str as is.
3988 */
3989 if (!(v->flags & VAR_KEEP)) {
3990 if (*freePtr) {
3991 free(nstr);
3992 *freePtr = NULL;
3993 }
3994 if (dynamic) {
3995 nstr = bmake_strndup(start, *lengthPtr);
3996 *freePtr = nstr;
3997 } else {
3998 nstr = (flags & VARF_UNDEFERR) ? var_Error : varNoError;
3999 }
4000 }
4001 if (nstr != Buf_GetAll(&v->val, NULL))
4002 Buf_Destroy(&v->val, TRUE);
4003 free(v->name);
4004 free(v);
4005 }
4006 return nstr;
4007 }
4008
4009 /*-
4010 *-----------------------------------------------------------------------
4011 * Var_Subst --
4012 * Substitute for all variables in the given string in the given context.
4013 * If flags & VARF_UNDEFERR, Parse_Error will be called when an undefined
4014 * variable is encountered.
4015 *
4016 * Input:
4017 * var Named variable || NULL for all
4018 * str the string which to substitute
4019 * ctxt the context wherein to find variables
4020 * flags VARF_UNDEFERR if undefineds are an error
4021 * VARF_WANTRES if we actually want the result
4022 * VARF_ASSIGN if we are in a := assignment
4023 *
4024 * Results:
4025 * The resulting string.
4026 *
4027 * Side Effects:
4028 * None.
4029 *-----------------------------------------------------------------------
4030 */
4031 char *
4032 Var_Subst(const char *var, const char *str, GNode *ctxt, Varf_Flags flags)
4033 {
4034 Buffer buf; /* Buffer for forming things */
4035 char *val; /* Value to substitute for a variable */
4036 int length; /* Length of the variable invocation */
4037 Boolean trailingBslash; /* variable ends in \ */
4038 void *freeIt = NULL; /* Set if it should be freed */
4039 static Boolean errorReported; /* Set true if an error has already
4040 * been reported to prevent a plethora
4041 * of messages when recursing */
4042
4043 Buf_Init(&buf, 0);
4044 errorReported = FALSE;
4045 trailingBslash = FALSE;
4046
4047 while (*str) {
4048 if (*str == '\n' && trailingBslash)
4049 Buf_AddByte(&buf, ' ');
4050 if (var == NULL && (*str == '$') && (str[1] == '$')) {
4051 /*
4052 * A dollar sign may be escaped either with another dollar sign.
4053 * In such a case, we skip over the escape character and store the
4054 * dollar sign into the buffer directly.
4055 */
4056 if (save_dollars && (flags & VARF_ASSIGN))
4057 Buf_AddByte(&buf, *str);
4058 str++;
4059 Buf_AddByte(&buf, *str);
4060 str++;
4061 } else if (*str != '$') {
4062 /*
4063 * Skip as many characters as possible -- either to the end of
4064 * the string or to the next dollar sign (variable invocation).
4065 */
4066 const char *cp;
4067
4068 for (cp = str++; *str != '$' && *str != '\0'; str++)
4069 continue;
4070 Buf_AddBytes(&buf, str - cp, cp);
4071 } else {
4072 if (var != NULL) {
4073 int expand;
4074 for (;;) {
4075 if (str[1] == '\0') {
4076 /* A trailing $ is kind of a special case */
4077 Buf_AddByte(&buf, str[0]);
4078 str++;
4079 expand = FALSE;
4080 } else if (str[1] != PROPEN && str[1] != BROPEN) {
4081 if (str[1] != *var || strlen(var) > 1) {
4082 Buf_AddBytes(&buf, 2, str);
4083 str += 2;
4084 expand = FALSE;
4085 } else
4086 expand = TRUE;
4087 break;
4088 } else {
4089 const char *p;
4090
4091 /* Scan up to the end of the variable name. */
4092 for (p = &str[2]; *p &&
4093 *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++)
4094 if (*p == '$')
4095 break;
4096 /*
4097 * A variable inside the variable. We cannot expand
4098 * the external variable yet, so we try again with
4099 * the nested one
4100 */
4101 if (*p == '$') {
4102 Buf_AddBytes(&buf, p - str, str);
4103 str = p;
4104 continue;
4105 }
4106
4107 if (strncmp(var, str + 2, p - str - 2) != 0 ||
4108 var[p - str - 2] != '\0') {
4109 /*
4110 * Not the variable we want to expand, scan
4111 * until the next variable
4112 */
4113 for (; *p != '$' && *p != '\0'; p++)
4114 continue;
4115 Buf_AddBytes(&buf, p - str, str);
4116 str = p;
4117 expand = FALSE;
4118 } else
4119 expand = TRUE;
4120 break;
4121 }
4122 }
4123 if (!expand)
4124 continue;
4125 }
4126
4127 val = Var_Parse(str, ctxt, flags, &length, &freeIt);
4128
4129 /*
4130 * When we come down here, val should either point to the
4131 * value of this variable, suitably modified, or be NULL.
4132 * Length should be the total length of the potential
4133 * variable invocation (from $ to end character...)
4134 */
4135 if (val == var_Error || val == varNoError) {
4136 /*
4137 * If performing old-time variable substitution, skip over
4138 * the variable and continue with the substitution. Otherwise,
4139 * store the dollar sign and advance str so we continue with
4140 * the string...
4141 */
4142 if (oldVars) {
4143 str += length;
4144 } else if ((flags & VARF_UNDEFERR) || val == var_Error) {
4145 /*
4146 * If variable is undefined, complain and skip the
4147 * variable. The complaint will stop us from doing anything
4148 * when the file is parsed.
4149 */
4150 if (!errorReported) {
4151 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"",
4152 length, str);
4153 }
4154 str += length;
4155 errorReported = TRUE;
4156 } else {
4157 Buf_AddByte(&buf, *str);
4158 str += 1;
4159 }
4160 } else {
4161 /*
4162 * We've now got a variable structure to store in. But first,
4163 * advance the string pointer.
4164 */
4165 str += length;
4166
4167 /*
4168 * Copy all the characters from the variable value straight
4169 * into the new string.
4170 */
4171 length = strlen(val);
4172 Buf_AddBytes(&buf, length, val);
4173 trailingBslash = length > 0 && val[length - 1] == '\\';
4174 }
4175 free(freeIt);
4176 freeIt = NULL;
4177 }
4178 }
4179
4180 return Buf_DestroyCompact(&buf);
4181 }
4182
4183 /* Initialize the module. */
4184 void
4185 Var_Init(void)
4186 {
4187 VAR_INTERNAL = Targ_NewGN("Internal");
4188 VAR_GLOBAL = Targ_NewGN("Global");
4189 VAR_CMD = Targ_NewGN("Command");
4190 }
4191
4192
4193 void
4194 Var_End(void)
4195 {
4196 }
4197
4198
4199 /****************** PRINT DEBUGGING INFO *****************/
4200 static void
4201 VarPrintVar(void *vp, void *data MAKE_ATTR_UNUSED)
4202 {
4203 Var *v = (Var *)vp;
4204 fprintf(debug_file, "%-16s = %s\n", v->name, Buf_GetAll(&v->val, NULL));
4205 }
4206
4207 /*-
4208 *-----------------------------------------------------------------------
4209 * Var_Dump --
4210 * print all variables in a context
4211 *-----------------------------------------------------------------------
4212 */
4213 void
4214 Var_Dump(GNode *ctxt)
4215 {
4216 Hash_ForEach(&ctxt->context, VarPrintVar, NULL);
4217 }
4218