VirtualBox

source: kBuild/branches/FREEBSD/src/kmk/var.c@ 163

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

Import of RELENG_4_7_0_RELEASE

  • 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.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette