source: trunk/src/kmk/var.c@ 23

Last change on this file since 23 was 9, checked in by bird, 23 years ago

Initial revision

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