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