BSD 4_4 release
[unix-history] / usr / src / usr.bin / make / var.c
CommitLineData
9320ab9e 1/*
ad787160
C
2 * Copyright (c) 1988, 1989, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
ab950546 4 * Copyright (c) 1989 by Berkeley Softworks
9320ab9e
KB
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor.
ab950546 9 *
ad787160
C
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.
9320ab9e
KB
37 */
38
39#ifndef lint
ad787160 40static char sccsid[] = "@(#)var.c 8.1 (Berkeley) 6/6/93";
9320ab9e
KB
41#endif /* not lint */
42
43/*-
44 * var.c --
45 * Variable-handling functions
ab950546
KB
46 *
47 * Interface:
48 * Var_Set Set the value of a variable in the given
49 * context. The variable is created if it doesn't
50 * yet exist. The value and variable name need not
51 * be preserved.
52 *
53 * Var_Append Append more characters to an existing variable
54 * in the given context. The variable needn't
55 * exist already -- it will be created if it doesn't.
56 * A space is placed between the old value and the
57 * new one.
58 *
59 * Var_Exists See if a variable exists.
60 *
61 * Var_Value Return the value of a variable in a context or
62 * NULL if the variable is undefined.
63 *
40a80f0c
KB
64 * Var_Subst Substitute named variable, or all variables if
65 * NULL in a string using
ab950546
KB
66 * the given context as the top-most one. If the
67 * third argument is non-zero, Parse_Error is
68 * called if any variables are undefined.
69 *
70 * Var_Parse Parse a variable expansion from a string and
71 * return the result and the number of characters
72 * consumed.
73 *
74 * Var_Delete Delete a variable in a context.
75 *
76 * Var_Init Initialize this module.
77 *
78 * Debugging:
79 * Var_Dump Print out all variables defined in the given
80 * context.
81 *
82 * XXX: There's a lot of duplication in these functions.
83 */
ab950546
KB
84
85#include <ctype.h>
86#include "make.h"
87#include "buf.h"
ab950546
KB
88
89/*
90 * This is a harmless return value for Var_Parse that can be used by Var_Subst
91 * to determine if there was an error in parsing -- easier than returning
92 * a flag, as things outside this module don't give a hoot.
93 */
94char var_Error[] = "";
95
96/*
97 * Similar to var_Error, but returned when the 'err' flag for Var_Parse is
98 * set false. Why not just use a constant? Well, gcc likes to condense
99 * identical string instances...
100 */
40a80f0c 101static char varNoError[] = "";
ab950546
KB
102
103/*
104 * Internally, variables are contained in four different contexts.
105 * 1) the environment. They may not be changed. If an environment
106 * variable is appended-to, the result is placed in the global
107 * context.
108 * 2) the global context. Variables set in the Makefile are located in
109 * the global context. It is the penultimate context searched when
110 * substituting.
111 * 3) the command-line context. All variables set on the command line
112 * are placed in this context. They are UNALTERABLE once placed here.
113 * 4) the local context. Each target has associated with it a context
114 * list. On this list are located the structures describing such
115 * local variables as $(@) and $(*)
116 * The four contexts are searched in the reverse order from which they are
117 * listed.
118 */
119GNode *VAR_GLOBAL; /* variables from the makefile */
120GNode *VAR_CMD; /* variables defined on the command-line */
121
122#define FIND_CMD 0x1 /* look in VAR_CMD when searching */
123#define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */
124#define FIND_ENV 0x4 /* look in the environment also */
125
126typedef struct Var {
127 char *name; /* the variable's name */
128 Buffer val; /* its value */
129 int flags; /* miscellaneous status flags */
130#define VAR_IN_USE 1 /* Variable's value currently being used.
131 * Used to avoid recursion */
132#define VAR_FROM_ENV 2 /* Variable comes from the environment */
133#define VAR_JUNK 4 /* Variable is a junk variable that
134 * should be destroyed when done with
135 * it. Used by Var_Parse for undefined,
136 * modified variables */
137} Var;
182ca07d 138
40a80f0c
KB
139typedef struct {
140 char *lhs; /* String to match */
141 int leftLen; /* Length of string */
142 char *rhs; /* Replacement string (w/ &'s removed) */
143 int rightLen; /* Length of replacement */
144 int flags;
145#define VAR_SUB_GLOBAL 1 /* Apply substitution globally */
146#define VAR_MATCH_START 2 /* Match at start of word */
147#define VAR_MATCH_END 4 /* Match at end of word */
148#define VAR_NO_SUB 8 /* Substitution is non-global and already done */
149} VarPattern;
150
151static int VarCmp __P((Var *, char *));
152static Var *VarFind __P((char *, GNode *, int));
153static void VarAdd __P((char *, char *, GNode *));
154static Boolean VarHead __P((char *, Boolean, Buffer));
155static Boolean VarTail __P((char *, Boolean, Buffer));
156static Boolean VarSuffix __P((char *, Boolean, Buffer));
157static Boolean VarRoot __P((char *, Boolean, Buffer));
158static Boolean VarMatch __P((char *, Boolean, Buffer, char *));
159static Boolean VarNoMatch __P((char *, Boolean, Buffer, char *));
160static Boolean VarSubstitute __P((char *, Boolean, Buffer, VarPattern *));
161static char *VarModify __P((char *, Boolean (*modProc )(), ClientData));
162static int VarPrintVar __P((Var *));
163
ab950546
KB
164/*-
165 *-----------------------------------------------------------------------
166 * VarCmp --
167 * See if the given variable matches the named one. Called from
168 * Lst_Find when searching for a variable of a given name.
169 *
170 * Results:
171 * 0 if they match. non-zero otherwise.
172 *
173 * Side Effects:
174 * none
175 *-----------------------------------------------------------------------
176 */
177static int
178VarCmp (v, name)
179 Var *v; /* VAR structure to compare */
180 char *name; /* name to look for */
181{
182 return (strcmp (name, v->name));
183}
182ca07d 184
ab950546
KB
185/*-
186 *-----------------------------------------------------------------------
187 * VarFind --
188 * Find the given variable in the given context and any other contexts
189 * indicated.
190 *
191 * Results:
192 * A pointer to the structure describing the desired variable or
193 * NIL if the variable does not exist.
194 *
195 * Side Effects:
196 * None
197 *-----------------------------------------------------------------------
198 */
199static Var *
200VarFind (name, ctxt, flags)
201 char *name; /* name to find */
202 GNode *ctxt; /* context in which to find it */
203 int flags; /* FIND_GLOBAL set means to look in the
204 * VAR_GLOBAL context as well.
205 * FIND_CMD set means to look in the VAR_CMD
206 * context also.
207 * FIND_ENV set means to look in the
208 * environment */
209{
210 LstNode var;
211 Var *v;
212
dc4b9e67
KB
213 /*
214 * If the variable name begins with a '.', it could very well be one of
215 * the local ones. We check the name against all the local variables
216 * and substitute the short version in for 'name' if it matches one of
217 * them.
218 */
219 if (*name == '.' && isupper(name[1]))
220 switch (name[1]) {
221 case 'A':
222 if (!strcmp(name, ".ALLSRC"))
223 name = ALLSRC;
224 if (!strcmp(name, ".ARCHIVE"))
225 name = ARCHIVE;
226 break;
227 case 'I':
228 if (!strcmp(name, ".IMPSRC"))
229 name = IMPSRC;
230 break;
231 case 'M':
232 if (!strcmp(name, ".MEMBER"))
233 name = MEMBER;
234 break;
235 case 'O':
236 if (!strcmp(name, ".OODATE"))
237 name = OODATE;
238 break;
239 case 'P':
240 if (!strcmp(name, ".PREFIX"))
241 name = PREFIX;
242 break;
243 case 'T':
244 if (!strcmp(name, ".TARGET"))
245 name = TARGET;
246 break;
247 }
ab950546
KB
248 /*
249 * First look for the variable in the given context. If it's not there,
250 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
251 * depending on the FIND_* flags in 'flags'
252 */
253 var = Lst_Find (ctxt->context, (ClientData)name, VarCmp);
254
255 if ((var == NILLNODE) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) {
256 var = Lst_Find (VAR_CMD->context, (ClientData)name, VarCmp);
257 }
258 if (!checkEnvFirst && (var == NILLNODE) && (flags & FIND_GLOBAL) &&
259 (ctxt != VAR_GLOBAL))
260 {
261 var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);
262 }
263 if ((var == NILLNODE) && (flags & FIND_ENV)) {
264 char *env;
265
266 if ((env = getenv (name)) != NULL) {
267 /*
268 * If the variable is found in the environment, we only duplicate
269 * its value (since eVarVal was allocated on the stack). The name
270 * doesn't need duplication since it's always in the environment
271 */
272 int len;
273
54527040 274 v = (Var *) emalloc(sizeof(Var));
ab950546
KB
275 v->name = name;
276
277 len = strlen(env);
278
279 v->val = Buf_Init(len);
280 Buf_AddBytes(v->val, len, (Byte *)env);
281
282 v->flags = VAR_FROM_ENV;
283 return (v);
284 } else if (checkEnvFirst && (flags & FIND_GLOBAL) &&
285 (ctxt != VAR_GLOBAL))
286 {
287 var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);
288 if (var == NILLNODE) {
289 return ((Var *) NIL);
290 } else {
291 return ((Var *)Lst_Datum(var));
292 }
293 } else {
294 return((Var *)NIL);
295 }
296 } else if (var == NILLNODE) {
297 return ((Var *) NIL);
298 } else {
299 return ((Var *) Lst_Datum (var));
300 }
301}
182ca07d 302
ab950546
KB
303/*-
304 *-----------------------------------------------------------------------
305 * VarAdd --
306 * Add a new variable of name name and value val to the given context
307 *
308 * Results:
309 * None
310 *
311 * Side Effects:
312 * The new variable is placed at the front of the given context
313 * The name and val arguments are duplicated so they may
314 * safely be freed.
315 *-----------------------------------------------------------------------
316 */
40a80f0c 317static void
ab950546
KB
318VarAdd (name, val, ctxt)
319 char *name; /* name of variable to add */
320 char *val; /* value to set it to */
321 GNode *ctxt; /* context in which to set it */
322{
323 register Var *v;
324 int len;
325
54527040 326 v = (Var *) emalloc (sizeof (Var));
ab950546 327
182ca07d 328 v->name = strdup (name);
ab950546 329
40a80f0c 330 len = val ? strlen(val) : 0;
ab950546
KB
331 v->val = Buf_Init(len+1);
332 Buf_AddBytes(v->val, len, (Byte *)val);
333
334 v->flags = 0;
335
336 (void) Lst_AtFront (ctxt->context, (ClientData)v);
337 if (DEBUG(VAR)) {
338 printf("%s:%s = %s\n", ctxt->name, name, val);
339 }
340}
182ca07d 341
ab950546
KB
342/*-
343 *-----------------------------------------------------------------------
344 * Var_Delete --
345 * Remove a variable from a context.
346 *
347 * Results:
348 * None.
349 *
350 * Side Effects:
351 * The Var structure is removed and freed.
352 *
353 *-----------------------------------------------------------------------
354 */
355void
356Var_Delete(name, ctxt)
357 char *name;
358 GNode *ctxt;
359{
360 LstNode ln;
361
362 if (DEBUG(VAR)) {
363 printf("%s:delete %s\n", ctxt->name, name);
364 }
365 ln = Lst_Find(ctxt->context, (ClientData)name, VarCmp);
366 if (ln != NILLNODE) {
367 register Var *v;
368
369 v = (Var *)Lst_Datum(ln);
370 Lst_Remove(ctxt->context, ln);
371 Buf_Destroy(v->val, TRUE);
372 free(v->name);
373 free((char *)v);
374 }
375}
182ca07d 376
ab950546
KB
377/*-
378 *-----------------------------------------------------------------------
379 * Var_Set --
380 * Set the variable name to the value val in the given context.
381 *
382 * Results:
383 * None.
384 *
385 * Side Effects:
386 * If the variable doesn't yet exist, a new record is created for it.
387 * Else the old value is freed and the new one stuck in its place
388 *
389 * Notes:
390 * The variable is searched for only in its context before being
391 * created in that context. I.e. if the context is VAR_GLOBAL,
392 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
393 * VAR_CMD->context is searched. This is done to avoid the literally
394 * thousands of unnecessary strcmp's that used to be done to
395 * set, say, $(@) or $(<).
396 *-----------------------------------------------------------------------
397 */
398void
399Var_Set (name, val, ctxt)
400 char *name; /* name of variable to set */
401 char *val; /* value to give to the variable */
402 GNode *ctxt; /* context in which to set it */
403{
404 register Var *v;
405
406 /*
407 * We only look for a variable in the given context since anything set
408 * here will override anything in a lower context, so there's not much
409 * point in searching them all just to save a bit of memory...
410 */
411 v = VarFind (name, ctxt, 0);
412 if (v == (Var *) NIL) {
413 VarAdd (name, val, ctxt);
414 } else {
415 Buf_Discard(v->val, Buf_Size(v->val));
416 Buf_AddBytes(v->val, strlen(val), (Byte *)val);
417
418 if (DEBUG(VAR)) {
419 printf("%s:%s = %s\n", ctxt->name, name, val);
420 }
421 }
422 /*
423 * Any variables given on the command line are automatically exported
424 * to the environment (as per POSIX standard)
425 */
426 if (ctxt == VAR_CMD) {
f022bac1 427 setenv(name, val, 1);
ab950546
KB
428 }
429}
182ca07d 430
ab950546
KB
431/*-
432 *-----------------------------------------------------------------------
433 * Var_Append --
434 * The variable of the given name has the given value appended to it in
435 * the given context.
436 *
437 * Results:
438 * None
439 *
440 * Side Effects:
441 * If the variable doesn't exist, it is created. Else the strings
442 * are concatenated (with a space in between).
443 *
444 * Notes:
445 * Only if the variable is being sought in the global context is the
446 * environment searched.
447 * XXX: Knows its calling circumstances in that if called with ctxt
448 * an actual target, it will only search that context since only
449 * a local variable could be being appended to. This is actually
450 * a big win and must be tolerated.
451 *-----------------------------------------------------------------------
452 */
453void
454Var_Append (name, val, ctxt)
455 char *name; /* Name of variable to modify */
456 char *val; /* String to append to it */
457 GNode *ctxt; /* Context in which this should occur */
458{
459 register Var *v;
ab950546
KB
460
461 v = VarFind (name, ctxt, (ctxt == VAR_GLOBAL) ? FIND_ENV : 0);
462
463 if (v == (Var *) NIL) {
464 VarAdd (name, val, ctxt);
465 } else {
466 Buf_AddByte(v->val, (Byte)' ');
467 Buf_AddBytes(v->val, strlen(val), (Byte *)val);
468
469 if (DEBUG(VAR)) {
470 printf("%s:%s = %s\n", ctxt->name, name,
471 Buf_GetAll(v->val, (int *)NULL));
472 }
473
474 if (v->flags & VAR_FROM_ENV) {
475 /*
476 * If the original variable came from the environment, we
477 * have to install it in the global context (we could place
478 * it in the environment, but then we should provide a way to
479 * export other variables...)
480 */
481 v->flags &= ~VAR_FROM_ENV;
482 Lst_AtFront(ctxt->context, (ClientData)v);
483 }
484 }
485}
182ca07d 486
ab950546
KB
487/*-
488 *-----------------------------------------------------------------------
489 * Var_Exists --
490 * See if the given variable exists.
491 *
492 * Results:
493 * TRUE if it does, FALSE if it doesn't
494 *
495 * Side Effects:
496 * None.
497 *
498 *-----------------------------------------------------------------------
499 */
500Boolean
501Var_Exists(name, ctxt)
502 char *name; /* Variable to find */
503 GNode *ctxt; /* Context in which to start search */
504{
505 Var *v;
506
507 v = VarFind(name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV);
508
509 if (v == (Var *)NIL) {
510 return(FALSE);
511 } else if (v->flags & VAR_FROM_ENV) {
512 Buf_Destroy(v->val, TRUE);
513 free((char *)v);
514 }
515 return(TRUE);
516}
182ca07d 517
ab950546
KB
518/*-
519 *-----------------------------------------------------------------------
520 * Var_Value --
521 * Return the value of the named variable in the given context
522 *
523 * Results:
524 * The value if the variable exists, NULL if it doesn't
525 *
526 * Side Effects:
527 * None
528 *-----------------------------------------------------------------------
529 */
530char *
531Var_Value (name, ctxt)
532 char *name; /* name to find */
533 GNode *ctxt; /* context in which to search for it */
534{
535 Var *v;
536
537 v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
538 if (v != (Var *) NIL) {
539 return ((char *)Buf_GetAll(v->val, (int *)NULL));
540 } else {
541 return ((char *) NULL);
542 }
543}
182ca07d 544
ab950546
KB
545/*-
546 *-----------------------------------------------------------------------
547 * VarHead --
548 * Remove the tail of the given word and place the result in the given
549 * buffer.
550 *
551 * Results:
552 * TRUE if characters were added to the buffer (a space needs to be
553 * added to the buffer before the next word).
554 *
555 * Side Effects:
556 * The trimmed word is added to the buffer.
557 *
558 *-----------------------------------------------------------------------
559 */
560static Boolean
561VarHead (word, addSpace, buf)
562 char *word; /* Word to trim */
563 Boolean addSpace; /* True if need to add a space to the buffer
564 * before sticking in the head */
565 Buffer buf; /* Buffer in which to store it */
566{
567 register char *slash;
568
40a80f0c 569 slash = strrchr (word, '/');
ab950546
KB
570 if (slash != (char *)NULL) {
571 if (addSpace) {
572 Buf_AddByte (buf, (Byte)' ');
573 }
574 *slash = '\0';
575 Buf_AddBytes (buf, strlen (word), (Byte *)word);
576 *slash = '/';
577 return (TRUE);
578 } else {
579 /*
580 * If no directory part, give . (q.v. the POSIX standard)
581 */
582 if (addSpace) {
583 Buf_AddBytes(buf, 2, (Byte *)" .");
584 } else {
585 Buf_AddByte(buf, (Byte)'.');
586 }
587 return(TRUE);
588 }
589}
182ca07d 590
ab950546
KB
591/*-
592 *-----------------------------------------------------------------------
593 * VarTail --
594 * Remove the head of the given word and place the result in the given
595 * buffer.
596 *
597 * Results:
598 * TRUE if characters were added to the buffer (a space needs to be
599 * added to the buffer before the next word).
600 *
601 * Side Effects:
602 * The trimmed word is added to the buffer.
603 *
604 *-----------------------------------------------------------------------
605 */
606static Boolean
607VarTail (word, addSpace, buf)
608 char *word; /* Word to trim */
609 Boolean addSpace; /* TRUE if need to stick a space in the
610 * buffer before adding the tail */
611 Buffer buf; /* Buffer in which to store it */
612{
613 register char *slash;
614
615 if (addSpace) {
616 Buf_AddByte (buf, (Byte)' ');
617 }
618
40a80f0c 619 slash = strrchr (word, '/');
ab950546
KB
620 if (slash != (char *)NULL) {
621 *slash++ = '\0';
622 Buf_AddBytes (buf, strlen(slash), (Byte *)slash);
623 slash[-1] = '/';
624 } else {
625 Buf_AddBytes (buf, strlen(word), (Byte *)word);
626 }
627 return (TRUE);
628}
182ca07d 629
ab950546
KB
630/*-
631 *-----------------------------------------------------------------------
632 * VarSuffix --
633 * Place the suffix of the given word in the given buffer.
634 *
635 * Results:
636 * TRUE if characters were added to the buffer (a space needs to be
637 * added to the buffer before the next word).
638 *
639 * Side Effects:
640 * The suffix from the word is placed in the buffer.
641 *
642 *-----------------------------------------------------------------------
643 */
644static Boolean
645VarSuffix (word, addSpace, buf)
646 char *word; /* Word to trim */
647 Boolean addSpace; /* TRUE if need to add a space before placing
648 * the suffix in the buffer */
649 Buffer buf; /* Buffer in which to store it */
650{
651 register char *dot;
652
40a80f0c 653 dot = strrchr (word, '.');
ab950546
KB
654 if (dot != (char *)NULL) {
655 if (addSpace) {
656 Buf_AddByte (buf, (Byte)' ');
657 }
658 *dot++ = '\0';
659 Buf_AddBytes (buf, strlen (dot), (Byte *)dot);
660 dot[-1] = '.';
661 return (TRUE);
662 } else {
663 return (addSpace);
664 }
665}
182ca07d 666
ab950546
KB
667/*-
668 *-----------------------------------------------------------------------
669 * VarRoot --
670 * Remove the suffix of the given word and place the result in the
671 * buffer.
672 *
673 * Results:
674 * TRUE if characters were added to the buffer (a space needs to be
675 * added to the buffer before the next word).
676 *
677 * Side Effects:
678 * The trimmed word is added to the buffer.
679 *
680 *-----------------------------------------------------------------------
681 */
682static Boolean
683VarRoot (word, addSpace, buf)
684 char *word; /* Word to trim */
685 Boolean addSpace; /* TRUE if need to add a space to the buffer
686 * before placing the root in it */
687 Buffer buf; /* Buffer in which to store it */
688{
689 register char *dot;
690
691 if (addSpace) {
692 Buf_AddByte (buf, (Byte)' ');
693 }
694
40a80f0c 695 dot = strrchr (word, '.');
ab950546
KB
696 if (dot != (char *)NULL) {
697 *dot = '\0';
698 Buf_AddBytes (buf, strlen (word), (Byte *)word);
699 *dot = '.';
700 } else {
701 Buf_AddBytes (buf, strlen(word), (Byte *)word);
702 }
703 return (TRUE);
704}
182ca07d 705
ab950546
KB
706/*-
707 *-----------------------------------------------------------------------
708 * VarMatch --
709 * Place the word in the buffer if it matches the given pattern.
710 * Callback function for VarModify to implement the :M modifier.
711 *
712 * Results:
713 * TRUE if a space should be placed in the buffer before the next
714 * word.
715 *
716 * Side Effects:
717 * The word may be copied to the buffer.
718 *
719 *-----------------------------------------------------------------------
720 */
721static Boolean
722VarMatch (word, addSpace, buf, pattern)
723 char *word; /* Word to examine */
724 Boolean addSpace; /* TRUE if need to add a space to the
725 * buffer before adding the word, if it
726 * matches */
727 Buffer buf; /* Buffer in which to store it */
728 char *pattern; /* Pattern the word must match */
729{
730 if (Str_Match(word, pattern)) {
731 if (addSpace) {
732 Buf_AddByte(buf, (Byte)' ');
733 }
734 addSpace = TRUE;
735 Buf_AddBytes(buf, strlen(word), (Byte *)word);
736 }
737 return(addSpace);
738}
182ca07d 739
ab950546
KB
740/*-
741 *-----------------------------------------------------------------------
742 * VarNoMatch --
743 * Place the word in the buffer if it doesn't match the given pattern.
744 * Callback function for VarModify to implement the :N modifier.
745 *
746 * Results:
747 * TRUE if a space should be placed in the buffer before the next
748 * word.
749 *
750 * Side Effects:
751 * The word may be copied to the buffer.
752 *
753 *-----------------------------------------------------------------------
754 */
755static Boolean
756VarNoMatch (word, addSpace, buf, pattern)
757 char *word; /* Word to examine */
758 Boolean addSpace; /* TRUE if need to add a space to the
759 * buffer before adding the word, if it
760 * matches */
761 Buffer buf; /* Buffer in which to store it */
762 char *pattern; /* Pattern the word must match */
763{
764 if (!Str_Match(word, pattern)) {
765 if (addSpace) {
766 Buf_AddByte(buf, (Byte)' ');
767 }
768 addSpace = TRUE;
769 Buf_AddBytes(buf, strlen(word), (Byte *)word);
770 }
771 return(addSpace);
772}
182ca07d 773
ab950546
KB
774
775/*-
776 *-----------------------------------------------------------------------
777 * VarSubstitute --
778 * Perform a string-substitution on the given word, placing the
779 * result in the passed buffer.
780 *
781 * Results:
782 * TRUE if a space is needed before more characters are added.
783 *
784 * Side Effects:
785 * None.
786 *
787 *-----------------------------------------------------------------------
788 */
789static Boolean
790VarSubstitute (word, addSpace, buf, pattern)
791 char *word; /* Word to modify */
792 Boolean addSpace; /* True if space should be added before
793 * other characters */
794 Buffer buf; /* Buffer for result */
795 register VarPattern *pattern; /* Pattern for substitution */
796{
797 register int wordLen; /* Length of word */
798 register char *cp; /* General pointer */
799
800 wordLen = strlen(word);
801 if ((pattern->flags & VAR_NO_SUB) == 0) {
802 /*
803 * Still substituting -- break it down into simple anchored cases
804 * and if none of them fits, perform the general substitution case.
805 */
806 if ((pattern->flags & VAR_MATCH_START) &&
807 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
808 /*
809 * Anchored at start and beginning of word matches pattern
810 */
811 if ((pattern->flags & VAR_MATCH_END) &&
812 (wordLen == pattern->leftLen)) {
813 /*
814 * Also anchored at end and matches to the end (word
815 * is same length as pattern) add space and rhs only
816 * if rhs is non-null.
817 */
818 if (pattern->rightLen != 0) {
819 if (addSpace) {
820 Buf_AddByte(buf, (Byte)' ');
821 }
822 addSpace = TRUE;
823 Buf_AddBytes(buf, pattern->rightLen,
824 (Byte *)pattern->rhs);
825 }
826 } else if (pattern->flags & VAR_MATCH_END) {
827 /*
828 * Doesn't match to end -- copy word wholesale
829 */
830 goto nosub;
831 } else {
832 /*
833 * Matches at start but need to copy in trailing characters
834 */
835 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
836 if (addSpace) {
837 Buf_AddByte(buf, (Byte)' ');
838 }
839 addSpace = TRUE;
840 }
841 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
842 Buf_AddBytes(buf, wordLen - pattern->leftLen,
843 (Byte *)(word + pattern->leftLen));
844 }
845 } else if (pattern->flags & VAR_MATCH_START) {
846 /*
847 * Had to match at start of word and didn't -- copy whole word.
848 */
849 goto nosub;
850 } else if (pattern->flags & VAR_MATCH_END) {
851 /*
852 * Anchored at end, Find only place match could occur (leftLen
853 * characters from the end of the word) and see if it does. Note
854 * that because the $ will be left at the end of the lhs, we have
855 * to use strncmp.
856 */
857 cp = word + (wordLen - pattern->leftLen);
858 if ((cp >= word) &&
859 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
860 /*
861 * Match found. If we will place characters in the buffer,
862 * add a space before hand as indicated by addSpace, then
863 * stuff in the initial, unmatched part of the word followed
864 * by the right-hand-side.
865 */
866 if (((cp - word) + pattern->rightLen) != 0) {
867 if (addSpace) {
868 Buf_AddByte(buf, (Byte)' ');
869 }
870 addSpace = TRUE;
871 }
872 Buf_AddBytes(buf, cp - word, (Byte *)word);
873 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
874 } else {
875 /*
876 * Had to match at end and didn't. Copy entire word.
877 */
878 goto nosub;
879 }
880 } else {
881 /*
882 * Pattern is unanchored: search for the pattern in the word using
883 * String_FindSubstring, copying unmatched portions and the
884 * right-hand-side for each match found, handling non-global
885 * subsititutions correctly, etc. When the loop is done, any
886 * remaining part of the word (word and wordLen are adjusted
887 * accordingly through the loop) is copied straight into the
888 * buffer.
889 * addSpace is set FALSE as soon as a space is added to the
890 * buffer.
891 */
892 register Boolean done;
893 int origSize;
894
895 done = FALSE;
896 origSize = Buf_Size(buf);
897 while (!done) {
898 cp = Str_FindSubstring(word, pattern->lhs);
899 if (cp != (char *)NULL) {
900 if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
901 Buf_AddByte(buf, (Byte)' ');
902 addSpace = FALSE;
903 }
904 Buf_AddBytes(buf, cp-word, (Byte *)word);
905 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
906 wordLen -= (cp - word) + pattern->leftLen;
907 word = cp + pattern->leftLen;
908 if (wordLen == 0) {
909 done = TRUE;
910 }
911 if ((pattern->flags & VAR_SUB_GLOBAL) == 0) {
912 done = TRUE;
913 pattern->flags |= VAR_NO_SUB;
914 }
915 } else {
916 done = TRUE;
917 }
918 }
919 if (wordLen != 0) {
920 if (addSpace) {
921 Buf_AddByte(buf, (Byte)' ');
922 }
923 Buf_AddBytes(buf, wordLen, (Byte *)word);
924 }
925 /*
926 * If added characters to the buffer, need to add a space
927 * before we add any more. If we didn't add any, just return
928 * the previous value of addSpace.
929 */
930 return ((Buf_Size(buf) != origSize) || addSpace);
931 }
932 /*
933 * Common code for anchored substitutions: if performed a substitution
934 * and it's not supposed to be global, mark the pattern as requiring
935 * no more substitutions. addSpace was set TRUE if characters were
936 * added to the buffer.
937 */
938 if ((pattern->flags & VAR_SUB_GLOBAL) == 0) {
939 pattern->flags |= VAR_NO_SUB;
940 }
941 return (addSpace);
942 }
943 nosub:
944 if (addSpace) {
945 Buf_AddByte(buf, (Byte)' ');
946 }
947 Buf_AddBytes(buf, wordLen, (Byte *)word);
948 return(TRUE);
949}
182ca07d 950
ab950546
KB
951/*-
952 *-----------------------------------------------------------------------
953 * VarModify --
954 * Modify each of the words of the passed string using the given
955 * function. Used to implement all modifiers.
956 *
957 * Results:
958 * A string of all the words modified appropriately.
959 *
960 * Side Effects:
961 * None.
962 *
963 *-----------------------------------------------------------------------
964 */
965static char *
966VarModify (str, modProc, datum)
967 char *str; /* String whose words should be trimmed */
968 Boolean (*modProc)(); /* Function to use to modify them */
969 ClientData datum; /* Datum to pass it */
970{
971 Buffer buf; /* Buffer for the new string */
972 register char *cp; /* Pointer to end of current word */
973 char endc; /* Character that ended the word */
974 Boolean addSpace; /* TRUE if need to add a space to the
975 * buffer before adding the trimmed
976 * word */
977
978 buf = Buf_Init (0);
979 cp = str;
980 addSpace = FALSE;
981
40a80f0c 982 for (;;) {
ab950546
KB
983 /*
984 * Skip to next word and place cp at its end.
985 */
986 while (isspace (*str)) {
987 str++;
988 }
40a80f0c
KB
989 for (cp = str; *cp != '\0' && !isspace (*cp); cp++)
990 continue;
ab950546
KB
991 if (cp == str) {
992 /*
993 * If we didn't go anywhere, we must be done!
994 */
995 Buf_AddByte (buf, '\0');
996 str = (char *)Buf_GetAll (buf, (int *)NULL);
997 Buf_Destroy (buf, FALSE);
998 return (str);
999 }
1000 /*
1001 * Nuke terminating character, but save it in endc b/c if str was
1002 * some variable's value, it would not be good to screw it
1003 * over...
1004 */
1005 endc = *cp;
1006 *cp = '\0';
1007
1008 addSpace = (* modProc) (str, addSpace, buf, datum);
1009
1010 if (endc) {
1011 *cp++ = endc;
1012 }
1013 str = cp;
1014 }
1015}
182ca07d 1016
ab950546
KB
1017/*-
1018 *-----------------------------------------------------------------------
1019 * Var_Parse --
1020 * Given the start of a variable invocation, extract the variable
1021 * name and find its value, then modify it according to the
1022 * specification.
1023 *
1024 * Results:
1025 * The (possibly-modified) value of the variable or var_Error if the
1026 * specification is invalid. The length of the specification is
1027 * placed in *lengthPtr (for invalid specifications, this is just
1028 * 2...?).
1029 * A Boolean in *freePtr telling whether the returned string should
1030 * be freed by the caller.
1031 *
1032 * Side Effects:
1033 * None.
1034 *
1035 *-----------------------------------------------------------------------
1036 */
1037char *
1038Var_Parse (str, ctxt, err, lengthPtr, freePtr)
1039 char *str; /* The string to parse */
1040 GNode *ctxt; /* The context for the variable */
1041 Boolean err; /* TRUE if undefined variables are an error */
1042 int *lengthPtr; /* OUT: The length of the specification */
1043 Boolean *freePtr; /* OUT: TRUE if caller should free result */
1044{
1045 register char *tstr; /* Pointer into str */
1046 Var *v; /* Variable in invocation */
1047 register char *cp; /* Secondary pointer into str (place marker
1048 * for tstr) */
1049 Boolean haveModifier;/* TRUE if have modifiers for the variable */
1050 register char endc; /* Ending character when variable in parens
1051 * or braces */
1052 char *start;
1053 Boolean dynamic; /* TRUE if the variable is local and we're
1054 * expanding it in a non-local context. This
1055 * is done to support dynamic sources. The
1056 * result is just the invocation, unaltered */
1057
1058 *freePtr = FALSE;
1059 dynamic = FALSE;
1060 start = str;
1061
1062 if (str[1] != '(' && str[1] != '{') {
1063 /*
1064 * If it's not bounded by braces of some sort, life is much simpler.
1065 * We just need to check for the first character and return the
1066 * value if it exists.
1067 */
1068 char name[2];
1069
1070 name[0] = str[1];
1071 name[1] = '\0';
1072
1073 v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1074 if (v == (Var *)NIL) {
1075 *lengthPtr = 2;
1076
1077 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
1078 /*
1079 * If substituting a local variable in a non-local context,
1080 * assume it's for dynamic source stuff. We have to handle
1081 * this specially and return the longhand for the variable
1082 * with the dollar sign escaped so it makes it back to the
1083 * caller. Only four of the local variables are treated
1084 * specially as they are the only four that will be set
1085 * when dynamic sources are expanded.
1086 */
1087 switch (str[1]) {
1088 case '@':
1089 return("$(.TARGET)");
1090 case '%':
1091 return("$(.ARCHIVE)");
1092 case '*':
1093 return("$(.PREFIX)");
1094 case '!':
1095 return("$(.MEMBER)");
1096 }
1097 }
1098 /*
1099 * Error
1100 */
1101 return (err ? var_Error : varNoError);
1102 } else {
1103 haveModifier = FALSE;
1104 tstr = &str[1];
1105 endc = str[1];
1106 }
1107 } else {
1108 endc = str[1] == '(' ? ')' : '}';
1109
1110 /*
1111 * Skip to the end character or a colon, whichever comes first.
1112 */
1113 for (tstr = str + 2;
1114 *tstr != '\0' && *tstr != endc && *tstr != ':';
1115 tstr++)
1116 {
1117 continue;
1118 }
1119 if (*tstr == ':') {
1120 haveModifier = TRUE;
1121 } else if (*tstr != '\0') {
1122 haveModifier = FALSE;
1123 } else {
1124 /*
1125 * If we never did find the end character, return NULL
1126 * right now, setting the length to be the distance to
1127 * the end of the string, since that's what make does.
1128 */
1129 *lengthPtr = tstr - str;
1130 return (var_Error);
1131 }
1132 *tstr = '\0';
1133
1134 v = VarFind (str + 2, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1135 if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
1136 ((tstr-str) == 4) && (str[3] == 'F' || str[3] == 'D'))
1137 {
1138 /*
1139 * Check for bogus D and F forms of local variables since we're
1140 * in a local context and the name is the right length.
1141 */
1142 switch(str[2]) {
1143 case '@':
1144 case '%':
1145 case '*':
1146 case '!':
1147 case '>':
1148 case '<':
1149 {
1150 char vname[2];
1151 char *val;
1152
1153 /*
1154 * Well, it's local -- go look for it.
1155 */
1156 vname[0] = str[2];
1157 vname[1] = '\0';
1158 v = VarFind(vname, ctxt, 0);
1159
1160 if (v != (Var *)NIL) {
1161 /*
1162 * No need for nested expansion or anything, as we're
1163 * the only one who sets these things and we sure don't
1164 * but nested invocations in them...
1165 */
1166 val = (char *)Buf_GetAll(v->val, (int *)NULL);
1167
1168 if (str[3] == 'D') {
1169 val = VarModify(val, VarHead, (ClientData)0);
1170 } else {
1171 val = VarModify(val, VarTail, (ClientData)0);
1172 }
1173 /*
1174 * Resulting string is dynamically allocated, so
1175 * tell caller to free it.
1176 */
1177 *freePtr = TRUE;
1178 *lengthPtr = tstr-start+1;
1179 *tstr = endc;
1180 return(val);
1181 }
1182 break;
1183 }
1184 }
1185 }
1186
1187 if (v == (Var *)NIL) {
1188 if ((((tstr-str) == 3) ||
1189 ((((tstr-str) == 4) && (str[3] == 'F' ||
1190 str[3] == 'D')))) &&
1191 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
1192 {
1193 /*
1194 * If substituting a local variable in a non-local context,
1195 * assume it's for dynamic source stuff. We have to handle
1196 * this specially and return the longhand for the variable
1197 * with the dollar sign escaped so it makes it back to the
1198 * caller. Only four of the local variables are treated
1199 * specially as they are the only four that will be set
1200 * when dynamic sources are expanded.
1201 */
1202 switch (str[2]) {
1203 case '@':
1204 case '%':
1205 case '*':
1206 case '!':
1207 dynamic = TRUE;
1208 break;
1209 }
1210 } else if (((tstr-str) > 4) && (str[2] == '.') &&
1211 isupper(str[3]) &&
1212 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
1213 {
1214 int len;
1215
1216 len = (tstr-str) - 3;
1217 if ((strncmp(str+2, ".TARGET", len) == 0) ||
1218 (strncmp(str+2, ".ARCHIVE", len) == 0) ||
1219 (strncmp(str+2, ".PREFIX", len) == 0) ||
1220 (strncmp(str+2, ".MEMBER", len) == 0))
1221 {
1222 dynamic = TRUE;
1223 }
1224 }
1225
1226 if (!haveModifier) {
1227 /*
1228 * No modifiers -- have specification length so we can return
1229 * now.
1230 */
1231 *lengthPtr = tstr - start + 1;
1232 *tstr = endc;
1233 if (dynamic) {
54527040 1234 str = emalloc(*lengthPtr + 1);
ab950546
KB
1235 strncpy(str, start, *lengthPtr);
1236 str[*lengthPtr] = '\0';
1237 *freePtr = TRUE;
1238 return(str);
1239 } else {
1240 return (err ? var_Error : varNoError);
1241 }
1242 } else {
1243 /*
1244 * Still need to get to the end of the variable specification,
1245 * so kludge up a Var structure for the modifications
1246 */
54527040 1247 v = (Var *) emalloc(sizeof(Var));
ab950546
KB
1248 v->name = &str[1];
1249 v->val = Buf_Init(1);
1250 v->flags = VAR_JUNK;
1251 }
1252 }
1253 }
1254
1255 if (v->flags & VAR_IN_USE) {
1256 Fatal("Variable %s is recursive.", v->name);
1257 /*NOTREACHED*/
1258 } else {
1259 v->flags |= VAR_IN_USE;
1260 }
1261 /*
1262 * Before doing any modification, we have to make sure the value
1263 * has been fully expanded. If it looks like recursion might be
1264 * necessary (there's a dollar sign somewhere in the variable's value)
1265 * we just call Var_Subst to do any other substitutions that are
1266 * necessary. Note that the value returned by Var_Subst will have
1267 * been dynamically-allocated, so it will need freeing when we
1268 * return.
1269 */
1270 str = (char *)Buf_GetAll(v->val, (int *)NULL);
40a80f0c
KB
1271 if (strchr (str, '$') != (char *)NULL) {
1272 str = Var_Subst(NULL, str, ctxt, err);
ab950546
KB
1273 *freePtr = TRUE;
1274 }
1275
1276 v->flags &= ~VAR_IN_USE;
1277
1278 /*
1279 * Now we need to apply any modifiers the user wants applied.
1280 * These are:
1281 * :M<pattern> words which match the given <pattern>.
1282 * <pattern> is of the standard file
1283 * wildcarding form.
1284 * :S<d><pat1><d><pat2><d>[g]
1285 * Substitute <pat2> for <pat1> in the value
1286 * :H Substitute the head of each word
1287 * :T Substitute the tail of each word
1288 * :E Substitute the extension (minus '.') of
1289 * each word
1290 * :R Substitute the root of each word
1291 * (pathname minus the suffix).
1292 * :lhs=rhs Like :S, but the rhs goes to the end of
1293 * the invocation.
1294 */
1295 if ((str != (char *)NULL) && haveModifier) {
1296 /*
1297 * Skip initial colon while putting it back.
1298 */
1299 *tstr++ = ':';
1300 while (*tstr != endc) {
1301 char *newStr; /* New value to return */
1302 char termc; /* Character which terminated scan */
1303
1304 if (DEBUG(VAR)) {
1305 printf("Applying :%c to \"%s\"\n", *tstr, str);
1306 }
1307 switch (*tstr) {
1308 case 'N':
1309 case 'M':
1310 {
1311 char *pattern;
1312 char *cp2;
1313 Boolean copy;
1314
1315 copy = FALSE;
1316 for (cp = tstr + 1;
1317 *cp != '\0' && *cp != ':' && *cp != endc;
1318 cp++)
1319 {
1320 if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){
1321 copy = TRUE;
1322 cp++;
1323 }
1324 }
1325 termc = *cp;
1326 *cp = '\0';
1327 if (copy) {
1328 /*
1329 * Need to compress the \:'s out of the pattern, so
1330 * allocate enough room to hold the uncompressed
1331 * pattern (note that cp started at tstr+1, so
1332 * cp - tstr takes the null byte into account) and
1333 * compress the pattern into the space.
1334 */
54527040 1335 pattern = emalloc(cp - tstr);
ab950546
KB
1336 for (cp2 = pattern, cp = tstr + 1;
1337 *cp != '\0';
1338 cp++, cp2++)
1339 {
1340 if ((*cp == '\\') &&
1341 (cp[1] == ':' || cp[1] == endc)) {
1342 cp++;
1343 }
1344 *cp2 = *cp;
1345 }
1346 *cp2 = '\0';
1347 } else {
1348 pattern = &tstr[1];
1349 }
1350 if (*tstr == 'M' || *tstr == 'm') {
1351 newStr = VarModify(str, VarMatch, (ClientData)pattern);
1352 } else {
1353 newStr = VarModify(str, VarNoMatch,
1354 (ClientData)pattern);
1355 }
1356 if (copy) {
1357 free(pattern);
1358 }
1359 break;
1360 }
1361 case 'S':
1362 {
1363 VarPattern pattern;
1364 register char delim;
1365 Buffer buf; /* Buffer for patterns */
ab950546
KB
1366
1367 pattern.flags = 0;
1368 delim = tstr[1];
1369 tstr += 2;
1370 /*
1371 * If pattern begins with '^', it is anchored to the
1372 * start of the word -- skip over it and flag pattern.
1373 */
1374 if (*tstr == '^') {
1375 pattern.flags |= VAR_MATCH_START;
1376 tstr += 1;
1377 }
1378
1379 buf = Buf_Init(0);
1380
1381 /*
1382 * Pass through the lhs looking for 1) escaped delimiters,
1383 * '$'s and backslashes (place the escaped character in
1384 * uninterpreted) and 2) unescaped $'s that aren't before
1385 * the delimiter (expand the variable substitution).
1386 * The result is left in the Buffer buf.
1387 */
1388 for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {
1389 if ((*cp == '\\') &&
1390 ((cp[1] == delim) ||
1391 (cp[1] == '$') ||
1392 (cp[1] == '\\')))
1393 {
1394 Buf_AddByte(buf, (Byte)cp[1]);
1395 cp++;
1396 } else if (*cp == '$') {
1397 if (cp[1] != delim) {
1398 /*
1399 * If unescaped dollar sign not before the
1400 * delimiter, assume it's a variable
1401 * substitution and recurse.
1402 */
1403 char *cp2;
1404 int len;
1405 Boolean freeIt;
1406
1407 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
1408 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
1409 if (freeIt) {
1410 free(cp2);
1411 }
1412 cp += len - 1;
1413 } else {
1414 /*
1415 * Unescaped $ at end of pattern => anchor
1416 * pattern at end.
1417 */
1418 pattern.flags |= VAR_MATCH_END;
1419 }
1420 } else {
1421 Buf_AddByte(buf, (Byte)*cp);
1422 }
1423 }
1424
1425 Buf_AddByte(buf, (Byte)'\0');
1426
1427 /*
1428 * If lhs didn't end with the delimiter, complain and
1429 * return NULL
1430 */
1431 if (*cp != delim) {
1432 *lengthPtr = cp - start + 1;
1433 if (*freePtr) {
1434 free(str);
1435 }
1436 Buf_Destroy(buf, TRUE);
1437 Error("Unclosed substitution for %s (%c missing)",
1438 v->name, delim);
1439 return (var_Error);
1440 }
1441
1442 /*
1443 * Fetch pattern and destroy buffer, but preserve the data
1444 * in it, since that's our lhs. Note that Buf_GetAll
1445 * will return the actual number of bytes, which includes
1446 * the null byte, so we have to decrement the length by
1447 * one.
1448 */
1449 pattern.lhs = (char *)Buf_GetAll(buf, &pattern.leftLen);
1450 pattern.leftLen--;
1451 Buf_Destroy(buf, FALSE);
1452
1453 /*
1454 * Now comes the replacement string. Three things need to
1455 * be done here: 1) need to compress escaped delimiters and
1456 * ampersands and 2) need to replace unescaped ampersands
1457 * with the l.h.s. (since this isn't regexp, we can do
1458 * it right here) and 3) expand any variable substitutions.
1459 */
1460 buf = Buf_Init(0);
1461
1462 tstr = cp + 1;
1463 for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {
1464 if ((*cp == '\\') &&
1465 ((cp[1] == delim) ||
1466 (cp[1] == '&') ||
1467 (cp[1] == '\\') ||
1468 (cp[1] == '$')))
1469 {
1470 Buf_AddByte(buf, (Byte)cp[1]);
1471 cp++;
1472 } else if ((*cp == '$') && (cp[1] != delim)) {
1473 char *cp2;
1474 int len;
1475 Boolean freeIt;
1476
1477 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
1478 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
1479 cp += len - 1;
1480 if (freeIt) {
1481 free(cp2);
1482 }
1483 } else if (*cp == '&') {
1484 Buf_AddBytes(buf, pattern.leftLen,
1485 (Byte *)pattern.lhs);
1486 } else {
1487 Buf_AddByte(buf, (Byte)*cp);
1488 }
1489 }
1490
1491 Buf_AddByte(buf, (Byte)'\0');
1492
1493 /*
1494 * If didn't end in delimiter character, complain
1495 */
1496 if (*cp != delim) {
1497 *lengthPtr = cp - start + 1;
1498 if (*freePtr) {
1499 free(str);
1500 }
1501 Buf_Destroy(buf, TRUE);
1502 Error("Unclosed substitution for %s (%c missing)",
1503 v->name, delim);
1504 return (var_Error);
1505 }
1506
1507 pattern.rhs = (char *)Buf_GetAll(buf, &pattern.rightLen);
1508 pattern.rightLen--;
1509 Buf_Destroy(buf, FALSE);
1510
1511 /*
1512 * Check for global substitution. If 'g' after the final
1513 * delimiter, substitution is global and is marked that
1514 * way.
1515 */
1516 cp++;
1517 if (*cp == 'g') {
1518 pattern.flags |= VAR_SUB_GLOBAL;
1519 cp++;
1520 }
1521
1522 termc = *cp;
1523 newStr = VarModify(str, VarSubstitute,
1524 (ClientData)&pattern);
1525 /*
1526 * Free the two strings.
1527 */
1528 free(pattern.lhs);
1529 free(pattern.rhs);
1530 break;
1531 }
1532 case 'T':
1533 if (tstr[1] == endc || tstr[1] == ':') {
1534 newStr = VarModify (str, VarTail, (ClientData)0);
1535 cp = tstr + 1;
1536 termc = *cp;
1537 break;
1538 }
1539 /*FALLTHRU*/
1540 case 'H':
1541 if (tstr[1] == endc || tstr[1] == ':') {
1542 newStr = VarModify (str, VarHead, (ClientData)0);
1543 cp = tstr + 1;
1544 termc = *cp;
1545 break;
1546 }
1547 /*FALLTHRU*/
1548 case 'E':
1549 if (tstr[1] == endc || tstr[1] == ':') {
1550 newStr = VarModify (str, VarSuffix, (ClientData)0);
1551 cp = tstr + 1;
1552 termc = *cp;
1553 break;
1554 }
1555 /*FALLTHRU*/
1556 case 'R':
1557 if (tstr[1] == endc || tstr[1] == ':') {
1558 newStr = VarModify (str, VarRoot, (ClientData)0);
1559 cp = tstr + 1;
1560 termc = *cp;
1561 break;
1562 }
1563 /*FALLTHRU*/
1564 default: {
1565 /*
1566 * This can either be a bogus modifier or a System-V
1567 * substitution command.
1568 */
1569 VarPattern pattern;
1570 Boolean eqFound;
1571
1572 pattern.flags = 0;
1573 eqFound = FALSE;
1574 /*
1575 * First we make a pass through the string trying
1576 * to verify it is a SYSV-make-style translation:
1577 * it must be: <string1>=<string2>)
1578 */
1579 for (cp = tstr; *cp != '\0' && *cp != endc; cp++) {
1580 if (*cp == '=') {
1581 eqFound = TRUE;
1582 /* continue looking for endc */
1583 }
1584 }
1585 if (*cp == endc && eqFound) {
1586
1587 /*
1588 * Now we break this sucker into the lhs and
1589 * rhs. We must null terminate them of course.
1590 */
40a80f0c
KB
1591 for (cp = tstr; *cp != '='; cp++)
1592 continue;
ab950546
KB
1593 pattern.lhs = tstr;
1594 pattern.leftLen = cp - tstr;
1595 *cp++ = '\0';
1596
1597 pattern.rhs = cp;
1598 while (*cp != endc) {
1599 cp++;
1600 }
1601 pattern.rightLen = cp - pattern.rhs;
1602 *cp = '\0';
1603
1604 /*
1605 * SYSV modifications happen through the whole
1606 * string. Note the pattern is anchored at the end.
1607 */
1608 pattern.flags |= VAR_SUB_GLOBAL|VAR_MATCH_END;
1609
1610 newStr = VarModify(str, VarSubstitute,
1611 (ClientData)&pattern);
1612
1613 /*
1614 * Restore the nulled characters
1615 */
1616 pattern.lhs[pattern.leftLen] = '=';
1617 pattern.rhs[pattern.rightLen] = endc;
1618 termc = endc;
1619 } else {
1620 Error ("Unknown modifier '%c'\n", *tstr);
1621 for (cp = tstr+1;
1622 *cp != ':' && *cp != endc && *cp != '\0';
40a80f0c
KB
1623 cp++)
1624 continue;
ab950546
KB
1625 termc = *cp;
1626 newStr = var_Error;
1627 }
1628 }
1629 }
1630 if (DEBUG(VAR)) {
1631 printf("Result is \"%s\"\n", newStr);
1632 }
1633
1634 if (*freePtr) {
1635 free (str);
1636 }
1637 str = newStr;
1638 if (str != var_Error) {
1639 *freePtr = TRUE;
1640 } else {
1641 *freePtr = FALSE;
1642 }
1643 if (termc == '\0') {
1644 Error("Unclosed variable specification for %s", v->name);
1645 } else if (termc == ':') {
1646 *cp++ = termc;
1647 } else {
1648 *cp = termc;
1649 }
1650 tstr = cp;
1651 }
1652 *lengthPtr = tstr - start + 1;
1653 } else {
1654 *lengthPtr = tstr - start + 1;
1655 *tstr = endc;
1656 }
1657
1658 if (v->flags & VAR_FROM_ENV) {
1659 Boolean destroy = FALSE;
1660
1661 if (str != (char *)Buf_GetAll(v->val, (int *)NULL)) {
1662 destroy = TRUE;
1663 } else {
1664 /*
1665 * Returning the value unmodified, so tell the caller to free
1666 * the thing.
1667 */
1668 *freePtr = TRUE;
1669 }
1670 Buf_Destroy(v->val, destroy);
1671 free((Address)v);
1672 } else if (v->flags & VAR_JUNK) {
1673 /*
1674 * Perform any free'ing needed and set *freePtr to FALSE so the caller
1675 * doesn't try to free a static pointer.
1676 */
1677 if (*freePtr) {
1678 free(str);
1679 }
1680 *freePtr = FALSE;
1681 free((Address)v);
1682 if (dynamic) {
54527040 1683 str = emalloc(*lengthPtr + 1);
ab950546
KB
1684 strncpy(str, start, *lengthPtr);
1685 str[*lengthPtr] = '\0';
1686 *freePtr = TRUE;
1687 } else {
1688 str = var_Error;
1689 }
1690 }
1691 return (str);
1692}
182ca07d 1693
ab950546
KB
1694/*-
1695 *-----------------------------------------------------------------------
1696 * Var_Subst --
1697 * Substitute for all variables in the given string in the given context
1698 * If undefErr is TRUE, Parse_Error will be called when an undefined
1699 * variable is encountered.
1700 *
1701 * Results:
1702 * The resulting string.
1703 *
1704 * Side Effects:
1705 * None. The old string must be freed by the caller
1706 *-----------------------------------------------------------------------
1707 */
1708char *
40a80f0c
KB
1709Var_Subst (var, str, ctxt, undefErr)
1710 char *var; /* Named variable || NULL for all */
1711 char *str; /* the string in which to substitute */
ab950546
KB
1712 GNode *ctxt; /* the context wherein to find variables */
1713 Boolean undefErr; /* TRUE if undefineds are an error */
1714{
1715 Buffer buf; /* Buffer for forming things */
1716 char *val; /* Value to substitute for a variable */
1717 int length; /* Length of the variable invocation */
1718 Boolean doFree; /* Set true if val should be freed */
1719 static Boolean errorReported; /* Set true if an error has already
1720 * been reported to prevent a plethora
1721 * of messages when recursing */
1722
40a80f0c 1723 buf = Buf_Init (MAKE_BSIZE);
ab950546
KB
1724 errorReported = FALSE;
1725
1726 while (*str) {
40a80f0c 1727 if (var == NULL && (*str == '$') && (str[1] == '$')) {
ab950546
KB
1728 /*
1729 * A dollar sign may be escaped either with another dollar sign.
1730 * In such a case, we skip over the escape character and store the
1731 * dollar sign into the buffer directly.
1732 */
1733 str++;
1734 Buf_AddByte(buf, (Byte)*str);
1735 str++;
1736 } else if (*str != '$') {
1737 /*
1738 * Skip as many characters as possible -- either to the end of
1739 * the string or to the next dollar sign (variable invocation).
1740 */
1741 char *cp;
1742
40a80f0c
KB
1743 for (cp = str++; *str != '$' && *str != '\0'; str++)
1744 continue;
ab950546
KB
1745 Buf_AddBytes(buf, str - cp, (Byte *)cp);
1746 } else {
40a80f0c
KB
1747 if (var != NULL) {
1748 int expand;
1749 for (;;) {
1750 if (str[1] != '(' && str[1] != '{') {
1751 if (str[1] != *var) {
1752 Buf_AddBytes(buf, 2, (Byte *) str);
1753 str += 2;
1754 expand = FALSE;
1755 }
1756 else
1757 expand = TRUE;
1758 break;
1759 }
1760 else {
1761 char *p;
1762
1763 /*
1764 * Scan up to the end of the variable name.
1765 */
1766 for (p = &str[2]; *p &&
1767 *p != ':' && *p != ')' && *p != '}'; p++)
1768 if (*p == '$')
1769 break;
1770 /*
1771 * A variable inside the variable. We cannot expand
1772 * the external variable yet, so we try again with
1773 * the nested one
1774 */
1775 if (*p == '$') {
1776 Buf_AddBytes(buf, p - str, (Byte *) str);
1777 str = p;
1778 continue;
1779 }
1780
1781 if (strncmp(var, str + 2, p - str - 2) != 0 ||
1782 var[p - str - 2] != '\0') {
1783 /*
1784 * Not the variable we want to expand, scan
1785 * until the next variable
1786 */
1787 for (;*p != '$' && *p != '\0'; p++)
1788 continue;
1789 Buf_AddBytes(buf, p - str, (Byte *) str);
1790 str = p;
1791 expand = FALSE;
1792 }
1793 else
1794 expand = TRUE;
1795 break;
1796 }
1797 }
1798 if (!expand)
1799 continue;
1800 }
1801
ab950546
KB
1802 val = Var_Parse (str, ctxt, undefErr, &length, &doFree);
1803
1804 /*
1805 * When we come down here, val should either point to the
1806 * value of this variable, suitably modified, or be NULL.
1807 * Length should be the total length of the potential
1808 * variable invocation (from $ to end character...)
1809 */
1810 if (val == var_Error || val == varNoError) {
1811 /*
1812 * If performing old-time variable substitution, skip over
1813 * the variable and continue with the substitution. Otherwise,
1814 * store the dollar sign and advance str so we continue with
1815 * the string...
1816 */
1817 if (oldVars) {
ab950546
KB
1818 str += length;
1819 } else if (undefErr) {
1820 /*
1821 * If variable is undefined, complain and skip the
1822 * variable. The complaint will stop us from doing anything
1823 * when the file is parsed.
1824 */
1825 if (!errorReported) {
1826 Parse_Error (PARSE_FATAL,
1827 "Undefined variable \"%.*s\"",length,str);
1828 }
1829 str += length;
1830 errorReported = TRUE;
1831 } else {
1832 Buf_AddByte (buf, (Byte)*str);
1833 str += 1;
1834 }
1835 } else {
1836 /*
1837 * We've now got a variable structure to store in. But first,
1838 * advance the string pointer.
1839 */
1840 str += length;
1841
1842 /*
1843 * Copy all the characters from the variable value straight
1844 * into the new string.
1845 */
1846 Buf_AddBytes (buf, strlen (val), (Byte *)val);
1847 if (doFree) {
1848 free ((Address)val);
1849 }
1850 }
1851 }
1852 }
1853
1854 Buf_AddByte (buf, '\0');
1855 str = (char *)Buf_GetAll (buf, (int *)NULL);
1856 Buf_Destroy (buf, FALSE);
1857 return (str);
1858}
182ca07d 1859
ab950546
KB
1860/*-
1861 *-----------------------------------------------------------------------
1862 * Var_GetTail --
1863 * Return the tail from each of a list of words. Used to set the
1864 * System V local variables.
1865 *
1866 * Results:
1867 * The resulting string.
1868 *
1869 * Side Effects:
1870 * None.
1871 *
1872 *-----------------------------------------------------------------------
1873 */
1874char *
1875Var_GetTail(file)
1876 char *file; /* Filename to modify */
1877{
1878 return(VarModify(file, VarTail, (ClientData)0));
1879}
182ca07d 1880
ab950546
KB
1881/*-
1882 *-----------------------------------------------------------------------
1883 * Var_GetHead --
1884 * Find the leading components of a (list of) filename(s).
1885 * XXX: VarHead does not replace foo by ., as (sun) System V make
1886 * does.
1887 *
1888 * Results:
1889 * The leading components.
1890 *
1891 * Side Effects:
1892 * None.
1893 *
1894 *-----------------------------------------------------------------------
1895 */
1896char *
1897Var_GetHead(file)
1898 char *file; /* Filename to manipulate */
1899{
1900 return(VarModify(file, VarHead, (ClientData)0));
1901}
182ca07d 1902
ab950546
KB
1903/*-
1904 *-----------------------------------------------------------------------
1905 * Var_Init --
1906 * Initialize the module
1907 *
1908 * Results:
1909 * None
1910 *
1911 * Side Effects:
1912 * The VAR_CMD and VAR_GLOBAL contexts are created
1913 *-----------------------------------------------------------------------
1914 */
1915void
1916Var_Init ()
1917{
1918 VAR_GLOBAL = Targ_NewGN ("Global");
1919 VAR_CMD = Targ_NewGN ("Command");
1920
1921}
182ca07d 1922
ab950546 1923/****************** PRINT DEBUGGING INFO *****************/
40a80f0c 1924static int
ab950546
KB
1925VarPrintVar (v)
1926 Var *v;
1927{
1928 printf ("%-16s = %s\n", v->name, Buf_GetAll(v->val, (int *)NULL));
1929 return (0);
1930}
182ca07d 1931
ab950546
KB
1932/*-
1933 *-----------------------------------------------------------------------
1934 * Var_Dump --
1935 * print all variables in a context
1936 *-----------------------------------------------------------------------
1937 */
40a80f0c 1938void
ab950546
KB
1939Var_Dump (ctxt)
1940 GNode *ctxt;
1941{
1942 Lst_ForEach (ctxt->context, VarPrintVar);
1943}