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