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