VirtualBox

source: kBuild/trunk/src/kmk/var.c@ 46

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

kMk changes. Made extensions configurable from config.h. fixed parents.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette