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