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