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