var.c revision 1.29 1 /* $NetBSD: var.c,v 1.29 1998/11/01 03:07:34 itohy 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.29 1998/11/01 03:07:34 itohy 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.29 1998/11/01 03:07:34 itohy 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 free(v->name);
611 Buf_Destroy(v->val, FALSE);
612 free((Address) v);
613 *frp = p;
614 }
615 return p;
616 } else {
617 return ((char *) NULL);
618 }
619 }
620
621 /*-
622 *-----------------------------------------------------------------------
623 * VarHead --
624 * Remove the tail of the given word and place the result in the given
625 * buffer.
626 *
627 * Results:
628 * TRUE if characters were added to the buffer (a space needs to be
629 * added to the buffer before the next word).
630 *
631 * Side Effects:
632 * The trimmed word is added to the buffer.
633 *
634 *-----------------------------------------------------------------------
635 */
636 static Boolean
637 VarHead (word, addSpace, buf, dummy)
638 char *word; /* Word to trim */
639 Boolean addSpace; /* True if need to add a space to the buffer
640 * before sticking in the head */
641 Buffer buf; /* Buffer in which to store it */
642 ClientData dummy;
643 {
644 register char *slash;
645
646 slash = strrchr (word, '/');
647 if (slash != (char *)NULL) {
648 if (addSpace) {
649 Buf_AddByte (buf, (Byte)' ');
650 }
651 *slash = '\0';
652 Buf_AddBytes (buf, strlen (word), (Byte *)word);
653 *slash = '/';
654 return (TRUE);
655 } else {
656 /*
657 * If no directory part, give . (q.v. the POSIX standard)
658 */
659 if (addSpace) {
660 Buf_AddBytes(buf, 2, (Byte *)" .");
661 } else {
662 Buf_AddByte(buf, (Byte)'.');
663 }
664 }
665 return(dummy ? TRUE : TRUE);
666 }
667
668 /*-
669 *-----------------------------------------------------------------------
670 * VarTail --
671 * Remove the head of the given word and place the result in the given
672 * buffer.
673 *
674 * Results:
675 * TRUE if characters were added to the buffer (a space needs to be
676 * added to the buffer before the next word).
677 *
678 * Side Effects:
679 * The trimmed word is added to the buffer.
680 *
681 *-----------------------------------------------------------------------
682 */
683 static Boolean
684 VarTail (word, addSpace, buf, dummy)
685 char *word; /* Word to trim */
686 Boolean addSpace; /* TRUE if need to stick a space in the
687 * buffer before adding the tail */
688 Buffer buf; /* Buffer in which to store it */
689 ClientData dummy;
690 {
691 register char *slash;
692
693 if (addSpace) {
694 Buf_AddByte (buf, (Byte)' ');
695 }
696
697 slash = strrchr (word, '/');
698 if (slash != (char *)NULL) {
699 *slash++ = '\0';
700 Buf_AddBytes (buf, strlen(slash), (Byte *)slash);
701 slash[-1] = '/';
702 } else {
703 Buf_AddBytes (buf, strlen(word), (Byte *)word);
704 }
705 return (dummy ? TRUE : TRUE);
706 }
707
708 /*-
709 *-----------------------------------------------------------------------
710 * VarSuffix --
711 * Place the suffix of the given word in the given buffer.
712 *
713 * Results:
714 * TRUE if characters were added to the buffer (a space needs to be
715 * added to the buffer before the next word).
716 *
717 * Side Effects:
718 * The suffix from the word is placed in the buffer.
719 *
720 *-----------------------------------------------------------------------
721 */
722 static Boolean
723 VarSuffix (word, addSpace, buf, dummy)
724 char *word; /* Word to trim */
725 Boolean addSpace; /* TRUE if need to add a space before placing
726 * the suffix in the buffer */
727 Buffer buf; /* Buffer in which to store it */
728 ClientData dummy;
729 {
730 register char *dot;
731
732 dot = strrchr (word, '.');
733 if (dot != (char *)NULL) {
734 if (addSpace) {
735 Buf_AddByte (buf, (Byte)' ');
736 }
737 *dot++ = '\0';
738 Buf_AddBytes (buf, strlen (dot), (Byte *)dot);
739 dot[-1] = '.';
740 addSpace = TRUE;
741 }
742 return (dummy ? addSpace : addSpace);
743 }
744
745 /*-
746 *-----------------------------------------------------------------------
747 * VarRoot --
748 * Remove the suffix of the given word and place the result in the
749 * buffer.
750 *
751 * Results:
752 * TRUE if characters were added to the buffer (a space needs to be
753 * added to the buffer before the next word).
754 *
755 * Side Effects:
756 * The trimmed word is added to the buffer.
757 *
758 *-----------------------------------------------------------------------
759 */
760 static Boolean
761 VarRoot (word, addSpace, buf, dummy)
762 char *word; /* Word to trim */
763 Boolean addSpace; /* TRUE if need to add a space to the buffer
764 * before placing the root in it */
765 Buffer buf; /* Buffer in which to store it */
766 ClientData dummy;
767 {
768 register char *dot;
769
770 if (addSpace) {
771 Buf_AddByte (buf, (Byte)' ');
772 }
773
774 dot = strrchr (word, '.');
775 if (dot != (char *)NULL) {
776 *dot = '\0';
777 Buf_AddBytes (buf, strlen (word), (Byte *)word);
778 *dot = '.';
779 } else {
780 Buf_AddBytes (buf, strlen(word), (Byte *)word);
781 }
782 return (dummy ? TRUE : TRUE);
783 }
784
785 /*-
786 *-----------------------------------------------------------------------
787 * VarMatch --
788 * Place the word in the buffer if it matches the given pattern.
789 * Callback function for VarModify to implement the :M modifier.
790 *
791 * Results:
792 * TRUE if a space should be placed in the buffer before the next
793 * word.
794 *
795 * Side Effects:
796 * The word may be copied to the buffer.
797 *
798 *-----------------------------------------------------------------------
799 */
800 static Boolean
801 VarMatch (word, addSpace, buf, pattern)
802 char *word; /* Word to examine */
803 Boolean addSpace; /* TRUE if need to add a space to the
804 * buffer before adding the word, if it
805 * matches */
806 Buffer buf; /* Buffer in which to store it */
807 ClientData pattern; /* Pattern the word must match */
808 {
809 if (Str_Match(word, (char *) pattern)) {
810 if (addSpace) {
811 Buf_AddByte(buf, (Byte)' ');
812 }
813 addSpace = TRUE;
814 Buf_AddBytes(buf, strlen(word), (Byte *)word);
815 }
816 return(addSpace);
817 }
818
819 #ifdef SYSVVARSUB
820 /*-
821 *-----------------------------------------------------------------------
822 * VarSYSVMatch --
823 * Place the word in the buffer if it matches the given pattern.
824 * Callback function for VarModify to implement the System V %
825 * modifiers.
826 *
827 * Results:
828 * TRUE if a space should be placed in the buffer before the next
829 * word.
830 *
831 * Side Effects:
832 * The word may be copied to the buffer.
833 *
834 *-----------------------------------------------------------------------
835 */
836 static Boolean
837 VarSYSVMatch (word, addSpace, buf, patp)
838 char *word; /* Word to examine */
839 Boolean addSpace; /* TRUE if need to add a space to the
840 * buffer before adding the word, if it
841 * matches */
842 Buffer buf; /* Buffer in which to store it */
843 ClientData patp; /* Pattern the word must match */
844 {
845 int len;
846 char *ptr;
847 VarPattern *pat = (VarPattern *) patp;
848
849 if (addSpace)
850 Buf_AddByte(buf, (Byte)' ');
851
852 addSpace = TRUE;
853
854 if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL)
855 Str_SYSVSubst(buf, pat->rhs, ptr, len);
856 else
857 Buf_AddBytes(buf, strlen(word), (Byte *) word);
858
859 return(addSpace);
860 }
861 #endif
862
863
864 /*-
865 *-----------------------------------------------------------------------
866 * VarNoMatch --
867 * Place the word in the buffer if it doesn't match the given pattern.
868 * Callback function for VarModify to implement the :N modifier.
869 *
870 * Results:
871 * TRUE if a space should be placed in the buffer before the next
872 * word.
873 *
874 * Side Effects:
875 * The word may be copied to the buffer.
876 *
877 *-----------------------------------------------------------------------
878 */
879 static Boolean
880 VarNoMatch (word, addSpace, buf, pattern)
881 char *word; /* Word to examine */
882 Boolean addSpace; /* TRUE if need to add a space to the
883 * buffer before adding the word, if it
884 * matches */
885 Buffer buf; /* Buffer in which to store it */
886 ClientData pattern; /* Pattern the word must match */
887 {
888 if (!Str_Match(word, (char *) pattern)) {
889 if (addSpace) {
890 Buf_AddByte(buf, (Byte)' ');
891 }
892 addSpace = TRUE;
893 Buf_AddBytes(buf, strlen(word), (Byte *)word);
894 }
895 return(addSpace);
896 }
897
898
899 /*-
900 *-----------------------------------------------------------------------
901 * VarSubstitute --
902 * Perform a string-substitution on the given word, placing the
903 * result in the passed buffer.
904 *
905 * Results:
906 * TRUE if a space is needed before more characters are added.
907 *
908 * Side Effects:
909 * None.
910 *
911 *-----------------------------------------------------------------------
912 */
913 static Boolean
914 VarSubstitute (word, addSpace, buf, patternp)
915 char *word; /* Word to modify */
916 Boolean addSpace; /* True if space should be added before
917 * other characters */
918 Buffer buf; /* Buffer for result */
919 ClientData patternp; /* Pattern for substitution */
920 {
921 register int wordLen; /* Length of word */
922 register char *cp; /* General pointer */
923 VarPattern *pattern = (VarPattern *) patternp;
924
925 wordLen = strlen(word);
926 if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) !=
927 (VAR_SUB_ONE|VAR_SUB_MATCHED)) {
928 /*
929 * Still substituting -- break it down into simple anchored cases
930 * and if none of them fits, perform the general substitution case.
931 */
932 if ((pattern->flags & VAR_MATCH_START) &&
933 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
934 /*
935 * Anchored at start and beginning of word matches pattern
936 */
937 if ((pattern->flags & VAR_MATCH_END) &&
938 (wordLen == pattern->leftLen)) {
939 /*
940 * Also anchored at end and matches to the end (word
941 * is same length as pattern) add space and rhs only
942 * if rhs is non-null.
943 */
944 if (pattern->rightLen != 0) {
945 if (addSpace) {
946 Buf_AddByte(buf, (Byte)' ');
947 }
948 addSpace = TRUE;
949 Buf_AddBytes(buf, pattern->rightLen,
950 (Byte *)pattern->rhs);
951 }
952 pattern->flags |= VAR_SUB_MATCHED;
953 } else if (pattern->flags & VAR_MATCH_END) {
954 /*
955 * Doesn't match to end -- copy word wholesale
956 */
957 goto nosub;
958 } else {
959 /*
960 * Matches at start but need to copy in trailing characters
961 */
962 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
963 if (addSpace) {
964 Buf_AddByte(buf, (Byte)' ');
965 }
966 addSpace = TRUE;
967 }
968 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
969 Buf_AddBytes(buf, wordLen - pattern->leftLen,
970 (Byte *)(word + pattern->leftLen));
971 pattern->flags |= VAR_SUB_MATCHED;
972 }
973 } else if (pattern->flags & VAR_MATCH_START) {
974 /*
975 * Had to match at start of word and didn't -- copy whole word.
976 */
977 goto nosub;
978 } else if (pattern->flags & VAR_MATCH_END) {
979 /*
980 * Anchored at end, Find only place match could occur (leftLen
981 * characters from the end of the word) and see if it does. Note
982 * that because the $ will be left at the end of the lhs, we have
983 * to use strncmp.
984 */
985 cp = word + (wordLen - pattern->leftLen);
986 if ((cp >= word) &&
987 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
988 /*
989 * Match found. If we will place characters in the buffer,
990 * add a space before hand as indicated by addSpace, then
991 * stuff in the initial, unmatched part of the word followed
992 * by the right-hand-side.
993 */
994 if (((cp - word) + pattern->rightLen) != 0) {
995 if (addSpace) {
996 Buf_AddByte(buf, (Byte)' ');
997 }
998 addSpace = TRUE;
999 }
1000 Buf_AddBytes(buf, cp - word, (Byte *)word);
1001 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
1002 pattern->flags |= VAR_SUB_MATCHED;
1003 } else {
1004 /*
1005 * Had to match at end and didn't. Copy entire word.
1006 */
1007 goto nosub;
1008 }
1009 } else {
1010 /*
1011 * Pattern is unanchored: search for the pattern in the word using
1012 * String_FindSubstring, copying unmatched portions and the
1013 * right-hand-side for each match found, handling non-global
1014 * substitutions correctly, etc. When the loop is done, any
1015 * remaining part of the word (word and wordLen are adjusted
1016 * accordingly through the loop) is copied straight into the
1017 * buffer.
1018 * addSpace is set FALSE as soon as a space is added to the
1019 * buffer.
1020 */
1021 register Boolean done;
1022 int origSize;
1023
1024 done = FALSE;
1025 origSize = Buf_Size(buf);
1026 while (!done) {
1027 cp = Str_FindSubstring(word, pattern->lhs);
1028 if (cp != (char *)NULL) {
1029 if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
1030 Buf_AddByte(buf, (Byte)' ');
1031 addSpace = FALSE;
1032 }
1033 Buf_AddBytes(buf, cp-word, (Byte *)word);
1034 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
1035 wordLen -= (cp - word) + pattern->leftLen;
1036 word = cp + pattern->leftLen;
1037 if (wordLen == 0) {
1038 done = TRUE;
1039 }
1040 if ((pattern->flags & VAR_SUB_GLOBAL) == 0) {
1041 done = TRUE;
1042 }
1043 pattern->flags |= VAR_SUB_MATCHED;
1044 } else {
1045 done = TRUE;
1046 }
1047 }
1048 if (wordLen != 0) {
1049 if (addSpace) {
1050 Buf_AddByte(buf, (Byte)' ');
1051 }
1052 Buf_AddBytes(buf, wordLen, (Byte *)word);
1053 }
1054 /*
1055 * If added characters to the buffer, need to add a space
1056 * before we add any more. If we didn't add any, just return
1057 * the previous value of addSpace.
1058 */
1059 return ((Buf_Size(buf) != origSize) || addSpace);
1060 }
1061 return (addSpace);
1062 }
1063 nosub:
1064 if (addSpace) {
1065 Buf_AddByte(buf, (Byte)' ');
1066 }
1067 Buf_AddBytes(buf, wordLen, (Byte *)word);
1068 return(TRUE);
1069 }
1070
1071 #ifndef MAKE_BOOTSTRAP
1072 /*-
1073 *-----------------------------------------------------------------------
1074 * VarREError --
1075 * Print the error caused by a regcomp or regexec call.
1076 *
1077 * Results:
1078 * None.
1079 *
1080 * Side Effects:
1081 * An error gets printed.
1082 *
1083 *-----------------------------------------------------------------------
1084 */
1085 static void
1086 VarREError(err, pat, str)
1087 int err;
1088 regex_t *pat;
1089 const char *str;
1090 {
1091 char *errbuf;
1092 int errlen;
1093
1094 errlen = regerror(err, pat, 0, 0);
1095 errbuf = emalloc(errlen);
1096 regerror(err, pat, errbuf, errlen);
1097 Error("%s: %s", str, errbuf);
1098 free(errbuf);
1099 }
1100
1101
1102 /*-
1103 *-----------------------------------------------------------------------
1104 * VarRESubstitute --
1105 * Perform a regex substitution on the given word, placing the
1106 * result in the passed buffer.
1107 *
1108 * Results:
1109 * TRUE if a space is needed before more characters are added.
1110 *
1111 * Side Effects:
1112 * None.
1113 *
1114 *-----------------------------------------------------------------------
1115 */
1116 static Boolean
1117 VarRESubstitute(word, addSpace, buf, patternp)
1118 char *word;
1119 Boolean addSpace;
1120 Buffer buf;
1121 ClientData patternp;
1122 {
1123 VarREPattern *pat;
1124 int xrv;
1125 char *wp;
1126 char *rp;
1127 int added;
1128 int flags = 0;
1129
1130 #define MAYBE_ADD_SPACE() \
1131 if (addSpace && !added) \
1132 Buf_AddByte(buf, ' '); \
1133 added = 1
1134
1135 added = 0;
1136 wp = word;
1137 pat = patternp;
1138
1139 if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==
1140 (VAR_SUB_ONE|VAR_SUB_MATCHED))
1141 xrv = REG_NOMATCH;
1142 else {
1143 tryagain:
1144 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
1145 }
1146
1147 switch (xrv) {
1148 case 0:
1149 pat->flags |= VAR_SUB_MATCHED;
1150 if (pat->matches[0].rm_so > 0) {
1151 MAYBE_ADD_SPACE();
1152 Buf_AddBytes(buf, pat->matches[0].rm_so, wp);
1153 }
1154
1155 for (rp = pat->replace; *rp; rp++) {
1156 if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
1157 MAYBE_ADD_SPACE();
1158 Buf_AddByte(buf,rp[1]);
1159 rp++;
1160 }
1161 else if ((*rp == '&') || ((*rp == '\\') && isdigit(rp[1]))) {
1162 int n;
1163 char *subbuf;
1164 int sublen;
1165 char errstr[3];
1166
1167 if (*rp == '&') {
1168 n = 0;
1169 errstr[0] = '&';
1170 errstr[1] = '\0';
1171 } else {
1172 n = rp[1] - '0';
1173 errstr[0] = '\\';
1174 errstr[1] = rp[1];
1175 errstr[2] = '\0';
1176 rp++;
1177 }
1178
1179 if (n > pat->nsub) {
1180 Error("No subexpression %s", &errstr[0]);
1181 subbuf = "";
1182 sublen = 0;
1183 } else if ((pat->matches[n].rm_so == -1) &&
1184 (pat->matches[n].rm_eo == -1)) {
1185 Error("No match for subexpression %s", &errstr[0]);
1186 subbuf = "";
1187 sublen = 0;
1188 } else {
1189 subbuf = wp + pat->matches[n].rm_so;
1190 sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
1191 }
1192
1193 if (sublen > 0) {
1194 MAYBE_ADD_SPACE();
1195 Buf_AddBytes(buf, sublen, subbuf);
1196 }
1197 } else {
1198 MAYBE_ADD_SPACE();
1199 Buf_AddByte(buf, *rp);
1200 }
1201 }
1202 wp += pat->matches[0].rm_eo;
1203 if (pat->flags & VAR_SUB_GLOBAL) {
1204 flags |= REG_NOTBOL;
1205 if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {
1206 MAYBE_ADD_SPACE();
1207 Buf_AddByte(buf, *wp);
1208 wp++;
1209
1210 }
1211 if (*wp)
1212 goto tryagain;
1213 }
1214 if (*wp) {
1215 MAYBE_ADD_SPACE();
1216 Buf_AddBytes(buf, strlen(wp), wp);
1217 }
1218 break;
1219 default:
1220 VarREError(xrv, &pat->re, "Unexpected regex error");
1221 /* fall through */
1222 case REG_NOMATCH:
1223 if (*wp) {
1224 MAYBE_ADD_SPACE();
1225 Buf_AddBytes(buf,strlen(wp),wp);
1226 }
1227 break;
1228 }
1229 return(addSpace||added);
1230 }
1231 #endif
1232
1233
1234 /*-
1235 *-----------------------------------------------------------------------
1236 * VarModify --
1237 * Modify each of the words of the passed string using the given
1238 * function. Used to implement all modifiers.
1239 *
1240 * Results:
1241 * A string of all the words modified appropriately.
1242 *
1243 * Side Effects:
1244 * None.
1245 *
1246 *-----------------------------------------------------------------------
1247 */
1248 static char *
1249 VarModify (str, modProc, datum)
1250 char *str; /* String whose words should be trimmed */
1251 /* Function to use to modify them */
1252 Boolean (*modProc) __P((char *, Boolean, Buffer, ClientData));
1253 ClientData datum; /* Datum to pass it */
1254 {
1255 Buffer buf; /* Buffer for the new string */
1256 Boolean addSpace; /* TRUE if need to add a space to the
1257 * buffer before adding the trimmed
1258 * word */
1259 char **av; /* word list [first word does not count] */
1260 char *as; /* word list memory */
1261 int ac, i;
1262
1263 buf = Buf_Init (0);
1264 addSpace = FALSE;
1265
1266 av = brk_string(str, &ac, FALSE, &as);
1267
1268 for (i = 0; i < ac; i++)
1269 addSpace = (*modProc)(av[i], addSpace, buf, datum);
1270
1271 free(as);
1272 free(av);
1273
1274 Buf_AddByte (buf, '\0');
1275 str = (char *)Buf_GetAll (buf, (int *)NULL);
1276 Buf_Destroy (buf, FALSE);
1277 return (str);
1278 }
1279
1280 /*-
1281 *-----------------------------------------------------------------------
1282 * VarGetPattern --
1283 * Pass through the tstr looking for 1) escaped delimiters,
1284 * '$'s and backslashes (place the escaped character in
1285 * uninterpreted) and 2) unescaped $'s that aren't before
1286 * the delimiter (expand the variable substitution).
1287 * Return the expanded string or NULL if the delimiter was missing
1288 * If pattern is specified, handle escaped ampersands, and replace
1289 * unescaped ampersands with the lhs of the pattern.
1290 *
1291 * Results:
1292 * A string of all the words modified appropriately.
1293 * If length is specified, return the string length of the buffer
1294 * If flags is specified and the last character of the pattern is a
1295 * $ set the VAR_MATCH_END bit of flags.
1296 *
1297 * Side Effects:
1298 * None.
1299 *-----------------------------------------------------------------------
1300 */
1301 static char *
1302 VarGetPattern(ctxt, err, tstr, delim, flags, length, pattern)
1303 GNode *ctxt;
1304 int err;
1305 char **tstr;
1306 int delim;
1307 int *flags;
1308 int *length;
1309 VarPattern *pattern;
1310 {
1311 char *cp;
1312 Buffer buf = Buf_Init(0);
1313 int junk;
1314 if (length == NULL)
1315 length = &junk;
1316
1317 #define IS_A_MATCH(cp, delim) \
1318 ((cp[0] == '\\') && ((cp[1] == delim) || \
1319 (cp[1] == '\\') || (cp[1] == '$') || (pattern && (cp[1] == '&'))))
1320
1321 /*
1322 * Skim through until the matching delimiter is found;
1323 * pick up variable substitutions on the way. Also allow
1324 * backslashes to quote the delimiter, $, and \, but don't
1325 * touch other backslashes.
1326 */
1327 for (cp = *tstr; *cp && (*cp != delim); cp++) {
1328 if (IS_A_MATCH(cp, delim)) {
1329 Buf_AddByte(buf, (Byte) cp[1]);
1330 cp++;
1331 } else if (*cp == '$') {
1332 if (cp[1] == delim) {
1333 if (flags == NULL)
1334 Buf_AddByte(buf, (Byte) *cp);
1335 else
1336 /*
1337 * Unescaped $ at end of pattern => anchor
1338 * pattern at end.
1339 */
1340 *flags |= VAR_MATCH_END;
1341 }
1342 else {
1343 char *cp2;
1344 int len;
1345 Boolean freeIt;
1346
1347 /*
1348 * If unescaped dollar sign not before the
1349 * delimiter, assume it's a variable
1350 * substitution and recurse.
1351 */
1352 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
1353 Buf_AddBytes(buf, strlen(cp2), (Byte *) cp2);
1354 if (freeIt)
1355 free(cp2);
1356 cp += len - 1;
1357 }
1358 }
1359 else if (pattern && *cp == '&')
1360 Buf_AddBytes(buf, pattern->leftLen, (Byte *)pattern->lhs);
1361 else
1362 Buf_AddByte(buf, (Byte) *cp);
1363 }
1364
1365 Buf_AddByte(buf, (Byte) '\0');
1366
1367 if (*cp != delim) {
1368 *tstr = cp;
1369 *length = 0;
1370 return NULL;
1371 }
1372 else {
1373 *tstr = ++cp;
1374 cp = (char *) Buf_GetAll(buf, length);
1375 *length -= 1; /* Don't count the NULL */
1376 Buf_Destroy(buf, FALSE);
1377 return cp;
1378 }
1379 }
1380
1381 /*-
1382 *-----------------------------------------------------------------------
1383 * VarQuote --
1384 * Quote shell meta-characters in the string
1385 *
1386 * Results:
1387 * The quoted string
1388 *
1389 * Side Effects:
1390 * None.
1391 *
1392 *-----------------------------------------------------------------------
1393 */
1394 static char *
1395 VarQuote(str)
1396 char *str;
1397 {
1398
1399 Buffer buf;
1400 /* This should cover most shells :-( */
1401 static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
1402
1403 buf = Buf_Init (MAKE_BSIZE);
1404 for (; *str; str++) {
1405 if (strchr(meta, *str) != NULL)
1406 Buf_AddByte(buf, (Byte)'\\');
1407 Buf_AddByte(buf, (Byte)*str);
1408 }
1409 Buf_AddByte(buf, (Byte) '\0');
1410 str = (char *)Buf_GetAll (buf, (int *)NULL);
1411 Buf_Destroy (buf, FALSE);
1412 return str;
1413 }
1414
1415
1416 /*-
1417 *-----------------------------------------------------------------------
1418 * Var_Parse --
1419 * Given the start of a variable invocation, extract the variable
1420 * name and find its value, then modify it according to the
1421 * specification.
1422 *
1423 * Results:
1424 * The (possibly-modified) value of the variable or var_Error if the
1425 * specification is invalid. The length of the specification is
1426 * placed in *lengthPtr (for invalid specifications, this is just
1427 * 2...?).
1428 * A Boolean in *freePtr telling whether the returned string should
1429 * be freed by the caller.
1430 *
1431 * Side Effects:
1432 * None.
1433 *
1434 *-----------------------------------------------------------------------
1435 */
1436 char *
1437 Var_Parse (str, ctxt, err, lengthPtr, freePtr)
1438 char *str; /* The string to parse */
1439 GNode *ctxt; /* The context for the variable */
1440 Boolean err; /* TRUE if undefined variables are an error */
1441 int *lengthPtr; /* OUT: The length of the specification */
1442 Boolean *freePtr; /* OUT: TRUE if caller should free result */
1443 {
1444 register char *tstr; /* Pointer into str */
1445 Var *v; /* Variable in invocation */
1446 char *cp; /* Secondary pointer into str (place marker
1447 * for tstr) */
1448 Boolean haveModifier;/* TRUE if have modifiers for the variable */
1449 register char endc; /* Ending character when variable in parens
1450 * or braces */
1451 register char startc=0; /* Starting character when variable in parens
1452 * or braces */
1453 int cnt; /* Used to count brace pairs when variable in
1454 * in parens or braces */
1455 int vlen; /* Length of variable name */
1456 char *start;
1457 char delim;
1458 Boolean dynamic; /* TRUE if the variable is local and we're
1459 * expanding it in a non-local context. This
1460 * is done to support dynamic sources. The
1461 * result is just the invocation, unaltered */
1462
1463 *freePtr = FALSE;
1464 dynamic = FALSE;
1465 start = str;
1466
1467 if (str[1] != '(' && str[1] != '{') {
1468 /*
1469 * If it's not bounded by braces of some sort, life is much simpler.
1470 * We just need to check for the first character and return the
1471 * value if it exists.
1472 */
1473 char name[2];
1474
1475 name[0] = str[1];
1476 name[1] = '\0';
1477
1478 v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1479 if (v == (Var *)NIL) {
1480 *lengthPtr = 2;
1481
1482 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
1483 /*
1484 * If substituting a local variable in a non-local context,
1485 * assume it's for dynamic source stuff. We have to handle
1486 * this specially and return the longhand for the variable
1487 * with the dollar sign escaped so it makes it back to the
1488 * caller. Only four of the local variables are treated
1489 * specially as they are the only four that will be set
1490 * when dynamic sources are expanded.
1491 */
1492 switch (str[1]) {
1493 case '@':
1494 return("$(.TARGET)");
1495 case '%':
1496 return("$(.ARCHIVE)");
1497 case '*':
1498 return("$(.PREFIX)");
1499 case '!':
1500 return("$(.MEMBER)");
1501 }
1502 }
1503 /*
1504 * Error
1505 */
1506 return (err ? var_Error : varNoError);
1507 } else {
1508 haveModifier = FALSE;
1509 tstr = &str[1];
1510 endc = str[1];
1511 }
1512 } else {
1513 Buffer buf; /* Holds the variable name */
1514
1515 startc = str[1];
1516 endc = startc == '(' ? ')' : '}';
1517 buf = Buf_Init (MAKE_BSIZE);
1518
1519 /*
1520 * Skip to the end character or a colon, whichever comes first.
1521 */
1522 for (tstr = str + 2;
1523 *tstr != '\0' && *tstr != endc && *tstr != ':';
1524 tstr++)
1525 {
1526 /*
1527 * A variable inside a variable, expand
1528 */
1529 if (*tstr == '$') {
1530 int rlen;
1531 Boolean rfree;
1532 char *rval = Var_Parse(tstr, ctxt, err, &rlen, &rfree);
1533 if (rval != NULL) {
1534 Buf_AddBytes(buf, strlen(rval), (Byte *) rval);
1535 if (rfree)
1536 free(rval);
1537 }
1538 tstr += rlen - 1;
1539 }
1540 else
1541 Buf_AddByte(buf, (Byte) *tstr);
1542 }
1543 if (*tstr == ':') {
1544 haveModifier = TRUE;
1545 } else if (*tstr != '\0') {
1546 haveModifier = FALSE;
1547 } else {
1548 /*
1549 * If we never did find the end character, return NULL
1550 * right now, setting the length to be the distance to
1551 * the end of the string, since that's what make does.
1552 */
1553 *lengthPtr = tstr - str;
1554 return (var_Error);
1555 }
1556 *tstr = '\0';
1557 Buf_AddByte(buf, (Byte) '\0');
1558 str = Buf_GetAll(buf, (int *) NULL);
1559 vlen = strlen(str);
1560
1561 v = VarFind (str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1562 if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
1563 (vlen == 2) && (str[1] == 'F' || str[1] == 'D'))
1564 {
1565 /*
1566 * Check for bogus D and F forms of local variables since we're
1567 * in a local context and the name is the right length.
1568 */
1569 switch(*str) {
1570 case '@':
1571 case '%':
1572 case '*':
1573 case '!':
1574 case '>':
1575 case '<':
1576 {
1577 char vname[2];
1578 char *val;
1579
1580 /*
1581 * Well, it's local -- go look for it.
1582 */
1583 vname[0] = *str;
1584 vname[1] = '\0';
1585 v = VarFind(vname, ctxt, 0);
1586
1587 if (v != (Var *)NIL) {
1588 /*
1589 * No need for nested expansion or anything, as we're
1590 * the only one who sets these things and we sure don't
1591 * but nested invocations in them...
1592 */
1593 val = (char *)Buf_GetAll(v->val, (int *)NULL);
1594
1595 if (str[1] == 'D') {
1596 val = VarModify(val, VarHead, (ClientData)0);
1597 } else {
1598 val = VarModify(val, VarTail, (ClientData)0);
1599 }
1600 /*
1601 * Resulting string is dynamically allocated, so
1602 * tell caller to free it.
1603 */
1604 *freePtr = TRUE;
1605 *lengthPtr = tstr-start+1;
1606 *tstr = endc;
1607 Buf_Destroy (buf, TRUE);
1608 return(val);
1609 }
1610 break;
1611 }
1612 }
1613 }
1614
1615 if (v == (Var *)NIL) {
1616 if (((vlen == 1) ||
1617 (((vlen == 2) && (str[1] == 'F' ||
1618 str[1] == 'D')))) &&
1619 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
1620 {
1621 /*
1622 * If substituting a local variable in a non-local context,
1623 * assume it's for dynamic source stuff. We have to handle
1624 * this specially and return the longhand for the variable
1625 * with the dollar sign escaped so it makes it back to the
1626 * caller. Only four of the local variables are treated
1627 * specially as they are the only four that will be set
1628 * when dynamic sources are expanded.
1629 */
1630 switch (*str) {
1631 case '@':
1632 case '%':
1633 case '*':
1634 case '!':
1635 dynamic = TRUE;
1636 break;
1637 }
1638 } else if ((vlen > 2) && (*str == '.') &&
1639 isupper((unsigned char) str[1]) &&
1640 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
1641 {
1642 int len;
1643
1644 len = vlen - 1;
1645 if ((strncmp(str, ".TARGET", len) == 0) ||
1646 (strncmp(str, ".ARCHIVE", len) == 0) ||
1647 (strncmp(str, ".PREFIX", len) == 0) ||
1648 (strncmp(str, ".MEMBER", len) == 0))
1649 {
1650 dynamic = TRUE;
1651 }
1652 }
1653
1654 if (!haveModifier) {
1655 /*
1656 * No modifiers -- have specification length so we can return
1657 * now.
1658 */
1659 *lengthPtr = tstr - start + 1;
1660 *tstr = endc;
1661 if (dynamic) {
1662 str = emalloc(*lengthPtr + 1);
1663 strncpy(str, start, *lengthPtr);
1664 str[*lengthPtr] = '\0';
1665 *freePtr = TRUE;
1666 Buf_Destroy (buf, TRUE);
1667 return(str);
1668 } else {
1669 Buf_Destroy (buf, TRUE);
1670 return (err ? var_Error : varNoError);
1671 }
1672 } else {
1673 /*
1674 * Still need to get to the end of the variable specification,
1675 * so kludge up a Var structure for the modifications
1676 */
1677 v = (Var *) emalloc(sizeof(Var));
1678 v->name = &str[1];
1679 v->val = Buf_Init(1);
1680 v->flags = VAR_JUNK;
1681 }
1682 }
1683 Buf_Destroy (buf, TRUE);
1684 }
1685
1686
1687 if (v->flags & VAR_IN_USE) {
1688 Fatal("Variable %s is recursive.", v->name);
1689 /*NOTREACHED*/
1690 } else {
1691 v->flags |= VAR_IN_USE;
1692 }
1693 /*
1694 * Before doing any modification, we have to make sure the value
1695 * has been fully expanded. If it looks like recursion might be
1696 * necessary (there's a dollar sign somewhere in the variable's value)
1697 * we just call Var_Subst to do any other substitutions that are
1698 * necessary. Note that the value returned by Var_Subst will have
1699 * been dynamically-allocated, so it will need freeing when we
1700 * return.
1701 */
1702 str = (char *)Buf_GetAll(v->val, (int *)NULL);
1703 if (strchr (str, '$') != (char *)NULL) {
1704 str = Var_Subst(NULL, str, ctxt, err);
1705 *freePtr = TRUE;
1706 }
1707
1708 v->flags &= ~VAR_IN_USE;
1709
1710 /*
1711 * Now we need to apply any modifiers the user wants applied.
1712 * These are:
1713 * :M<pattern> words which match the given <pattern>.
1714 * <pattern> is of the standard file
1715 * wildcarding form.
1716 * :S<d><pat1><d><pat2><d>[g]
1717 * Substitute <pat2> for <pat1> in the value
1718 * :C<d><pat1><d><pat2><d>[g]
1719 * Substitute <pat2> for regex <pat1> in the value
1720 * :H Substitute the head of each word
1721 * :T Substitute the tail of each word
1722 * :E Substitute the extension (minus '.') of
1723 * each word
1724 * :R Substitute the root of each word
1725 * (pathname minus the suffix).
1726 * :?<true-value>:<false-value>
1727 * If the variable evaluates to true, return
1728 * true value, else return the second value.
1729 * :lhs=rhs Like :S, but the rhs goes to the end of
1730 * the invocation.
1731 */
1732 if ((str != (char *)NULL) && haveModifier) {
1733 /*
1734 * Skip initial colon while putting it back.
1735 */
1736 *tstr++ = ':';
1737 while (*tstr != endc) {
1738 char *newStr; /* New value to return */
1739 char termc; /* Character which terminated scan */
1740
1741 if (DEBUG(VAR)) {
1742 printf("Applying :%c to \"%s\"\n", *tstr, str);
1743 }
1744 switch (*tstr) {
1745 case 'N':
1746 case 'M':
1747 {
1748 char *pattern;
1749 char *cp2;
1750 Boolean copy;
1751
1752 copy = FALSE;
1753 for (cp = tstr + 1;
1754 *cp != '\0' && *cp != ':' && *cp != endc;
1755 cp++)
1756 {
1757 if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){
1758 copy = TRUE;
1759 cp++;
1760 }
1761 }
1762 termc = *cp;
1763 *cp = '\0';
1764 if (copy) {
1765 /*
1766 * Need to compress the \:'s out of the pattern, so
1767 * allocate enough room to hold the uncompressed
1768 * pattern (note that cp started at tstr+1, so
1769 * cp - tstr takes the null byte into account) and
1770 * compress the pattern into the space.
1771 */
1772 pattern = emalloc(cp - tstr);
1773 for (cp2 = pattern, cp = tstr + 1;
1774 *cp != '\0';
1775 cp++, cp2++)
1776 {
1777 if ((*cp == '\\') &&
1778 (cp[1] == ':' || cp[1] == endc)) {
1779 cp++;
1780 }
1781 *cp2 = *cp;
1782 }
1783 *cp2 = '\0';
1784 } else {
1785 pattern = &tstr[1];
1786 }
1787 if (*tstr == 'M' || *tstr == 'm') {
1788 newStr = VarModify(str, VarMatch, (ClientData)pattern);
1789 } else {
1790 newStr = VarModify(str, VarNoMatch,
1791 (ClientData)pattern);
1792 }
1793 if (copy) {
1794 free(pattern);
1795 }
1796 break;
1797 }
1798 case 'S':
1799 {
1800 VarPattern pattern;
1801
1802 pattern.flags = 0;
1803 delim = tstr[1];
1804 tstr += 2;
1805
1806 /*
1807 * If pattern begins with '^', it is anchored to the
1808 * start of the word -- skip over it and flag pattern.
1809 */
1810 if (*tstr == '^') {
1811 pattern.flags |= VAR_MATCH_START;
1812 tstr += 1;
1813 }
1814
1815 cp = tstr;
1816 if ((pattern.lhs = VarGetPattern(ctxt, err, &cp, delim,
1817 &pattern.flags, &pattern.leftLen, NULL)) == NULL)
1818 goto cleanup;
1819
1820 if ((pattern.rhs = VarGetPattern(ctxt, err, &cp, delim,
1821 NULL, &pattern.rightLen, &pattern)) == NULL)
1822 goto cleanup;
1823
1824 /*
1825 * Check for global substitution. If 'g' after the final
1826 * delimiter, substitution is global and is marked that
1827 * way.
1828 */
1829 for (;; cp++) {
1830 switch (*cp) {
1831 case 'g':
1832 pattern.flags |= VAR_SUB_GLOBAL;
1833 continue;
1834 case '1':
1835 pattern.flags |= VAR_SUB_ONE;
1836 continue;
1837 }
1838 break;
1839 }
1840
1841 termc = *cp;
1842 newStr = VarModify(str, VarSubstitute,
1843 (ClientData)&pattern);
1844
1845 /*
1846 * Free the two strings.
1847 */
1848 free(pattern.lhs);
1849 free(pattern.rhs);
1850 break;
1851 }
1852 case '?':
1853 {
1854 VarPattern pattern;
1855 Boolean value;
1856
1857 /* find ':', and then substitute accordingly */
1858
1859 pattern.flags = 0;
1860
1861 cp = ++tstr;
1862 delim = ':';
1863 if ((pattern.lhs = VarGetPattern(ctxt, err, &cp, delim,
1864 NULL, &pattern.leftLen, NULL)) == NULL)
1865 goto cleanup;
1866
1867 delim = '}';
1868 if ((pattern.rhs = VarGetPattern(ctxt, err, &cp, delim,
1869 NULL, &pattern.rightLen, NULL)) == NULL)
1870 goto cleanup;
1871
1872 termc = *--cp;
1873 delim = '\0';
1874 if (Cond_EvalExpression(1, str, &value, 0) == COND_INVALID){
1875 Error("Bad conditional expression `%s' in %s?%s:%s",
1876 str, str, pattern.lhs, pattern.rhs);
1877 goto cleanup;
1878 }
1879
1880 if (value) {
1881 newStr = pattern.lhs;
1882 free(pattern.rhs);
1883 } else {
1884 newStr = pattern.rhs;
1885 free(pattern.lhs);
1886 }
1887 break;
1888 }
1889 #ifndef MAKE_BOOTSTRAP
1890 case 'C':
1891 {
1892 VarREPattern pattern;
1893 char *re;
1894 int error;
1895
1896 pattern.flags = 0;
1897 delim = tstr[1];
1898 tstr += 2;
1899
1900 cp = tstr;
1901
1902 if ((re = VarGetPattern(ctxt, err, &cp, delim, NULL,
1903 NULL, NULL)) == NULL)
1904 goto cleanup;
1905
1906 if ((pattern.replace = VarGetPattern(ctxt, err, &cp,
1907 delim, NULL, NULL, NULL)) == NULL){
1908 free(re);
1909 goto cleanup;
1910 }
1911
1912 for (;; cp++) {
1913 switch (*cp) {
1914 case 'g':
1915 pattern.flags |= VAR_SUB_GLOBAL;
1916 continue;
1917 case '1':
1918 pattern.flags |= VAR_SUB_ONE;
1919 continue;
1920 }
1921 break;
1922 }
1923
1924 termc = *cp;
1925
1926 error = regcomp(&pattern.re, re, REG_EXTENDED);
1927 free(re);
1928 if (error) {
1929 *lengthPtr = cp - start + 1;
1930 VarREError(error, &pattern.re, "RE substitution error");
1931 free(pattern.replace);
1932 return (var_Error);
1933 }
1934
1935 pattern.nsub = pattern.re.re_nsub + 1;
1936 if (pattern.nsub < 1)
1937 pattern.nsub = 1;
1938 if (pattern.nsub > 10)
1939 pattern.nsub = 10;
1940 pattern.matches = emalloc(pattern.nsub *
1941 sizeof(regmatch_t));
1942 newStr = VarModify(str, VarRESubstitute,
1943 (ClientData) &pattern);
1944 regfree(&pattern.re);
1945 free(pattern.replace);
1946 free(pattern.matches);
1947 break;
1948 }
1949 #endif
1950 case 'Q':
1951 if (tstr[1] == endc || tstr[1] == ':') {
1952 newStr = VarQuote (str);
1953 cp = tstr + 1;
1954 termc = *cp;
1955 break;
1956 }
1957 /*FALLTHRU*/
1958 case 'T':
1959 if (tstr[1] == endc || tstr[1] == ':') {
1960 newStr = VarModify (str, VarTail, (ClientData)0);
1961 cp = tstr + 1;
1962 termc = *cp;
1963 break;
1964 }
1965 /*FALLTHRU*/
1966 case 'H':
1967 if (tstr[1] == endc || tstr[1] == ':') {
1968 newStr = VarModify (str, VarHead, (ClientData)0);
1969 cp = tstr + 1;
1970 termc = *cp;
1971 break;
1972 }
1973 /*FALLTHRU*/
1974 case 'E':
1975 if (tstr[1] == endc || tstr[1] == ':') {
1976 newStr = VarModify (str, VarSuffix, (ClientData)0);
1977 cp = tstr + 1;
1978 termc = *cp;
1979 break;
1980 }
1981 /*FALLTHRU*/
1982 case 'R':
1983 if (tstr[1] == endc || tstr[1] == ':') {
1984 newStr = VarModify (str, VarRoot, (ClientData)0);
1985 cp = tstr + 1;
1986 termc = *cp;
1987 break;
1988 }
1989 /*FALLTHRU*/
1990 #ifdef SUNSHCMD
1991 case 's':
1992 if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) {
1993 char *err;
1994 newStr = Cmd_Exec (str, &err);
1995 if (err)
1996 Error (err, str);
1997 cp = tstr + 2;
1998 termc = *cp;
1999 break;
2000 }
2001 /*FALLTHRU*/
2002 #endif
2003 default:
2004 {
2005 #ifdef SYSVVARSUB
2006 /*
2007 * This can either be a bogus modifier or a System-V
2008 * substitution command.
2009 */
2010 VarPattern pattern;
2011 Boolean eqFound;
2012
2013 pattern.flags = 0;
2014 eqFound = FALSE;
2015 /*
2016 * First we make a pass through the string trying
2017 * to verify it is a SYSV-make-style translation:
2018 * it must be: <string1>=<string2>)
2019 */
2020 cp = tstr;
2021 cnt = 1;
2022 while (*cp != '\0' && cnt) {
2023 if (*cp == '=') {
2024 eqFound = TRUE;
2025 /* continue looking for endc */
2026 }
2027 else if (*cp == endc)
2028 cnt--;
2029 else if (*cp == startc)
2030 cnt++;
2031 if (cnt)
2032 cp++;
2033 }
2034 if (*cp == endc && eqFound) {
2035
2036 /*
2037 * Now we break this sucker into the lhs and
2038 * rhs. We must null terminate them of course.
2039 */
2040 for (cp = tstr; *cp != '='; cp++)
2041 continue;
2042 pattern.lhs = tstr;
2043 pattern.leftLen = cp - tstr;
2044 *cp++ = '\0';
2045
2046 pattern.rhs = cp;
2047 cnt = 1;
2048 while (cnt) {
2049 if (*cp == endc)
2050 cnt--;
2051 else if (*cp == startc)
2052 cnt++;
2053 if (cnt)
2054 cp++;
2055 }
2056 pattern.rightLen = cp - pattern.rhs;
2057 *cp = '\0';
2058
2059 /*
2060 * SYSV modifications happen through the whole
2061 * string. Note the pattern is anchored at the end.
2062 */
2063 newStr = VarModify(str, VarSYSVMatch,
2064 (ClientData)&pattern);
2065
2066 /*
2067 * Restore the nulled characters
2068 */
2069 pattern.lhs[pattern.leftLen] = '=';
2070 pattern.rhs[pattern.rightLen] = endc;
2071 termc = endc;
2072 } else
2073 #endif
2074 {
2075 Error ("Unknown modifier '%c'\n", *tstr);
2076 for (cp = tstr+1;
2077 *cp != ':' && *cp != endc && *cp != '\0';
2078 cp++)
2079 continue;
2080 termc = *cp;
2081 newStr = var_Error;
2082 }
2083 }
2084 }
2085 if (DEBUG(VAR)) {
2086 printf("Result is \"%s\"\n", newStr);
2087 }
2088
2089 if (*freePtr) {
2090 free (str);
2091 }
2092 str = newStr;
2093 if (str != var_Error) {
2094 *freePtr = TRUE;
2095 } else {
2096 *freePtr = FALSE;
2097 }
2098 if (termc == '\0') {
2099 Error("Unclosed variable specification for %s", v->name);
2100 } else if (termc == ':') {
2101 *cp++ = termc;
2102 } else {
2103 *cp = termc;
2104 }
2105 tstr = cp;
2106 }
2107 *lengthPtr = tstr - start + 1;
2108 } else {
2109 *lengthPtr = tstr - start + 1;
2110 *tstr = endc;
2111 }
2112
2113 if (v->flags & VAR_FROM_ENV) {
2114 Boolean destroy = FALSE;
2115
2116 if (str != (char *)Buf_GetAll(v->val, (int *)NULL)) {
2117 destroy = TRUE;
2118 } else {
2119 /*
2120 * Returning the value unmodified, so tell the caller to free
2121 * the thing.
2122 */
2123 *freePtr = TRUE;
2124 }
2125 free(v->name);
2126 Buf_Destroy(v->val, destroy);
2127 free((Address)v);
2128 } else if (v->flags & VAR_JUNK) {
2129 /*
2130 * Perform any free'ing needed and set *freePtr to FALSE so the caller
2131 * doesn't try to free a static pointer.
2132 */
2133 if (*freePtr) {
2134 free(str);
2135 }
2136 *freePtr = FALSE;
2137 Buf_Destroy(v->val, TRUE);
2138 free((Address)v);
2139 if (dynamic) {
2140 str = emalloc(*lengthPtr + 1);
2141 strncpy(str, start, *lengthPtr);
2142 str[*lengthPtr] = '\0';
2143 *freePtr = TRUE;
2144 } else {
2145 str = var_Error;
2146 }
2147 }
2148 return (str);
2149
2150 cleanup:
2151 *lengthPtr = cp - start + 1;
2152 if (*freePtr)
2153 free(str);
2154 if (delim != '\0')
2155 Error("Unclosed substitution for %s (%c missing)",
2156 v->name, delim);
2157 return (var_Error);
2158 }
2159
2160 /*-
2161 *-----------------------------------------------------------------------
2162 * Var_Subst --
2163 * Substitute for all variables in the given string in the given context
2164 * If undefErr is TRUE, Parse_Error will be called when an undefined
2165 * variable is encountered.
2166 *
2167 * Results:
2168 * The resulting string.
2169 *
2170 * Side Effects:
2171 * None. The old string must be freed by the caller
2172 *-----------------------------------------------------------------------
2173 */
2174 char *
2175 Var_Subst (var, str, ctxt, undefErr)
2176 char *var; /* Named variable || NULL for all */
2177 char *str; /* the string in which to substitute */
2178 GNode *ctxt; /* the context wherein to find variables */
2179 Boolean undefErr; /* TRUE if undefineds are an error */
2180 {
2181 Buffer buf; /* Buffer for forming things */
2182 char *val; /* Value to substitute for a variable */
2183 int length; /* Length of the variable invocation */
2184 Boolean doFree; /* Set true if val should be freed */
2185 static Boolean errorReported; /* Set true if an error has already
2186 * been reported to prevent a plethora
2187 * of messages when recursing */
2188
2189 buf = Buf_Init (MAKE_BSIZE);
2190 errorReported = FALSE;
2191
2192 while (*str) {
2193 if (var == NULL && (*str == '$') && (str[1] == '$')) {
2194 /*
2195 * A dollar sign may be escaped either with another dollar sign.
2196 * In such a case, we skip over the escape character and store the
2197 * dollar sign into the buffer directly.
2198 */
2199 str++;
2200 Buf_AddByte(buf, (Byte)*str);
2201 str++;
2202 } else if (*str != '$') {
2203 /*
2204 * Skip as many characters as possible -- either to the end of
2205 * the string or to the next dollar sign (variable invocation).
2206 */
2207 char *cp;
2208
2209 for (cp = str++; *str != '$' && *str != '\0'; str++)
2210 continue;
2211 Buf_AddBytes(buf, str - cp, (Byte *)cp);
2212 } else {
2213 if (var != NULL) {
2214 int expand;
2215 for (;;) {
2216 if (str[1] != '(' && str[1] != '{') {
2217 if (str[1] != *var) {
2218 Buf_AddBytes(buf, 2, (Byte *) str);
2219 str += 2;
2220 expand = FALSE;
2221 }
2222 else
2223 expand = TRUE;
2224 break;
2225 }
2226 else {
2227 char *p;
2228
2229 /*
2230 * Scan up to the end of the variable name.
2231 */
2232 for (p = &str[2]; *p &&
2233 *p != ':' && *p != ')' && *p != '}'; p++)
2234 if (*p == '$')
2235 break;
2236 /*
2237 * A variable inside the variable. We cannot expand
2238 * the external variable yet, so we try again with
2239 * the nested one
2240 */
2241 if (*p == '$') {
2242 Buf_AddBytes(buf, p - str, (Byte *) str);
2243 str = p;
2244 continue;
2245 }
2246
2247 if (strncmp(var, str + 2, p - str - 2) != 0 ||
2248 var[p - str - 2] != '\0') {
2249 /*
2250 * Not the variable we want to expand, scan
2251 * until the next variable
2252 */
2253 for (;*p != '$' && *p != '\0'; p++)
2254 continue;
2255 Buf_AddBytes(buf, p - str, (Byte *) str);
2256 str = p;
2257 expand = FALSE;
2258 }
2259 else
2260 expand = TRUE;
2261 break;
2262 }
2263 }
2264 if (!expand)
2265 continue;
2266 }
2267
2268 val = Var_Parse (str, ctxt, undefErr, &length, &doFree);
2269
2270 /*
2271 * When we come down here, val should either point to the
2272 * value of this variable, suitably modified, or be NULL.
2273 * Length should be the total length of the potential
2274 * variable invocation (from $ to end character...)
2275 */
2276 if (val == var_Error || val == varNoError) {
2277 /*
2278 * If performing old-time variable substitution, skip over
2279 * the variable and continue with the substitution. Otherwise,
2280 * store the dollar sign and advance str so we continue with
2281 * the string...
2282 */
2283 if (oldVars) {
2284 str += length;
2285 } else if (undefErr) {
2286 /*
2287 * If variable is undefined, complain and skip the
2288 * variable. The complaint will stop us from doing anything
2289 * when the file is parsed.
2290 */
2291 if (!errorReported) {
2292 Parse_Error (PARSE_FATAL,
2293 "Undefined variable \"%.*s\"",length,str);
2294 }
2295 str += length;
2296 errorReported = TRUE;
2297 } else {
2298 Buf_AddByte (buf, (Byte)*str);
2299 str += 1;
2300 }
2301 } else {
2302 /*
2303 * We've now got a variable structure to store in. But first,
2304 * advance the string pointer.
2305 */
2306 str += length;
2307
2308 /*
2309 * Copy all the characters from the variable value straight
2310 * into the new string.
2311 */
2312 Buf_AddBytes (buf, strlen (val), (Byte *)val);
2313 if (doFree) {
2314 free ((Address)val);
2315 }
2316 }
2317 }
2318 }
2319
2320 Buf_AddByte (buf, '\0');
2321 str = (char *)Buf_GetAll (buf, (int *)NULL);
2322 Buf_Destroy (buf, FALSE);
2323 return (str);
2324 }
2325
2326 /*-
2327 *-----------------------------------------------------------------------
2328 * Var_GetTail --
2329 * Return the tail from each of a list of words. Used to set the
2330 * System V local variables.
2331 *
2332 * Results:
2333 * The resulting string.
2334 *
2335 * Side Effects:
2336 * None.
2337 *
2338 *-----------------------------------------------------------------------
2339 */
2340 char *
2341 Var_GetTail(file)
2342 char *file; /* Filename to modify */
2343 {
2344 return(VarModify(file, VarTail, (ClientData)0));
2345 }
2346
2347 /*-
2348 *-----------------------------------------------------------------------
2349 * Var_GetHead --
2350 * Find the leading components of a (list of) filename(s).
2351 * XXX: VarHead does not replace foo by ., as (sun) System V make
2352 * does.
2353 *
2354 * Results:
2355 * The leading components.
2356 *
2357 * Side Effects:
2358 * None.
2359 *
2360 *-----------------------------------------------------------------------
2361 */
2362 char *
2363 Var_GetHead(file)
2364 char *file; /* Filename to manipulate */
2365 {
2366 return(VarModify(file, VarHead, (ClientData)0));
2367 }
2368
2369 /*-
2370 *-----------------------------------------------------------------------
2371 * Var_Init --
2372 * Initialize the module
2373 *
2374 * Results:
2375 * None
2376 *
2377 * Side Effects:
2378 * The VAR_CMD and VAR_GLOBAL contexts are created
2379 *-----------------------------------------------------------------------
2380 */
2381 void
2382 Var_Init ()
2383 {
2384 VAR_GLOBAL = Targ_NewGN ("Global");
2385 VAR_CMD = Targ_NewGN ("Command");
2386 allVars = Lst_Init(FALSE);
2387
2388 }
2389
2390
2391 void
2392 Var_End ()
2393 {
2394 Lst_Destroy(allVars, VarDelete);
2395 }
2396
2397
2398 /****************** PRINT DEBUGGING INFO *****************/
2399 static int
2400 VarPrintVar (vp, dummy)
2401 ClientData vp;
2402 ClientData dummy;
2403 {
2404 Var *v = (Var *) vp;
2405 printf ("%-16s = %s\n", v->name, (char *) Buf_GetAll(v->val, (int *)NULL));
2406 return (dummy ? 0 : 0);
2407 }
2408
2409 /*-
2410 *-----------------------------------------------------------------------
2411 * Var_Dump --
2412 * print all variables in a context
2413 *-----------------------------------------------------------------------
2414 */
2415 void
2416 Var_Dump (ctxt)
2417 GNode *ctxt;
2418 {
2419 Lst_ForEach (ctxt->context, VarPrintVar, (ClientData) 0);
2420 }
2421