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

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

This commit was generated by cvs2svn to compensate for changes in r24,
which included commits to RCS files with non-trunk default branches.

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