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