Annotation of src/usr.bin/make/var.c, Revision 1.109
1.109 ! christos 1: /* $NetBSD: var.c,v 1.108 2006/05/11 15:37:07 sjg Exp $ */
1.11 christos 2:
1.1 cgd 3: /*
1.15 christos 4: * Copyright (c) 1988, 1989, 1990, 1993
5: * The Regents of the University of California. All rights reserved.
1.80 agc 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. Neither the name of the University nor the names of its contributors
19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: */
34:
35: /*
1.1 cgd 36: * Copyright (c) 1989 by Berkeley Softworks
37: * All rights reserved.
38: *
39: * This code is derived from software contributed to Berkeley by
40: * Adam de Boor.
41: *
42: * Redistribution and use in source and binary forms, with or without
43: * modification, are permitted provided that the following conditions
44: * are met:
45: * 1. Redistributions of source code must retain the above copyright
46: * notice, this list of conditions and the following disclaimer.
47: * 2. Redistributions in binary form must reproduce the above copyright
48: * notice, this list of conditions and the following disclaimer in the
49: * documentation and/or other materials provided with the distribution.
50: * 3. All advertising materials mentioning features or use of this software
51: * must display the following acknowledgement:
52: * This product includes software developed by the University of
53: * California, Berkeley and its contributors.
54: * 4. Neither the name of the University nor the names of its contributors
55: * may be used to endorse or promote products derived from this software
56: * without specific prior written permission.
57: *
58: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68: * SUCH DAMAGE.
69: */
70:
1.88 ross 71: #ifndef MAKE_NATIVE
1.109 ! christos 72: static char rcsid[] = "$NetBSD: var.c,v 1.108 2006/05/11 15:37:07 sjg Exp $";
1.23 lukem 73: #else
1.19 christos 74: #include <sys/cdefs.h>
1.1 cgd 75: #ifndef lint
1.11 christos 76: #if 0
1.15 christos 77: static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
1.11 christos 78: #else
1.109 ! christos 79: __RCSID("$NetBSD: var.c,v 1.108 2006/05/11 15:37:07 sjg Exp $");
1.11 christos 80: #endif
1.1 cgd 81: #endif /* not lint */
1.23 lukem 82: #endif
1.1 cgd 83:
84: /*-
85: * var.c --
86: * Variable-handling functions
87: *
88: * Interface:
89: * Var_Set Set the value of a variable in the given
90: * context. The variable is created if it doesn't
91: * yet exist. The value and variable name need not
92: * be preserved.
93: *
94: * Var_Append Append more characters to an existing variable
95: * in the given context. The variable needn't
96: * exist already -- it will be created if it doesn't.
97: * A space is placed between the old value and the
98: * new one.
99: *
100: * Var_Exists See if a variable exists.
101: *
102: * Var_Value Return the value of a variable in a context or
103: * NULL if the variable is undefined.
104: *
1.5 cgd 105: * Var_Subst Substitute named variable, or all variables if
106: * NULL in a string using
1.1 cgd 107: * the given context as the top-most one. If the
108: * third argument is non-zero, Parse_Error is
109: * called if any variables are undefined.
110: *
111: * Var_Parse Parse a variable expansion from a string and
112: * return the result and the number of characters
113: * consumed.
114: *
115: * Var_Delete Delete a variable in a context.
116: *
117: * Var_Init Initialize this module.
118: *
119: * Debugging:
120: * Var_Dump Print out all variables defined in the given
121: * context.
122: *
123: * XXX: There's a lot of duplication in these functions.
124: */
125:
1.31 gwr 126: #ifndef NO_REGEX
1.28 wsanchez 127: #include <sys/types.h>
1.16 christos 128: #include <regex.h>
1.17 christos 129: #endif
1.70 wiz 130: #include <ctype.h>
1.17 christos 131: #include <stdlib.h>
1.82 jmc 132: #include <limits.h>
1.70 wiz 133:
1.1 cgd 134: #include "make.h"
135: #include "buf.h"
1.103 sjg 136: #include "dir.h"
1.1 cgd 137:
138: /*
139: * This is a harmless return value for Var_Parse that can be used by Var_Subst
140: * to determine if there was an error in parsing -- easier than returning
141: * a flag, as things outside this module don't give a hoot.
142: */
143: char var_Error[] = "";
144:
145: /*
146: * Similar to var_Error, but returned when the 'err' flag for Var_Parse is
147: * set false. Why not just use a constant? Well, gcc likes to condense
148: * identical string instances...
149: */
1.5 cgd 150: static char varNoError[] = "";
1.1 cgd 151:
152: /*
153: * Internally, variables are contained in four different contexts.
154: * 1) the environment. They may not be changed. If an environment
155: * variable is appended-to, the result is placed in the global
156: * context.
157: * 2) the global context. Variables set in the Makefile are located in
158: * the global context. It is the penultimate context searched when
159: * substituting.
160: * 3) the command-line context. All variables set on the command line
161: * are placed in this context. They are UNALTERABLE once placed here.
162: * 4) the local context. Each target has associated with it a context
163: * list. On this list are located the structures describing such
164: * local variables as $(@) and $(*)
165: * The four contexts are searched in the reverse order from which they are
166: * listed.
167: */
168: GNode *VAR_GLOBAL; /* variables from the makefile */
169: GNode *VAR_CMD; /* variables defined on the command-line */
170:
171: #define FIND_CMD 0x1 /* look in VAR_CMD when searching */
172: #define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */
173: #define FIND_ENV 0x4 /* look in the environment also */
174:
175: typedef struct Var {
176: char *name; /* the variable's name */
177: Buffer val; /* its value */
178: int flags; /* miscellaneous status flags */
179: #define VAR_IN_USE 1 /* Variable's value currently being used.
180: * Used to avoid recursion */
181: #define VAR_FROM_ENV 2 /* Variable comes from the environment */
182: #define VAR_JUNK 4 /* Variable is a junk variable that
183: * should be destroyed when done with
184: * it. Used by Var_Parse for undefined,
185: * modified variables */
1.40 sjg 186: #define VAR_KEEP 8 /* Variable is VAR_JUNK, but we found
187: * a use for it in some modifier and
188: * the value is therefore valid */
1.1 cgd 189: } Var;
190:
1.16 christos 191:
192: /* Var*Pattern flags */
193: #define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */
194: #define VAR_SUB_ONE 0x02 /* Apply substitution to one word */
195: #define VAR_SUB_MATCHED 0x04 /* There was a match */
196: #define VAR_MATCH_START 0x08 /* Match at start of word */
197: #define VAR_MATCH_END 0x10 /* Match at end of word */
1.40 sjg 198: #define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */
1.16 christos 199:
1.65 sjg 200: /* Var_Set flags */
201: #define VAR_NO_EXPORT 0x01 /* do not export */
202:
1.5 cgd 203: typedef struct {
1.81 sjg 204: /*
205: * The following fields are set by Var_Parse() when it
206: * encounters modifiers that need to keep state for use by
207: * subsequent modifiers within the same variable expansion.
208: */
209: Byte varSpace; /* Word separator in expansions */
210: Boolean oneBigWord; /* TRUE if we will treat the variable as a
211: * single big word, even if it contains
212: * embedded spaces (as opposed to the
213: * usual behaviour of treating it as
214: * several space-separated words). */
215: } Var_Parse_State;
216:
217: /* struct passed as ClientData to VarSubstitute() for ":S/lhs/rhs/",
218: * to VarSYSVMatch() for ":lhs=rhs". */
219: typedef struct {
1.73 christos 220: const char *lhs; /* String to match */
221: int leftLen; /* Length of string */
222: const char *rhs; /* Replacement string (w/ &'s removed) */
1.5 cgd 223: int rightLen; /* Length of replacement */
224: int flags;
225: } VarPattern;
226:
1.81 sjg 227: /* struct passed as ClientData to VarLoopExpand() for ":@tvar@str@" */
1.41 sjg 228: typedef struct {
229: GNode *ctxt; /* variable context */
230: char *tvar; /* name of temp var */
231: int tvarLen;
232: char *str; /* string to expand */
233: int strLen;
234: int err; /* err for not defined */
235: } VarLoop_t;
236:
1.31 gwr 237: #ifndef NO_REGEX
1.81 sjg 238: /* struct passed as ClientData to VarRESubstitute() for ":C///" */
1.16 christos 239: typedef struct {
240: regex_t re;
241: int nsub;
242: regmatch_t *matches;
243: char *replace;
244: int flags;
245: } VarREPattern;
1.17 christos 246: #endif
1.16 christos 247:
1.81 sjg 248: /* struct passed to VarSelectWords() for ":[start..end]" */
249: typedef struct {
250: int start; /* first word to select */
251: int end; /* last word to select */
252: } VarSelectWords_t;
253:
1.73 christos 254: static Var *VarFind(const char *, GNode *, int);
255: static void VarAdd(const char *, const char *, GNode *);
1.81 sjg 256: static Boolean VarHead(GNode *, Var_Parse_State *,
257: char *, Boolean, Buffer, ClientData);
258: static Boolean VarTail(GNode *, Var_Parse_State *,
259: char *, Boolean, Buffer, ClientData);
260: static Boolean VarSuffix(GNode *, Var_Parse_State *,
261: char *, Boolean, Buffer, ClientData);
262: static Boolean VarRoot(GNode *, Var_Parse_State *,
263: char *, Boolean, Buffer, ClientData);
264: static Boolean VarMatch(GNode *, Var_Parse_State *,
265: char *, Boolean, Buffer, ClientData);
1.13 christos 266: #ifdef SYSVVARSUB
1.81 sjg 267: static Boolean VarSYSVMatch(GNode *, Var_Parse_State *,
268: char *, Boolean, Buffer, ClientData);
1.13 christos 269: #endif
1.81 sjg 270: static Boolean VarNoMatch(GNode *, Var_Parse_State *,
271: char *, Boolean, Buffer, ClientData);
1.31 gwr 272: #ifndef NO_REGEX
1.70 wiz 273: static void VarREError(int, regex_t *, const char *);
1.81 sjg 274: static Boolean VarRESubstitute(GNode *, Var_Parse_State *,
275: char *, Boolean, Buffer, ClientData);
1.17 christos 276: #endif
1.81 sjg 277: static Boolean VarSubstitute(GNode *, Var_Parse_State *,
278: char *, Boolean, Buffer, ClientData);
279: static Boolean VarLoopExpand(GNode *, Var_Parse_State *,
280: char *, Boolean, Buffer, ClientData);
281: static char *VarGetPattern(GNode *, Var_Parse_State *,
282: int, const char **, int, int *, int *,
1.70 wiz 283: VarPattern *);
284: static char *VarQuote(char *);
285: static char *VarChangeCase(char *, int);
1.81 sjg 286: static char *VarModify(GNode *, Var_Parse_State *,
287: const char *,
288: Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer, ClientData),
1.73 christos 289: ClientData);
1.93 sjg 290: static char *VarOrder(const char *, const char);
1.73 christos 291: static char *VarUniq(const char *);
1.70 wiz 292: static int VarWordCompare(const void *, const void *);
293: static void VarPrintVar(ClientData);
1.1 cgd 294:
1.73 christos 295: #define WR(a) ((char *)UNCONST(a))
296:
1.100 christos 297: #define BROPEN '{'
298: #define BRCLOSE '}'
299: #define PROPEN '('
300: #define PRCLOSE ')'
301:
1.1 cgd 302: /*-
303: *-----------------------------------------------------------------------
304: * VarFind --
305: * Find the given variable in the given context and any other contexts
306: * indicated.
307: *
1.70 wiz 308: * Input:
309: * name name to find
310: * ctxt context in which to find it
311: * flags FIND_GLOBAL set means to look in the
312: * VAR_GLOBAL context as well. FIND_CMD set means
313: * to look in the VAR_CMD context also. FIND_ENV
314: * set means to look in the environment
315: *
1.1 cgd 316: * Results:
317: * A pointer to the structure describing the desired variable or
318: * NIL if the variable does not exist.
319: *
320: * Side Effects:
321: * None
322: *-----------------------------------------------------------------------
323: */
324: static Var *
1.73 christos 325: VarFind(const char *name, GNode *ctxt, int flags)
1.1 cgd 326: {
1.36 mycroft 327: Hash_Entry *var;
1.1 cgd 328: Var *v;
329:
330: /*
331: * If the variable name begins with a '.', it could very well be one of
332: * the local ones. We check the name against all the local variables
333: * and substitute the short version in for 'name' if it matches one of
334: * them.
335: */
1.6 jtc 336: if (*name == '.' && isupper((unsigned char) name[1]))
1.1 cgd 337: switch (name[1]) {
338: case 'A':
339: if (!strcmp(name, ".ALLSRC"))
340: name = ALLSRC;
341: if (!strcmp(name, ".ARCHIVE"))
342: name = ARCHIVE;
343: break;
344: case 'I':
345: if (!strcmp(name, ".IMPSRC"))
346: name = IMPSRC;
347: break;
348: case 'M':
349: if (!strcmp(name, ".MEMBER"))
350: name = MEMBER;
351: break;
352: case 'O':
353: if (!strcmp(name, ".OODATE"))
354: name = OODATE;
355: break;
356: case 'P':
357: if (!strcmp(name, ".PREFIX"))
358: name = PREFIX;
359: break;
360: case 'T':
361: if (!strcmp(name, ".TARGET"))
362: name = TARGET;
363: break;
364: }
365: /*
366: * First look for the variable in the given context. If it's not there,
367: * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
368: * depending on the FIND_* flags in 'flags'
369: */
1.92 christos 370: var = Hash_FindEntry(&ctxt->context, name);
1.1 cgd 371:
1.36 mycroft 372: if ((var == NULL) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) {
1.92 christos 373: var = Hash_FindEntry(&VAR_CMD->context, name);
1.1 cgd 374: }
1.36 mycroft 375: if (!checkEnvFirst && (var == NULL) && (flags & FIND_GLOBAL) &&
1.1 cgd 376: (ctxt != VAR_GLOBAL))
377: {
1.92 christos 378: var = Hash_FindEntry(&VAR_GLOBAL->context, name);
1.1 cgd 379: }
1.36 mycroft 380: if ((var == NULL) && (flags & FIND_ENV)) {
1.1 cgd 381: char *env;
382:
1.97 christos 383: if ((env = getenv(name)) != NULL) {
1.1 cgd 384: int len;
1.15 christos 385:
1.92 christos 386: v = emalloc(sizeof(Var));
1.14 christos 387: v->name = estrdup(name);
1.1 cgd 388:
389: len = strlen(env);
1.15 christos 390:
1.1 cgd 391: v->val = Buf_Init(len);
392: Buf_AddBytes(v->val, len, (Byte *)env);
1.15 christos 393:
1.1 cgd 394: v->flags = VAR_FROM_ENV;
395: return (v);
396: } else if (checkEnvFirst && (flags & FIND_GLOBAL) &&
397: (ctxt != VAR_GLOBAL))
398: {
1.92 christos 399: var = Hash_FindEntry(&VAR_GLOBAL->context, name);
1.36 mycroft 400: if (var == NULL) {
1.99 christos 401: return ((Var *)NIL);
1.1 cgd 402: } else {
1.36 mycroft 403: return ((Var *)Hash_GetValue(var));
1.1 cgd 404: }
405: } else {
406: return((Var *)NIL);
407: }
1.36 mycroft 408: } else if (var == NULL) {
1.99 christos 409: return ((Var *)NIL);
1.1 cgd 410: } else {
1.97 christos 411: return ((Var *)Hash_GetValue(var));
1.1 cgd 412: }
413: }
414:
415: /*-
416: *-----------------------------------------------------------------------
1.105 christos 417: * VarFreeEnv --
418: * If the variable is an environment variable, free it
419: *
420: * Input:
421: * v the variable
422: * destroy true if the value buffer should be destroyed.
423: *
424: * Results:
425: * 1 if it is an environment variable 0 ow.
426: *
427: * Side Effects:
428: * The variable is free'ed if it is an environent variable.
429: *-----------------------------------------------------------------------
430: */
431: static Boolean
432: VarFreeEnv(Var *v, Boolean destroy)
433: {
434: if ((v->flags & VAR_FROM_ENV) == 0)
435: return FALSE;
436: free(v->name);
437: Buf_Destroy(v->val, destroy);
438: free(v);
439: return TRUE;
440: }
441:
442: /*-
443: *-----------------------------------------------------------------------
1.1 cgd 444: * VarAdd --
445: * Add a new variable of name name and value val to the given context
446: *
1.70 wiz 447: * Input:
448: * name name of variable to add
449: * val value to set it to
450: * ctxt context in which to set it
451: *
1.1 cgd 452: * Results:
453: * None
454: *
455: * Side Effects:
456: * The new variable is placed at the front of the given context
457: * The name and val arguments are duplicated so they may
458: * safely be freed.
459: *-----------------------------------------------------------------------
460: */
1.5 cgd 461: static void
1.73 christos 462: VarAdd(const char *name, const char *val, GNode *ctxt)
1.1 cgd 463: {
1.70 wiz 464: Var *v;
1.1 cgd 465: int len;
1.70 wiz 466: Hash_Entry *h;
1.1 cgd 467:
1.92 christos 468: v = emalloc(sizeof(Var));
1.1 cgd 469:
1.5 cgd 470: len = val ? strlen(val) : 0;
1.1 cgd 471: v->val = Buf_Init(len+1);
1.73 christos 472: Buf_AddBytes(v->val, len, (const Byte *)val);
1.1 cgd 473:
474: v->flags = 0;
475:
1.92 christos 476: h = Hash_CreateEntry(&ctxt->context, name, NULL);
1.36 mycroft 477: Hash_SetValue(h, v);
1.37 sommerfe 478: v->name = h->name;
1.1 cgd 479: if (DEBUG(VAR)) {
480: printf("%s:%s = %s\n", ctxt->name, name, val);
481: }
482: }
483:
484: /*-
485: *-----------------------------------------------------------------------
486: * Var_Delete --
487: * Remove a variable from a context.
488: *
489: * Results:
490: * None.
491: *
492: * Side Effects:
493: * The Var structure is removed and freed.
494: *
495: *-----------------------------------------------------------------------
496: */
497: void
1.73 christos 498: Var_Delete(const char *name, GNode *ctxt)
1.1 cgd 499: {
1.36 mycroft 500: Hash_Entry *ln;
1.1 cgd 501:
502: if (DEBUG(VAR)) {
503: printf("%s:delete %s\n", ctxt->name, name);
504: }
1.36 mycroft 505: ln = Hash_FindEntry(&ctxt->context, name);
506: if (ln != NULL) {
1.70 wiz 507: Var *v;
1.1 cgd 508:
1.36 mycroft 509: v = (Var *)Hash_GetValue(ln);
1.37 sommerfe 510: if (v->name != ln->name)
511: free(v->name);
1.36 mycroft 512: Hash_DeleteEntry(&ctxt->context, ln);
1.37 sommerfe 513: Buf_Destroy(v->val, TRUE);
1.98 christos 514: free(v);
1.1 cgd 515: }
516: }
517:
518: /*-
519: *-----------------------------------------------------------------------
520: * Var_Set --
521: * Set the variable name to the value val in the given context.
522: *
1.70 wiz 523: * Input:
524: * name name of variable to set
525: * val value to give to the variable
526: * ctxt context in which to set it
527: *
1.1 cgd 528: * Results:
529: * None.
530: *
531: * Side Effects:
532: * If the variable doesn't yet exist, a new record is created for it.
533: * Else the old value is freed and the new one stuck in its place
534: *
535: * Notes:
536: * The variable is searched for only in its context before being
537: * created in that context. I.e. if the context is VAR_GLOBAL,
538: * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
539: * VAR_CMD->context is searched. This is done to avoid the literally
540: * thousands of unnecessary strcmp's that used to be done to
541: * set, say, $(@) or $(<).
542: *-----------------------------------------------------------------------
543: */
544: void
1.73 christos 545: Var_Set(const char *name, const char *val, GNode *ctxt, int flags)
1.1 cgd 546: {
1.70 wiz 547: Var *v;
1.73 christos 548: const char *cp = name;
1.42 sjg 549:
1.1 cgd 550: /*
551: * We only look for a variable in the given context since anything set
552: * here will override anything in a lower context, so there's not much
553: * point in searching them all just to save a bit of memory...
554: */
1.42 sjg 555: if ((name = strchr(cp, '$'))) {
556: name = Var_Subst(NULL, cp, ctxt, 0);
557: } else
558: name = cp;
1.92 christos 559: v = VarFind(name, ctxt, 0);
1.99 christos 560: if (v == (Var *)NIL) {
1.92 christos 561: VarAdd(name, val, ctxt);
1.1 cgd 562: } else {
563: Buf_Discard(v->val, Buf_Size(v->val));
1.73 christos 564: Buf_AddBytes(v->val, strlen(val), (const Byte *)val);
1.1 cgd 565:
566: if (DEBUG(VAR)) {
567: printf("%s:%s = %s\n", ctxt->name, name, val);
568: }
569: }
570: /*
571: * Any variables given on the command line are automatically exported
572: * to the environment (as per POSIX standard)
573: */
1.65 sjg 574: if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
1.64 sjg 575:
1.71 thorpej 576: /*
577: * If requested, don't export these in the environment
578: * individually. We still put them in MAKEOVERRIDES so
579: * that the command-line settings continue to override
580: * Makefile settings.
581: */
582: if (varNoExportEnv != TRUE)
583: setenv(name, val, 1);
1.62 sjg 584:
1.64 sjg 585: Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
1.1 cgd 586: }
1.42 sjg 587: if (name != cp)
1.73 christos 588: free(UNCONST(name));
1.107 christos 589: if (v != (Var *)NIL)
590: VarFreeEnv(v, TRUE);
1.1 cgd 591: }
592:
593: /*-
594: *-----------------------------------------------------------------------
595: * Var_Append --
596: * The variable of the given name has the given value appended to it in
597: * the given context.
598: *
1.70 wiz 599: * Input:
600: * name name of variable to modify
601: * val String to append to it
602: * ctxt Context in which this should occur
603: *
1.1 cgd 604: * Results:
605: * None
606: *
607: * Side Effects:
608: * If the variable doesn't exist, it is created. Else the strings
609: * are concatenated (with a space in between).
610: *
611: * Notes:
612: * Only if the variable is being sought in the global context is the
613: * environment searched.
614: * XXX: Knows its calling circumstances in that if called with ctxt
615: * an actual target, it will only search that context since only
616: * a local variable could be being appended to. This is actually
617: * a big win and must be tolerated.
618: *-----------------------------------------------------------------------
619: */
620: void
1.73 christos 621: Var_Append(const char *name, const char *val, GNode *ctxt)
1.1 cgd 622: {
1.70 wiz 623: Var *v;
1.36 mycroft 624: Hash_Entry *h;
1.73 christos 625: const char *cp = name;
1.1 cgd 626:
1.42 sjg 627: if ((name = strchr(cp, '$'))) {
628: name = Var_Subst(NULL, cp, ctxt, 0);
629: } else
630: name = cp;
631:
1.92 christos 632: v = VarFind(name, ctxt, (ctxt == VAR_GLOBAL) ? FIND_ENV : 0);
1.1 cgd 633:
1.99 christos 634: if (v == (Var *)NIL) {
1.92 christos 635: VarAdd(name, val, ctxt);
1.1 cgd 636: } else {
637: Buf_AddByte(v->val, (Byte)' ');
1.73 christos 638: Buf_AddBytes(v->val, strlen(val), (const Byte *)val);
1.1 cgd 639:
640: if (DEBUG(VAR)) {
641: printf("%s:%s = %s\n", ctxt->name, name,
1.99 christos 642: (char *)Buf_GetAll(v->val, NULL));
1.1 cgd 643: }
644:
645: if (v->flags & VAR_FROM_ENV) {
646: /*
647: * If the original variable came from the environment, we
648: * have to install it in the global context (we could place
649: * it in the environment, but then we should provide a way to
650: * export other variables...)
651: */
652: v->flags &= ~VAR_FROM_ENV;
1.92 christos 653: h = Hash_CreateEntry(&ctxt->context, name, NULL);
1.36 mycroft 654: Hash_SetValue(h, v);
1.1 cgd 655: }
656: }
1.42 sjg 657: if (name != cp)
1.73 christos 658: free(UNCONST(name));
1.1 cgd 659: }
660:
661: /*-
662: *-----------------------------------------------------------------------
663: * Var_Exists --
664: * See if the given variable exists.
665: *
1.70 wiz 666: * Input:
667: * name Variable to find
668: * ctxt Context in which to start search
669: *
1.1 cgd 670: * Results:
671: * TRUE if it does, FALSE if it doesn't
672: *
673: * Side Effects:
674: * None.
675: *
676: *-----------------------------------------------------------------------
677: */
678: Boolean
1.73 christos 679: Var_Exists(const char *name, GNode *ctxt)
1.1 cgd 680: {
681: Var *v;
682:
683: v = VarFind(name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV);
684:
685: if (v == (Var *)NIL) {
686: return(FALSE);
1.105 christos 687: } else {
688: (void)VarFreeEnv(v, TRUE);
1.1 cgd 689: }
690: return(TRUE);
691: }
692:
693: /*-
694: *-----------------------------------------------------------------------
695: * Var_Value --
696: * Return the value of the named variable in the given context
697: *
1.70 wiz 698: * Input:
699: * name name to find
700: * ctxt context in which to search for it
701: *
1.1 cgd 702: * Results:
703: * The value if the variable exists, NULL if it doesn't
704: *
705: * Side Effects:
706: * None
707: *-----------------------------------------------------------------------
708: */
709: char *
1.73 christos 710: Var_Value(const char *name, GNode *ctxt, char **frp)
1.1 cgd 711: {
712: Var *v;
713:
1.92 christos 714: v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1.6 jtc 715: *frp = NULL;
1.99 christos 716: if (v != (Var *)NIL) {
717: char *p = ((char *)Buf_GetAll(v->val, NULL));
1.105 christos 718: if (VarFreeEnv(v, FALSE))
1.6 jtc 719: *frp = p;
720: return p;
1.1 cgd 721: } else {
1.99 christos 722: return (NULL);
1.1 cgd 723: }
724: }
725:
726: /*-
727: *-----------------------------------------------------------------------
728: * VarHead --
729: * Remove the tail of the given word and place the result in the given
730: * buffer.
731: *
1.70 wiz 732: * Input:
733: * word Word to trim
734: * addSpace True if need to add a space to the buffer
735: * before sticking in the head
736: * buf Buffer in which to store it
737: *
1.1 cgd 738: * Results:
739: * TRUE if characters were added to the buffer (a space needs to be
740: * added to the buffer before the next word).
741: *
742: * Side Effects:
743: * The trimmed word is added to the buffer.
744: *
745: *-----------------------------------------------------------------------
746: */
747: static Boolean
1.90 jmc 748: VarHead(GNode *ctx __unused, Var_Parse_State *vpstate,
1.89 jmc 749: char *word, Boolean addSpace, Buffer buf,
750: ClientData dummy)
1.1 cgd 751: {
1.70 wiz 752: char *slash;
1.1 cgd 753:
1.97 christos 754: slash = strrchr(word, '/');
1.99 christos 755: if (slash != NULL) {
1.81 sjg 756: if (addSpace && vpstate->varSpace) {
1.97 christos 757: Buf_AddByte(buf, vpstate->varSpace);
1.1 cgd 758: }
759: *slash = '\0';
1.97 christos 760: Buf_AddBytes(buf, strlen(word), (Byte *)word);
1.1 cgd 761: *slash = '/';
762: return (TRUE);
763: } else {
764: /*
765: * If no directory part, give . (q.v. the POSIX standard)
766: */
1.81 sjg 767: if (addSpace && vpstate->varSpace)
768: Buf_AddByte(buf, vpstate->varSpace);
1.74 sjg 769: Buf_AddByte(buf, (Byte)'.');
1.1 cgd 770: }
1.6 jtc 771: return(dummy ? TRUE : TRUE);
1.1 cgd 772: }
773:
774: /*-
775: *-----------------------------------------------------------------------
776: * VarTail --
777: * Remove the head of the given word and place the result in the given
778: * buffer.
779: *
1.70 wiz 780: * Input:
781: * word Word to trim
782: * addSpace True if need to add a space to the buffer
783: * before adding the tail
784: * buf Buffer in which to store it
785: *
1.1 cgd 786: * Results:
787: * TRUE if characters were added to the buffer (a space needs to be
788: * added to the buffer before the next word).
789: *
790: * Side Effects:
791: * The trimmed word is added to the buffer.
792: *
793: *-----------------------------------------------------------------------
794: */
795: static Boolean
1.90 jmc 796: VarTail(GNode *ctx __unused, Var_Parse_State *vpstate,
1.89 jmc 797: char *word, Boolean addSpace, Buffer buf,
798: ClientData dummy)
1.1 cgd 799: {
1.70 wiz 800: char *slash;
1.1 cgd 801:
1.81 sjg 802: if (addSpace && vpstate->varSpace) {
1.97 christos 803: Buf_AddByte(buf, vpstate->varSpace);
1.1 cgd 804: }
805:
1.97 christos 806: slash = strrchr(word, '/');
1.99 christos 807: if (slash != NULL) {
1.1 cgd 808: *slash++ = '\0';
1.92 christos 809: Buf_AddBytes(buf, strlen(slash), (Byte *)slash);
1.1 cgd 810: slash[-1] = '/';
811: } else {
1.92 christos 812: Buf_AddBytes(buf, strlen(word), (Byte *)word);
1.1 cgd 813: }
1.6 jtc 814: return (dummy ? TRUE : TRUE);
1.1 cgd 815: }
816:
817: /*-
818: *-----------------------------------------------------------------------
819: * VarSuffix --
820: * Place the suffix of the given word in the given buffer.
821: *
1.70 wiz 822: * Input:
823: * word Word to trim
824: * addSpace TRUE if need to add a space before placing the
825: * suffix in the buffer
826: * buf Buffer in which to store it
827: *
1.1 cgd 828: * Results:
829: * TRUE if characters were added to the buffer (a space needs to be
830: * added to the buffer before the next word).
831: *
832: * Side Effects:
833: * The suffix from the word is placed in the buffer.
834: *
835: *-----------------------------------------------------------------------
836: */
837: static Boolean
1.90 jmc 838: VarSuffix(GNode *ctx __unused, Var_Parse_State *vpstate,
1.81 sjg 839: char *word, Boolean addSpace, Buffer buf,
1.70 wiz 840: ClientData dummy)
1.1 cgd 841: {
1.70 wiz 842: char *dot;
1.1 cgd 843:
1.97 christos 844: dot = strrchr(word, '.');
1.99 christos 845: if (dot != NULL) {
1.81 sjg 846: if (addSpace && vpstate->varSpace) {
1.97 christos 847: Buf_AddByte(buf, vpstate->varSpace);
1.1 cgd 848: }
849: *dot++ = '\0';
1.97 christos 850: Buf_AddBytes(buf, strlen(dot), (Byte *)dot);
1.1 cgd 851: dot[-1] = '.';
1.6 jtc 852: addSpace = TRUE;
1.1 cgd 853: }
1.6 jtc 854: return (dummy ? addSpace : addSpace);
1.1 cgd 855: }
856:
857: /*-
858: *-----------------------------------------------------------------------
859: * VarRoot --
860: * Remove the suffix of the given word and place the result in the
861: * buffer.
862: *
1.70 wiz 863: * Input:
864: * word Word to trim
865: * addSpace TRUE if need to add a space to the buffer
866: * before placing the root in it
867: * buf Buffer in which to store it
868: *
1.1 cgd 869: * Results:
870: * TRUE if characters were added to the buffer (a space needs to be
871: * added to the buffer before the next word).
872: *
873: * Side Effects:
874: * The trimmed word is added to the buffer.
875: *
876: *-----------------------------------------------------------------------
877: */
878: static Boolean
1.90 jmc 879: VarRoot(GNode *ctx __unused, Var_Parse_State *vpstate,
1.81 sjg 880: char *word, Boolean addSpace, Buffer buf,
1.70 wiz 881: ClientData dummy)
1.1 cgd 882: {
1.70 wiz 883: char *dot;
1.1 cgd 884:
1.81 sjg 885: if (addSpace && vpstate->varSpace) {
1.97 christos 886: Buf_AddByte(buf, vpstate->varSpace);
1.1 cgd 887: }
888:
1.97 christos 889: dot = strrchr(word, '.');
1.99 christos 890: if (dot != NULL) {
1.1 cgd 891: *dot = '\0';
1.97 christos 892: Buf_AddBytes(buf, strlen(word), (Byte *)word);
1.1 cgd 893: *dot = '.';
894: } else {
1.92 christos 895: Buf_AddBytes(buf, strlen(word), (Byte *)word);
1.1 cgd 896: }
1.6 jtc 897: return (dummy ? TRUE : TRUE);
1.1 cgd 898: }
899:
900: /*-
901: *-----------------------------------------------------------------------
902: * VarMatch --
903: * Place the word in the buffer if it matches the given pattern.
904: * Callback function for VarModify to implement the :M modifier.
1.15 christos 905: *
1.70 wiz 906: * Input:
907: * word Word to examine
908: * addSpace TRUE if need to add a space to the buffer
909: * before adding the word, if it matches
910: * buf Buffer in which to store it
911: * pattern Pattern the word must match
912: *
1.1 cgd 913: * Results:
914: * TRUE if a space should be placed in the buffer before the next
915: * word.
916: *
917: * Side Effects:
918: * The word may be copied to the buffer.
919: *
920: *-----------------------------------------------------------------------
921: */
922: static Boolean
1.90 jmc 923: VarMatch(GNode *ctx __unused, Var_Parse_State *vpstate,
1.89 jmc 924: char *word, Boolean addSpace, Buffer buf,
925: ClientData pattern)
1.1 cgd 926: {
1.99 christos 927: if (Str_Match(word, (char *)pattern)) {
1.81 sjg 928: if (addSpace && vpstate->varSpace) {
929: Buf_AddByte(buf, vpstate->varSpace);
1.1 cgd 930: }
931: addSpace = TRUE;
932: Buf_AddBytes(buf, strlen(word), (Byte *)word);
933: }
934: return(addSpace);
935: }
936:
1.13 christos 937: #ifdef SYSVVARSUB
1.5 cgd 938: /*-
939: *-----------------------------------------------------------------------
940: * VarSYSVMatch --
941: * Place the word in the buffer if it matches the given pattern.
942: * Callback function for VarModify to implement the System V %
943: * modifiers.
1.15 christos 944: *
1.70 wiz 945: * Input:
946: * word Word to examine
947: * addSpace TRUE if need to add a space to the buffer
948: * before adding the word, if it matches
949: * buf Buffer in which to store it
950: * patp Pattern the word must match
951: *
1.5 cgd 952: * Results:
953: * TRUE if a space should be placed in the buffer before the next
954: * word.
955: *
956: * Side Effects:
957: * The word may be copied to the buffer.
958: *
959: *-----------------------------------------------------------------------
960: */
961: static Boolean
1.81 sjg 962: VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate,
963: char *word, Boolean addSpace, Buffer buf,
1.70 wiz 964: ClientData patp)
1.5 cgd 965: {
966: int len;
967: char *ptr;
1.99 christos 968: VarPattern *pat = (VarPattern *)patp;
1.61 explorer 969: char *varexp;
1.5 cgd 970:
1.81 sjg 971: if (addSpace && vpstate->varSpace)
972: Buf_AddByte(buf, vpstate->varSpace);
1.5 cgd 973:
974: addSpace = TRUE;
975:
1.61 explorer 976: if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL) {
977: varexp = Var_Subst(NULL, pat->rhs, ctx, 0);
978: Str_SYSVSubst(buf, varexp, ptr, len);
979: free(varexp);
980: } else {
1.99 christos 981: Buf_AddBytes(buf, strlen(word), (Byte *)word);
1.61 explorer 982: }
1.5 cgd 983:
984: return(addSpace);
985: }
1.13 christos 986: #endif
1.5 cgd 987:
988:
1.1 cgd 989: /*-
990: *-----------------------------------------------------------------------
991: * VarNoMatch --
992: * Place the word in the buffer if it doesn't match the given pattern.
993: * Callback function for VarModify to implement the :N modifier.
1.15 christos 994: *
1.70 wiz 995: * Input:
996: * word Word to examine
997: * addSpace TRUE if need to add a space to the buffer
998: * before adding the word, if it matches
999: * buf Buffer in which to store it
1000: * pattern Pattern the word must match
1001: *
1.1 cgd 1002: * Results:
1003: * TRUE if a space should be placed in the buffer before the next
1004: * word.
1005: *
1006: * Side Effects:
1007: * The word may be copied to the buffer.
1008: *
1009: *-----------------------------------------------------------------------
1010: */
1011: static Boolean
1.90 jmc 1012: VarNoMatch(GNode *ctx __unused, Var_Parse_State *vpstate,
1.89 jmc 1013: char *word, Boolean addSpace, Buffer buf,
1014: ClientData pattern)
1.1 cgd 1015: {
1.99 christos 1016: if (!Str_Match(word, (char *)pattern)) {
1.81 sjg 1017: if (addSpace && vpstate->varSpace) {
1018: Buf_AddByte(buf, vpstate->varSpace);
1.1 cgd 1019: }
1020: addSpace = TRUE;
1021: Buf_AddBytes(buf, strlen(word), (Byte *)word);
1022: }
1023: return(addSpace);
1024: }
1025:
1026:
1027: /*-
1028: *-----------------------------------------------------------------------
1029: * VarSubstitute --
1030: * Perform a string-substitution on the given word, placing the
1031: * result in the passed buffer.
1032: *
1.70 wiz 1033: * Input:
1034: * word Word to modify
1035: * addSpace True if space should be added before
1036: * other characters
1037: * buf Buffer for result
1038: * patternp Pattern for substitution
1039: *
1.1 cgd 1040: * Results:
1041: * TRUE if a space is needed before more characters are added.
1042: *
1043: * Side Effects:
1044: * None.
1045: *
1046: *-----------------------------------------------------------------------
1047: */
1048: static Boolean
1.90 jmc 1049: VarSubstitute(GNode *ctx __unused, Var_Parse_State *vpstate,
1.81 sjg 1050: char *word, Boolean addSpace, Buffer buf,
1.70 wiz 1051: ClientData patternp)
1.1 cgd 1052: {
1.70 wiz 1053: int wordLen; /* Length of word */
1054: char *cp; /* General pointer */
1.99 christos 1055: VarPattern *pattern = (VarPattern *)patternp;
1.1 cgd 1056:
1057: wordLen = strlen(word);
1.16 christos 1058: if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) !=
1059: (VAR_SUB_ONE|VAR_SUB_MATCHED)) {
1.1 cgd 1060: /*
1.16 christos 1061: * Still substituting -- break it down into simple anchored cases
1.1 cgd 1062: * and if none of them fits, perform the general substitution case.
1063: */
1064: if ((pattern->flags & VAR_MATCH_START) &&
1065: (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
1066: /*
1067: * Anchored at start and beginning of word matches pattern
1068: */
1069: if ((pattern->flags & VAR_MATCH_END) &&
1070: (wordLen == pattern->leftLen)) {
1071: /*
1072: * Also anchored at end and matches to the end (word
1073: * is same length as pattern) add space and rhs only
1074: * if rhs is non-null.
1075: */
1076: if (pattern->rightLen != 0) {
1.81 sjg 1077: if (addSpace && vpstate->varSpace) {
1078: Buf_AddByte(buf, vpstate->varSpace);
1.1 cgd 1079: }
1080: addSpace = TRUE;
1081: Buf_AddBytes(buf, pattern->rightLen,
1.73 christos 1082: (const Byte *)pattern->rhs);
1.1 cgd 1083: }
1.16 christos 1084: pattern->flags |= VAR_SUB_MATCHED;
1.1 cgd 1085: } else if (pattern->flags & VAR_MATCH_END) {
1086: /*
1087: * Doesn't match to end -- copy word wholesale
1088: */
1089: goto nosub;
1090: } else {
1091: /*
1092: * Matches at start but need to copy in trailing characters
1093: */
1094: if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
1.81 sjg 1095: if (addSpace && vpstate->varSpace) {
1096: Buf_AddByte(buf, vpstate->varSpace);
1.1 cgd 1097: }
1098: addSpace = TRUE;
1099: }
1.73 christos 1100: Buf_AddBytes(buf, pattern->rightLen,
1101: (const Byte *)pattern->rhs);
1.1 cgd 1102: Buf_AddBytes(buf, wordLen - pattern->leftLen,
1103: (Byte *)(word + pattern->leftLen));
1.16 christos 1104: pattern->flags |= VAR_SUB_MATCHED;
1.1 cgd 1105: }
1106: } else if (pattern->flags & VAR_MATCH_START) {
1107: /*
1108: * Had to match at start of word and didn't -- copy whole word.
1109: */
1110: goto nosub;
1111: } else if (pattern->flags & VAR_MATCH_END) {
1112: /*
1113: * Anchored at end, Find only place match could occur (leftLen
1114: * characters from the end of the word) and see if it does. Note
1115: * that because the $ will be left at the end of the lhs, we have
1116: * to use strncmp.
1117: */
1118: cp = word + (wordLen - pattern->leftLen);
1119: if ((cp >= word) &&
1120: (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
1121: /*
1122: * Match found. If we will place characters in the buffer,
1123: * add a space before hand as indicated by addSpace, then
1124: * stuff in the initial, unmatched part of the word followed
1125: * by the right-hand-side.
1126: */
1127: if (((cp - word) + pattern->rightLen) != 0) {
1.81 sjg 1128: if (addSpace && vpstate->varSpace) {
1129: Buf_AddByte(buf, vpstate->varSpace);
1.1 cgd 1130: }
1131: addSpace = TRUE;
1132: }
1.73 christos 1133: Buf_AddBytes(buf, cp - word, (const Byte *)word);
1134: Buf_AddBytes(buf, pattern->rightLen,
1135: (const Byte *)pattern->rhs);
1.16 christos 1136: pattern->flags |= VAR_SUB_MATCHED;
1.1 cgd 1137: } else {
1138: /*
1139: * Had to match at end and didn't. Copy entire word.
1140: */
1141: goto nosub;
1142: }
1143: } else {
1144: /*
1145: * Pattern is unanchored: search for the pattern in the word using
1146: * String_FindSubstring, copying unmatched portions and the
1147: * right-hand-side for each match found, handling non-global
1.15 christos 1148: * substitutions correctly, etc. When the loop is done, any
1.1 cgd 1149: * remaining part of the word (word and wordLen are adjusted
1150: * accordingly through the loop) is copied straight into the
1151: * buffer.
1152: * addSpace is set FALSE as soon as a space is added to the
1153: * buffer.
1154: */
1.70 wiz 1155: Boolean done;
1.1 cgd 1156: int origSize;
1157:
1158: done = FALSE;
1159: origSize = Buf_Size(buf);
1160: while (!done) {
1161: cp = Str_FindSubstring(word, pattern->lhs);
1.99 christos 1162: if (cp != NULL) {
1.1 cgd 1163: if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
1.81 sjg 1164: Buf_AddByte(buf, vpstate->varSpace);
1.1 cgd 1165: addSpace = FALSE;
1166: }
1.73 christos 1167: Buf_AddBytes(buf, cp-word, (const Byte *)word);
1168: Buf_AddBytes(buf, pattern->rightLen,
1169: (const Byte *)pattern->rhs);
1.1 cgd 1170: wordLen -= (cp - word) + pattern->leftLen;
1171: word = cp + pattern->leftLen;
1.16 christos 1172: if (wordLen == 0) {
1173: done = TRUE;
1174: }
1175: if ((pattern->flags & VAR_SUB_GLOBAL) == 0) {
1.1 cgd 1176: done = TRUE;
1177: }
1.16 christos 1178: pattern->flags |= VAR_SUB_MATCHED;
1.1 cgd 1179: } else {
1180: done = TRUE;
1181: }
1182: }
1183: if (wordLen != 0) {
1.81 sjg 1184: if (addSpace && vpstate->varSpace) {
1185: Buf_AddByte(buf, vpstate->varSpace);
1.1 cgd 1186: }
1187: Buf_AddBytes(buf, wordLen, (Byte *)word);
1188: }
1189: /*
1190: * If added characters to the buffer, need to add a space
1191: * before we add any more. If we didn't add any, just return
1192: * the previous value of addSpace.
1193: */
1194: return ((Buf_Size(buf) != origSize) || addSpace);
1195: }
1196: return (addSpace);
1197: }
1198: nosub:
1.81 sjg 1199: if (addSpace && vpstate->varSpace) {
1200: Buf_AddByte(buf, vpstate->varSpace);
1.1 cgd 1201: }
1202: Buf_AddBytes(buf, wordLen, (Byte *)word);
1203: return(TRUE);
1204: }
1205:
1.31 gwr 1206: #ifndef NO_REGEX
1.16 christos 1207: /*-
1208: *-----------------------------------------------------------------------
1209: * VarREError --
1210: * Print the error caused by a regcomp or regexec call.
1211: *
1212: * Results:
1213: * None.
1214: *
1215: * Side Effects:
1216: * An error gets printed.
1217: *
1218: *-----------------------------------------------------------------------
1219: */
1220: static void
1.70 wiz 1221: VarREError(int err, regex_t *pat, const char *str)
1.16 christos 1222: {
1223: char *errbuf;
1224: int errlen;
1225:
1226: errlen = regerror(err, pat, 0, 0);
1227: errbuf = emalloc(errlen);
1228: regerror(err, pat, errbuf, errlen);
1229: Error("%s: %s", str, errbuf);
1230: free(errbuf);
1231: }
1232:
1233:
1234: /*-
1235: *-----------------------------------------------------------------------
1236: * VarRESubstitute --
1237: * Perform a regex substitution on the given word, placing the
1238: * result in the passed buffer.
1239: *
1240: * Results:
1241: * TRUE if a space is needed before more characters are added.
1242: *
1243: * Side Effects:
1244: * None.
1245: *
1246: *-----------------------------------------------------------------------
1247: */
1248: static Boolean
1.90 jmc 1249: VarRESubstitute(GNode *ctx __unused, Var_Parse_State *vpstate __unused,
1.89 jmc 1250: char *word, Boolean addSpace, Buffer buf,
1251: ClientData patternp)
1.16 christos 1252: {
1253: VarREPattern *pat;
1254: int xrv;
1255: char *wp;
1256: char *rp;
1257: int added;
1.20 christos 1258: int flags = 0;
1.16 christos 1259:
1260: #define MAYBE_ADD_SPACE() \
1261: if (addSpace && !added) \
1262: Buf_AddByte(buf, ' '); \
1263: added = 1
1264:
1265: added = 0;
1266: wp = word;
1267: pat = patternp;
1268:
1269: if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==
1270: (VAR_SUB_ONE|VAR_SUB_MATCHED))
1271: xrv = REG_NOMATCH;
1272: else {
1273: tryagain:
1.21 christos 1274: xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
1.16 christos 1275: }
1276:
1277: switch (xrv) {
1278: case 0:
1279: pat->flags |= VAR_SUB_MATCHED;
1280: if (pat->matches[0].rm_so > 0) {
1281: MAYBE_ADD_SPACE();
1282: Buf_AddBytes(buf, pat->matches[0].rm_so, wp);
1283: }
1284:
1285: for (rp = pat->replace; *rp; rp++) {
1286: if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
1287: MAYBE_ADD_SPACE();
1288: Buf_AddByte(buf,rp[1]);
1289: rp++;
1290: }
1.30 christos 1291: else if ((*rp == '&') ||
1292: ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
1.16 christos 1293: int n;
1.73 christos 1294: const char *subbuf;
1.16 christos 1295: int sublen;
1296: char errstr[3];
1297:
1298: if (*rp == '&') {
1299: n = 0;
1300: errstr[0] = '&';
1301: errstr[1] = '\0';
1302: } else {
1303: n = rp[1] - '0';
1304: errstr[0] = '\\';
1305: errstr[1] = rp[1];
1306: errstr[2] = '\0';
1307: rp++;
1308: }
1309:
1310: if (n > pat->nsub) {
1311: Error("No subexpression %s", &errstr[0]);
1312: subbuf = "";
1313: sublen = 0;
1314: } else if ((pat->matches[n].rm_so == -1) &&
1315: (pat->matches[n].rm_eo == -1)) {
1316: Error("No match for subexpression %s", &errstr[0]);
1317: subbuf = "";
1318: sublen = 0;
1319: } else {
1320: subbuf = wp + pat->matches[n].rm_so;
1321: sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
1322: }
1323:
1324: if (sublen > 0) {
1325: MAYBE_ADD_SPACE();
1326: Buf_AddBytes(buf, sublen, subbuf);
1327: }
1328: } else {
1329: MAYBE_ADD_SPACE();
1330: Buf_AddByte(buf, *rp);
1331: }
1332: }
1333: wp += pat->matches[0].rm_eo;
1.20 christos 1334: if (pat->flags & VAR_SUB_GLOBAL) {
1335: flags |= REG_NOTBOL;
1336: if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {
1337: MAYBE_ADD_SPACE();
1338: Buf_AddByte(buf, *wp);
1339: wp++;
1340:
1341: }
1342: if (*wp)
1343: goto tryagain;
1344: }
1.16 christos 1345: if (*wp) {
1346: MAYBE_ADD_SPACE();
1347: Buf_AddBytes(buf, strlen(wp), wp);
1348: }
1349: break;
1350: default:
1351: VarREError(xrv, &pat->re, "Unexpected regex error");
1352: /* fall through */
1353: case REG_NOMATCH:
1354: if (*wp) {
1355: MAYBE_ADD_SPACE();
1356: Buf_AddBytes(buf,strlen(wp),wp);
1357: }
1358: break;
1359: }
1360: return(addSpace||added);
1361: }
1.17 christos 1362: #endif
1.16 christos 1363:
1364:
1.40 sjg 1365:
1366: /*-
1367: *-----------------------------------------------------------------------
1368: * VarLoopExpand --
1369: * Implements the :@<temp>@<string>@ modifier of ODE make.
1370: * We set the temp variable named in pattern.lhs to word and expand
1371: * pattern.rhs storing the result in the passed buffer.
1372: *
1.70 wiz 1373: * Input:
1374: * word Word to modify
1375: * addSpace True if space should be added before
1376: * other characters
1377: * buf Buffer for result
1378: * pattern Datafor substitution
1379: *
1.40 sjg 1380: * Results:
1381: * TRUE if a space is needed before more characters are added.
1382: *
1383: * Side Effects:
1384: * None.
1385: *
1386: *-----------------------------------------------------------------------
1387: */
1388: static Boolean
1.90 jmc 1389: VarLoopExpand(GNode *ctx __unused, Var_Parse_State *vpstate __unused,
1.89 jmc 1390: char *word, Boolean addSpace, Buffer buf,
1391: ClientData loopp)
1.40 sjg 1392: {
1.99 christos 1393: VarLoop_t *loop = (VarLoop_t *)loopp;
1.40 sjg 1394: char *s;
1.60 sjg 1395: int slen;
1.64 sjg 1396:
1397: if (word && *word) {
1.65 sjg 1398: Var_Set(loop->tvar, word, loop->ctxt, VAR_NO_EXPORT);
1.64 sjg 1399: s = Var_Subst(NULL, loop->str, loop->ctxt, loop->err);
1400: if (s != NULL && *s != '\0') {
1401: if (addSpace && *s != '\n')
1402: Buf_AddByte(buf, ' ');
1403: Buf_AddBytes(buf, (slen = strlen(s)), (Byte *)s);
1404: addSpace = (slen > 0 && s[slen - 1] != '\n');
1405: free(s);
1406: }
1.40 sjg 1407: }
1408: return addSpace;
1409: }
1410:
1.81 sjg 1411:
1412: /*-
1413: *-----------------------------------------------------------------------
1414: * VarSelectWords --
1415: * Implements the :[start..end] modifier.
1416: * This is a special case of VarModify since we want to be able
1417: * to scan the list backwards if start > end.
1418: *
1419: * Input:
1420: * str String whose words should be trimmed
1421: * seldata words to select
1422: *
1423: * Results:
1424: * A string of all the words selected.
1425: *
1426: * Side Effects:
1427: * None.
1428: *
1429: *-----------------------------------------------------------------------
1430: */
1431: static char *
1.90 jmc 1432: VarSelectWords(GNode *ctx __unused, Var_Parse_State *vpstate,
1.81 sjg 1433: const char *str, VarSelectWords_t *seldata)
1434: {
1435: Buffer buf; /* Buffer for the new string */
1436: Boolean addSpace; /* TRUE if need to add a space to the
1437: * buffer before adding the trimmed
1438: * word */
1439: char **av; /* word list */
1440: char *as; /* word list memory */
1441: int ac, i;
1442: int start, end, step;
1443:
1.92 christos 1444: buf = Buf_Init(0);
1.81 sjg 1445: addSpace = FALSE;
1446:
1447: if (vpstate->oneBigWord) {
1448: /* fake what brk_string() would do if there were only one word */
1449: ac = 1;
1.92 christos 1450: av = emalloc((ac + 1) * sizeof(char *));
1.81 sjg 1451: as = strdup(str);
1452: av[0] = as;
1453: av[1] = NULL;
1454: } else {
1455: av = brk_string(str, &ac, FALSE, &as);
1456: }
1457:
1458: /*
1459: * Now sanitize seldata.
1460: * If seldata->start or seldata->end are negative, convert them to
1461: * the positive equivalents (-1 gets converted to argc, -2 gets
1462: * converted to (argc-1), etc.).
1463: */
1464: if (seldata->start < 0)
1465: seldata->start = ac + seldata->start + 1;
1466: if (seldata->end < 0)
1467: seldata->end = ac + seldata->end + 1;
1468:
1469: /*
1470: * We avoid scanning more of the list than we need to.
1471: */
1472: if (seldata->start > seldata->end) {
1473: start = MIN(ac, seldata->start) - 1;
1474: end = MAX(0, seldata->end - 1);
1475: step = -1;
1476: } else {
1477: start = MAX(0, seldata->start - 1);
1478: end = MIN(ac, seldata->end);
1479: step = 1;
1480: }
1481:
1482: for (i = start;
1483: (step < 0 && i >= end) || (step > 0 && i < end);
1484: i += step) {
1485: if (av[i] && *av[i]) {
1486: if (addSpace && vpstate->varSpace) {
1487: Buf_AddByte(buf, vpstate->varSpace);
1488: }
1489: Buf_AddBytes(buf, strlen(av[i]), (Byte *)av[i]);
1490: addSpace = TRUE;
1491: }
1492: }
1493:
1494: free(as);
1495: free(av);
1496:
1.97 christos 1497: Buf_AddByte(buf, '\0');
1.99 christos 1498: as = (char *)Buf_GetAll(buf, NULL);
1.92 christos 1499: Buf_Destroy(buf, FALSE);
1.81 sjg 1500: return (as);
1501: }
1502:
1.1 cgd 1503: /*-
1504: *-----------------------------------------------------------------------
1505: * VarModify --
1506: * Modify each of the words of the passed string using the given
1507: * function. Used to implement all modifiers.
1508: *
1.70 wiz 1509: * Input:
1510: * str String whose words should be trimmed
1511: * modProc Function to use to modify them
1512: * datum Datum to pass it
1513: *
1.1 cgd 1514: * Results:
1515: * A string of all the words modified appropriately.
1516: *
1517: * Side Effects:
1518: * None.
1519: *
1520: *-----------------------------------------------------------------------
1521: */
1522: static char *
1.81 sjg 1523: VarModify(GNode *ctx, Var_Parse_State *vpstate,
1524: const char *str,
1525: Boolean (*modProc)(GNode *, Var_Parse_State *, char *,
1526: Boolean, Buffer, ClientData),
1.73 christos 1527: ClientData datum)
1.1 cgd 1528: {
1529: Buffer buf; /* Buffer for the new string */
1530: Boolean addSpace; /* TRUE if need to add a space to the
1531: * buffer before adding the trimmed
1532: * word */
1.81 sjg 1533: char **av; /* word list */
1.24 christos 1534: char *as; /* word list memory */
1.7 jtc 1535: int ac, i;
1536:
1.92 christos 1537: buf = Buf_Init(0);
1.1 cgd 1538: addSpace = FALSE;
1539:
1.81 sjg 1540: if (vpstate->oneBigWord) {
1541: /* fake what brk_string() would do if there were only one word */
1542: ac = 1;
1.92 christos 1543: av = emalloc((ac + 1) * sizeof(char *));
1.81 sjg 1544: as = strdup(str);
1545: av[0] = as;
1546: av[1] = NULL;
1547: } else {
1548: av = brk_string(str, &ac, FALSE, &as);
1549: }
1.1 cgd 1550:
1.81 sjg 1551: for (i = 0; i < ac; i++) {
1552: addSpace = (*modProc)(ctx, vpstate, av[i], addSpace, buf, datum);
1553: }
1.24 christos 1554:
1555: free(as);
1556: free(av);
1.15 christos 1557:
1.97 christos 1558: Buf_AddByte(buf, '\0');
1.99 christos 1559: as = (char *)Buf_GetAll(buf, NULL);
1.92 christos 1560: Buf_Destroy(buf, FALSE);
1.73 christos 1561: return (as);
1.1 cgd 1562: }
1563:
1.35 christos 1564:
1565: static int
1.70 wiz 1566: VarWordCompare(const void *a, const void *b)
1.35 christos 1567: {
1.79 scw 1568: int r = strcmp(*(const char * const *)a, *(const char * const *)b);
1.35 christos 1569: return r;
1570: }
1571:
1572: /*-
1573: *-----------------------------------------------------------------------
1.93 sjg 1574: * VarOrder --
1575: * Order the words in the string.
1.35 christos 1576: *
1.70 wiz 1577: * Input:
1.93 sjg 1578: * str String whose words should be sorted.
1579: * otype How to order: s - sort, x - random.
1.70 wiz 1580: *
1.35 christos 1581: * Results:
1.93 sjg 1582: * A string containing the words ordered.
1.35 christos 1583: *
1584: * Side Effects:
1585: * None.
1586: *
1587: *-----------------------------------------------------------------------
1588: */
1589: static char *
1.93 sjg 1590: VarOrder(const char *str, const char otype)
1.35 christos 1591: {
1592: Buffer buf; /* Buffer for the new string */
1593: char **av; /* word list [first word does not count] */
1594: char *as; /* word list memory */
1595: int ac, i;
1596:
1.92 christos 1597: buf = Buf_Init(0);
1.35 christos 1598:
1599: av = brk_string(str, &ac, FALSE, &as);
1600:
1601: if (ac > 0)
1.93 sjg 1602: switch (otype) {
1603: case 's': /* sort alphabetically */
1604: qsort(av, ac, sizeof(char *), VarWordCompare);
1605: break;
1606: case 'x': /* randomize */
1607: {
1608: int rndidx;
1609: char *t;
1610:
1611: /*
1612: * We will use [ac..2] range for mod factors. This will produce
1613: * random numbers in [(ac-1)..0] interval, and minimal
1614: * reasonable value for mod factor is 2 (the mod 1 will produce
1615: * 0 with probability 1).
1616: */
1617: for (i = ac-1; i > 0; i--) {
1618: rndidx = random() % (i + 1);
1619: if (i != rndidx) {
1620: t = av[i];
1621: av[i] = av[rndidx];
1622: av[rndidx] = t;
1623: }
1624: }
1625: }
1626: } /* end of switch */
1.35 christos 1627:
1628: for (i = 0; i < ac; i++) {
1.99 christos 1629: Buf_AddBytes(buf, strlen(av[i]), (Byte *)av[i]);
1.35 christos 1630: if (i != ac - 1)
1.97 christos 1631: Buf_AddByte(buf, ' ');
1.35 christos 1632: }
1633:
1634: free(as);
1635: free(av);
1636:
1.97 christos 1637: Buf_AddByte(buf, '\0');
1.99 christos 1638: as = (char *)Buf_GetAll(buf, NULL);
1.92 christos 1639: Buf_Destroy(buf, FALSE);
1.73 christos 1640: return (as);
1.35 christos 1641: }
1642:
1643:
1.1 cgd 1644: /*-
1645: *-----------------------------------------------------------------------
1.55 christos 1646: * VarUniq --
1647: * Remove adjacent duplicate words.
1648: *
1.70 wiz 1649: * Input:
1650: * str String whose words should be sorted
1651: *
1.55 christos 1652: * Results:
1653: * A string containing the resulting words.
1654: *
1655: * Side Effects:
1656: * None.
1657: *
1658: *-----------------------------------------------------------------------
1659: */
1660: static char *
1.73 christos 1661: VarUniq(const char *str)
1.55 christos 1662: {
1663: Buffer buf; /* Buffer for new string */
1664: char **av; /* List of words to affect */
1665: char *as; /* Word list memory */
1666: int ac, i, j;
1667:
1668: buf = Buf_Init(0);
1669: av = brk_string(str, &ac, FALSE, &as);
1670:
1671: if (ac > 1) {
1672: for (j = 0, i = 1; i < ac; i++)
1673: if (strcmp(av[i], av[j]) != 0 && (++j != i))
1674: av[j] = av[i];
1675: ac = j + 1;
1676: }
1677:
1678: for (i = 0; i < ac; i++) {
1679: Buf_AddBytes(buf, strlen(av[i]), (Byte *)av[i]);
1680: if (i != ac - 1)
1681: Buf_AddByte(buf, ' ');
1682: }
1683:
1684: free(as);
1685: free(av);
1686:
1687: Buf_AddByte(buf, '\0');
1.99 christos 1688: as = (char *)Buf_GetAll(buf, NULL);
1.55 christos 1689: Buf_Destroy(buf, FALSE);
1.73 christos 1690: return as;
1.55 christos 1691: }
1692:
1693:
1694: /*-
1695: *-----------------------------------------------------------------------
1.16 christos 1696: * VarGetPattern --
1697: * Pass through the tstr looking for 1) escaped delimiters,
1698: * '$'s and backslashes (place the escaped character in
1699: * uninterpreted) and 2) unescaped $'s that aren't before
1.40 sjg 1700: * the delimiter (expand the variable substitution unless flags
1701: * has VAR_NOSUBST set).
1.16 christos 1702: * Return the expanded string or NULL if the delimiter was missing
1.25 christos 1703: * If pattern is specified, handle escaped ampersands, and replace
1.16 christos 1704: * unescaped ampersands with the lhs of the pattern.
1705: *
1706: * Results:
1707: * A string of all the words modified appropriately.
1708: * If length is specified, return the string length of the buffer
1709: * If flags is specified and the last character of the pattern is a
1710: * $ set the VAR_MATCH_END bit of flags.
1711: *
1712: * Side Effects:
1713: * None.
1714: *-----------------------------------------------------------------------
1715: */
1716: static char *
1.90 jmc 1717: VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate __unused,
1.89 jmc 1718: int err, const char **tstr, int delim, int *flags,
1719: int *length, VarPattern *pattern)
1.16 christos 1720: {
1.73 christos 1721: const char *cp;
1.16 christos 1722: Buffer buf = Buf_Init(0);
1723: int junk;
1724: if (length == NULL)
1725: length = &junk;
1726:
1727: #define IS_A_MATCH(cp, delim) \
1728: ((cp[0] == '\\') && ((cp[1] == delim) || \
1729: (cp[1] == '\\') || (cp[1] == '$') || (pattern && (cp[1] == '&'))))
1730:
1731: /*
1732: * Skim through until the matching delimiter is found;
1733: * pick up variable substitutions on the way. Also allow
1734: * backslashes to quote the delimiter, $, and \, but don't
1735: * touch other backslashes.
1736: */
1737: for (cp = *tstr; *cp && (*cp != delim); cp++) {
1738: if (IS_A_MATCH(cp, delim)) {
1.99 christos 1739: Buf_AddByte(buf, (Byte)cp[1]);
1.16 christos 1740: cp++;
1741: } else if (*cp == '$') {
1742: if (cp[1] == delim) {
1743: if (flags == NULL)
1.99 christos 1744: Buf_AddByte(buf, (Byte)*cp);
1.16 christos 1745: else
1746: /*
1747: * Unescaped $ at end of pattern => anchor
1748: * pattern at end.
1749: */
1750: *flags |= VAR_MATCH_END;
1.40 sjg 1751: } else {
1752: if (flags == NULL || (*flags & VAR_NOSUBST) == 0) {
1753: char *cp2;
1754: int len;
1.104 christos 1755: void *freeIt;
1.40 sjg 1756:
1757: /*
1758: * If unescaped dollar sign not before the
1759: * delimiter, assume it's a variable
1760: * substitution and recurse.
1761: */
1762: cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
1.99 christos 1763: Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
1.40 sjg 1764: if (freeIt)
1.104 christos 1765: free(freeIt);
1.40 sjg 1766: cp += len - 1;
1767: } else {
1.73 christos 1768: const char *cp2 = &cp[1];
1.16 christos 1769:
1.100 christos 1770: if (*cp2 == PROPEN || *cp2 == BROPEN) {
1.40 sjg 1771: /*
1772: * Find the end of this variable reference
1773: * and suck it in without further ado.
1774: * It will be interperated later.
1775: */
1776: int have = *cp2;
1.100 christos 1777: int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE;
1.40 sjg 1778: int depth = 1;
1779:
1780: for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) {
1781: if (cp2[-1] != '\\') {
1782: if (*cp2 == have)
1783: ++depth;
1784: if (*cp2 == want)
1785: --depth;
1786: }
1787: }
1.73 christos 1788: Buf_AddBytes(buf, cp2 - cp, (const Byte *)cp);
1.40 sjg 1789: cp = --cp2;
1790: } else
1.99 christos 1791: Buf_AddByte(buf, (Byte)*cp);
1.40 sjg 1792: }
1.16 christos 1793: }
1794: }
1795: else if (pattern && *cp == '&')
1.73 christos 1796: Buf_AddBytes(buf, pattern->leftLen, (const Byte *)pattern->lhs);
1.16 christos 1797: else
1.99 christos 1798: Buf_AddByte(buf, (Byte)*cp);
1.16 christos 1799: }
1800:
1.99 christos 1801: Buf_AddByte(buf, (Byte)'\0');
1.16 christos 1802:
1803: if (*cp != delim) {
1804: *tstr = cp;
1805: *length = 0;
1806: return NULL;
1807: }
1808: else {
1.73 christos 1809: char *rstr;
1.16 christos 1810: *tstr = ++cp;
1.97 christos 1811: rstr = (char *)Buf_GetAll(buf, length);
1.16 christos 1812: *length -= 1; /* Don't count the NULL */
1813: Buf_Destroy(buf, FALSE);
1.73 christos 1814: return rstr;
1.16 christos 1815: }
1816: }
1817:
1818: /*-
1819: *-----------------------------------------------------------------------
1820: * VarQuote --
1821: * Quote shell meta-characters in the string
1822: *
1823: * Results:
1824: * The quoted string
1825: *
1826: * Side Effects:
1827: * None.
1828: *
1829: *-----------------------------------------------------------------------
1830: */
1831: static char *
1.70 wiz 1832: VarQuote(char *str)
1.16 christos 1833: {
1834:
1835: Buffer buf;
1836: /* This should cover most shells :-( */
1837: static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
1838:
1.92 christos 1839: buf = Buf_Init(MAKE_BSIZE);
1.16 christos 1840: for (; *str; str++) {
1841: if (strchr(meta, *str) != NULL)
1842: Buf_AddByte(buf, (Byte)'\\');
1843: Buf_AddByte(buf, (Byte)*str);
1844: }
1.99 christos 1845: Buf_AddByte(buf, (Byte)'\0');
1846: str = (char *)Buf_GetAll(buf, NULL);
1.92 christos 1847: Buf_Destroy(buf, FALSE);
1.16 christos 1848: return str;
1849: }
1850:
1.68 pk 1851: /*-
1852: *-----------------------------------------------------------------------
1853: * VarChangeCase --
1854: * Change the string to all uppercase or all lowercase
1855: *
1.70 wiz 1856: * Input:
1857: * str String to modify
1858: * upper TRUE -> uppercase, else lowercase
1859: *
1.68 pk 1860: * Results:
1861: * The string with case changed
1862: *
1863: * Side Effects:
1864: * None.
1865: *
1866: *-----------------------------------------------------------------------
1867: */
1868: static char *
1.70 wiz 1869: VarChangeCase(char *str, int upper)
1.68 pk 1870: {
1871: Buffer buf;
1.70 wiz 1872: int (*modProc)(int);
1.68 pk 1873:
1874: modProc = (upper ? toupper : tolower);
1.92 christos 1875: buf = Buf_Init(MAKE_BSIZE);
1.68 pk 1876: for (; *str ; str++) {
1.99 christos 1877: Buf_AddByte(buf, (Byte)modProc(*str));
1.68 pk 1878: }
1.99 christos 1879: Buf_AddByte(buf, (Byte)'\0');
1880: str = (char *)Buf_GetAll(buf, NULL);
1.92 christos 1881: Buf_Destroy(buf, FALSE);
1.68 pk 1882: return str;
1883: }
1.16 christos 1884:
1.108 sjg 1885: /*
1886: * Now we need to apply any modifiers the user wants applied.
1887: * These are:
1888: * :M<pattern> words which match the given <pattern>.
1889: * <pattern> is of the standard file
1890: * wildcarding form.
1891: * :N<pattern> words which do not match the given <pattern>.
1892: * :S<d><pat1><d><pat2><d>[1gW]
1893: * Substitute <pat2> for <pat1> in the value
1894: * :C<d><pat1><d><pat2><d>[1gW]
1895: * Substitute <pat2> for regex <pat1> in the value
1896: * :H Substitute the head of each word
1897: * :T Substitute the tail of each word
1898: * :E Substitute the extension (minus '.') of
1899: * each word
1900: * :R Substitute the root of each word
1901: * (pathname minus the suffix).
1902: * :O ("Order") Alphabeticaly sort words in variable.
1903: * :Ox ("intermiX") Randomize words in variable.
1904: * :u ("uniq") Remove adjacent duplicate words.
1905: * :tu Converts the variable contents to uppercase.
1906: * :tl Converts the variable contents to lowercase.
1907: * :ts[c] Sets varSpace - the char used to
1908: * separate words to 'c'. If 'c' is
1909: * omitted then no separation is used.
1910: * :tW Treat the variable contents as a single
1911: * word, even if it contains spaces.
1912: * (Mnemonic: one big 'W'ord.)
1913: * :tw Treat the variable contents as multiple
1914: * space-separated words.
1915: * (Mnemonic: many small 'w'ords.)
1916: * :[index] Select a single word from the value.
1917: * :[start..end] Select multiple words from the value.
1918: * :[*] or :[0] Select the entire value, as a single
1919: * word. Equivalent to :tW.
1920: * :[@] Select the entire value, as multiple
1921: * words. Undoes the effect of :[*].
1922: * Equivalent to :tw.
1923: * :[#] Returns the number of words in the value.
1924: *
1925: * :?<true-value>:<false-value>
1926: * If the variable evaluates to true, return
1927: * true value, else return the second value.
1928: * :lhs=rhs Like :S, but the rhs goes to the end of
1929: * the invocation.
1930: * :sh Treat the current value as a command
1931: * to be run, new value is its output.
1932: * The following added so we can handle ODE makefiles.
1933: * :@<tmpvar>@<newval>@
1934: * Assign a temporary local variable <tmpvar>
1935: * to the current value of each word in turn
1936: * and replace each word with the result of
1937: * evaluating <newval>
1938: * :D<newval> Use <newval> as value if variable defined
1939: * :U<newval> Use <newval> as value if variable undefined
1940: * :L Use the name of the variable as the value.
1941: * :P Use the path of the node that has the same
1942: * name as the variable as the value. This
1943: * basically includes an implied :L so that
1944: * the common method of refering to the path
1945: * of your dependent 'x' in a rule is to use
1946: * the form '${x:P}'.
1947: * :!<cmd>! Run cmd much the same as :sh run's the
1948: * current value of the variable.
1949: * The ::= modifiers, actually assign a value to the variable.
1950: * Their main purpose is in supporting modifiers of .for loop
1951: * iterators and other obscure uses. They always expand to
1952: * nothing. In a target rule that would otherwise expand to an
1953: * empty line they can be preceded with @: to keep make happy.
1954: * Eg.
1955: *
1956: * foo: .USE
1957: * .for i in ${.TARGET} ${.TARGET:R}.gz
1958: * @: ${t::=$i}
1959: * @echo blah ${t:T}
1960: * .endfor
1961: *
1962: * ::=<str> Assigns <str> as the new value of variable.
1963: * ::?=<str> Assigns <str> as value of variable if
1964: * it was not already set.
1965: * ::+=<str> Appends <str> to variable.
1966: * ::!=<cmd> Assigns output of <cmd> as the new value of
1967: * variable.
1.1 cgd 1968: */
1.108 sjg 1969:
1970: static char *
1971: ApplyModifiers(char *nstr, const char *tstr,
1972: int startc, int endc,
1973: Var *v, GNode *ctxt, Boolean err,
1974: int *lengthPtr, void **freePtr)
1.1 cgd 1975: {
1.108 sjg 1976: const char *start;
1.73 christos 1977: const char *cp; /* Secondary pointer into str (place marker
1.1 cgd 1978: * for tstr) */
1.108 sjg 1979: char *newStr; /* New value to return */
1980: char termc; /* Character which terminated scan */
1.9 christos 1981: int cnt; /* Used to count brace pairs when variable in
1982: * in parens or braces */
1.108 sjg 1983: char delim;
1.89 jmc 1984: Var_Parse_State parsestate; /* Flags passed to helper functions */
1.15 christos 1985:
1.108 sjg 1986: delim = '\0';
1.81 sjg 1987: parsestate.oneBigWord = FALSE;
1988: parsestate.varSpace = ' '; /* word separator */
1.15 christos 1989:
1.108 sjg 1990: start = cp = tstr;
1991:
1992: while (*tstr && *tstr != endc) {
1.15 christos 1993:
1.108 sjg 1994: if (*tstr == '$') {
1995: /*
1996: * We have some complex modifiers in a variable.
1.1 cgd 1997: */
1.108 sjg 1998: void *freeIt;
1999: char *rval;
2000: int rlen;
1.22 christos 2001:
1.108 sjg 2002: rval = Var_Parse(tstr, ctxt, err, &rlen, &freeIt);
1.1 cgd 2003:
1.108 sjg 2004: if (DEBUG(VAR)) {
2005: printf("Got '%s' from '%.*s'%.*s\n",
2006: rval, rlen, tstr, rlen, tstr + rlen);
1.22 christos 2007: }
1.1 cgd 2008:
1.108 sjg 2009: tstr += rlen;
1.15 christos 2010:
1.108 sjg 2011: if (rval != NULL && *rval) {
2012: int used;
1.15 christos 2013:
1.108 sjg 2014: nstr = ApplyModifiers(nstr, rval,
2015: 0, 0,
2016: v, ctxt, err, &used, freePtr);
2017: if (nstr == var_Error
2018: || (nstr == varNoError && err == 0)
2019: || strlen(rval) != used) {
2020: if (freeIt)
2021: free(freeIt);
2022: goto out; /* error already reported */
1.1 cgd 2023: }
2024: }
1.108 sjg 2025: if (freeIt)
2026: free(freeIt);
2027: if (*tstr == ':')
2028: tstr++;
2029: continue;
2030: }
2031: if (DEBUG(VAR)) {
2032: printf("Applying :%c to \"%s\"\n", *tstr, nstr);
1.1 cgd 2033: }
1.108 sjg 2034: newStr = var_Error;
2035: switch (*tstr) {
2036: case ':':
1.1 cgd 2037: {
1.45 sjg 2038: if (tstr[1] == '=' ||
2039: (tstr[2] == '=' &&
2040: (tstr[1] == '!' || tstr[1] == '+' || tstr[1] == '?'))) {
1.81 sjg 2041: /*
2042: * "::=", "::!=", "::+=", or "::?="
2043: */
1.44 sjg 2044: GNode *v_ctxt; /* context where v belongs */
1.73 christos 2045: const char *emsg;
1.86 dsl 2046: char *sv_name;
1.44 sjg 2047: VarPattern pattern;
2048: int how;
1.45 sjg 2049:
1.95 lukem 2050: v_ctxt = ctxt;
2051: sv_name = NULL;
1.45 sjg 2052: ++tstr;
1.44 sjg 2053: if (v->flags & VAR_JUNK) {
2054: /*
2055: * We need to strdup() it incase
2056: * VarGetPattern() recurses.
2057: */
1.86 dsl 2058: sv_name = v->name;
1.44 sjg 2059: v->name = strdup(v->name);
2060: } else if (ctxt != VAR_GLOBAL) {
1.109 ! christos 2061: Var *gv = VarFind(v->name, ctxt, 0);
! 2062: if (gv == (Var *)NIL)
1.44 sjg 2063: v_ctxt = VAR_GLOBAL;
1.109 ! christos 2064: else
! 2065: VarFreeEnv(gv, TRUE);
1.44 sjg 2066: }
2067:
1.45 sjg 2068: switch ((how = *tstr)) {
1.44 sjg 2069: case '+':
2070: case '?':
2071: case '!':
2072: cp = &tstr[2];
2073: break;
2074: default:
2075: cp = ++tstr;
2076: break;
2077: }
1.100 christos 2078: delim = BRCLOSE;
1.44 sjg 2079: pattern.flags = 0;
2080:
1.86 dsl 2081: pattern.rhs = VarGetPattern(ctxt, &parsestate, err,
1.108 sjg 2082: &cp, delim, NULL,
2083: &pattern.rightLen,
2084: NULL);
1.86 dsl 2085: if (v->flags & VAR_JUNK) {
2086: /* restore original name */
2087: free(v->name);
2088: v->name = sv_name;
2089: }
2090: if (pattern.rhs == NULL)
1.44 sjg 2091: goto cleanup;
1.86 dsl 2092:
1.44 sjg 2093: termc = *--cp;
2094: delim = '\0';
2095:
1.48 mycroft 2096: switch (how) {
2097: case '+':
2098: Var_Append(v->name, pattern.rhs, v_ctxt);
2099: break;
2100: case '!':
1.92 christos 2101: newStr = Cmd_Exec(pattern.rhs, &emsg);
1.48 mycroft 2102: if (emsg)
1.92 christos 2103: Error(emsg, nstr);
1.48 mycroft 2104: else
1.108 sjg 2105: Var_Set(v->name, newStr, v_ctxt, 0);
1.48 mycroft 2106: if (newStr)
2107: free(newStr);
2108: break;
2109: case '?':
2110: if ((v->flags & VAR_JUNK) == 0)
1.47 sjg 2111: break;
1.48 mycroft 2112: /* FALLTHROUGH */
2113: default:
1.65 sjg 2114: Var_Set(v->name, pattern.rhs, v_ctxt, 0);
1.48 mycroft 2115: break;
1.44 sjg 2116: }
1.73 christos 2117: free(UNCONST(pattern.rhs));
1.44 sjg 2118: newStr = var_Error;
2119: break;
2120: }
1.81 sjg 2121: goto default_case; /* "::<unrecognised>" */
1.108 sjg 2122: }
2123: case '@':
2124: {
2125: VarLoop_t loop;
2126: int flags = VAR_NOSUBST;
1.40 sjg 2127:
1.108 sjg 2128: cp = ++tstr;
2129: delim = '@';
2130: if ((loop.tvar = VarGetPattern(ctxt, &parsestate, err,
2131: &cp, delim,
2132: &flags, &loop.tvarLen,
2133: NULL)) == NULL)
2134: goto cleanup;
2135:
2136: if ((loop.str = VarGetPattern(ctxt, &parsestate, err,
2137: &cp, delim,
2138: &flags, &loop.strLen,
2139: NULL)) == NULL)
2140: goto cleanup;
2141:
2142: termc = *cp;
2143: delim = '\0';
2144:
2145: loop.err = err;
2146: loop.ctxt = ctxt;
2147: newStr = VarModify(ctxt, &parsestate, nstr, VarLoopExpand,
2148: (ClientData)&loop);
2149: free(loop.tvar);
2150: free(loop.str);
2151: break;
2152: }
2153: case 'D':
2154: case 'U':
2155: {
2156: Buffer buf; /* Buffer for patterns */
2157: int wantit; /* want data in buffer */
1.40 sjg 2158:
1.108 sjg 2159: /*
2160: * Pass through tstr looking for 1) escaped delimiters,
2161: * '$'s and backslashes (place the escaped character in
2162: * uninterpreted) and 2) unescaped $'s that aren't before
2163: * the delimiter (expand the variable substitution).
2164: * The result is left in the Buffer buf.
2165: */
2166: buf = Buf_Init(0);
2167: for (cp = tstr + 1;
2168: *cp != endc && *cp != ':' && *cp != '\0';
2169: cp++) {
2170: if ((*cp == '\\') &&
2171: ((cp[1] == ':') ||
2172: (cp[1] == '$') ||
2173: (cp[1] == endc) ||
2174: (cp[1] == '\\')))
1.49 mycroft 2175: {
1.99 christos 2176: Buf_AddByte(buf, (Byte)cp[1]);
1.49 mycroft 2177: cp++;
2178: } else if (*cp == '$') {
2179: /*
2180: * If unescaped dollar sign, assume it's a
2181: * variable substitution and recurse.
2182: */
2183: char *cp2;
2184: int len;
1.104 christos 2185: void *freeIt;
1.49 mycroft 2186:
2187: cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
1.99 christos 2188: Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
1.49 mycroft 2189: if (freeIt)
1.104 christos 2190: free(freeIt);
1.49 mycroft 2191: cp += len - 1;
2192: } else {
1.99 christos 2193: Buf_AddByte(buf, (Byte)*cp);
1.49 mycroft 2194: }
1.108 sjg 2195: }
2196: Buf_AddByte(buf, (Byte)'\0');
1.40 sjg 2197:
1.108 sjg 2198: termc = *cp;
1.40 sjg 2199:
1.108 sjg 2200: if (*tstr == 'U')
2201: wantit = ((v->flags & VAR_JUNK) != 0);
2202: else
2203: wantit = ((v->flags & VAR_JUNK) == 0);
2204: if ((v->flags & VAR_JUNK) != 0)
2205: v->flags |= VAR_KEEP;
2206: if (wantit) {
2207: newStr = (char *)Buf_GetAll(buf, NULL);
2208: Buf_Destroy(buf, FALSE);
2209: } else {
2210: newStr = nstr;
2211: Buf_Destroy(buf, TRUE);
2212: }
2213: break;
2214: }
2215: case 'L':
2216: {
2217: if ((v->flags & VAR_JUNK) != 0)
2218: v->flags |= VAR_KEEP;
2219: newStr = strdup(v->name);
2220: cp = ++tstr;
2221: termc = *tstr;
2222: break;
2223: }
2224: case 'P':
2225: {
2226: GNode *gn;
2227:
2228: if ((v->flags & VAR_JUNK) != 0)
2229: v->flags |= VAR_KEEP;
2230: gn = Targ_FindNode(v->name, TARG_NOCREATE);
2231: if (gn == NILGNODE || gn->type & OP_NOPATH) {
2232: newStr = NULL;
2233: } else if (gn->path) {
2234: newStr = strdup(gn->path);
2235: } else {
2236: newStr = Dir_FindFile(v->name, Suff_FindPath(gn));
1.40 sjg 2237: }
1.108 sjg 2238: if (!newStr) {
1.52 mycroft 2239: newStr = strdup(v->name);
1.40 sjg 2240: }
1.108 sjg 2241: cp = ++tstr;
2242: termc = *tstr;
2243: break;
2244: }
2245: case '!':
2246: {
2247: const char *emsg;
2248: VarPattern pattern;
2249: pattern.flags = 0;
2250:
2251: delim = '!';
2252:
2253: cp = ++tstr;
2254: if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, err,
2255: &cp, delim,
2256: NULL, &pattern.rightLen,
2257: NULL)) == NULL)
2258: goto cleanup;
2259: newStr = Cmd_Exec(pattern.rhs, &emsg);
2260: free(UNCONST(pattern.rhs));
2261: if (emsg)
2262: Error(emsg, nstr);
2263: termc = *cp;
2264: delim = '\0';
2265: if (v->flags & VAR_JUNK) {
2266: v->flags |= VAR_KEEP;
2267: }
2268: break;
2269: }
2270: case '[':
2271: {
2272: /*
2273: * Look for the closing ']', recursively
2274: * expanding any embedded variables.
2275: *
2276: * estr is a pointer to the expanded result,
2277: * which we must free().
2278: */
2279: char *estr;
1.40 sjg 2280:
1.108 sjg 2281: cp = tstr+1; /* point to char after '[' */
2282: delim = ']'; /* look for closing ']' */
2283: estr = VarGetPattern(ctxt, &parsestate,
2284: err, &cp, delim,
2285: NULL, NULL, NULL);
2286: if (estr == NULL)
2287: goto cleanup; /* report missing ']' */
2288: /* now cp points just after the closing ']' */
2289: delim = '\0';
2290: if (cp[0] != ':' && cp[0] != endc) {
2291: /* Found junk after ']' */
2292: free(estr);
2293: goto bad_modifier;
2294: }
2295: if (estr[0] == '\0') {
2296: /* Found empty square brackets in ":[]". */
2297: free(estr);
2298: goto bad_modifier;
2299: } else if (estr[0] == '#' && estr[1] == '\0') {
2300: /* Found ":[#]" */
2301:
2302: /*
2303: * We will need enough space for the decimal
2304: * representation of an int. We calculate the
2305: * space needed for the octal representation,
2306: * and add enough slop to cope with a '-' sign
2307: * (which should never be needed) and a '\0'
2308: * string terminator.
2309: */
2310: int newStrSize =
2311: (sizeof(int) * CHAR_BIT + 2) / 3 + 2;
2312:
2313: newStr = emalloc(newStrSize);
2314: if (parsestate.oneBigWord) {
2315: strncpy(newStr, "1", newStrSize);
1.103 sjg 2316: } else {
1.108 sjg 2317: /* XXX: brk_string() is a rather expensive
2318: * way of counting words. */
2319: char **av;
2320: char *as;
2321: int ac;
2322:
2323: av = brk_string(nstr, &ac, FALSE, &as);
2324: snprintf(newStr, newStrSize, "%d", ac);
2325: free(as);
2326: free(av);
1.103 sjg 2327: }
1.108 sjg 2328: termc = *cp;
2329: free(estr);
2330: break;
2331: } else if (estr[0] == '*' && estr[1] == '\0') {
2332: /* Found ":[*]" */
2333: parsestate.oneBigWord = TRUE;
2334: newStr = nstr;
2335: termc = *cp;
2336: free(estr);
1.40 sjg 2337: break;
1.108 sjg 2338: } else if (estr[0] == '@' && estr[1] == '\0') {
2339: /* Found ":[@]" */
2340: parsestate.oneBigWord = FALSE;
2341: newStr = nstr;
1.40 sjg 2342: termc = *cp;
1.108 sjg 2343: free(estr);
1.68 pk 2344: break;
1.108 sjg 2345: } else {
1.81 sjg 2346: /*
1.108 sjg 2347: * We expect estr to contain a single
2348: * integer for :[N], or two integers
2349: * separated by ".." for :[start..end].
1.81 sjg 2350: */
1.108 sjg 2351: char *ep;
2352:
2353: VarSelectWords_t seldata = { 0, 0 };
2354:
2355: seldata.start = strtol(estr, &ep, 0);
2356: if (ep == estr) {
2357: /* Found junk instead of a number */
1.81 sjg 2358: free(estr);
2359: goto bad_modifier;
1.108 sjg 2360: } else if (ep[0] == '\0') {
2361: /* Found only one integer in :[N] */
2362: seldata.end = seldata.start;
2363: } else if (ep[0] == '.' && ep[1] == '.' &&
2364: ep[2] != '\0') {
2365: /* Expecting another integer after ".." */
2366: ep += 2;
2367: seldata.end = strtol(ep, &ep, 0);
2368: if (ep[0] != '\0') {
2369: /* Found junk after ".." */
2370: free(estr);
2371: goto bad_modifier;
2372: }
2373: } else {
2374: /* Found junk instead of ".." */
1.81 sjg 2375: free(estr);
2376: goto bad_modifier;
1.108 sjg 2377: }
2378: /*
2379: * Now seldata is properly filled in,
2380: * but we still have to check for 0 as
2381: * a special case.
2382: */
2383: if (seldata.start == 0 && seldata.end == 0) {
2384: /* ":[0]" or perhaps ":[0..0]" */
1.81 sjg 2385: parsestate.oneBigWord = TRUE;
2386: newStr = nstr;
2387: termc = *cp;
2388: free(estr);
2389: break;
1.108 sjg 2390: } else if (seldata.start == 0 ||
2391: seldata.end == 0) {
2392: /* ":[0..N]" or ":[N..0]" */
1.81 sjg 2393: free(estr);
1.108 sjg 2394: goto bad_modifier;
2395: }
2396: /*
2397: * Normal case: select the words
2398: * described by seldata.
2399: */
2400: newStr = VarSelectWords(ctxt, &parsestate,
2401: nstr, &seldata);
2402:
2403: termc = *cp;
2404: free(estr);
2405: break;
2406: }
2407:
2408: }
2409: case 't':
2410: {
2411: cp = tstr + 1; /* make sure it is set */
2412: if (tstr[1] != endc && tstr[1] != ':') {
2413: if (tstr[1] == 's') {
1.81 sjg 2414: /*
1.108 sjg 2415: * Use the char (if any) at tstr[2]
2416: * as the word separator.
1.81 sjg 2417: */
1.108 sjg 2418: VarPattern pattern;
1.81 sjg 2419:
1.108 sjg 2420: if (tstr[2] != endc &&
2421: (tstr[3] == endc || tstr[3] == ':')) {
2422: /* ":ts<unrecognised><endc>" or
2423: * ":ts<unrecognised>:" */
2424: parsestate.varSpace = tstr[2];
2425: cp = tstr + 3;
2426: } else if (tstr[2] == endc || tstr[2] == ':') {
2427: /* ":ts<endc>" or ":ts:" */
2428: parsestate.varSpace = 0; /* no separator */
2429: cp = tstr + 2;
2430: } else if (tstr[2] == '\\') {
2431: switch (tstr[3]) {
2432: case 'n':
2433: parsestate.varSpace = '\n';
2434: cp = tstr + 4;
2435: break;
2436: case 't':
2437: parsestate.varSpace = '\t';
2438: cp = tstr + 4;
2439: break;
2440: default:
2441: if (isdigit((unsigned char)tstr[3])) {
2442: char *ep;
2443:
2444: parsestate.varSpace =
2445: strtoul(&tstr[3], &ep, 0);
2446: if (*ep != ':' && *ep != endc)
2447: goto bad_modifier;
2448: cp = ep;
2449: } else {
2450: /*
2451: * ":ts<backslash><unrecognised>".
2452: */
2453: goto bad_modifier;
2454: }
2455: break;
1.81 sjg 2456: }
2457: } else {
1.108 sjg 2458: /*
2459: * Found ":ts<unrecognised><unrecognised>".
2460: */
1.81 sjg 2461: goto bad_modifier;
2462: }
1.108 sjg 2463:
2464: termc = *cp;
2465:
1.81 sjg 2466: /*
1.108 sjg 2467: * We cannot be certain that VarModify
2468: * will be used - even if there is a
2469: * subsequent modifier, so do a no-op
2470: * VarSubstitute now to for str to be
2471: * re-expanded without the spaces.
1.81 sjg 2472: */
1.108 sjg 2473: pattern.flags = VAR_SUB_ONE;
2474: pattern.lhs = pattern.rhs = "\032";
2475: pattern.leftLen = pattern.rightLen = 1;
2476:
2477: newStr = VarModify(ctxt, &parsestate, nstr,
2478: VarSubstitute,
2479: (ClientData)&pattern);
2480: } else if (tstr[2] == endc || tstr[2] == ':') {
1.81 sjg 2481: /*
1.108 sjg 2482: * Check for two-character options:
2483: * ":tu", ":tl"
1.81 sjg 2484: */
1.108 sjg 2485: if (tstr[1] == 'u' || tstr[1] == 'l') {
2486: newStr = VarChangeCase(nstr, (tstr[1] == 'u'));
2487: cp = tstr + 2;
2488: termc = *cp;
2489: } else if (tstr[1] == 'W' || tstr[1] == 'w') {
2490: parsestate.oneBigWord = (tstr[1] == 'W');
2491: newStr = nstr;
2492: cp = tstr + 2;
1.74 sjg 2493: termc = *cp;
1.81 sjg 2494: } else {
1.108 sjg 2495: /* Found ":t<unrecognised>:" or
2496: * ":t<unrecognised><endc>". */
1.95 lukem 2497: goto bad_modifier;
1.74 sjg 2498: }
1.81 sjg 2499: } else {
2500: /*
1.108 sjg 2501: * Found ":t<unrecognised><unrecognised>".
1.81 sjg 2502: */
1.95 lukem 2503: goto bad_modifier;
1.40 sjg 2504: }
1.108 sjg 2505: } else {
2506: /*
2507: * Found ":t<endc>" or ":t:".
2508: */
2509: goto bad_modifier;
1.40 sjg 2510: }
1.108 sjg 2511: break;
2512: }
2513: case 'N':
2514: case 'M':
2515: {
2516: char *pattern;
2517: char *cp2;
2518: Boolean copy;
2519: int nest;
1.1 cgd 2520:
1.108 sjg 2521: copy = FALSE;
2522: nest = 1;
2523: /*
2524: * In the loop below, ignore ':' unless we are at
2525: * (or back to) the original brace level.
2526: * XXX This will likely not work right if $() and ${}
2527: * are intermixed.
2528: */
2529: for (cp = tstr + 1;
2530: *cp != '\0' && !(*cp == ':' && nest == 1);
2531: cp++)
1.1 cgd 2532: {
1.43 sjg 2533: if (*cp == '\\' &&
2534: (cp[1] == ':' ||
2535: cp[1] == endc || cp[1] == startc)) {
1.1 cgd 2536: copy = TRUE;
2537: cp++;
1.43 sjg 2538: continue;
2539: }
2540: if (*cp == startc)
2541: ++nest;
2542: if (*cp == endc) {
2543: --nest;
2544: if (nest == 0)
2545: break;
1.1 cgd 2546: }
2547: }
1.108 sjg 2548: termc = *cp;
2549: *WR(cp) = '\0';
2550: if (copy) {
2551: /*
2552: * Need to compress the \:'s out of the pattern, so
2553: * allocate enough room to hold the uncompressed
2554: * pattern (note that cp started at tstr+1, so
2555: * cp - tstr takes the null byte into account) and
2556: * compress the pattern into the space.
2557: */
2558: pattern = emalloc(cp - tstr);
2559: for (cp2 = pattern, cp = tstr + 1;
2560: *cp != '\0';
2561: cp++, cp2++)
1.1 cgd 2562: {
2563: if ((*cp == '\\') &&
2564: (cp[1] == ':' || cp[1] == endc)) {
1.108 sjg 2565: cp++;
1.1 cgd 2566: }
2567: *cp2 = *cp;
2568: }
1.108 sjg 2569: *cp2 = '\0';
2570: } else {
2571: pattern = UNCONST(&tstr[1]);
2572: }
2573: if ((cp2 = strchr(pattern, '$'))) {
2574: cp2 = pattern;
2575: pattern = Var_Subst(NULL, cp2, ctxt, err);
2576: if (copy)
2577: free(cp2);
2578: copy = TRUE;
2579: }
2580: if (*tstr == 'M' || *tstr == 'm') {
2581: newStr = VarModify(ctxt, &parsestate, nstr, VarMatch,
2582: (ClientData)pattern);
2583: } else {
2584: newStr = VarModify(ctxt, &parsestate, nstr, VarNoMatch,
2585: (ClientData)pattern);
2586: }
2587: if (copy) {
2588: free(pattern);
2589: }
2590: break;
2591: }
2592: case 'S':
2593: {
2594: VarPattern pattern;
2595: Var_Parse_State tmpparsestate;
2596:
2597: pattern.flags = 0;
2598: tmpparsestate = parsestate;
2599: delim = tstr[1];
2600: tstr += 2;
2601:
2602: /*
2603: * If pattern begins with '^', it is anchored to the
2604: * start of the word -- skip over it and flag pattern.
2605: */
2606: if (*tstr == '^') {
2607: pattern.flags |= VAR_MATCH_START;
2608: tstr += 1;
2609: }
2610:
2611: cp = tstr;
2612: if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, err,
2613: &cp, delim,
2614: &pattern.flags,
2615: &pattern.leftLen,
2616: NULL)) == NULL)
2617: goto cleanup;
2618:
2619: if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, err,
2620: &cp, delim, NULL,
2621: &pattern.rightLen,
2622: &pattern)) == NULL)
2623: goto cleanup;
2624:
2625: /*
2626: * Check for global substitution. If 'g' after the final
2627: * delimiter, substitution is global and is marked that
2628: * way.
2629: */
2630: for (;; cp++) {
2631: switch (*cp) {
2632: case 'g':
2633: pattern.flags |= VAR_SUB_GLOBAL;
2634: continue;
2635: case '1':
2636: pattern.flags |= VAR_SUB_ONE;
2637: continue;
2638: case 'W':
2639: tmpparsestate.oneBigWord = TRUE;
2640: continue;
1.1 cgd 2641: }
2642: break;
2643: }
2644:
1.108 sjg 2645: termc = *cp;
2646: newStr = VarModify(ctxt, &tmpparsestate, nstr,
2647: VarSubstitute,
2648: (ClientData)&pattern);
2649:
2650: /*
2651: * Free the two strings.
2652: */
2653: free(UNCONST(pattern.lhs));
2654: free(UNCONST(pattern.rhs));
2655: delim = '\0';
2656: break;
2657: }
2658: case '?':
2659: {
2660: VarPattern pattern;
2661: Boolean value;
2662:
2663: /* find ':', and then substitute accordingly */
2664:
2665: pattern.flags = 0;
2666:
2667: cp = ++tstr;
2668: delim = ':';
2669: if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, err,
2670: &cp, delim, NULL,
2671: &pattern.leftLen,
2672: NULL)) == NULL)
2673: goto cleanup;
2674:
2675: /* BROPEN or PROPEN */
2676: delim = endc;
2677: if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, err,
2678: &cp, delim, NULL,
2679: &pattern.rightLen,
2680: NULL)) == NULL)
2681: goto cleanup;
2682:
2683: termc = *--cp;
2684: delim = '\0';
2685: if (Cond_EvalExpression(1, v->name, &value, 0)
2686: == COND_INVALID) {
2687: Error("Bad conditional expression `%s' in %s?%s:%s",
2688: v->name, v->name, pattern.lhs, pattern.rhs);
2689: goto cleanup;
2690: }
2691:
2692: if (value) {
2693: newStr = UNCONST(pattern.lhs);
2694: free(UNCONST(pattern.rhs));
2695: } else {
2696: newStr = UNCONST(pattern.rhs);
2697: free(UNCONST(pattern.lhs));
2698: }
2699: if (v->flags & VAR_JUNK) {
2700: v->flags |= VAR_KEEP;
2701: }
2702: break;
2703: }
2704: #ifndef NO_REGEX
2705: case 'C':
2706: {
2707: VarREPattern pattern;
2708: char *re;
2709: int error;
2710: Var_Parse_State tmpparsestate;
2711:
2712: pattern.flags = 0;
2713: tmpparsestate = parsestate;
2714: delim = tstr[1];
2715: tstr += 2;
2716:
2717: cp = tstr;
2718:
2719: if ((re = VarGetPattern(ctxt, &parsestate, err, &cp, delim,
2720: NULL, NULL, NULL)) == NULL)
2721: goto cleanup;
2722:
2723: if ((pattern.replace = VarGetPattern(ctxt, &parsestate,
2724: err, &cp, delim, NULL,
2725: NULL, NULL)) == NULL){
2726: free(re);
2727: goto cleanup;
2728: }
1.16 christos 2729:
1.108 sjg 2730: for (;; cp++) {
2731: switch (*cp) {
2732: case 'g':
2733: pattern.flags |= VAR_SUB_GLOBAL;
2734: continue;
2735: case '1':
2736: pattern.flags |= VAR_SUB_ONE;
2737: continue;
2738: case 'W':
2739: tmpparsestate.oneBigWord = TRUE;
2740: continue;
1.1 cgd 2741: }
1.108 sjg 2742: break;
2743: }
1.1 cgd 2744:
1.108 sjg 2745: termc = *cp;
1.16 christos 2746:
1.108 sjg 2747: error = regcomp(&pattern.re, re, REG_EXTENDED);
2748: free(re);
2749: if (error) {
2750: *lengthPtr = cp - start + 1;
2751: VarREError(error, &pattern.re, "RE substitution error");
2752: free(pattern.replace);
2753: goto cleanup;
2754: }
1.15 christos 2755:
1.108 sjg 2756: pattern.nsub = pattern.re.re_nsub + 1;
2757: if (pattern.nsub < 1)
2758: pattern.nsub = 1;
2759: if (pattern.nsub > 10)
2760: pattern.nsub = 10;
2761: pattern.matches = emalloc(pattern.nsub *
2762: sizeof(regmatch_t));
2763: newStr = VarModify(ctxt, &tmpparsestate, nstr,
2764: VarRESubstitute,
2765: (ClientData) &pattern);
2766: regfree(&pattern.re);
2767: free(pattern.replace);
2768: free(pattern.matches);
2769: delim = '\0';
2770: break;
2771: }
2772: #endif
2773: case 'Q':
2774: if (tstr[1] == endc || tstr[1] == ':') {
2775: newStr = VarQuote(nstr);
2776: cp = tstr + 1;
2777: termc = *cp;
2778: break;
2779: }
2780: goto default_case;
2781: case 'T':
2782: if (tstr[1] == endc || tstr[1] == ':') {
2783: newStr = VarModify(ctxt, &parsestate, nstr, VarTail,
2784: (ClientData)0);
2785: cp = tstr + 1;
2786: termc = *cp;
2787: break;
2788: }
2789: goto default_case;
2790: case 'H':
2791: if (tstr[1] == endc || tstr[1] == ':') {
2792: newStr = VarModify(ctxt, &parsestate, nstr, VarHead,
2793: (ClientData)0);
2794: cp = tstr + 1;
2795: termc = *cp;
2796: break;
2797: }
2798: goto default_case;
2799: case 'E':
2800: if (tstr[1] == endc || tstr[1] == ':') {
2801: newStr = VarModify(ctxt, &parsestate, nstr, VarSuffix,
2802: (ClientData)0);
2803: cp = tstr + 1;
2804: termc = *cp;
2805: break;
2806: }
2807: goto default_case;
2808: case 'R':
2809: if (tstr[1] == endc || tstr[1] == ':') {
2810: newStr = VarModify(ctxt, &parsestate, nstr, VarRoot,
2811: (ClientData)0);
2812: cp = tstr + 1;
2813: termc = *cp;
2814: break;
2815: }
2816: goto default_case;
2817: case 'O':
2818: {
2819: char otype;
1.1 cgd 2820:
1.108 sjg 2821: cp = tstr + 1; /* skip to the rest in any case */
2822: if (tstr[1] == endc || tstr[1] == ':') {
2823: otype = 's';
1.16 christos 2824: termc = *cp;
1.108 sjg 2825: } else if ( (tstr[1] == 'x') &&
2826: (tstr[2] == endc || tstr[2] == ':') ) {
2827: otype = tstr[1];
2828: cp = tstr + 2;
2829: termc = *cp;
2830: } else {
2831: goto bad_modifier;
2832: }
2833: newStr = VarOrder(nstr, otype);
2834: break;
2835: }
2836: case 'u':
2837: if (tstr[1] == endc || tstr[1] == ':') {
2838: newStr = VarUniq(nstr);
2839: cp = tstr + 1;
2840: termc = *cp;
2841: break;
2842: }
2843: goto default_case;
2844: #ifdef SUNSHCMD
2845: case 's':
2846: if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) {
2847: const char *emsg;
2848: newStr = Cmd_Exec(nstr, &emsg);
2849: if (emsg)
2850: Error(emsg, nstr);
2851: cp = tstr + 2;
2852: termc = *cp;
2853: break;
2854: }
2855: goto default_case;
2856: #endif
2857: default:
2858: default_case:
2859: {
2860: #ifdef SYSVVARSUB
2861: /*
2862: * This can either be a bogus modifier or a System-V
2863: * substitution command.
2864: */
2865: VarPattern pattern;
2866: Boolean eqFound;
1.15 christos 2867:
1.108 sjg 2868: pattern.flags = 0;
2869: eqFound = FALSE;
2870: /*
2871: * First we make a pass through the string trying
2872: * to verify it is a SYSV-make-style translation:
2873: * it must be: <string1>=<string2>)
2874: */
2875: cp = tstr;
2876: cnt = 1;
2877: while (*cp != '\0' && cnt) {
2878: if (*cp == '=') {
2879: eqFound = TRUE;
2880: /* continue looking for endc */
2881: }
2882: else if (*cp == endc)
2883: cnt--;
2884: else if (*cp == startc)
2885: cnt++;
2886: if (cnt)
2887: cp++;
2888: }
2889: if (*cp == endc && eqFound) {
1.25 christos 2890:
1.108 sjg 2891: /*
2892: * Now we break this sucker into the lhs and
2893: * rhs. We must null terminate them of course.
2894: */
2895: delim='=';
2896: cp = tstr;
2897: if ((pattern.lhs = VarGetPattern(ctxt, &parsestate,
2898: err, &cp, delim, &pattern.flags,
2899: &pattern.leftLen, NULL)) == NULL)
2900: goto cleanup;
2901: delim = endc;
2902: if ((pattern.rhs = VarGetPattern(ctxt, &parsestate,
2903: err, &cp, delim, NULL, &pattern.rightLen,
2904: &pattern)) == NULL)
2905: goto cleanup;
1.25 christos 2906:
1.108 sjg 2907: /*
2908: * SYSV modifications happen through the whole
2909: * string. Note the pattern is anchored at the end.
2910: */
2911: termc = *--cp;
2912: delim = '\0';
2913: newStr = VarModify(ctxt, &parsestate, nstr,
2914: VarSYSVMatch,
2915: (ClientData)&pattern);
2916: free(UNCONST(pattern.lhs));
2917: free(UNCONST(pattern.rhs));
2918: } else
2919: #endif
2920: {
2921: Error("Unknown modifier '%c'", *tstr);
2922: for (cp = tstr+1;
2923: *cp != ':' && *cp != endc && *cp != '\0';
2924: cp++)
2925: continue;
2926: termc = *cp;
2927: newStr = var_Error;
2928: }
2929: }
2930: }
2931: if (DEBUG(VAR)) {
2932: printf("Result is \"%s\"\n", newStr);
2933: }
1.25 christos 2934:
1.108 sjg 2935: if (newStr != nstr) {
2936: if (*freePtr) {
2937: free(nstr);
2938: *freePtr = NULL;
2939: }
2940: nstr = newStr;
2941: if (nstr != var_Error && nstr != varNoError) {
2942: *freePtr = nstr;
2943: }
2944: }
2945: if (termc == '\0' && endc != '\0') {
2946: Error("Unclosed variable specification for %s", v->name);
2947: } else if (termc == ':') {
2948: *WR(cp) = termc;
2949: cp++;
2950: } else {
2951: *WR(cp) = termc;
2952: }
2953: tstr = cp;
2954: }
2955: out:
2956: *lengthPtr = tstr - start;
2957: return (nstr);
1.25 christos 2958:
1.108 sjg 2959: bad_modifier:
2960: /* "{(" */
2961: Error("Bad modifier `:%.*s' for %s", (int)strcspn(tstr, ":)}"), tstr,
2962: v->name);
1.25 christos 2963:
1.108 sjg 2964: cleanup:
2965: *lengthPtr = cp - start;
2966: if (delim != '\0')
2967: Error("Unclosed substitution for %s (%c missing)",
2968: v->name, delim);
2969: if (*freePtr) {
2970: free(*freePtr);
2971: *freePtr = NULL;
2972: }
2973: return (var_Error);
2974: }
1.25 christos 2975:
1.108 sjg 2976: /*-
2977: *-----------------------------------------------------------------------
2978: * Var_Parse --
2979: * Given the start of a variable invocation, extract the variable
2980: * name and find its value, then modify it according to the
2981: * specification.
2982: *
2983: * Input:
2984: * str The string to parse
2985: * ctxt The context for the variable
2986: * err TRUE if undefined variables are an error
2987: * lengthPtr OUT: The length of the specification
2988: * freePtr OUT: TRUE if caller should free result
2989: *
2990: * Results:
2991: * The (possibly-modified) value of the variable or var_Error if the
2992: * specification is invalid. The length of the specification is
2993: * placed in *lengthPtr (for invalid specifications, this is just
2994: * 2...?).
2995: * A Boolean in *freePtr telling whether the returned string should
2996: * be freed by the caller.
2997: *
2998: * Side Effects:
2999: * None.
3000: *
3001: *-----------------------------------------------------------------------
3002: */
3003: /* coverity[+alloc : arg-*4] */
3004: char *
3005: Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
3006: void **freePtr)
3007: {
3008: const char *tstr; /* Pointer into str */
3009: Var *v; /* Variable in invocation */
3010: Boolean haveModifier;/* TRUE if have modifiers for the variable */
3011: char endc; /* Ending character when variable in parens
3012: * or braces */
3013: char startc=0; /* Starting character when variable in parens
3014: * or braces */
3015: int vlen; /* Length of variable name */
3016: const char *start;
3017: char *nstr;
3018: Boolean dynamic; /* TRUE if the variable is local and we're
3019: * expanding it in a non-local context. This
3020: * is done to support dynamic sources. The
3021: * result is just the invocation, unaltered */
3022: Var_Parse_State parsestate; /* Flags passed to helper functions */
1.1 cgd 3023:
1.108 sjg 3024: *freePtr = NULL;
3025: dynamic = FALSE;
3026: start = str;
3027: parsestate.oneBigWord = FALSE;
3028: parsestate.varSpace = ' '; /* word separator */
1.1 cgd 3029:
1.108 sjg 3030: if (str[1] != PROPEN && str[1] != BROPEN) {
3031: /*
3032: * If it's not bounded by braces of some sort, life is much simpler.
3033: * We just need to check for the first character and return the
3034: * value if it exists.
3035: */
3036: char name[2];
1.15 christos 3037:
1.108 sjg 3038: name[0] = str[1];
3039: name[1] = '\0';
1.16 christos 3040:
1.108 sjg 3041: v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
3042: if (v == (Var *)NIL) {
3043: *lengthPtr = 2;
1.1 cgd 3044:
1.108 sjg 3045: if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
3046: /*
3047: * If substituting a local variable in a non-local context,
3048: * assume it's for dynamic source stuff. We have to handle
3049: * this specially and return the longhand for the variable
3050: * with the dollar sign escaped so it makes it back to the
3051: * caller. Only four of the local variables are treated
3052: * specially as they are the only four that will be set
3053: * when dynamic sources are expanded.
3054: */
3055: switch (str[1]) {
3056: case '@':
3057: return UNCONST("$(.TARGET)");
3058: case '%':
3059: return UNCONST("$(.ARCHIVE)");
3060: case '*':
3061: return UNCONST("$(.PREFIX)");
3062: case '!':
3063: return UNCONST("$(.MEMBER)");
3064: }
3065: }
3066: /*
3067: * Error
3068: */
3069: return (err ? var_Error : varNoError);
3070: } else {
3071: haveModifier = FALSE;
3072: tstr = &str[1];
3073: endc = str[1];
3074: }
3075: } else if (str[1] == '\0') {
3076: *lengthPtr = 1;
3077: return (err ? var_Error : varNoError);
3078: } else {
3079: Buffer buf; /* Holds the variable name */
1.1 cgd 3080:
1.108 sjg 3081: startc = str[1];
3082: endc = startc == PROPEN ? PRCLOSE : BRCLOSE;
3083: buf = Buf_Init(MAKE_BSIZE);
1.1 cgd 3084:
1.108 sjg 3085: /*
3086: * Skip to the end character or a colon, whichever comes first.
3087: */
3088: for (tstr = str + 2;
3089: *tstr != '\0' && *tstr != endc && *tstr != ':';
3090: tstr++)
3091: {
3092: /*
3093: * A variable inside a variable, expand
3094: */
3095: if (*tstr == '$') {
3096: int rlen;
3097: void *freeIt;
3098: char *rval = Var_Parse(tstr, ctxt, err, &rlen, &freeIt);
3099: if (rval != NULL) {
3100: Buf_AddBytes(buf, strlen(rval), (Byte *)rval);
1.1 cgd 3101: }
1.108 sjg 3102: if (freeIt)
3103: free(freeIt);
3104: tstr += rlen - 1;
3105: }
3106: else
3107: Buf_AddByte(buf, (Byte)*tstr);
3108: }
3109: if (*tstr == ':') {
3110: haveModifier = TRUE;
3111: } else if (*tstr != '\0') {
3112: haveModifier = FALSE;
3113: } else {
3114: /*
3115: * If we never did find the end character, return NULL
3116: * right now, setting the length to be the distance to
3117: * the end of the string, since that's what make does.
3118: */
3119: *lengthPtr = tstr - str;
3120: return (var_Error);
3121: }
3122: *WR(tstr) = '\0';
3123: Buf_AddByte(buf, (Byte)'\0');
3124: str = Buf_GetAll(buf, NULL);
3125: vlen = strlen(str);
1.93 sjg 3126:
1.108 sjg 3127: v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
3128: if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
3129: (vlen == 2) && (str[1] == 'F' || str[1] == 'D'))
3130: {
3131: /*
3132: * Check for bogus D and F forms of local variables since we're
3133: * in a local context and the name is the right length.
3134: */
3135: switch(*str) {
3136: case '@':
3137: case '%':
3138: case '*':
3139: case '!':
3140: case '>':
3141: case '<':
1.13 christos 3142: {
1.108 sjg 3143: char vname[2];
3144: char *val;
1.15 christos 3145:
1.1 cgd 3146: /*
1.108 sjg 3147: * Well, it's local -- go look for it.
1.1 cgd 3148: */
1.108 sjg 3149: vname[0] = *str;
3150: vname[1] = '\0';
3151: v = VarFind(vname, ctxt, 0);
1.15 christos 3152:
1.108 sjg 3153: if (v != (Var *)NIL) {
1.1 cgd 3154: /*
1.108 sjg 3155: * No need for nested expansion or anything, as we're
3156: * the only one who sets these things and we sure don't
3157: * but nested invocations in them...
1.1 cgd 3158: */
1.108 sjg 3159: val = (char *)Buf_GetAll(v->val, NULL);
1.15 christos 3160:
1.108 sjg 3161: if (str[1] == 'D') {
3162: val = VarModify(ctxt, &parsestate, val, VarHead,
3163: (ClientData)0);
3164: } else {
3165: val = VarModify(ctxt, &parsestate, val, VarTail,
3166: (ClientData)0);
3167: }
1.1 cgd 3168: /*
1.108 sjg 3169: * Resulting string is dynamically allocated, so
3170: * tell caller to free it.
1.1 cgd 3171: */
1.108 sjg 3172: *freePtr = val;
3173: *lengthPtr = tstr-start+1;
3174: *WR(tstr) = endc;
3175: Buf_Destroy(buf, TRUE);
3176: VarFreeEnv(v, TRUE);
3177: return(val);
1.1 cgd 3178: }
1.108 sjg 3179: break;
1.1 cgd 3180: }
3181: }
1.108 sjg 3182: }
3183:
3184: if (v == (Var *)NIL) {
3185: if (((vlen == 1) ||
3186: (((vlen == 2) && (str[1] == 'F' ||
3187: str[1] == 'D')))) &&
3188: ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
3189: {
3190: /*
3191: * If substituting a local variable in a non-local context,
3192: * assume it's for dynamic source stuff. We have to handle
3193: * this specially and return the longhand for the variable
3194: * with the dollar sign escaped so it makes it back to the
3195: * caller. Only four of the local variables are treated
3196: * specially as they are the only four that will be set
3197: * when dynamic sources are expanded.
3198: */
3199: switch (*str) {
3200: case '@':
3201: case '%':
3202: case '*':
3203: case '!':
3204: dynamic = TRUE;
3205: break;
3206: }
3207: } else if ((vlen > 2) && (*str == '.') &&
3208: isupper((unsigned char) str[1]) &&
3209: ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
3210: {
3211: int len;
3212:
3213: len = vlen - 1;
3214: if ((strncmp(str, ".TARGET", len) == 0) ||
3215: (strncmp(str, ".ARCHIVE", len) == 0) ||
3216: (strncmp(str, ".PREFIX", len) == 0) ||
3217: (strncmp(str, ".MEMBER", len) == 0))
3218: {
3219: dynamic = TRUE;
3220: }
1.1 cgd 3221: }
1.15 christos 3222:
1.108 sjg 3223: if (!haveModifier) {
3224: /*
3225: * No modifiers -- have specification length so we can return
3226: * now.
3227: */
3228: *lengthPtr = tstr - start + 1;
3229: *WR(tstr) = endc;
3230: if (dynamic) {
3231: char *pstr = emalloc(*lengthPtr + 1);
3232: strncpy(pstr, start, *lengthPtr);
3233: pstr[*lengthPtr] = '\0';
3234: *freePtr = pstr;
3235: Buf_Destroy(buf, TRUE);
3236: return(pstr);
1.40 sjg 3237: } else {
1.108 sjg 3238: Buf_Destroy(buf, TRUE);
3239: return (err ? var_Error : varNoError);
1.40 sjg 3240: }
1.1 cgd 3241: } else {
1.108 sjg 3242: /*
3243: * Still need to get to the end of the variable specification,
3244: * so kludge up a Var structure for the modifications
3245: */
3246: v = emalloc(sizeof(Var));
3247: v->name = UNCONST(str);
3248: v->val = Buf_Init(1);
3249: v->flags = VAR_JUNK;
3250: Buf_Destroy(buf, FALSE);
1.1 cgd 3251: }
1.108 sjg 3252: } else
3253: Buf_Destroy(buf, TRUE);
3254: }
3255:
3256:
3257: if (v->flags & VAR_IN_USE) {
3258: Fatal("Variable %s is recursive.", v->name);
3259: /*NOTREACHED*/
3260: } else {
3261: v->flags |= VAR_IN_USE;
3262: }
3263: /*
3264: * Before doing any modification, we have to make sure the value
3265: * has been fully expanded. If it looks like recursion might be
3266: * necessary (there's a dollar sign somewhere in the variable's value)
3267: * we just call Var_Subst to do any other substitutions that are
3268: * necessary. Note that the value returned by Var_Subst will have
3269: * been dynamically-allocated, so it will need freeing when we
3270: * return.
3271: */
3272: nstr = (char *)Buf_GetAll(v->val, NULL);
3273: if (strchr(nstr, '$') != NULL) {
3274: nstr = Var_Subst(NULL, nstr, ctxt, err);
3275: *freePtr = nstr;
3276: }
3277:
3278: v->flags &= ~VAR_IN_USE;
3279:
3280: if ((nstr != NULL) && haveModifier) {
3281: int used;
3282: /*
3283: * Skip initial colon while putting it back.
3284: */
3285: *WR(tstr) = ':';
3286: tstr++;
3287:
3288: nstr = ApplyModifiers(nstr, tstr, startc, endc,
3289: v, ctxt, err, &used, freePtr);
3290: tstr += used;
1.1 cgd 3291: *lengthPtr = tstr - start + 1;
3292: } else {
3293: *lengthPtr = tstr - start + 1;
1.73 christos 3294: *WR(tstr) = endc;
1.1 cgd 3295: }
1.15 christos 3296:
1.1 cgd 3297: if (v->flags & VAR_FROM_ENV) {
3298: Boolean destroy = FALSE;
1.15 christos 3299:
1.99 christos 3300: if (nstr != (char *)Buf_GetAll(v->val, NULL)) {
1.1 cgd 3301: destroy = TRUE;
3302: } else {
3303: /*
3304: * Returning the value unmodified, so tell the caller to free
3305: * the thing.
3306: */
1.104 christos 3307: *freePtr = nstr;
1.1 cgd 3308: }
1.105 christos 3309: VarFreeEnv(v, destroy);
1.1 cgd 3310: } else if (v->flags & VAR_JUNK) {
3311: /*
3312: * Perform any free'ing needed and set *freePtr to FALSE so the caller
3313: * doesn't try to free a static pointer.
1.40 sjg 3314: * If VAR_KEEP is also set then we want to keep str as is.
1.1 cgd 3315: */
1.58 itojun 3316: if (!(v->flags & VAR_KEEP)) {
1.40 sjg 3317: if (*freePtr) {
1.73 christos 3318: free(nstr);
1.108 sjg 3319: *freePtr = NULL;
1.40 sjg 3320: }
3321: if (dynamic) {
1.73 christos 3322: nstr = emalloc(*lengthPtr + 1);
3323: strncpy(nstr, start, *lengthPtr);
3324: nstr[*lengthPtr] = '\0';
1.104 christos 3325: *freePtr = nstr;
1.40 sjg 3326: } else {
1.73 christos 3327: nstr = var_Error;
1.40 sjg 3328: }
1.34 christos 3329: }
1.99 christos 3330: if (nstr != (char *)Buf_GetAll(v->val, NULL))
1.58 itojun 3331: Buf_Destroy(v->val, TRUE);
1.98 christos 3332: free(v->name);
3333: free(v);
1.1 cgd 3334: }
1.73 christos 3335: return (nstr);
1.1 cgd 3336: }
3337:
3338: /*-
3339: *-----------------------------------------------------------------------
3340: * Var_Subst --
3341: * Substitute for all variables in the given string in the given context
3342: * If undefErr is TRUE, Parse_Error will be called when an undefined
3343: * variable is encountered.
3344: *
1.70 wiz 3345: * Input:
3346: * var Named variable || NULL for all
3347: * str the string which to substitute
3348: * ctxt the context wherein to find variables
3349: * undefErr TRUE if undefineds are an error
3350: *
1.1 cgd 3351: * Results:
3352: * The resulting string.
3353: *
3354: * Side Effects:
3355: * None. The old string must be freed by the caller
3356: *-----------------------------------------------------------------------
3357: */
3358: char *
1.73 christos 3359: Var_Subst(const char *var, const char *str, GNode *ctxt, Boolean undefErr)
1.1 cgd 3360: {
3361: Buffer buf; /* Buffer for forming things */
3362: char *val; /* Value to substitute for a variable */
3363: int length; /* Length of the variable invocation */
1.96 christos 3364: Boolean trailingBslash; /* variable ends in \ */
1.104 christos 3365: void *freeIt = NULL; /* Set if it should be freed */
1.1 cgd 3366: static Boolean errorReported; /* Set true if an error has already
3367: * been reported to prevent a plethora
3368: * of messages when recursing */
3369:
1.92 christos 3370: buf = Buf_Init(MAKE_BSIZE);
1.1 cgd 3371: errorReported = FALSE;
1.96 christos 3372: trailingBslash = FALSE;
1.1 cgd 3373:
3374: while (*str) {
1.96 christos 3375: if (*str == '\n' && trailingBslash)
3376: Buf_AddByte(buf, ' ');
1.48 mycroft 3377: if (var == NULL && (*str == '$') && (str[1] == '$')) {
1.1 cgd 3378: /*
3379: * A dollar sign may be escaped either with another dollar sign.
3380: * In such a case, we skip over the escape character and store the
3381: * dollar sign into the buffer directly.
3382: */
3383: str++;
3384: Buf_AddByte(buf, (Byte)*str);
3385: str++;
3386: } else if (*str != '$') {
3387: /*
3388: * Skip as many characters as possible -- either to the end of
3389: * the string or to the next dollar sign (variable invocation).
3390: */
1.73 christos 3391: const char *cp;
1.1 cgd 3392:
1.5 cgd 3393: for (cp = str++; *str != '$' && *str != '\0'; str++)
3394: continue;
1.73 christos 3395: Buf_AddBytes(buf, str - cp, (const Byte *)cp);
1.1 cgd 3396: } else {
1.48 mycroft 3397: if (var != NULL) {
3398: int expand;
3399: for (;;) {
1.100 christos 3400: if (str[1] == '\0') {
3401: /* A trailing $ is kind of a special case */
3402: Buf_AddByte(buf, str[0]);
3403: str++;
3404: expand = FALSE;
3405: } else if (str[1] != PROPEN && str[1] != BROPEN) {
1.48 mycroft 3406: if (str[1] != *var || strlen(var) > 1) {
1.73 christos 3407: Buf_AddBytes(buf, 2, (const Byte *)str);
1.48 mycroft 3408: str += 2;
3409: expand = FALSE;
3410: }
3411: else
3412: expand = TRUE;
3413: break;
3414: }
3415: else {
1.73 christos 3416: const char *p;
1.48 mycroft 3417:
3418: /*
3419: * Scan up to the end of the variable name.
3420: */
3421: for (p = &str[2]; *p &&
1.100 christos 3422: *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++)
1.48 mycroft 3423: if (*p == '$')
3424: break;
3425: /*
3426: * A variable inside the variable. We cannot expand
3427: * the external variable yet, so we try again with
3428: * the nested one
3429: */
3430: if (*p == '$') {
1.73 christos 3431: Buf_AddBytes(buf, p - str, (const Byte *)str);
1.48 mycroft 3432: str = p;
3433: continue;
3434: }
3435:
3436: if (strncmp(var, str + 2, p - str - 2) != 0 ||
3437: var[p - str - 2] != '\0') {
3438: /*
3439: * Not the variable we want to expand, scan
3440: * until the next variable
3441: */
3442: for (;*p != '$' && *p != '\0'; p++)
3443: continue;
1.73 christos 3444: Buf_AddBytes(buf, p - str, (const Byte *)str);
1.48 mycroft 3445: str = p;
3446: expand = FALSE;
3447: }
3448: else
3449: expand = TRUE;
3450: break;
3451: }
3452: }
3453: if (!expand)
3454: continue;
3455: }
3456:
1.104 christos 3457: val = Var_Parse(str, ctxt, undefErr, &length, &freeIt);
1.1 cgd 3458:
3459: /*
3460: * When we come down here, val should either point to the
3461: * value of this variable, suitably modified, or be NULL.
3462: * Length should be the total length of the potential
3463: * variable invocation (from $ to end character...)
3464: */
3465: if (val == var_Error || val == varNoError) {
3466: /*
3467: * If performing old-time variable substitution, skip over
3468: * the variable and continue with the substitution. Otherwise,
3469: * store the dollar sign and advance str so we continue with
3470: * the string...
3471: */
3472: if (oldVars) {
3473: str += length;
3474: } else if (undefErr) {
3475: /*
3476: * If variable is undefined, complain and skip the
3477: * variable. The complaint will stop us from doing anything
3478: * when the file is parsed.
3479: */
3480: if (!errorReported) {
1.92 christos 3481: Parse_Error(PARSE_FATAL,
1.1 cgd 3482: "Undefined variable \"%.*s\"",length,str);
3483: }
3484: str += length;
3485: errorReported = TRUE;
3486: } else {
1.97 christos 3487: Buf_AddByte(buf, (Byte)*str);
1.1 cgd 3488: str += 1;
3489: }
3490: } else {
3491: /*
3492: * We've now got a variable structure to store in. But first,
3493: * advance the string pointer.
3494: */
3495: str += length;
1.15 christos 3496:
1.1 cgd 3497: /*
3498: * Copy all the characters from the variable value straight
3499: * into the new string.
3500: */
1.96 christos 3501: length = strlen(val);
3502: Buf_AddBytes(buf, length, (Byte *)val);
3503: trailingBslash = length > 0 && val[length - 1] == '\\';
1.104 christos 3504: }
3505: if (freeIt) {
3506: free(freeIt);
3507: freeIt = NULL;
1.1 cgd 3508: }
3509: }
3510: }
1.15 christos 3511:
1.97 christos 3512: Buf_AddByte(buf, '\0');
1.99 christos 3513: val = (char *)Buf_GetAll(buf, NULL);
1.92 christos 3514: Buf_Destroy(buf, FALSE);
1.73 christos 3515: return (val);
1.1 cgd 3516: }
3517:
3518: /*-
3519: *-----------------------------------------------------------------------
3520: * Var_GetTail --
3521: * Return the tail from each of a list of words. Used to set the
3522: * System V local variables.
3523: *
1.70 wiz 3524: * Input:
3525: * file Filename to modify
3526: *
1.1 cgd 3527: * Results:
3528: * The resulting string.
3529: *
3530: * Side Effects:
3531: * None.
3532: *
3533: *-----------------------------------------------------------------------
3534: */
1.61 explorer 3535: #if 0
1.1 cgd 3536: char *
1.70 wiz 3537: Var_GetTail(char *file)
1.1 cgd 3538: {
3539: return(VarModify(file, VarTail, (ClientData)0));
3540: }
3541:
3542: /*-
3543: *-----------------------------------------------------------------------
3544: * Var_GetHead --
3545: * Find the leading components of a (list of) filename(s).
3546: * XXX: VarHead does not replace foo by ., as (sun) System V make
3547: * does.
3548: *
1.70 wiz 3549: * Input:
3550: * file Filename to manipulate
3551: *
1.1 cgd 3552: * Results:
3553: * The leading components.
3554: *
3555: * Side Effects:
3556: * None.
3557: *
3558: *-----------------------------------------------------------------------
3559: */
3560: char *
1.70 wiz 3561: Var_GetHead(char *file)
1.1 cgd 3562: {
3563: return(VarModify(file, VarHead, (ClientData)0));
3564: }
1.61 explorer 3565: #endif
1.1 cgd 3566:
3567: /*-
3568: *-----------------------------------------------------------------------
3569: * Var_Init --
3570: * Initialize the module
3571: *
3572: * Results:
3573: * None
3574: *
3575: * Side Effects:
1.15 christos 3576: * The VAR_CMD and VAR_GLOBAL contexts are created
1.1 cgd 3577: *-----------------------------------------------------------------------
3578: */
3579: void
1.70 wiz 3580: Var_Init(void)
1.1 cgd 3581: {
1.92 christos 3582: VAR_GLOBAL = Targ_NewGN("Global");
3583: VAR_CMD = Targ_NewGN("Command");
1.6 jtc 3584:
3585: }
3586:
1.1 cgd 3587:
1.6 jtc 3588: void
1.70 wiz 3589: Var_End(void)
1.6 jtc 3590: {
1.1 cgd 3591: }
1.15 christos 3592:
1.1 cgd 3593:
3594: /****************** PRINT DEBUGGING INFO *****************/
1.36 mycroft 3595: static void
1.70 wiz 3596: VarPrintVar(ClientData vp)
1.1 cgd 3597: {
1.99 christos 3598: Var *v = (Var *)vp;
3599: printf("%-16s = %s\n", v->name, (char *)Buf_GetAll(v->val, NULL));
1.1 cgd 3600: }
3601:
3602: /*-
3603: *-----------------------------------------------------------------------
3604: * Var_Dump --
3605: * print all variables in a context
3606: *-----------------------------------------------------------------------
3607: */
1.5 cgd 3608: void
1.70 wiz 3609: Var_Dump(GNode *ctxt)
1.1 cgd 3610: {
1.36 mycroft 3611: Hash_Search search;
3612: Hash_Entry *h;
3613:
3614: for (h = Hash_EnumFirst(&ctxt->context, &search);
3615: h != NULL;
3616: h = Hash_EnumNext(&search)) {
3617: VarPrintVar(Hash_GetValue(h));
3618: }
1.1 cgd 3619: }
CVSweb <webmaster@jp.NetBSD.org>