VirtualBox

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

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

VarStrCmp().

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