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