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