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