1 /*-
2 * Copyright (c) 2002 Juli Mallett.
3 * Copyright (c) 1988, 1989, 1990, 1993
4 * The Regents of the University of California. All rights reserved.
5 * Copyright (c) 1989 by Berkeley Softworks
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Adam de Boor.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)var.c 8.3 (Berkeley) 3/19/94
40 */
41
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44
45 /**
46 * var.c --
47 * Variable-handling functions
48 *
49 * Interface:
50 * Var_Set Set the value of a variable in the given
51 * context. The variable is created if it doesn't
52 * yet exist. The value and variable name need not
53 * be preserved.
54 *
55 * Var_Append Append more characters to an existing variable
56 * in the given context. The variable needn't
57 * exist already -- it will be created if it doesn't.
58 * A space is placed between the old value and the
59 * new one.
60 *
61 * Var_Exists See if a variable exists.
62 *
63 * Var_Value Return the value of a variable in a context or
64 * NULL if the variable is undefined.
65 *
66 * Var_Subst Substitute named variable, or all variables if
67 * NULL in a string using
68 * the given context as the top-most one. If the
69 * third argument is non-zero, Parse_Error is
70 * called if any variables are undefined.
71 *
72 * Var_Parse Parse a variable expansion from a string and
73 * return the result and the number of characters
74 * consumed.
75 *
76 * Var_Delete Delete a variable in a context.
77 *
78 * Var_Init Initialize this module.
79 *
80 * Debugging:
81 * Var_Dump Print out all variables defined in the given
82 * context.
83 *
84 * XXX: There's a lot of duplication in these functions.
85 */
86
87 #include <ctype.h>
88 #include <stdlib.h>
89 #include <string.h>
90 #include <sys/types.h>
91 #include <regex.h>
92
93 #include "buf.h"
94 #include "config.h"
95 #include "globals.h"
96 #include "GNode.h"
97 #include "job.h"
98 #include "lst.h"
99 #include "parse.h"
100 #include "str.h"
101 #include "targ.h"
102 #include "util.h"
103 #include "var.h"
104
105 /**
106 *
107 */
108 typedef struct VarParser {
109 const char *const input; /* pointer to input string */
110 const char *ptr; /* current parser pos in input str */
111 GNode *ctxt;
112 Boolean err;
113 Boolean execute;
114 } VarParser;
115
116 typedef struct Var {
117 char *name; /* the variable's name */
118 struct Buffer *val; /* its value */
119 int flags; /* miscellaneous status flags */
120
121 #define VAR_IN_USE 1 /* Variable's value currently being used.
122 * Used to avoid recursion */
123
124 #define VAR_JUNK 4 /* Variable is a junk variable that
125 * should be destroyed when done with
126 * it. Used by Var_Parse for undefined,
127 * modified variables */
128
129 #define VAR_TO_ENV 8 /* Place variable in environment */
130 } Var;
131
132 typedef struct {
133 struct Buffer *lhs; /* String to match */
134 struct Buffer *rhs; /* Replacement string (w/ &'s removed) */
135
136 regex_t re;
137 int nsub;
138 regmatch_t *matches;
139
140 int flags;
141 #define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */
142 #define VAR_SUB_ONE 0x02 /* Apply substitution to one word */
143 #define VAR_SUB_MATCHED 0x04 /* There was a match */
144 #define VAR_MATCH_START 0x08 /* Match at start of word */
145 #define VAR_MATCH_END 0x10 /* Match at end of word */
146 } VarPattern;
147
148 typedef Boolean VarModifyProc(const char *, Boolean, struct Buffer *, void *);
149
150 static char *VarParse(VarParser *, Boolean *);
151
152 /*
153 * This is a harmless return value for Var_Parse that can be used by Var_Subst
154 * to determine if there was an error in parsing -- easier than returning
155 * a flag, as things outside this module don't give a hoot.
156 */
157 char var_Error[] = "";
158
159 /*
160 * Similar to var_Error, but returned when the 'err' flag for Var_Parse is
161 * set false. Why not just use a constant? Well, gcc likes to condense
162 * identical string instances...
163 */
164 static char varNoError[] = "";
165
166 /*
167 * Internally, variables are contained in four different contexts.
168 * 1) the environment. They may not be changed. If an environment
169 * variable is appended-to, the result is placed in the global
170 * context.
171 * 2) the global context. Variables set in the Makefile are located in
172 * the global context. It is the penultimate context searched when
173 * substituting.
174 * 3) the command-line context. All variables set on the command line
175 * are placed in this context. They are UNALTERABLE once placed here.
176 * 4) the local context. Each target has associated with it a context
177 * list. On this list are located the structures describing such
178 * local variables as $(@) and $(*)
179 * The four contexts are searched in the reverse order from which they are
180 * listed.
181 */
182 static GNode *VAR_ENV; /* variables from the environment */
183 GNode *VAR_GLOBAL; /* variables from the makefile */
184 GNode *VAR_CMD; /* variables defined on the command-line */
185
186 Boolean oldVars; /* variable substitution style */
187 Boolean checkEnvFirst; /* -e flag */
188
189 #define OPEN_PAREN '('
190 #define CLOSE_PAREN ')'
191 #define OPEN_BRACE '{'
192 #define CLOSE_BRACE '}'
193
194 /**
195 * Create a Var object.
196 *
197 * Params:
198 * name Name of variable (copied).
199 * value Value of variable (copied) or NULL.
200 * flags Flags set on variable.
201 *
202 * Returns:
203 * New variable.
204 */
205 static Var *
VarCreate(const char name[],const char value[],int flags)206 VarCreate(const char name[], const char value[], int flags)
207 {
208 Var *v;
209
210 v = emalloc(sizeof(Var));
211 v->name = estrdup(name);
212 v->val = Buf_Init(0);
213 v->flags = flags;
214
215 if (value != NULL) {
216 Buf_Append(v->val, value);
217 }
218 return (v);
219 }
220
221 /**
222 * Destroy a Var object.
223 *
224 * Params:
225 * v Object to destroy.
226 * f True if internal buffer in Buffer object is to be removed.
227 */
228 static void
VarDestroy(Var * v,Boolean f)229 VarDestroy(Var *v, Boolean f)
230 {
231
232 Buf_Destroy(v->val, f);
233 free(v->name);
234 free(v);
235 }
236
237 /**
238 * Remove the tail of the given word and place the result in the given
239 * buffer.
240 *
241 * Results:
242 * TRUE if characters were added to the buffer (a space needs to be
243 * added to the buffer before the next word).
244 *
245 * Side Effects:
246 * The trimmed word is added to the buffer.
247 */
248 static Boolean
VarHead(const char * word,Boolean addSpace,Buffer * buf,void * dummy __unused)249 VarHead(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
250 {
251 char *slash;
252
253 slash = strrchr(word, '/');
254 if (slash != NULL) {
255 if (addSpace) {
256 Buf_AddByte(buf, (Byte)' ');
257 }
258 Buf_AppendRange(buf, word, slash);
259 } else {
260 /*
261 * If no directory part, give . (q.v. the POSIX standard)
262 */
263 if (addSpace) {
264 Buf_Append(buf, " .");
265 } else {
266 Buf_AddByte(buf, (Byte)'.');
267 }
268 }
269 return (TRUE);
270 }
271
272 /**
273 * Remove the head of the given word and place the result in the given
274 * buffer.
275 *
276 * Results:
277 * TRUE if characters were added to the buffer (a space needs to be
278 * added to the buffer before the next word).
279 *
280 * Side Effects:
281 * The trimmed word is added to the buffer.
282 */
283 static Boolean
VarTail(const char * word,Boolean addSpace,Buffer * buf,void * dummy __unused)284 VarTail(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
285 {
286 const char *slash;
287
288 if (addSpace) {
289 Buf_AddByte (buf, (Byte)' ');
290 }
291
292 slash = strrchr(word, '/');
293 if (slash != NULL) {
294 slash++;
295 Buf_Append(buf, slash);
296 } else {
297 Buf_Append(buf, word);
298 }
299 return (TRUE);
300 }
301
302 /**
303 * Place the suffix of the given word in the given buffer.
304 *
305 * Results:
306 * TRUE if characters were added to the buffer (a space needs to be
307 * added to the buffer before the next word).
308 *
309 * Side Effects:
310 * The suffix from the word is placed in the buffer.
311 */
312 static Boolean
VarSuffix(const char * word,Boolean addSpace,Buffer * buf,void * dummy __unused)313 VarSuffix(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
314 {
315 const char *dot;
316
317 dot = strrchr(word, '.');
318 if (dot != NULL) {
319 if (addSpace) {
320 Buf_AddByte(buf, (Byte)' ');
321 }
322 dot++;
323 Buf_Append(buf, dot);
324 addSpace = TRUE;
325 }
326 return (addSpace);
327 }
328
329 /**
330 * Remove the suffix of the given word and place the result in the
331 * buffer.
332 *
333 * Results:
334 * TRUE if characters were added to the buffer (a space needs to be
335 * added to the buffer before the next word).
336 *
337 * Side Effects:
338 * The trimmed word is added to the buffer.
339 */
340 static Boolean
VarRoot(const char * word,Boolean addSpace,Buffer * buf,void * dummy __unused)341 VarRoot(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
342 {
343 char *dot;
344
345 if (addSpace) {
346 Buf_AddByte(buf, (Byte)' ');
347 }
348
349 dot = strrchr(word, '.');
350 if (dot != NULL) {
351 Buf_AppendRange(buf, word, dot);
352 } else {
353 Buf_Append(buf, word);
354 }
355 return (TRUE);
356 }
357
358 /**
359 * Place the word in the buffer if it matches the given pattern.
360 * Callback function for VarModify to implement the :M modifier.
361 * A space will be added if requested. A pattern is supplied
362 * which the word must match.
363 *
364 * Results:
365 * TRUE if a space should be placed in the buffer before the next
366 * word.
367 *
368 * Side Effects:
369 * The word may be copied to the buffer.
370 */
371 static Boolean
VarMatch(const char * word,Boolean addSpace,Buffer * buf,void * pattern)372 VarMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern)
373 {
374
375 if (Str_Match(word, pattern)) {
376 if (addSpace) {
377 Buf_AddByte(buf, (Byte)' ');
378 }
379 addSpace = TRUE;
380 Buf_Append(buf, word);
381 }
382 return (addSpace);
383 }
384
385 #ifdef SYSVVARSUB
386 /**
387 * Place the word in the buffer if it matches the given pattern.
388 * Callback function for VarModify to implement the System V %
389 * modifiers. A space is added if requested.
390 *
391 * Results:
392 * TRUE if a space should be placed in the buffer before the next
393 * word.
394 *
395 * Side Effects:
396 * The word may be copied to the buffer.
397 */
398 static Boolean
VarSYSVMatch(const char * word,Boolean addSpace,Buffer * buf,void * patp)399 VarSYSVMatch(const char *word, Boolean addSpace, Buffer *buf, void *patp)
400 {
401 int len;
402 const char *ptr;
403 VarPattern *pat = (VarPattern *)patp;
404
405 if (addSpace)
406 Buf_AddByte(buf, (Byte)' ');
407
408 addSpace = TRUE;
409
410 if ((ptr = Str_SYSVMatch(word, Buf_Data(pat->lhs), &len)) != NULL)
411 Str_SYSVSubst(buf, Buf_Data(pat->rhs), ptr, len);
412 else
413 Buf_Append(buf, word);
414
415 return (addSpace);
416 }
417 #endif
418
419 /**
420 * Place the word in the buffer if it doesn't match the given pattern.
421 * Callback function for VarModify to implement the :N modifier. A
422 * space is added if requested.
423 *
424 * Results:
425 * TRUE if a space should be placed in the buffer before the next
426 * word.
427 *
428 * Side Effects:
429 * The word may be copied to the buffer.
430 */
431 static Boolean
VarNoMatch(const char * word,Boolean addSpace,Buffer * buf,void * pattern)432 VarNoMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern)
433 {
434
435 if (!Str_Match(word, pattern)) {
436 if (addSpace) {
437 Buf_AddByte(buf, (Byte)' ');
438 }
439 addSpace = TRUE;
440 Buf_Append(buf, word);
441 }
442 return (addSpace);
443 }
444
445 /**
446 * Perform a string-substitution on the given word, placing the
447 * result in the passed buffer. A space is added if requested.
448 *
449 * Results:
450 * TRUE if a space is needed before more characters are added.
451 */
452 static Boolean
VarSubstitute(const char * word,Boolean addSpace,Buffer * buf,void * patternp)453 VarSubstitute(const char *word, Boolean addSpace, Buffer *buf, void *patternp)
454 {
455 size_t wordLen; /* Length of word */
456 const char *cp; /* General pointer */
457 VarPattern *pattern = patternp;
458
459 wordLen = strlen(word);
460 if (1) { /* substitute in each word of the variable */
461 /*
462 * Break substitution down into simple anchored cases
463 * and if none of them fits, perform the general substitution
464 * case.
465 */
466 if ((pattern->flags & VAR_MATCH_START) &&
467 (strncmp(word, Buf_Data(pattern->lhs),
468 Buf_Size(pattern->lhs)) == 0)) {
469 /*
470 * Anchored at start and beginning of word matches
471 * pattern.
472 */
473 if ((pattern->flags & VAR_MATCH_END) &&
474 (wordLen == Buf_Size(pattern->lhs))) {
475 /*
476 * Also anchored at end and matches to the end
477 * (word is same length as pattern) add space
478 * and rhs only if rhs is non-null.
479 */
480 if (Buf_Size(pattern->rhs) != 0) {
481 if (addSpace) {
482 Buf_AddByte(buf, (Byte)' ');
483 }
484 addSpace = TRUE;
485 Buf_AppendBuf(buf, pattern->rhs);
486 }
487
488 } else if (pattern->flags & VAR_MATCH_END) {
489 /*
490 * Doesn't match to end -- copy word wholesale
491 */
492 goto nosub;
493
494 } else {
495 /*
496 * Matches at start but need to copy in
497 * trailing characters.
498 */
499 if ((Buf_Size(pattern->rhs) + wordLen -
500 Buf_Size(pattern->lhs)) != 0) {
501 if (addSpace) {
502 Buf_AddByte(buf, (Byte)' ');
503 }
504 addSpace = TRUE;
505 }
506 Buf_AppendBuf(buf, pattern->rhs);
507 Buf_AddBytes(buf, wordLen -
508 Buf_Size(pattern->lhs),
509 (word + Buf_Size(pattern->lhs)));
510 }
511
512 } else if (pattern->flags & VAR_MATCH_START) {
513 /*
514 * Had to match at start of word and didn't -- copy
515 * whole word.
516 */
517 goto nosub;
518
519 } else if (pattern->flags & VAR_MATCH_END) {
520 /*
521 * Anchored at end, Find only place match could occur
522 * (leftLen characters from the end of the word) and
523 * see if it does. Note that because the $ will be
524 * left at the end of the lhs, we have to use strncmp.
525 */
526 cp = word + (wordLen - Buf_Size(pattern->lhs));
527 if ((cp >= word) && (strncmp(cp, Buf_Data(pattern->lhs),
528 Buf_Size(pattern->lhs)) == 0)) {
529 /*
530 * Match found. If we will place characters in
531 * the buffer, add a space before hand as
532 * indicated by addSpace, then stuff in the
533 * initial, unmatched part of the word followed
534 * by the right-hand-side.
535 */
536 if ((cp - word) + Buf_Size(pattern->rhs) != 0) {
537 if (addSpace) {
538 Buf_AddByte(buf, (Byte)' ');
539 }
540 addSpace = TRUE;
541 }
542 Buf_AppendRange(buf, word, cp);
543 Buf_AppendBuf(buf, pattern->rhs);
544
545 } else {
546 /*
547 * Had to match at end and didn't. Copy entire
548 * word.
549 */
550 goto nosub;
551 }
552 } else {
553 /*
554 * Pattern is unanchored: search for the pattern in the
555 * word using strstr(3), copying unmatched portions and
556 * the right-hand-side for each match found, handling
557 * non-global substitutions correctly, etc. When the
558 * loop is done, any remaining part of the word (word
559 * and wordLen are adjusted accordingly through the
560 * loop) is copied straight into the buffer.
561 * addSpace is set FALSE as soon as a space is added
562 * to the buffer.
563 */
564 Boolean done;
565 size_t origSize;
566
567 done = FALSE;
568 origSize = Buf_Size(buf);
569 while (!done) {
570 cp = strstr(word, Buf_Data(pattern->lhs));
571 if (cp != NULL) {
572 if (addSpace && (((cp - word) +
573 Buf_Size(pattern->rhs)) != 0)) {
574 Buf_AddByte(buf, (Byte)' ');
575 addSpace = FALSE;
576 }
577 Buf_AppendRange(buf, word, cp);
578 Buf_AppendBuf(buf, pattern->rhs);
579 wordLen -= (cp - word) +
580 Buf_Size(pattern->lhs);
581 word = cp + Buf_Size(pattern->lhs);
582 if (wordLen == 0 || (pattern->flags &
583 VAR_SUB_GLOBAL) == 0) {
584 done = TRUE;
585 }
586 } else {
587 done = TRUE;
588 }
589 }
590 if (wordLen != 0) {
591 if (addSpace) {
592 Buf_AddByte(buf, (Byte)' ');
593 }
594 Buf_AddBytes(buf, wordLen, (const Byte *)word);
595 }
596
597 /*
598 * If added characters to the buffer, need to add a
599 * space before we add any more. If we didn't add any,
600 * just return the previous value of addSpace.
601 */
602 return ((Buf_Size(buf) != origSize) || addSpace);
603 }
604 /*
605 * Common code for anchored substitutions:
606 * addSpace was set TRUE if characters were added to the buffer.
607 */
608 return (addSpace);
609 }
610 nosub:
611 if (addSpace) {
612 Buf_AddByte(buf, (Byte)' ');
613 }
614 Buf_AddBytes(buf, wordLen, (const Byte *)word);
615 return (TRUE);
616 }
617
618 /**
619 * Print the error caused by a regcomp or regexec call.
620 *
621 * Side Effects:
622 * An error gets printed.
623 */
624 static void
VarREError(int err,regex_t * pat,const char * str)625 VarREError(int err, regex_t *pat, const char *str)
626 {
627 char *errbuf;
628 int errlen;
629
630 errlen = regerror(err, pat, 0, 0);
631 errbuf = emalloc(errlen);
632 regerror(err, pat, errbuf, errlen);
633 Error("%s: %s", str, errbuf);
634 free(errbuf);
635 }
636
637
638 /**
639 * Perform a regex substitution on the given word, placing the
640 * result in the passed buffer. A space is added if requested.
641 *
642 * Results:
643 * TRUE if a space is needed before more characters are added.
644 */
645 static Boolean
VarRESubstitute(const char * word,Boolean addSpace,Buffer * buf,void * patternp)646 VarRESubstitute(const char *word, Boolean addSpace, Buffer *buf, void *patternp)
647 {
648 VarPattern *pat;
649 int xrv;
650 const char *wp;
651 char *rp;
652 int added;
653 int flags = 0;
654
655 #define MAYBE_ADD_SPACE() \
656 if (addSpace && !added) \
657 Buf_AddByte(buf, (Byte)' '); \
658 added = 1
659
660 added = 0;
661 wp = word;
662 pat = patternp;
663
664 if ((pat->flags & (VAR_SUB_ONE | VAR_SUB_MATCHED)) ==
665 (VAR_SUB_ONE | VAR_SUB_MATCHED)) {
666 xrv = REG_NOMATCH;
667 } else {
668 tryagain:
669 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
670 }
671
672 switch (xrv) {
673 case 0:
674 pat->flags |= VAR_SUB_MATCHED;
675 if (pat->matches[0].rm_so > 0) {
676 MAYBE_ADD_SPACE();
677 Buf_AddBytes(buf, pat->matches[0].rm_so,
678 (const Byte *)wp);
679 }
680
681 for (rp = Buf_Data(pat->rhs); *rp; rp++) {
682 if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
683 MAYBE_ADD_SPACE();
684 Buf_AddByte(buf, (Byte)rp[1]);
685 rp++;
686
687 } else if ((*rp == '&') ||
688 ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
689 int n;
690 const char *subbuf;
691 int sublen;
692 char errstr[3];
693
694 if (*rp == '&') {
695 n = 0;
696 errstr[0] = '&';
697 errstr[1] = '\0';
698 } else {
699 n = rp[1] - '0';
700 errstr[0] = '\\';
701 errstr[1] = rp[1];
702 errstr[2] = '\0';
703 rp++;
704 }
705
706 if (n > pat->nsub) {
707 Error("No subexpression %s",
708 &errstr[0]);
709 subbuf = "";
710 sublen = 0;
711
712 } else if ((pat->matches[n].rm_so == -1) &&
713 (pat->matches[n].rm_eo == -1)) {
714 Error("No match for subexpression %s",
715 &errstr[0]);
716 subbuf = "";
717 sublen = 0;
718
719 } else {
720 subbuf = wp + pat->matches[n].rm_so;
721 sublen = pat->matches[n].rm_eo -
722 pat->matches[n].rm_so;
723 }
724
725 if (sublen > 0) {
726 MAYBE_ADD_SPACE();
727 Buf_AddBytes(buf, sublen,
728 (const Byte *)subbuf);
729 }
730 } else {
731 MAYBE_ADD_SPACE();
732 Buf_AddByte(buf, (Byte)*rp);
733 }
734 }
735 wp += pat->matches[0].rm_eo;
736 if (pat->flags & VAR_SUB_GLOBAL) {
737 flags |= REG_NOTBOL;
738 if (pat->matches[0].rm_so == 0 &&
739 pat->matches[0].rm_eo == 0) {
740 MAYBE_ADD_SPACE();
741 Buf_AddByte(buf, (Byte)*wp);
742 wp++;
743 }
744 if (*wp)
745 goto tryagain;
746 }
747 if (*wp) {
748 MAYBE_ADD_SPACE();
749 Buf_Append(buf, wp);
750 }
751 break;
752
753 default:
754 VarREError(xrv, &pat->re, "Unexpected regex error");
755 /* fall through */
756
757 case REG_NOMATCH:
758 if (*wp) {
759 MAYBE_ADD_SPACE();
760 Buf_Append(buf, wp);
761 }
762 break;
763 }
764 return (addSpace || added);
765 }
766
767 /**
768 * Find a variable in a variable list.
769 */
770 static Var *
VarLookup(Lst * vlist,const char * name)771 VarLookup(Lst *vlist, const char *name)
772 {
773 LstNode *ln;
774
775 LST_FOREACH(ln, vlist)
776 if (strcmp(((const Var *)Lst_Datum(ln))->name, name) == 0)
777 return (Lst_Datum(ln));
778 return (NULL);
779 }
780
781 /**
782 * Expand a variable name's embedded variables in the given context.
783 *
784 * Results:
785 * The contents of name, possibly expanded.
786 */
787 static char *
VarPossiblyExpand(const char * name,GNode * ctxt)788 VarPossiblyExpand(const char *name, GNode *ctxt)
789 {
790 Buffer *buf;
791
792 if (strchr(name, '$') != NULL) {
793 buf = Var_Subst(name, ctxt, 0);
794 return (Buf_Peel(buf));
795 } else {
796 return estrdup(name);
797 }
798 }
799
800 /**
801 * If the variable name begins with a '.', it could very well be
802 * one of the local ones. We check the name against all the local
803 * variables and substitute the short version in for 'name' if it
804 * matches one of them.
805 */
806 static const char *
VarLocal(const char name[])807 VarLocal(const char name[])
808 {
809 if (name[0] == '.') {
810 switch (name[1]) {
811 case 'A':
812 if (!strcmp(name, ".ALLSRC"))
813 return (ALLSRC);
814 if (!strcmp(name, ".ARCHIVE"))
815 return (ARCHIVE);
816 break;
817 case 'I':
818 if (!strcmp(name, ".IMPSRC"))
819 return (IMPSRC);
820 break;
821 case 'M':
822 if (!strcmp(name, ".MEMBER"))
823 return (MEMBER);
824 break;
825 case 'O':
826 if (!strcmp(name, ".OODATE"))
827 return (OODATE);
828 break;
829 case 'P':
830 if (!strcmp(name, ".PREFIX"))
831 return (PREFIX);
832 break;
833 case 'T':
834 if (!strcmp(name, ".TARGET"))
835 return (TARGET);
836 break;
837 default:
838 break;
839 }
840 }
841 return (name);
842 }
843
844 /**
845 * Find the given variable in the given context and the environment.
846 *
847 * Results:
848 * A pointer to the structure describing the desired variable or
849 * NULL if the variable does not exist.
850 */
851 static Var *
VarFindEnv(const char name[],GNode * ctxt)852 VarFindEnv(const char name[], GNode *ctxt)
853 {
854 Var *var;
855
856 name = VarLocal(name);
857
858 if ((var = VarLookup(&ctxt->context, name)) != NULL)
859 return (var);
860
861 if ((var = VarLookup(&VAR_ENV->context, name)) != NULL)
862 return (var);
863
864 return (NULL);
865 }
866
867 /**
868 * Look for the variable in the given context.
869 */
870 static Var *
VarFindOnly(const char name[],GNode * ctxt)871 VarFindOnly(const char name[], GNode *ctxt)
872 {
873 Var *var;
874
875 name = VarLocal(name);
876
877 if ((var = VarLookup(&ctxt->context, name)) != NULL)
878 return (var);
879
880 return (NULL);
881 }
882
883 /**
884 * Look for the variable in all contexts.
885 */
886 static Var *
VarFindAny(const char name[],GNode * ctxt)887 VarFindAny(const char name[], GNode *ctxt)
888 {
889 Boolean localCheckEnvFirst;
890 LstNode *ln;
891 Var *var;
892
893 name = VarLocal(name);
894
895 /*
896 * Note whether this is one of the specific variables we were told
897 * through the -E flag to use environment-variable-override for.
898 */
899 localCheckEnvFirst = FALSE;
900 LST_FOREACH(ln, &envFirstVars) {
901 if (strcmp(Lst_Datum(ln), name) == 0) {
902 localCheckEnvFirst = TRUE;
903 break;
904 }
905 }
906
907 /*
908 * First look for the variable in the given context. If it's not there,
909 * look for it in VAR_CMD, VAR_GLOBAL and the environment,
910 * in that order, depending on the FIND_* flags in 'flags'
911 */
912 if ((var = VarLookup(&ctxt->context, name)) != NULL)
913 return (var);
914
915 /* not there - try command line context */
916 if (ctxt != VAR_CMD) {
917 if ((var = VarLookup(&VAR_CMD->context, name)) != NULL)
918 return (var);
919 }
920
921 /* not there - try global context, but only if not -e/-E */
922 if (ctxt != VAR_GLOBAL && (!checkEnvFirst && !localCheckEnvFirst)) {
923 if ((var = VarLookup(&VAR_GLOBAL->context, name)) != NULL)
924 return (var);
925 }
926
927 if ((var = VarLookup(&VAR_ENV->context, name)) != NULL)
928 return (var);
929
930 /* deferred check for the environment (in case of -e/-E) */
931 if ((ctxt != VAR_GLOBAL) && (checkEnvFirst || localCheckEnvFirst)) {
932 if ((var = VarLookup(&VAR_GLOBAL->context, name)) != NULL)
933 return (var);
934 }
935
936 return (NULL);
937 }
938
939 /**
940 * Add a new variable of name name and value val to the given context.
941 *
942 * Side Effects:
943 * The new variable is placed at the front of the given context
944 * The name and val arguments are duplicated so they may
945 * safely be freed.
946 */
947 static Var *
VarAdd(const char * name,const char * val,GNode * ctxt)948 VarAdd(const char *name, const char *val, GNode *ctxt)
949 {
950 Var *v;
951
952 Lst_AtFront(&ctxt->context, v = VarCreate(name, val, 0));
953 DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, name, val));
954 return (v);
955 }
956
957 /**
958 * Remove a variable from a context.
959 *
960 * Side Effects:
961 * The Var structure is removed and freed.
962 */
963 void
Var_Delete(const char * name,GNode * ctxt)964 Var_Delete(const char *name, GNode *ctxt)
965 {
966 LstNode *ln;
967
968 DEBUGF(VAR, ("%s:delete %s\n", ctxt->name, name));
969 LST_FOREACH(ln, &ctxt->context) {
970 if (strcmp(((const Var *)Lst_Datum(ln))->name, name) == 0) {
971 VarDestroy(Lst_Datum(ln), TRUE);
972 Lst_Remove(&ctxt->context, ln);
973 break;
974 }
975 }
976 }
977
978 /**
979 * Set the variable name to the value val in the given context.
980 *
981 * Side Effects:
982 * If the variable doesn't yet exist, a new record is created for it.
983 * Else the old value is freed and the new one stuck in its place
984 *
985 * Notes:
986 * The variable is searched for only in its context before being
987 * created in that context. I.e. if the context is VAR_GLOBAL,
988 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
989 * VAR_CMD->context is searched. This is done to avoid the literally
990 * thousands of unnecessary strcmp's that used to be done to
991 * set, say, $(@) or $(<).
992 */
993 void
Var_Set(const char * name,const char * val,GNode * ctxt)994 Var_Set(const char *name, const char *val, GNode *ctxt)
995 {
996 Var *v;
997 char *n;
998
999 /*
1000 * We only look for a variable in the given context since anything
1001 * set here will override anything in a lower context, so there's not
1002 * much point in searching them all just to save a bit of memory...
1003 */
1004 n = VarPossiblyExpand(name, ctxt);
1005 v = VarFindOnly(n, ctxt);
1006 if (v == NULL) {
1007 v = VarAdd(n, val, ctxt);
1008 } else {
1009 Buf_Clear(v->val);
1010 Buf_Append(v->val, val);
1011 DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, n, val));
1012 }
1013
1014 if (ctxt == VAR_CMD || (v->flags & VAR_TO_ENV)) {
1015 /*
1016 * Any variables given on the command line
1017 * are automatically exported to the
1018 * environment (as per POSIX standard)
1019 */
1020 setenv(n, val, 1);
1021 }
1022
1023 free(n);
1024 }
1025
1026 /**
1027 * Set the a global name variable to the value.
1028 */
1029 void
Var_SetGlobal(const char name[],const char value[])1030 Var_SetGlobal(const char name[], const char value[])
1031 {
1032
1033 Var_Set(name, value, VAR_GLOBAL);
1034 }
1035
1036
1037 /**
1038 * Set the VAR_TO_ENV flag on a variable
1039 */
1040 void
Var_SetEnv(const char * name,GNode * ctxt)1041 Var_SetEnv(const char *name, GNode *ctxt)
1042 {
1043 Var *v;
1044
1045 v = VarFindOnly(name, VAR_CMD);
1046 if (v != NULL) {
1047 /*
1048 * Do not allow .EXPORT: to be set on variables
1049 * from the comand line or MAKEFLAGS.
1050 */
1051 Error(
1052 "Warning: Did not set .EXPORTVAR: on %s because it "
1053 "is from the comand line or MAKEFLAGS", name);
1054 return;
1055 }
1056
1057 v = VarFindAny(name, ctxt);
1058 if (v == NULL) {
1059 Lst_AtFront(&VAR_ENV->context,
1060 VarCreate(name, NULL, VAR_TO_ENV));
1061 setenv(name, "", 1);
1062 Error("Warning: .EXPORTVAR: set on undefined variable %s", name);
1063 } else {
1064 if ((v->flags & VAR_TO_ENV) == 0) {
1065 v->flags |= VAR_TO_ENV;
1066 setenv(v->name, Buf_Data(v->val), 1);
1067 }
1068 }
1069 }
1070
1071 /**
1072 * The variable of the given name has the given value appended to it in
1073 * the given context.
1074 *
1075 * Side Effects:
1076 * If the variable doesn't exist, it is created. Else the strings
1077 * are concatenated (with a space in between).
1078 *
1079 * Notes:
1080 * Only if the variable is being sought in the global context is the
1081 * environment searched.
1082 * XXX: Knows its calling circumstances in that if called with ctxt
1083 * an actual target, it will only search that context since only
1084 * a local variable could be being appended to. This is actually
1085 * a big win and must be tolerated.
1086 */
1087 void
Var_Append(const char * name,const char * val,GNode * ctxt)1088 Var_Append(const char *name, const char *val, GNode *ctxt)
1089 {
1090 Var *v;
1091 char *n;
1092
1093 n = VarPossiblyExpand(name, ctxt);
1094 if (ctxt == VAR_GLOBAL) {
1095 v = VarFindEnv(n, ctxt);
1096 } else {
1097 v = VarFindOnly(n, ctxt);
1098 }
1099 if (v == NULL) {
1100 VarAdd(n, val, ctxt);
1101 } else {
1102 Buf_AddByte(v->val, (Byte)' ');
1103 Buf_Append(v->val, val);
1104 DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, n, Buf_Data(v->val)));
1105 }
1106 free(n);
1107 }
1108
1109 /**
1110 * See if the given variable exists.
1111 *
1112 * Results:
1113 * TRUE if it does, FALSE if it doesn't
1114 */
1115 Boolean
Var_Exists(const char * name,GNode * ctxt)1116 Var_Exists(const char *name, GNode *ctxt)
1117 {
1118 Var *v;
1119 char *n;
1120
1121 n = VarPossiblyExpand(name, ctxt);
1122 v = VarFindAny(n, ctxt);
1123 if (v == NULL) {
1124 free(n);
1125 return (FALSE);
1126 } else {
1127 free(n);
1128 return (TRUE);
1129 }
1130 }
1131
1132 /**
1133 * Return the value of the named variable in the given context
1134 *
1135 * Results:
1136 * The value if the variable exists, NULL if it doesn't.
1137 */
1138 const char *
Var_Value(const char name[],GNode * ctxt)1139 Var_Value(const char name[], GNode *ctxt)
1140 {
1141 Var *v;
1142 char *n;
1143
1144 n = VarPossiblyExpand(name, ctxt);
1145 v = VarFindAny(n, ctxt);
1146 free(n);
1147 if (v == NULL) {
1148 return (NULL);
1149 } else {
1150 return (Buf_Data(v->val));
1151 }
1152 }
1153
1154 /**
1155 * Modify each of the words of the passed string using the given
1156 * function. Used to implement all modifiers.
1157 *
1158 * Results:
1159 * A string of all the words modified appropriately.
1160 *
1161 * Side Effects:
1162 * Uses brk_string() so it invalidates any previous call to
1163 * brk_string().
1164 */
1165 static char *
VarModify(const char * str,VarModifyProc * modProc,void * datum)1166 VarModify(const char *str, VarModifyProc *modProc, void *datum)
1167 {
1168 ArgArray aa;
1169 Buffer *buf; /* Buffer for the new string */
1170 int i;
1171 Boolean addSpace; /*
1172 * TRUE if need to add a space to
1173 * the buffer before adding the
1174 * trimmed word
1175 */
1176
1177 brk_string(&aa, str, FALSE);
1178
1179 addSpace = FALSE;
1180 buf = Buf_Init(0);
1181 for (i = 1; i < aa.argc; i++)
1182 addSpace = (*modProc)(aa.argv[i], addSpace, buf, datum);
1183
1184 ArgArray_Done(&aa);
1185 return (Buf_Peel(buf));
1186 }
1187
1188 /**
1189 * Sort the words in the string.
1190 *
1191 * Input:
1192 * str String whose words should be sorted
1193 * cmp A comparison function to control the ordering
1194 *
1195 * Results:
1196 * A string containing the words sorted
1197 */
1198 static char *
VarSortWords(const char * str,int (* cmp)(const void *,const void *))1199 VarSortWords(const char *str, int (*cmp)(const void *, const void *))
1200 {
1201 ArgArray aa;
1202 Buffer *buf;
1203 int i;
1204
1205 brk_string(&aa, str, FALSE);
1206 qsort(aa.argv + 1, aa.argc - 1, sizeof(char *), cmp);
1207
1208 buf = Buf_Init(0);
1209 for (i = 1; i < aa.argc; i++) {
1210 Buf_Append(buf, aa.argv[i]);
1211 Buf_AddByte(buf, (Byte)((i < aa.argc - 1) ? ' ' : '\0'));
1212 }
1213
1214 ArgArray_Done(&aa);
1215 return (Buf_Peel(buf));
1216 }
1217
1218 static int
SortIncreasing(const void * l,const void * r)1219 SortIncreasing(const void *l, const void *r)
1220 {
1221
1222 return (strcmp(*(const char* const*)l, *(const char* const*)r));
1223 }
1224
1225 /**
1226 * Remove adjacent duplicate words.
1227 *
1228 * Results:
1229 * A string containing the resulting words.
1230 */
1231 static char *
VarUniq(const char * str)1232 VarUniq(const char *str)
1233 {
1234 ArgArray aa;
1235 Buffer *buf; /* Buffer for new string */
1236 int i, j;
1237
1238 buf = Buf_Init(0);
1239 brk_string(&aa, str, FALSE);
1240
1241 if (aa.argc > 2) {
1242 for (j = 1, i = 2; i < aa.argc; i++) {
1243 if (strcmp(aa.argv[i], aa.argv[j]) != 0 && (++j != i))
1244 aa.argv[j] = aa.argv[i];
1245 }
1246 aa.argc = j + 1;
1247 }
1248
1249 for (i = 1; i < aa.argc; i++) {
1250 Buf_AddBytes(buf, strlen(aa.argv[i]), (Byte *)aa.argv[i]);
1251 if (i != aa.argc - 1)
1252 Buf_AddByte(buf, ' ');
1253 }
1254 Buf_AddByte(buf, '\0');
1255
1256 ArgArray_Done(&aa);
1257 return (Buf_Peel(buf));
1258 }
1259
1260 /**
1261 * Pass through the tstr looking for 1) escaped delimiters,
1262 * '$'s and backslashes (place the escaped character in
1263 * uninterpreted) and 2) unescaped $'s that aren't before
1264 * the delimiter (expand the variable substitution).
1265 * Return the expanded string or NULL if the delimiter was missing
1266 * If pattern is specified, handle escaped ampersands, and replace
1267 * unescaped ampersands with the lhs of the pattern.
1268 *
1269 * Results:
1270 * A string of all the words modified appropriately.
1271 * If length is specified, return the string length of the buffer
1272 * If flags is specified and the last character of the pattern is a
1273 * $ set the VAR_MATCH_END bit of flags.
1274 */
1275 static Buffer *
VarGetPattern(VarParser * vp,int delim,int * flags,VarPattern * patt)1276 VarGetPattern(VarParser *vp, int delim, int *flags, VarPattern *patt)
1277 {
1278 Buffer *buf;
1279
1280 buf = Buf_Init(0);
1281
1282 /*
1283 * Skim through until the matching delimiter is found; pick up
1284 * variable substitutions on the way. Also allow backslashes to quote
1285 * the delimiter, $, and \, but don't touch other backslashes.
1286 */
1287 while (*vp->ptr != '\0') {
1288 if (*vp->ptr == delim) {
1289 return (buf);
1290
1291 } else if ((vp->ptr[0] == '\\') &&
1292 ((vp->ptr[1] == delim) ||
1293 (vp->ptr[1] == '\\') ||
1294 (vp->ptr[1] == '$') ||
1295 (vp->ptr[1] == '&' && patt != NULL))) {
1296 vp->ptr++; /* consume backslash */
1297 Buf_AddByte(buf, (Byte)vp->ptr[0]);
1298 vp->ptr++;
1299
1300 } else if (vp->ptr[0] == '$') {
1301 if (vp->ptr[1] == delim) {
1302 if (flags == NULL) {
1303 Buf_AddByte(buf, (Byte)vp->ptr[0]);
1304 vp->ptr++;
1305 } else {
1306 /*
1307 * Unescaped $ at end of patt =>
1308 * anchor patt at end.
1309 */
1310 *flags |= VAR_MATCH_END;
1311 vp->ptr++;
1312 }
1313 } else {
1314 VarParser subvp = {
1315 vp->ptr,
1316 vp->ptr,
1317 vp->ctxt,
1318 vp->err,
1319 vp->execute
1320 };
1321 char *rval;
1322 Boolean rfree;
1323
1324 /*
1325 * If unescaped dollar sign not
1326 * before the delimiter, assume it's
1327 * a variable substitution and
1328 * recurse.
1329 */
1330 rval = VarParse(&subvp, &rfree);
1331 Buf_Append(buf, rval);
1332 if (rfree)
1333 free(rval);
1334 vp->ptr = subvp.ptr;
1335 }
1336 } else if (vp->ptr[0] == '&' && patt != NULL) {
1337 Buf_AppendBuf(buf, patt->lhs);
1338 vp->ptr++;
1339 } else {
1340 Buf_AddByte(buf, (Byte)vp->ptr[0]);
1341 vp->ptr++;
1342 }
1343 }
1344
1345 Buf_Destroy(buf, TRUE);
1346 return (NULL);
1347 }
1348
1349 /**
1350 * Make sure this variable is fully expanded.
1351 */
1352 static char *
VarExpand(Var * v,VarParser * vp)1353 VarExpand(Var *v, VarParser *vp)
1354 {
1355 char *value;
1356 char *result;
1357
1358 if (v->flags & VAR_IN_USE) {
1359 Fatal("Variable %s is recursive.", v->name);
1360 /* NOTREACHED */
1361 }
1362
1363 v->flags |= VAR_IN_USE;
1364
1365 /*
1366 * Before doing any modification, we have to make sure the
1367 * value has been fully expanded. If it looks like recursion
1368 * might be necessary (there's a dollar sign somewhere in the
1369 * variable's value) we just call Var_Subst to do any other
1370 * substitutions that are necessary. Note that the value
1371 * returned by Var_Subst will have been
1372 * dynamically-allocated, so it will need freeing when we
1373 * return.
1374 */
1375 value = Buf_Data(v->val);
1376 if (strchr(value, '$') == NULL) {
1377 result = strdup(value);
1378 } else {
1379 Buffer *buf;
1380
1381 buf = Var_Subst(value, vp->ctxt, vp->err);
1382 result = Buf_Peel(buf);
1383 }
1384
1385 v->flags &= ~VAR_IN_USE;
1386
1387 return (result);
1388 }
1389
1390 /**
1391 * Select only those words in value that match the modifier.
1392 */
1393 static char *
modifier_M(VarParser * vp,const char value[],char endc)1394 modifier_M(VarParser *vp, const char value[], char endc)
1395 {
1396 char *patt;
1397 char *ptr;
1398 char *newValue;
1399 char modifier;
1400
1401 modifier = vp->ptr[0];
1402 vp->ptr++; /* consume 'M' or 'N' */
1403
1404 /*
1405 * Compress the \:'s out of the pattern, so allocate enough
1406 * room to hold the uncompressed pattern and compress the
1407 * pattern into that space.
1408 */
1409 patt = estrdup(vp->ptr);
1410 ptr = patt;
1411 while (vp->ptr[0] != '\0') {
1412 if (vp->ptr[0] == endc || vp->ptr[0] == ':') {
1413 break;
1414 }
1415 if (vp->ptr[0] == '\\' &&
1416 (vp->ptr[1] == endc || vp->ptr[1] == ':')) {
1417 vp->ptr++; /* consume backslash */
1418 }
1419 *ptr = vp->ptr[0];
1420 ptr++;
1421 vp->ptr++;
1422 }
1423 *ptr = '\0';
1424 DEBUGF(VAR, ("Pattern :%s\n", patt));
1425
1426 if (modifier == 'M') {
1427 newValue = VarModify(value, VarMatch, patt);
1428 } else {
1429 newValue = VarModify(value, VarNoMatch, patt);
1430 }
1431 free(patt);
1432
1433 return (newValue);
1434 }
1435
1436 /**
1437 * Substitute the replacement string for the pattern. The substitution
1438 * is applied to each word in value.
1439 */
1440 static char *
modifier_S(VarParser * vp,const char value[],Var * v)1441 modifier_S(VarParser *vp, const char value[], Var *v)
1442 {
1443 VarPattern patt;
1444 char delim;
1445 char *newValue;
1446
1447 patt.flags = 0;
1448
1449 vp->ptr++; /* consume 'S' */
1450
1451 delim = *vp->ptr; /* used to find end of pattern */
1452 vp->ptr++; /* consume 1st delim */
1453
1454 /*
1455 * If pattern begins with '^', it is anchored to the start of the
1456 * word -- skip over it and flag pattern.
1457 */
1458 if (*vp->ptr == '^') {
1459 patt.flags |= VAR_MATCH_START;
1460 vp->ptr++;
1461 }
1462
1463 patt.lhs = VarGetPattern(vp, delim, &patt.flags, NULL);
1464 if (patt.lhs == NULL) {
1465 /*
1466 * LHS didn't end with the delim, complain and exit.
1467 */
1468 Fatal("Unclosed substitution for %s (%c missing)",
1469 v->name, delim);
1470 }
1471
1472 vp->ptr++; /* consume 2nd delim */
1473
1474 patt.rhs = VarGetPattern(vp, delim, NULL, &patt);
1475 if (patt.rhs == NULL) {
1476 /*
1477 * RHS didn't end with the delim, complain and exit.
1478 */
1479 Fatal("Unclosed substitution for %s (%c missing)",
1480 v->name, delim);
1481 }
1482
1483 vp->ptr++; /* consume last delim */
1484
1485 /*
1486 * Check for global substitution. If 'g' after the final delimiter,
1487 * substitution is global and is marked that way.
1488 */
1489 if (vp->ptr[0] == 'g') {
1490 patt.flags |= VAR_SUB_GLOBAL;
1491 vp->ptr++;
1492 }
1493
1494 /*
1495 * Global substitution of the empty string causes an infinite number
1496 * of matches, unless anchored by '^' (start of string) or '$' (end
1497 * of string). Catch the infinite substitution here. Note that flags
1498 * can only contain the 3 bits we're interested in so we don't have
1499 * to mask unrelated bits. We can test for equality.
1500 */
1501 if (Buf_Size(patt.lhs) == 0 && patt.flags == VAR_SUB_GLOBAL)
1502 Fatal("Global substitution of the empty string");
1503
1504 newValue = VarModify(value, VarSubstitute, &patt);
1505
1506 /*
1507 * Free the two strings.
1508 */
1509 free(patt.lhs);
1510 free(patt.rhs);
1511
1512 return (newValue);
1513 }
1514
1515 static char *
modifier_C(VarParser * vp,char value[],Var * v)1516 modifier_C(VarParser *vp, char value[], Var *v)
1517 {
1518 VarPattern patt;
1519 char delim;
1520 int error;
1521 char *newValue;
1522
1523 patt.flags = 0;
1524
1525 vp->ptr++; /* consume 'C' */
1526
1527 delim = *vp->ptr; /* delimiter between sections */
1528
1529 vp->ptr++; /* consume 1st delim */
1530
1531 patt.lhs = VarGetPattern(vp, delim, NULL, NULL);
1532 if (patt.lhs == NULL) {
1533 Fatal("Unclosed substitution for %s (%c missing)",
1534 v->name, delim);
1535 }
1536
1537 vp->ptr++; /* consume 2st delim */
1538
1539 patt.rhs = VarGetPattern(vp, delim, NULL, NULL);
1540 if (patt.rhs == NULL) {
1541 Fatal("Unclosed substitution for %s (%c missing)",
1542 v->name, delim);
1543 }
1544
1545 vp->ptr++; /* consume last delim */
1546
1547 switch (*vp->ptr) {
1548 case 'g':
1549 patt.flags |= VAR_SUB_GLOBAL;
1550 vp->ptr++; /* consume 'g' */
1551 break;
1552 case '1':
1553 patt.flags |= VAR_SUB_ONE;
1554 vp->ptr++; /* consume '1' */
1555 break;
1556 default:
1557 break;
1558 }
1559
1560 error = regcomp(&patt.re, Buf_Data(patt.lhs), REG_EXTENDED);
1561 if (error) {
1562 VarREError(error, &patt.re, "RE substitution error");
1563 free(patt.rhs);
1564 free(patt.lhs);
1565 return (var_Error);
1566 }
1567
1568 patt.nsub = patt.re.re_nsub + 1;
1569 if (patt.nsub < 1)
1570 patt.nsub = 1;
1571 if (patt.nsub > 10)
1572 patt.nsub = 10;
1573 patt.matches = emalloc(patt.nsub * sizeof(regmatch_t));
1574
1575 newValue = VarModify(value, VarRESubstitute, &patt);
1576
1577 regfree(&patt.re);
1578 free(patt.matches);
1579 free(patt.rhs);
1580 free(patt.lhs);
1581
1582 return (newValue);
1583 }
1584
1585 static char *
sysVvarsub(VarParser * vp,char startc,Var * v,const char value[])1586 sysVvarsub(VarParser *vp, char startc, Var *v, const char value[])
1587 {
1588 #ifdef SYSVVARSUB
1589 /*
1590 * This can either be a bogus modifier or a System-V substitution
1591 * command.
1592 */
1593 char endc;
1594 VarPattern patt;
1595 Boolean eqFound;
1596 int cnt;
1597 char *newStr;
1598 const char *cp;
1599
1600 endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
1601
1602 patt.flags = 0;
1603
1604 /*
1605 * First we make a pass through the string trying to verify it is a
1606 * SYSV-make-style translation: it must be: <string1>=<string2>)
1607 */
1608 eqFound = FALSE;
1609 cp = vp->ptr;
1610 cnt = 1;
1611 while (*cp != '\0' && cnt) {
1612 if (*cp == '=') {
1613 eqFound = TRUE;
1614 /* continue looking for endc */
1615 } else if (*cp == endc)
1616 cnt--;
1617 else if (*cp == startc)
1618 cnt++;
1619 if (cnt)
1620 cp++;
1621 }
1622
1623 if (*cp == endc && eqFound) {
1624 /*
1625 * Now we break this sucker into the lhs and rhs.
1626 */
1627 patt.lhs = VarGetPattern(vp, '=', &patt.flags, NULL);
1628 if (patt.lhs == NULL) {
1629 Fatal("Unclosed substitution for %s (%c missing)",
1630 v->name, '=');
1631 }
1632 vp->ptr++; /* consume '=' */
1633
1634 patt.rhs = VarGetPattern(vp, endc, NULL, &patt);
1635 if (patt.rhs == NULL) {
1636 Fatal("Unclosed substitution for %s (%c missing)",
1637 v->name, endc);
1638 }
1639
1640 /*
1641 * SYSV modifications happen through the whole string. Note
1642 * the pattern is anchored at the end.
1643 */
1644 newStr = VarModify(value, VarSYSVMatch, &patt);
1645
1646 free(patt.lhs);
1647 free(patt.rhs);
1648 } else
1649 #endif
1650 {
1651 Error("Unknown modifier '%c'\n", *vp->ptr);
1652 vp->ptr++;
1653 while (*vp->ptr != '\0') {
1654 if (*vp->ptr == endc && *vp->ptr == ':') {
1655 break;
1656 }
1657 vp->ptr++;
1658 }
1659 newStr = var_Error;
1660 }
1661
1662 return (newStr);
1663 }
1664
1665 /**
1666 * Quote shell meta-characters in the string
1667 *
1668 * Results:
1669 * The quoted string
1670 */
1671 static char *
Var_Quote(const char * str)1672 Var_Quote(const char *str)
1673 {
1674 Buffer *buf;
1675 /* This should cover most shells :-( */
1676 static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
1677
1678 buf = Buf_Init(MAKE_BSIZE);
1679 for (; *str; str++) {
1680 if (strchr(meta, *str) != NULL)
1681 Buf_AddByte(buf, (Byte)'\\');
1682 Buf_AddByte(buf, (Byte)*str);
1683 }
1684
1685 return (Buf_Peel(buf));
1686 }
1687
1688
1689 /*
1690 * Now we need to apply any modifiers the user wants applied.
1691 * These are:
1692 * :M<pattern>
1693 * words which match the given <pattern>.
1694 * <pattern> is of the standard file
1695 * wildcarding form.
1696 * :N<pattern>
1697 * words which do not match the given <pattern>
1698 * <pattern> is of the standard file
1699 * wildcarding form.
1700 * :S<d><pat1><d><pat2><d>[g]
1701 * Substitute <pat2> for <pat1> in the value
1702 * :C<d><pat1><d><pat2><d>[g]
1703 * Substitute <pat2> for regex <pat1> in the value
1704 * :H Substitute the head of each word
1705 * :T Substitute the tail of each word
1706 * :E Substitute the extension (minus '.') of
1707 * each word
1708 * :R Substitute the root of each word
1709 * (pathname minus the suffix).
1710 * :lhs=rhs
1711 * Like :S, but the rhs goes to the end of
1712 * the invocation.
1713 * :U Converts variable to upper-case.
1714 * :L Converts variable to lower-case.
1715 * :O ("Order") Alphabeticaly sort words in variable.
1716 * :u ("uniq") Remove adjacent duplicate words.
1717 */
1718 static char *
ParseModifier(VarParser * vp,char startc,Var * v,Boolean * freeResult)1719 ParseModifier(VarParser *vp, char startc, Var *v, Boolean *freeResult)
1720 {
1721 char *value;
1722 char endc;
1723
1724 value = VarExpand(v, vp);
1725 *freeResult = TRUE;
1726
1727 endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
1728
1729 vp->ptr++; /* consume first colon */
1730
1731 while (*vp->ptr != '\0') {
1732 char *newStr; /* New value to return */
1733
1734 if (*vp->ptr == endc) {
1735 return (value);
1736 }
1737
1738 DEBUGF(VAR, ("Applying :%c to \"%s\"\n", *vp->ptr, value));
1739 switch (*vp->ptr) {
1740 case 'N':
1741 case 'M':
1742 newStr = modifier_M(vp, value, endc);
1743 break;
1744 case 'S':
1745 newStr = modifier_S(vp, value, v);
1746 break;
1747 case 'C':
1748 newStr = modifier_C(vp, value, v);
1749 break;
1750 case 't':
1751 /* :tl :tu for OSF ODE & NetBSD make compatibility */
1752 switch (vp->ptr[1]) {
1753 case 'l':
1754 vp->ptr++;
1755 goto mod_lower;
1756 break;
1757 case 'u':
1758 vp->ptr++;
1759 goto mod_upper;
1760 break;
1761 }
1762 /* FALLTHROUGH */
1763 default:
1764 if (vp->ptr[1] != endc && vp->ptr[1] != ':') {
1765 #ifdef SUNSHCMD
1766 if ((vp->ptr[0] == 's') &&
1767 (vp->ptr[1] == 'h') &&
1768 (vp->ptr[2] == endc || vp->ptr[2] == ':')) {
1769 const char *error = NULL;
1770
1771 if (vp->execute) {
1772 newStr = Buf_Peel(
1773 Cmd_Exec(value, &error));
1774 } else {
1775 newStr = estrdup("");
1776 }
1777
1778 if (error)
1779 Error(error, value);
1780 vp->ptr += 2;
1781 } else
1782 #endif
1783 {
1784 newStr = sysVvarsub(vp, startc, v, value);
1785 }
1786 break;
1787 }
1788
1789 switch (vp->ptr[0]) {
1790 case 'L':
1791 mod_lower:
1792 {
1793 const char *cp;
1794 Buffer *buf;
1795 buf = Buf_Init(MAKE_BSIZE);
1796 for (cp = value; *cp; cp++)
1797 Buf_AddByte(buf, (Byte)tolower(*cp));
1798
1799 newStr = Buf_Peel(buf);
1800
1801 vp->ptr++;
1802 break;
1803 }
1804 case 'O':
1805 newStr = VarSortWords(value, SortIncreasing);
1806 vp->ptr++;
1807 break;
1808 case 'Q':
1809 newStr = Var_Quote(value);
1810 vp->ptr++;
1811 break;
1812 case 'T':
1813 newStr = VarModify(value, VarTail, NULL);
1814 vp->ptr++;
1815 break;
1816 case 'U':
1817 mod_upper:
1818 {
1819 const char *cp;
1820 Buffer *buf;
1821 buf = Buf_Init(MAKE_BSIZE);
1822 for (cp = value; *cp; cp++)
1823 Buf_AddByte(buf, (Byte)toupper(*cp));
1824
1825 newStr = Buf_Peel(buf);
1826
1827 vp->ptr++;
1828 break;
1829 }
1830 case 'H':
1831 newStr = VarModify(value, VarHead, NULL);
1832 vp->ptr++;
1833 break;
1834 case 'E':
1835 newStr = VarModify(value, VarSuffix, NULL);
1836 vp->ptr++;
1837 break;
1838 case 'R':
1839 newStr = VarModify(value, VarRoot, NULL);
1840 vp->ptr++;
1841 break;
1842 case 'u':
1843 newStr = VarUniq(value);
1844 vp->ptr++;
1845 break;
1846 default:
1847 newStr = sysVvarsub(vp, startc, v, value);
1848 break;
1849 }
1850 break;
1851 }
1852
1853 DEBUGF(VAR, ("Result is \"%s\"\n", newStr));
1854 if (*freeResult) {
1855 free(value);
1856 }
1857
1858 value = newStr;
1859 *freeResult = (value == var_Error) ? FALSE : TRUE;
1860
1861 if (vp->ptr[0] == ':') {
1862 vp->ptr++; /* consume colon */
1863 }
1864 }
1865
1866 return (value);
1867 }
1868
1869 static char *
ParseRestModifier(VarParser * vp,char startc,Buffer * buf,Boolean * freeResult)1870 ParseRestModifier(VarParser *vp, char startc, Buffer *buf, Boolean *freeResult)
1871 {
1872 const char *vname;
1873 size_t vlen;
1874 Var *v;
1875 char *value;
1876
1877 vname = Buf_GetAll(buf, &vlen);
1878
1879 v = VarFindAny(vname, vp->ctxt);
1880 if (v != NULL) {
1881 value = ParseModifier(vp, startc, v, freeResult);
1882 return (value);
1883 }
1884
1885 if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
1886 size_t consumed;
1887 /*
1888 * Still need to get to the end of the variable
1889 * specification, so kludge up a Var structure for the
1890 * modifications
1891 */
1892 v = VarCreate(vname, NULL, VAR_JUNK);
1893 value = ParseModifier(vp, startc, v, freeResult);
1894 if (*freeResult) {
1895 free(value);
1896 }
1897 VarDestroy(v, TRUE);
1898
1899 consumed = vp->ptr - vp->input + 1;
1900 /*
1901 * If substituting a local variable in a non-local context,
1902 * assume it's for dynamic source stuff. We have to handle
1903 * this specially and return the longhand for the variable
1904 * with the dollar sign escaped so it makes it back to the
1905 * caller. Only four of the local variables are treated
1906 * specially as they are the only four that will be set when
1907 * dynamic sources are expanded.
1908 */
1909 if (vlen == 1 ||
1910 (vlen == 2 && (vname[1] == 'F' || vname[1] == 'D'))) {
1911 if (strchr("!%*@", vname[0]) != NULL) {
1912 value = emalloc(consumed + 1);
1913 strncpy(value, vp->input, consumed);
1914 value[consumed] = '\0';
1915
1916 *freeResult = TRUE;
1917 return (value);
1918 }
1919 }
1920 if (vlen > 2 &&
1921 vname[0] == '.' &&
1922 isupper((unsigned char)vname[1])) {
1923 if ((strncmp(vname, ".TARGET", vlen - 1) == 0) ||
1924 (strncmp(vname, ".ARCHIVE", vlen - 1) == 0) ||
1925 (strncmp(vname, ".PREFIX", vlen - 1) == 0) ||
1926 (strncmp(vname, ".MEMBER", vlen - 1) == 0)) {
1927 value = emalloc(consumed + 1);
1928 strncpy(value, vp->input, consumed);
1929 value[consumed] = '\0';
1930
1931 *freeResult = TRUE;
1932 return (value);
1933 }
1934 }
1935
1936 *freeResult = FALSE;
1937 return (vp->err ? var_Error : varNoError);
1938 } else {
1939 /*
1940 * Check for D and F forms of local variables since we're in
1941 * a local context and the name is the right length.
1942 */
1943 if (vlen == 2 &&
1944 (vname[1] == 'F' || vname[1] == 'D') &&
1945 (strchr("!%*<>@", vname[0]) != NULL)) {
1946 char name[2];
1947
1948 name[0] = vname[0];
1949 name[1] = '\0';
1950
1951 v = VarFindOnly(name, vp->ctxt);
1952 if (v != NULL) {
1953 value = ParseModifier(vp, startc, v, freeResult);
1954 return (value);
1955 }
1956 }
1957
1958 /*
1959 * Still need to get to the end of the variable
1960 * specification, so kludge up a Var structure for the
1961 * modifications
1962 */
1963 v = VarCreate(vname, NULL, VAR_JUNK);
1964 value = ParseModifier(vp, startc, v, freeResult);
1965 if (*freeResult) {
1966 free(value);
1967 }
1968 VarDestroy(v, TRUE);
1969
1970 *freeResult = FALSE;
1971 return (vp->err ? var_Error : varNoError);
1972 }
1973 }
1974
1975 static char *
ParseRestEnd(VarParser * vp,Buffer * buf,Boolean * freeResult)1976 ParseRestEnd(VarParser *vp, Buffer *buf, Boolean *freeResult)
1977 {
1978 const char *vname;
1979 size_t vlen;
1980 Var *v;
1981 char *value;
1982
1983 vname = Buf_GetAll(buf, &vlen);
1984
1985 v = VarFindAny(vname, vp->ctxt);
1986 if (v != NULL) {
1987 value = VarExpand(v, vp);
1988 *freeResult = TRUE;
1989 return (value);
1990 }
1991
1992 if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
1993 size_t consumed = vp->ptr - vp->input + 1;
1994
1995 /*
1996 * If substituting a local variable in a non-local context,
1997 * assume it's for dynamic source stuff. We have to handle
1998 * this specially and return the longhand for the variable
1999 * with the dollar sign escaped so it makes it back to the
2000 * caller. Only four of the local variables are treated
2001 * specially as they are the only four that will be set when
2002 * dynamic sources are expanded.
2003 */
2004 if (vlen == 1 ||
2005 (vlen == 2 && (vname[1] == 'F' || vname[1] == 'D'))) {
2006 if (strchr("!%*@", vname[0]) != NULL) {
2007 value = emalloc(consumed + 1);
2008 strncpy(value, vp->input, consumed);
2009 value[consumed] = '\0';
2010
2011 *freeResult = TRUE;
2012 return (value);
2013 }
2014 }
2015 if (vlen > 2 &&
2016 vname[0] == '.' &&
2017 isupper((unsigned char)vname[1])) {
2018 if ((strncmp(vname, ".TARGET", vlen - 1) == 0) ||
2019 (strncmp(vname, ".ARCHIVE", vlen - 1) == 0) ||
2020 (strncmp(vname, ".PREFIX", vlen - 1) == 0) ||
2021 (strncmp(vname, ".MEMBER", vlen - 1) == 0)) {
2022 value = emalloc(consumed + 1);
2023 strncpy(value, vp->input, consumed);
2024 value[consumed] = '\0';
2025
2026 *freeResult = TRUE;
2027 return (value);
2028 }
2029 }
2030 } else {
2031 /*
2032 * Check for D and F forms of local variables since we're in
2033 * a local context and the name is the right length.
2034 */
2035 if (vlen == 2 &&
2036 (vname[1] == 'F' || vname[1] == 'D') &&
2037 (strchr("!%*<>@", vname[0]) != NULL)) {
2038 char name[2];
2039
2040 name[0] = vname[0];
2041 name[1] = '\0';
2042
2043 v = VarFindOnly(name, vp->ctxt);
2044 if (v != NULL) {
2045 char *val;
2046 /*
2047 * No need for nested expansion or anything,
2048 * as we're the only one who sets these
2049 * things and we sure don't put nested
2050 * invocations in them...
2051 */
2052 val = Buf_Data(v->val);
2053
2054 if (vname[1] == 'D') {
2055 val = VarModify(val, VarHead, NULL);
2056 } else {
2057 val = VarModify(val, VarTail, NULL);
2058 }
2059
2060 *freeResult = TRUE;
2061 return (val);
2062 }
2063 }
2064 }
2065
2066 *freeResult = FALSE;
2067 return (vp->err ? var_Error : varNoError);
2068 }
2069
2070 /**
2071 * Parse a multi letter variable name, and return it's value.
2072 */
2073 static char *
VarParseLong(VarParser * vp,Boolean * freeResult)2074 VarParseLong(VarParser *vp, Boolean *freeResult)
2075 {
2076 Buffer *buf;
2077 char startc;
2078 char endc;
2079 char *value;
2080
2081 buf = Buf_Init(MAKE_BSIZE);
2082
2083 startc = vp->ptr[0];
2084 vp->ptr++; /* consume opening paren or brace */
2085
2086 endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
2087
2088 /*
2089 * Process characters until we reach an end character or a colon,
2090 * replacing embedded variables as we go.
2091 */
2092 while (*vp->ptr != '\0') {
2093 if (*vp->ptr == endc) {
2094 value = ParseRestEnd(vp, buf, freeResult);
2095 vp->ptr++; /* consume closing paren or brace */
2096 Buf_Destroy(buf, TRUE);
2097 return (value);
2098
2099 } else if (*vp->ptr == ':') {
2100 value = ParseRestModifier(vp, startc, buf, freeResult);
2101 vp->ptr++; /* consume closing paren or brace */
2102 Buf_Destroy(buf, TRUE);
2103 return (value);
2104
2105 } else if (*vp->ptr == '$') {
2106 VarParser subvp = {
2107 vp->ptr,
2108 vp->ptr,
2109 vp->ctxt,
2110 vp->err,
2111 vp->execute
2112 };
2113 char *rval;
2114 Boolean rfree;
2115
2116 rval = VarParse(&subvp, &rfree);
2117 if (rval == var_Error) {
2118 Fatal("Error expanding embedded variable.");
2119 }
2120 Buf_Append(buf, rval);
2121 if (rfree)
2122 free(rval);
2123 vp->ptr = subvp.ptr;
2124 } else {
2125 Buf_AddByte(buf, (Byte)*vp->ptr);
2126 vp->ptr++;
2127 }
2128 }
2129
2130 /* If we did not find the end character, return var_Error */
2131 Buf_Destroy(buf, TRUE);
2132 *freeResult = FALSE;
2133 return (var_Error);
2134 }
2135
2136 /**
2137 * Parse a single letter variable name, and return it's value.
2138 */
2139 static char *
VarParseShort(VarParser * vp,Boolean * freeResult)2140 VarParseShort(VarParser *vp, Boolean *freeResult)
2141 {
2142 char vname[2];
2143 Var *v;
2144 char *value;
2145
2146 vname[0] = vp->ptr[0];
2147 vname[1] = '\0';
2148
2149 vp->ptr++; /* consume single letter */
2150
2151 v = VarFindAny(vname, vp->ctxt);
2152 if (v != NULL) {
2153 value = VarExpand(v, vp);
2154 *freeResult = TRUE;
2155 return (value);
2156 }
2157
2158 /*
2159 * If substituting a local variable in a non-local context, assume
2160 * it's for dynamic source stuff. We have to handle this specially
2161 * and return the longhand for the variable with the dollar sign
2162 * escaped so it makes it back to the caller. Only four of the local
2163 * variables are treated specially as they are the only four that
2164 * will be set when dynamic sources are expanded.
2165 */
2166 if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
2167
2168 /* XXX: It looks like $% and $! are reversed here */
2169 switch (vname[0]) {
2170 case '@':
2171 *freeResult = TRUE;
2172 return (estrdup("$(.TARGET)"));
2173 case '%':
2174 *freeResult = TRUE;
2175 return (estrdup("$(.ARCHIVE)"));
2176 case '*':
2177 *freeResult = TRUE;
2178 return (estrdup("$(.PREFIX)"));
2179 case '!':
2180 *freeResult = TRUE;
2181 return (estrdup("$(.MEMBER)"));
2182 default:
2183 *freeResult = FALSE;
2184 return (vp->err ? var_Error : varNoError);
2185 }
2186 }
2187
2188 /* Variable name was not found. */
2189 *freeResult = FALSE;
2190 return (vp->err ? var_Error : varNoError);
2191 }
2192
2193 static char *
VarParse(VarParser * vp,Boolean * freeResult)2194 VarParse(VarParser *vp, Boolean *freeResult)
2195 {
2196
2197 vp->ptr++; /* consume '$' or last letter of conditional */
2198
2199 if (vp->ptr[0] == '\0') {
2200 /* Error, there is only a dollar sign in the input string. */
2201 *freeResult = FALSE;
2202 return (vp->err ? var_Error : varNoError);
2203
2204 } else if (vp->ptr[0] == OPEN_PAREN || vp->ptr[0] == OPEN_BRACE) {
2205 /* multi letter variable name */
2206 return (VarParseLong(vp, freeResult));
2207
2208 } else {
2209 /* single letter variable name */
2210 return (VarParseShort(vp, freeResult));
2211 }
2212 }
2213
2214 /**
2215 * Given the start of a variable invocation, extract the variable
2216 * name and find its value, then modify it according to the
2217 * specification.
2218 *
2219 * Results:
2220 * The value of the variable or var_Error if the specification
2221 * is invalid. The number of characters in the specification
2222 * is placed in the variable pointed to by consumed. (for
2223 * invalid specifications, this is just 2 to skip the '$' and
2224 * the following letter, or 1 if '$' was the last character
2225 * in the string). A Boolean in *freeResult telling whether the
2226 * returned string should be freed by the caller.
2227 */
2228 char *
Var_Parse(const char input[],GNode * ctxt,Boolean err,size_t * consumed,Boolean * freeResult)2229 Var_Parse(const char input[], GNode *ctxt, Boolean err,
2230 size_t *consumed, Boolean *freeResult)
2231 {
2232 VarParser vp = {
2233 input,
2234 input,
2235 ctxt,
2236 err,
2237 TRUE
2238 };
2239 char *value;
2240
2241 value = VarParse(&vp, freeResult);
2242 *consumed += vp.ptr - vp.input;
2243 return (value);
2244 }
2245
2246 /*
2247 * Given the start of a variable invocation, determine the length
2248 * of the specification.
2249 *
2250 * Results:
2251 * The number of characters in the specification. For invalid
2252 * specifications, this is just 2 to skip the '$' and the
2253 * following letter, or 1 if '$' was the last character in the
2254 * string.
2255 */
2256 size_t
Var_Match(const char input[],GNode * ctxt)2257 Var_Match(const char input[], GNode *ctxt)
2258 {
2259 VarParser vp = {
2260 input,
2261 input,
2262 ctxt,
2263 FALSE,
2264 FALSE
2265 };
2266 char *value;
2267 Boolean freeResult;
2268
2269 value = VarParse(&vp, &freeResult);
2270 if (freeResult) {
2271 free(value);
2272 }
2273 return (vp.ptr - vp.input);
2274 }
2275
2276 static int
match_var(const char str[],const char var[])2277 match_var(const char str[], const char var[])
2278 {
2279 const char *start = str;
2280 size_t len;
2281
2282 str++; /* consume '$' */
2283
2284 if (str[0] == OPEN_PAREN || str[0] == OPEN_BRACE) {
2285 str++; /* consume opening paren or brace */
2286
2287 while (str[0] != '\0') {
2288 if (str[0] == '$') {
2289 /*
2290 * A variable inside the variable. We cannot
2291 * expand the external variable yet.
2292 */
2293 return (str - start);
2294 } else if (str[0] == ':' ||
2295 str[0] == CLOSE_PAREN ||
2296 str[0] == CLOSE_BRACE) {
2297 len = str - (start + 2);
2298
2299 if (strncmp(var, start + 2, len) == 0 && var[len] == '\0') {
2300 return (0); /* match */
2301 } else {
2302 /*
2303 * Not the variable we want to
2304 * expand.
2305 */
2306 return (str - start);
2307 }
2308 } else {
2309 ++str;
2310 }
2311 }
2312 return (str - start);
2313 } else {
2314 /* Single letter variable name */
2315 if (var[1] == '\0' && var[0] == str[0]) {
2316 return (0); /* match */
2317 } else {
2318 str++; /* consume variable name */
2319 return (str - start);
2320 }
2321 }
2322 }
2323
2324 /**
2325 * Substitute for all variables in the given string in the given
2326 * context If err is TRUE, Parse_Error will be called when an
2327 * undefined variable is encountered.
2328 *
2329 * Results:
2330 * The resulting string.
2331 *
2332 * Side Effects:
2333 * None. The old string must be freed by the caller
2334 */
2335 Buffer *
Var_Subst(const char * str,GNode * ctxt,Boolean err)2336 Var_Subst(const char *str, GNode *ctxt, Boolean err)
2337 {
2338 Boolean errorReported;
2339 Buffer *buf; /* Buffer for forming things */
2340
2341 /*
2342 * Set TRUE if an error has already been reported to prevent a
2343 * plethora of messages when recursing. XXXHB this comment sounds
2344 * wrong.
2345 */
2346 errorReported = FALSE;
2347
2348 buf = Buf_Init(0);
2349 while (str[0] != '\0') {
2350 if ((str[0] == '$') && (str[1] == '$')) {
2351 /*
2352 * A dollar sign may be escaped with another dollar
2353 * sign. In such a case, we skip over the escape
2354 * character and store the dollar sign into the
2355 * buffer directly.
2356 */
2357 str++;
2358 Buf_AddByte(buf, (Byte)str[0]);
2359 str++;
2360
2361 } else if (str[0] == '$') {
2362 /* Variable invocation. */
2363 VarParser subvp = {
2364 str,
2365 str,
2366 ctxt,
2367 err,
2368 TRUE
2369 };
2370 char *rval;
2371 Boolean rfree;
2372
2373 rval = VarParse(&subvp, &rfree);
2374
2375 /*
2376 * When we come down here, val should either point to
2377 * the value of this variable, suitably modified, or
2378 * be NULL. Length should be the total length of the
2379 * potential variable invocation (from $ to end
2380 * character...)
2381 */
2382 if (rval == var_Error || rval == varNoError) {
2383 /*
2384 * If performing old-time variable
2385 * substitution, skip over the variable and
2386 * continue with the substitution. Otherwise,
2387 * store the dollar sign and advance str so
2388 * we continue with the string...
2389 */
2390 if (oldVars) {
2391 str = subvp.ptr;
2392 } else if (err) {
2393 /*
2394 * If variable is undefined, complain
2395 * and skip the variable. The
2396 * complaint will stop us from doing
2397 * anything when the file is parsed.
2398 */
2399 if (!errorReported) {
2400 Parse_Error(PARSE_FATAL,
2401 "Undefined variable \"%.*s\"", subvp.ptr - subvp.input, str);
2402 }
2403 errorReported = TRUE;
2404 str = subvp.ptr;
2405 } else {
2406 Buf_AddByte(buf, (Byte)str[0]);
2407 str++;
2408 }
2409 } else {
2410 /*
2411 * Copy all the characters from the variable
2412 * value straight into the new string.
2413 */
2414 Buf_Append(buf, rval);
2415 if (rfree) {
2416 free(rval);
2417 }
2418 str = subvp.ptr;
2419 }
2420 } else {
2421 Buf_AddByte(buf, (Byte)str[0]);
2422 str++;
2423 }
2424 }
2425
2426 return (buf);
2427 }
2428
2429 /**
2430 * Substitute for all variables except if it is the same as 'var',
2431 * in the given string in the given context. If err is TRUE,
2432 * Parse_Error will be called when an undefined variable is
2433 * encountered.
2434 *
2435 * Results:
2436 * The resulting string.
2437 *
2438 * Side Effects:
2439 * None. The old string must be freed by the caller
2440 */
2441 Buffer *
Var_SubstOnly(const char * var,const char * str,Boolean err)2442 Var_SubstOnly(const char *var, const char *str, Boolean err)
2443 {
2444 GNode *ctxt = VAR_GLOBAL;
2445 Boolean errorReported;
2446 Buffer *buf; /* Buffer for forming things */
2447
2448 /*
2449 * Set TRUE if an error has already been reported to prevent a
2450 * plethora of messages when recursing. XXXHB this comment sounds
2451 * wrong.
2452 */
2453 errorReported = FALSE;
2454
2455 buf = Buf_Init(0);
2456 while (str[0] != '\0') {
2457 if (str[0] == '$') {
2458 int skip;
2459
2460 skip = match_var(str, var);
2461 if (skip > 0) {
2462 Buf_AddBytes(buf, skip, str);
2463 str += skip;
2464 } else {
2465 /* Variable invocation. */
2466 VarParser subvp = {
2467 str,
2468 str,
2469 ctxt,
2470 err,
2471 TRUE
2472 };
2473 char *rval;
2474 Boolean rfree;
2475
2476 rval = VarParse(&subvp, &rfree);
2477
2478 /*
2479 * When we get down here, rval should either
2480 * point to the value of this variable, or be
2481 * NULL.
2482 */
2483 if (rval == var_Error || rval == varNoError) {
2484 /*
2485 * If performing old-time variable
2486 * substitution, skip over the
2487 * variable and continue with the
2488 * substitution. Otherwise, store the
2489 * dollar sign and advance str so we
2490 * continue with the string...
2491 */
2492 if (oldVars) {
2493 str = subvp.ptr;
2494 } else if (err) {
2495 /*
2496 * If variable is undefined,
2497 * complain and skip the
2498 * variable. The complaint
2499 * will stop us from doing
2500 * anything when the file is
2501 * parsed.
2502 */
2503 if (!errorReported) {
2504 Parse_Error(PARSE_FATAL,
2505 "Undefined variable \"%.*s\"", subvp.ptr - subvp.input, str);
2506 }
2507 errorReported = TRUE;
2508 str = subvp.ptr;
2509 } else {
2510 Buf_AddByte(buf, (Byte)str[0]);
2511 str++;
2512 }
2513 } else {
2514 /*
2515 * Copy all the characters from the
2516 * variable value straight into the
2517 * new string.
2518 */
2519 Buf_Append(buf, rval);
2520 if (rfree) {
2521 free(rval);
2522 }
2523 str = subvp.ptr;
2524 }
2525 }
2526 } else {
2527 Buf_AddByte(buf, (Byte)str[0]);
2528 str++;
2529 }
2530 }
2531
2532 return (buf);
2533 }
2534
2535 /**
2536 * Initialize the module
2537 *
2538 * Side Effects:
2539 * The VAR_CMD and VAR_GLOBAL contexts are created
2540 */
2541 void
Var_Init(char ** env)2542 Var_Init(char **env)
2543 {
2544 char **ptr;
2545
2546 VAR_CMD = Targ_NewGN("Command");
2547 VAR_ENV = Targ_NewGN("Environment");
2548 VAR_GLOBAL = Targ_NewGN("Global");
2549
2550 /*
2551 * Copy user environment variables into ENV context.
2552 */
2553 for (ptr = env; *ptr != NULL; ++ptr) {
2554 char *tmp = estrdup(*ptr);
2555 const char *name = tmp;
2556 char *sep = strchr(name, '=');
2557 const char *value = sep + 1;
2558
2559 if (sep != NULL) {
2560 *sep = '\0';
2561 VarAdd(name, value, VAR_ENV);
2562 }
2563 free(tmp);
2564 }
2565 }
2566
2567 /**
2568 * Print all variables in global and command line contexts.
2569 */
2570 void
Var_Dump(void)2571 Var_Dump(void)
2572 {
2573 const LstNode *ln;
2574 const Var *v;
2575
2576 printf("#*** Global Variables:\n");
2577 LST_FOREACH(ln, &VAR_GLOBAL->context) {
2578 v = Lst_Datum(ln);
2579 printf("%-16s = %s\n", v->name, Buf_Data(v->val));
2580 }
2581
2582 printf("#*** Command-line Variables:\n");
2583 LST_FOREACH(ln, &VAR_CMD->context) {
2584 v = Lst_Datum(ln);
2585 printf("%-16s = %s\n", v->name, Buf_Data(v->val));
2586 }
2587 }
2588
2589 /**
2590 * Print the values of any variables requested by
2591 * the user.
2592 */
2593 void
Var_Print(Lst * vlist,Boolean expandVars)2594 Var_Print(Lst *vlist, Boolean expandVars)
2595 {
2596 LstNode *n;
2597 char *name;
2598
2599 LST_FOREACH(n, vlist) {
2600 name = Lst_Datum(n);
2601 if (expandVars) {
2602 char *value;
2603 char *v;
2604
2605 if (*name == '$') {
2606 v = name;
2607 } else {
2608 v = emalloc(strlen(name) + 1 + 3);
2609 sprintf(v, "${%s}", name);
2610 }
2611 value = Buf_Peel(Var_Subst(v, VAR_GLOBAL, FALSE));
2612 printf("%s\n", value);
2613
2614 if (v != name)
2615 free(v);
2616 free(value);
2617 } else {
2618 const char *value = Var_Value(name, VAR_GLOBAL);
2619 printf("%s\n", value != NULL ? value : "");
2620 }
2621 }
2622 }
2623
2624