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