source: trunk/src/kmk/var.c@ 45

Last change on this file since 45 was 45, checked in by bird, 22 years ago

KMK changes..

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