Annotation of src/usr.bin/make/var.c, Revision 1.53
1.53 ! espie 1: /* $OpenPackages$ */
! 2: /* $OpenBSD: var.c,v 1.12 1999/09/28 21:57:04 espie Exp $ */
1.6 millert 3: /* $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $ */
1.1 deraadt 4:
5: /*
1.53 ! espie 6: * Copyright (c) 1999,2000 Marc Espie.
1.17 espie 7: *
8: * Extensive code modifications for the OpenBSD project.
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: *
19: * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
23: * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30: */
31: /*
1.5 millert 32: * Copyright (c) 1988, 1989, 1990, 1993
33: * The Regents of the University of California. All rights reserved.
1.1 deraadt 34: * Copyright (c) 1989 by Berkeley Softworks
35: * All rights reserved.
36: *
37: * This code is derived from software contributed to Berkeley by
38: * Adam de Boor.
39: *
40: * Redistribution and use in source and binary forms, with or without
41: * modification, are permitted provided that the following conditions
42: * are met:
43: * 1. Redistributions of source code must retain the above copyright
44: * notice, this list of conditions and the following disclaimer.
45: * 2. Redistributions in binary form must reproduce the above copyright
46: * notice, this list of conditions and the following disclaimer in the
47: * documentation and/or other materials provided with the distribution.
48: * 3. All advertising materials mentioning features or use of this software
49: * must display the following acknowledgement:
50: * This product includes software developed by the University of
51: * California, Berkeley and its contributors.
52: * 4. Neither the name of the University nor the names of its contributors
53: * may be used to endorse or promote products derived from this software
54: * without specific prior written permission.
55: *
56: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66: * SUCH DAMAGE.
67: */
68:
69: /*-
70: * var.c --
71: * Variable-handling functions
72: *
1.53 ! espie 73: * Basic interface:
! 74: * Var_Set Set the value of a variable in the given
! 75: * context. The variable is created if it doesn't
! 76: * yet exist. The value and variable name need not
! 77: * be preserved.
1.1 deraadt 78: *
79: * Var_Append Append more characters to an existing variable
1.53 ! espie 80: * in the given context. The variable needn't
! 81: * exist already -- it will be created if it doesn't.
! 82: * A space is placed between the old value and the
! 83: * new one.
! 84: *
! 85: * Var_Value Return the value of a variable in a context or
! 86: * NULL if the variable is undefined.
1.1 deraadt 87: *
88: * Var_Delete Delete a variable in a context.
89: *
1.53 ! espie 90: * Var_Init Initialize this module.
! 91: *
! 92: * Fast interface:
! 93: * Varq_Set, Varq_Append, Varq_Value:
! 94: * Use index form of local variables
! 95: *
! 96: * Higher level functions:
! 97: * Var_Subst Substitute variables in a string using
! 98: * the given context as the top-most one. If the
! 99: * third argument is non-zero, Parse_Error is
! 100: * called if any variables are undefined.
! 101: *
! 102: * Var_SubstVar Substitute a named variable in a string using
! 103: * the given context as the top-most one,
! 104: * accumulating the result into a user-supplied
! 105: * buffer.
! 106: *
! 107: * Var_Parse Parse a variable expansion from a string and
! 108: * return the result and the number of characters
! 109: * consumed.
1.1 deraadt 110: *
111: * Debugging:
1.53 ! espie 112: * Var_Dump Print out all global variables.
1.1 deraadt 113: */
114:
1.53 ! espie 115: #include <assert.h>
1.1 deraadt 116: #include <ctype.h>
1.6 millert 117: #include <stdlib.h>
1.35 espie 118: #include <stddef.h>
1.53 ! espie 119: #include <string.h>
1.1 deraadt 120: #include "make.h"
121: #include "buf.h"
1.53 ! espie 122: #include "stats.h"
1.38 espie 123: #include "ohash.h"
1.43 espie 124: #include "varmodifiers.h"
1.34 espie 125:
1.48 espie 126: #ifndef lint
127: #if 0
128: static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
129: #else
130: UNUSED
1.53 ! espie 131: static char rcsid[] = "$OpenBSD: var.c,v 1.12 1999/09/28 21:57:04 espie Exp $";
1.48 espie 132: #endif
133: #endif /* not lint */
134:
1.34 espie 135:
1.1 deraadt 136: /*
137: * This is a harmless return value for Var_Parse that can be used by Var_Subst
138: * to determine if there was an error in parsing -- easier than returning
139: * a flag, as things outside this module don't give a hoot.
140: */
1.53 ! espie 141: char var_Error[] = "";
1.1 deraadt 142:
143: /*
144: * Similar to var_Error, but returned when the 'err' flag for Var_Parse is
145: * set false. Why not just use a constant? Well, gcc likes to condense
146: * identical string instances...
147: */
148: static char varNoError[] = "";
149:
150: /*
1.53 ! espie 151: * Variable values are obtained from four different contexts:
! 152: * 1) the process environment. The process environment itself
! 153: * may not be changed, but these variables may be modified,
! 154: * unless make is invoked with -e, in which case those variables
! 155: * are unmodifiable and supersede the global context.
1.1 deraadt 156: * 2) the global context. Variables set in the Makefile are located in
157: * the global context. It is the penultimate context searched when
158: * substituting.
159: * 3) the command-line context. All variables set on the command line
160: * are placed in this context. They are UNALTERABLE once placed here.
161: * 4) the local context. Each target has associated with it a context
162: * list. On this list are located the structures describing such
163: * local variables as $(@) and $(*)
164: * The four contexts are searched in the reverse order from which they are
165: * listed.
166: */
1.37 espie 167: GSymT *VAR_GLOBAL; /* variables from the makefile */
168: GSymT *VAR_CMD; /* variables defined on the command-line */
1.53 ! espie 169:
! 170: static SymTable *CTXT_GLOBAL, *CTXT_CMD;
! 171:
! 172:
! 173: static char *varnames[] = {
! 174: TARGET,
! 175: PREFIX,
! 176: ARCHIVE,
! 177: MEMBER,
! 178: OODATE,
! 179: ALLSRC,
! 180: IMPSRC,
! 181: FTARGET,
! 182: DTARGET,
! 183: FPREFIX,
! 184: DPREFIX,
! 185: FARCHIVE,
! 186: DARCHIVE,
! 187: FMEMBER,
! 188: DMEMBER
! 189: };
! 190:
1.1 deraadt 191:
1.39 espie 192: #define FIND_MINE 0x1 /* look in CTXT_CMD and CTXT_GLOBAL */
1.53 ! espie 193: #define FIND_ENV 0x2 /* look in the environment */
1.1 deraadt 194:
1.37 espie 195: typedef struct Var_ {
1.53 ! espie 196: BUFFER val; /* its value */
! 197: unsigned int flags; /* miscellaneous status flags */
! 198: #define VAR_IN_USE 1 /* Variable's value currently being used.
! 199: * Used to avoid recursion */
! 200: #define VAR_READ_ONLY 2 /* Environment variable not modifiable */
! 201: #define VAR_FROM_ENV 4 /* Var was read from env */
! 202: #define VAR_DUMMY 8 /* Var does not exist, actually */
! 203: char name[1]; /* the variable's name */
1.1 deraadt 204: } Var;
205:
1.53 ! espie 206:
! 207: static struct ohash_info var_info = {
! 208: offsetof(Var, name),
1.38 espie 209: NULL, hash_alloc, hash_free, element_alloc };
1.53 ! espie 210: static int quick_lookup(const char *, const char **, u_int32_t *);
1.23 espie 211: #define VarValue(v) Buf_Retrieve(&((v)->val))
1.53 ! espie 212: static Var *varfind(const char *, const char *, SymTable *, int, int, u_int32_t);
! 213: static Var *VarFind_interval(const char *, const char *, SymTable *, int);
! 214: static Var *VarAdd(const char *, const char *, u_int32_t, const char *, GSymT *);
! 215: static void VarDelete(void *);
! 216: static void VarPrintVar(Var *);
! 217: static const char *context_name(GSymT *);
! 218: static Var *new_var(const char *, const char *, const char *);
! 219: static Var *getvar(GSymT *, const char *, const char *, u_int32_t);
! 220: static Var *create_var(const char *, const char *);
! 221: static Var *var_from_env(const char *, const char *, u_int32_t);
! 222: static void var_init_string(Var *, const char *);
! 223:
! 224: static const char *find_0(const char *);
! 225: static const char *find_rparen(const char *);
! 226: static const char *find_ket(const char *);
! 227: typedef const char * (*find_t)(const char *);
! 228: static find_t find_pos(int);
! 229:
! 230: /* retrieve the hashed values for well-known variables. */
! 231: #include "varhashconsts.h"
! 232:
! 233: /* Parse a variable name for embedded $, to handle recursive variables */
! 234: const char *
! 235: Var_Name_Get(start, name, ctxt, err, cont)
! 236: const char *start; /* start of variable spec */
! 237: struct Name *name; /* result, might be a copy or not */
! 238: SymTable *ctxt; /* context in which to expand */
! 239: Boolean err; /* whether to error out for undefined sub */
! 240: const char *(*cont)(const char *);
! 241: /* hook: find the next interesting character */
! 242: {
! 243: const char *p;
! 244: size_t len;
! 245:
! 246: p = cont(start);
! 247: /* If we don't want recursive variables, we skip over '$' */
! 248: if (!FEATURES(FEATURE_RECVARS)) {
! 249: while (*p == '$')
! 250: p = cont(p);
! 251: }
! 252: if (*p != '$') {
! 253: name->s = start;
! 254: name->e = p;
! 255: name->tofree = FALSE;
! 256: return p;
! 257: } else {
! 258: BUFFER buf;
! 259: Buf_Init(&buf, MAKE_BSIZE);
! 260: for (;;) {
! 261: Buf_AddInterval(&buf, start, p);
! 262: if (*p != '$') {
! 263: name->s = (const char *)Buf_Retrieve(&buf);
! 264: name->e = name->s + Buf_Size(&buf);
! 265: name->tofree = TRUE;
! 266: return p;
! 267: }
! 268: start = p;
! 269: Var_ParseBuffer(&buf, start, ctxt, err, &len);
! 270: start += len;
! 271: p = cont(start);
! 272: }
! 273: }
! 274: }
! 275:
! 276: void
! 277: Var_Name_Free(name)
! 278: struct Name *name;
! 279: {
! 280: if (name->tofree)
! 281: free((char *)name->s);
! 282: }
1.37 espie 283:
284: void
285: SymTable_Init(ctxt)
286: SymTable *ctxt;
287: {
1.53 ! espie 288: static SymTable sym_template;
1.37 espie 289: memcpy(ctxt, &sym_template, sizeof(*ctxt));
290: }
291:
1.53 ! espie 292: #ifdef CLEANUP
1.37 espie 293: void
294: SymTable_Destroy(ctxt)
295: SymTable *ctxt;
296: {
297: int i;
298:
299: for (i = 0; i < LOCAL_SIZE; i++)
300: if (ctxt->locals[i] != NULL)
301: VarDelete(ctxt->locals[i]);
302: }
1.53 ! espie 303: #endif
1.37 espie 304:
1.38 espie 305: static int
306: quick_lookup(name, end, pk)
307: const char *name;
308: const char **end;
309: u_int32_t *pk;
310: {
311: size_t len;
312:
1.52 espie 313: *pk = ohash_interval(name, end);
1.38 espie 314: len = *end - name;
315: /* substitute short version for long local name */
1.53 ! espie 316: switch (*pk % MAGICSLOTS1) { /* MAGICSLOTS should be the */
! 317: case K_LONGALLSRC % MAGICSLOTS1: /* smallest constant yielding */
! 318: /* distinct case values */
1.38 espie 319: if (*pk == K_LONGALLSRC && strncmp(name, LONGALLSRC, len) == 0 &&
320: len == strlen(LONGALLSRC))
321: return ALLSRC_INDEX;
322: break;
1.53 ! espie 323: case K_LONGARCHIVE % MAGICSLOTS1:
1.38 espie 324: if (*pk == K_LONGARCHIVE && strncmp(name, LONGARCHIVE, len) == 0 &&
325: len == strlen(LONGARCHIVE))
326: return ARCHIVE_INDEX;
327: break;
1.53 ! espie 328: case K_LONGIMPSRC % MAGICSLOTS1:
1.38 espie 329: if (*pk == K_LONGIMPSRC && strncmp(name, LONGIMPSRC, len) == 0 &&
330: len == strlen(LONGIMPSRC))
331: return IMPSRC_INDEX;
332: break;
1.53 ! espie 333: case K_LONGMEMBER % MAGICSLOTS1:
1.38 espie 334: if (*pk == K_LONGMEMBER && strncmp(name, LONGMEMBER, len) == 0 &&
335: len == strlen(LONGMEMBER))
336: return MEMBER_INDEX;
337: break;
1.53 ! espie 338: case K_LONGOODATE % MAGICSLOTS1:
1.38 espie 339: if (*pk == K_LONGOODATE && strncmp(name, LONGOODATE, len) == 0 &&
340: len == strlen(LONGOODATE))
341: return OODATE_INDEX;
342: break;
1.53 ! espie 343: case K_LONGPREFIX % MAGICSLOTS1:
1.38 espie 344: if (*pk == K_LONGPREFIX && strncmp(name, LONGPREFIX, len) == 0 &&
345: len == strlen(LONGPREFIX))
346: return PREFIX_INDEX;
347: break;
1.53 ! espie 348: case K_LONGTARGET % MAGICSLOTS1:
1.38 espie 349: if (*pk == K_LONGTARGET && strncmp(name, LONGTARGET, len) == 0 &&
350: len == strlen(LONGTARGET))
351: return TARGET_INDEX;
352: break;
1.53 ! espie 353: case K_TARGET % MAGICSLOTS1:
1.38 espie 354: if (name[0] == TARGET[0] && len == 1)
355: return TARGET_INDEX;
356: break;
1.53 ! espie 357: case K_OODATE % MAGICSLOTS1:
1.38 espie 358: if (name[0] == OODATE[0] && len == 1)
359: return OODATE_INDEX;
360: break;
1.53 ! espie 361: case K_ALLSRC % MAGICSLOTS1:
1.38 espie 362: if (name[0] == ALLSRC[0] && len == 1)
363: return ALLSRC_INDEX;
364: break;
1.53 ! espie 365: case K_IMPSRC % MAGICSLOTS1:
1.38 espie 366: if (name[0] == IMPSRC[0] && len == 1)
367: return IMPSRC_INDEX;
368: break;
1.53 ! espie 369: case K_PREFIX % MAGICSLOTS1:
1.38 espie 370: if (name[0] == PREFIX[0] && len == 1)
371: return PREFIX_INDEX;
372: break;
1.53 ! espie 373: case K_ARCHIVE % MAGICSLOTS1:
1.38 espie 374: if (name[0] == ARCHIVE[0] && len == 1)
375: return ARCHIVE_INDEX;
376: break;
1.53 ! espie 377: case K_MEMBER % MAGICSLOTS1:
1.38 espie 378: if (name[0] == MEMBER[0] && len == 1)
379: return MEMBER_INDEX;
380: break;
1.53 ! espie 381: case K_FTARGET % MAGICSLOTS1:
! 382: if (name[0] == FTARGET[0] && name[1] == FTARGET[1] && len == 2)
! 383: return FTARGET_INDEX;
! 384: break;
! 385: case K_DTARGET % MAGICSLOTS1:
! 386: if (name[0] == DTARGET[0] && name[1] == DTARGET[1] && len == 2)
! 387: return DTARGET_INDEX;
! 388: break;
! 389: case K_FPREFIX % MAGICSLOTS1:
! 390: if (name[0] == FPREFIX[0] && name[1] == FPREFIX[1] && len == 2)
! 391: return FPREFIX_INDEX;
! 392: break;
! 393: case K_DPREFIX % MAGICSLOTS1:
! 394: if (name[0] == DPREFIX[0] && name[1] == DPREFIX[1] && len == 2)
! 395: return DPREFIX_INDEX;
! 396: break;
! 397: case K_FARCHIVE % MAGICSLOTS1:
! 398: if (name[0] == FARCHIVE[0] && name[1] == FARCHIVE[1] && len == 2)
! 399: return FARCHIVE_INDEX;
! 400: break;
! 401: case K_DARCHIVE % MAGICSLOTS1:
! 402: if (name[0] == DARCHIVE[0] && name[1] == DARCHIVE[1] && len == 2)
! 403: return DARCHIVE_INDEX;
! 404: break;
! 405: case K_FMEMBER % MAGICSLOTS1:
! 406: if (name[0] == FMEMBER[0] && name[1] == FMEMBER[1] && len == 2)
! 407: return FMEMBER_INDEX;
! 408: break;
! 409: case K_DMEMBER % MAGICSLOTS1:
! 410: if (name[0] == DMEMBER[0] && name[1] == DMEMBER[1] && len == 2)
! 411: return DMEMBER_INDEX;
! 412: break;
1.38 espie 413: default:
414: break;
415: }
416: return -1;
417: }
1.37 espie 418:
1.53 ! espie 419: void
1.37 espie 420: Varq_Set(idx, val, gn)
421: int idx;
1.53 ! espie 422: const char *val;
! 423: GNode *gn;
1.37 espie 424: {
1.38 espie 425: /* We only look for a variable in the given context since anything set
426: * here will override anything in a lower context, so there's not much
427: * point in searching them all just to save a bit of memory... */
1.37 espie 428: Var *v = gn->context.locals[idx];
429:
430: if (v == NULL) {
1.53 ! espie 431: v = new_var(varnames[idx], NULL, val);
1.37 espie 432: v->flags = 0;
433: gn->context.locals[idx] = v;
434: } else {
435: Buf_Reset(&(v->val));
436: Buf_AddString(&(v->val), val);
1.53 ! espie 437:
1.37 espie 438: }
439: if (DEBUG(VAR))
440: printf("%s:%s = %s\n", gn->name, varnames[idx], val);
441: }
442:
1.53 ! espie 443: void
1.37 espie 444: Varq_Append(idx, val, gn)
1.53 ! espie 445: int idx;
1.48 espie 446: const char *val;
1.37 espie 447: GNode *gn;
448: {
1.53 ! espie 449: Var *v = gn->context.locals[idx];
1.37 espie 450:
451: if (v == NULL) {
1.53 ! espie 452: v = new_var(varnames[idx], NULL, val);
1.37 espie 453: v->flags = 0;
454: gn->context.locals[idx] = v;
455: } else {
456: Buf_AddSpace(&(v->val));
457: Buf_AddString(&(v->val), val);
458: }
459: if (DEBUG(VAR))
460: printf("%s:%s = %s\n", gn->name, varnames[idx], VarValue(v));
461: }
462:
463: char *
464: Varq_Value(idx, gn)
1.53 ! espie 465: int idx;
1.37 espie 466: GNode *gn;
467: {
468: Var *v = gn->context.locals[idx];
469:
1.53 ! espie 470: if (v == NULL)
! 471: return NULL;
1.37 espie 472: else
1.53 ! espie 473: return VarValue(v);
! 474: }
! 475:
! 476: static const char *
! 477: context_name(ctxt)
! 478: GSymT *ctxt;
! 479: {
! 480: if (ctxt == VAR_GLOBAL)
! 481: return "Global";
! 482: if (ctxt == VAR_CMD)
! 483: return "Command";
! 484: return "Error";
1.37 espie 485: }
486:
1.53 ! espie 487: /* We separate var creation proper from setting of initial value:
! 488: * VAR_DUMMY corresponds to `lazy' setup, e.g., always create global
! 489: * variable at first lookup, and then fill it up when value is wanted.
! 490: * This avoids looking through the environment several times.
! 491: */
! 492: static Var *
! 493: create_var(name, end)
! 494: const char *name;
! 495: const char *end;
1.37 espie 496: {
1.53 ! espie 497: return ohash_create_entry(&var_info, name, &end);
1.37 espie 498: }
1.1 deraadt 499:
1.53 ! espie 500: /* Set the initial value a var should have */
! 501: static void
! 502: var_init_string(v, val)
! 503: Var *v;
! 504: const char *val;
! 505: {
! 506: size_t len;
! 507:
! 508: len = strlen(val);
! 509: Buf_Init(&(v->val), len+1);
! 510: Buf_AddChars(&(v->val), len, val);
! 511: }
1.35 espie 512:
1.53 ! espie 513: static Var *
! 514: new_var(name, end, val)
! 515: const char *name;
! 516: const char *end;
! 517: const char *val;
1.35 espie 518: {
1.53 ! espie 519: Var *v;
! 520:
! 521: v = create_var(name, end);
! 522: #ifdef STATS_VAR_LOOKUP
! 523: STAT_VAR_CREATION++;
! 524: #endif
! 525: if (val != NULL)
! 526: var_init_string(v, val);
1.37 espie 527: else
1.53 ! espie 528: Buf_Init(&(v->val), 1);
! 529:
! 530: return v;
1.35 espie 531: }
1.53 ! espie 532:
1.37 espie 533: static Var *
1.53 ! espie 534: var_from_env(name, end, k)
! 535: const char *name;
! 536: const char *end;
! 537: u_int32_t k;
1.37 espie 538: {
1.53 ! espie 539: char *env;
! 540: Var *v;
1.37 espie 541:
1.53 ! espie 542: /* getenv requires a null-terminated name, so we create the var
! 543: * structure first. */
! 544: v = create_var(name, end);
! 545: env = getenv(v->name);
! 546: if (env == NULL)
! 547: v->flags = VAR_DUMMY;
! 548: else {
! 549: var_init_string(v, env);
! 550: if (checkEnvFirst)
! 551: v->flags = VAR_READ_ONLY | VAR_FROM_ENV;
! 552: else
! 553: v->flags = VAR_FROM_ENV;
! 554: }
1.37 espie 555:
1.53 ! espie 556: #ifdef STATS_VAR_LOOKUP
! 557: STAT_VAR_FROM_ENV++;
! 558: #endif
1.37 espie 559:
1.53 ! espie 560: ohash_insert(VAR_GLOBAL, ohash_lookup_interval(VAR_GLOBAL, name, end, k), v);
1.37 espie 561: return v;
562: }
563:
1.38 espie 564: static Var *
565: getvar(ctxt, name, end, k)
566: GSymT *ctxt;
1.53 ! espie 567: const char *name;
1.38 espie 568: const char *end;
569: u_int32_t k;
1.1 deraadt 570: {
1.52 espie 571: return ohash_find(ctxt, ohash_lookup_interval(ctxt, name, end, k));
1.37 espie 572: }
573:
1.1 deraadt 574: /*-
575: *-----------------------------------------------------------------------
1.39 espie 576: * VarFind_interval --
1.1 deraadt 577: * Find the given variable in the given context and any other contexts
1.39 espie 578: * indicated. if end is NULL, name is a string, otherwise, only
1.53 ! espie 579: * the interval name - end is concerned.
1.1 deraadt 580: *
581: * Results:
582: * A pointer to the structure describing the desired variable or
1.26 espie 583: * NULL if the variable does not exist.
1.1 deraadt 584: *-----------------------------------------------------------------------
585: */
586: static Var *
1.39 espie 587: VarFind_interval(name, end, ctxt, flags)
1.53 ! espie 588: const char *name; /* name to find */
1.39 espie 589: const char *end; /* end of name */
1.53 ! espie 590: SymTable *ctxt; /* context in which to find it */
! 591: int flags; /* FIND_MINE set means to look in the
1.39 espie 592: * CTXT_GLOBAL and CTXT_CMD contexts also.
1.1 deraadt 593: * FIND_ENV set means to look in the
1.39 espie 594: * environment */
1.1 deraadt 595: {
1.53 ! espie 596: u_int32_t k;
1.38 espie 597: int idx;
1.53 ! espie 598:
! 599: #ifdef STATS_VAR_LOOKUP
! 600: STAT_VAR_FIND++;
! 601: #endif
1.38 espie 602:
603: idx = quick_lookup(name, &end, &k);
1.39 espie 604: return varfind(name, end, ctxt, flags, idx, k);
605: }
606:
607: static Var *
608: varfind(name, end, ctxt, flags, idx, k)
609: const char *name;
610: const char *end;
611: SymTable *ctxt;
1.53 ! espie 612: int flags;
! 613: int idx;
1.39 espie 614: u_int32_t k;
615: {
1.53 ! espie 616: Var *v;
1.1 deraadt 617:
1.53 ! espie 618: /* Handle local variables first */
! 619: if (idx != -1) {
! 620: if (ctxt != NULL && ctxt != CTXT_CMD && ctxt != CTXT_GLOBAL) {
! 621: if (idx < LOCAL_SIZE)
! 622: return ctxt->locals[idx];
! 623: else
! 624: return ctxt->locals[EXTENDED2SIMPLE(idx)];
! 625: } else
! 626: return NULL;
! 627: }
! 628: /* First look for the variable in the given context. If it's not there,
! 629: look for it in CTXT_CMD, CTXT_GLOBAL and the environment,
! 630: depending on the FIND_* flags in 'flags' */
! 631: if (ctxt == CTXT_CMD || ctxt == CTXT_GLOBAL)
! 632: v = getvar((GSymT *)ctxt, name, end, k);
! 633: else
1.37 espie 634: v = NULL;
1.17 espie 635:
1.53 ! espie 636: if (v == NULL)
! 637: switch (flags) {
! 638: case 0:
! 639: break;
! 640: case FIND_MINE:
! 641: if (ctxt != CTXT_CMD)
! 642: v = getvar(VAR_CMD, name, end, k);
! 643: if (v == NULL && ctxt != CTXT_GLOBAL)
! 644: v = getvar(VAR_GLOBAL, name, end, k);
! 645: break;
! 646: case FIND_ENV:
! 647: v = var_from_env(name, end, k);
! 648: break;
! 649: case FIND_ENV | FIND_MINE:
! 650: if (ctxt != CTXT_CMD)
! 651: v = getvar(VAR_CMD, name, end, k);
! 652: if (v == NULL) {
! 653: if (ctxt != CTXT_GLOBAL)
! 654: v = getvar(VAR_GLOBAL, name, end, k);
! 655: if (v == NULL)
! 656: v = var_from_env(name, end, k);
! 657: else if (checkEnvFirst && (v->flags & VAR_FROM_ENV) == 0) {
! 658: char *env;
! 659:
! 660: env = getenv(v->name);
! 661: if (env != NULL) {
! 662: Buf_Reset(&(v->val));
! 663: Buf_AddString(&(v->val), env);
! 664: }
! 665: /* XXX even if no such env variable, fake it, to avoid
! 666: * further lookup */
! 667: v->flags |= VAR_FROM_ENV;
! 668: }
! 669: }
! 670: break;
! 671: }
1.37 espie 672: return v;
1.1 deraadt 673: }
674:
675: /*-
676: *-----------------------------------------------------------------------
677: * VarAdd --
678: * Add a new variable of name name and value val to the given context
679: *
680: * Results:
1.53 ! espie 681: * The added variable.
1.1 deraadt 682: *
683: * Side Effects:
1.48 espie 684: * The new variable is placed in the given context.
1.1 deraadt 685: * The name and val arguments are duplicated so they may
686: * safely be freed.
687: *-----------------------------------------------------------------------
688: */
1.17 espie 689: static Var *
1.53 ! espie 690: VarAdd(name, end, k, val, ctxt)
1.39 espie 691: const char *name; /* name of variable to add */
1.53 ! espie 692: const char *end;
! 693: u_int32_t k;
1.39 espie 694: const char *val; /* value to set it to */
1.37 espie 695: GSymT *ctxt; /* context in which to set it */
1.1 deraadt 696: {
1.53 ! espie 697: Var *v;
1.1 deraadt 698:
1.53 ! espie 699: v = new_var(name, end, val);
1.1 deraadt 700:
701: v->flags = 0;
702:
1.53 ! espie 703: ohash_insert(ctxt, ohash_lookup_interval(ctxt, name, end, k), v);
! 704: if (DEBUG(VAR))
! 705: printf("%s:%s = %s\n", context_name(ctxt), v->name, val);
1.17 espie 706: return v;
1.1 deraadt 707: }
708:
709: /*-
710: *-----------------------------------------------------------------------
711: * VarDelete --
712: * Delete a variable and all the space associated with it.
713: *-----------------------------------------------------------------------
714: */
715: static void
716: VarDelete(vp)
1.53 ! espie 717: void *vp;
1.1 deraadt 718: {
1.53 ! espie 719: Var *v = (Var *)vp;
1.48 espie 720:
1.53 ! espie 721: if ((v->flags & VAR_DUMMY) == 0)
! 722: Buf_Destroy(&(v->val));
1.23 espie 723: free(v);
1.1 deraadt 724: }
725:
726:
727:
728: /*-
729: *-----------------------------------------------------------------------
730: * Var_Delete --
1.53 ! espie 731: * Remove a global variable.
1.1 deraadt 732: *
733: * Side Effects:
734: * The Var structure is removed and freed.
735: *-----------------------------------------------------------------------
736: */
737: void
1.53 ! espie 738: Var_Delete(name)
! 739: const char *name;
1.1 deraadt 740: {
1.48 espie 741: Var *v;
742: u_int32_t k;
1.53 ! espie 743: unsigned int slot;
1.48 espie 744: const char *end = NULL;
1.53 ! espie 745: int idx;
! 746:
1.1 deraadt 747:
1.37 espie 748: if (DEBUG(VAR))
1.53 ! espie 749: printf("delete %s\n", name);
1.37 espie 750:
1.53 ! espie 751: idx = quick_lookup(name, &end, &k);
! 752: if (idx != -1)
! 753: Parse_Error(PARSE_FATAL, "Trying to delete dynamic variable");
! 754: slot = ohash_lookup_interval(VAR_GLOBAL, name, end, k);
! 755: v = ohash_find(VAR_GLOBAL, slot);
! 756: if (v != NULL && (v->flags & VAR_READ_ONLY) == 0) {
! 757: ohash_remove(VAR_GLOBAL, slot);
1.30 espie 758: VarDelete(v);
1.53 ! espie 759: }
1.1 deraadt 760: }
761:
762: /*-
763: *-----------------------------------------------------------------------
764: * Var_Set --
765: * Set the variable name to the value val in the given context.
766: *
767: * Side Effects:
768: * If the variable doesn't yet exist, a new record is created for it.
769: * Else the old value is freed and the new one stuck in its place
770: *
771: * Notes:
772: * The variable is searched for only in its context before being
1.53 ! espie 773: * created in that context. I.e. if the context is CTXT_GLOBAL,
! 774: * only CTXT_GLOBAL is searched. Likewise if it is CTXT_CMD, only
! 775: * CTXT_CMD is searched.
1.1 deraadt 776: *-----------------------------------------------------------------------
777: */
778: void
1.53 ! espie 779: Var_Set_interval(name, end, val, ctxt)
1.48 espie 780: const char *name; /* name of variable to set */
1.53 ! espie 781: const char *end;
1.48 espie 782: const char *val; /* value to give to the variable */
1.53 ! espie 783: GSymT *ctxt; /* context in which to set it */
1.1 deraadt 784: {
1.48 espie 785: Var *v;
1.53 ! espie 786: u_int32_t k;
! 787: int idx;
! 788:
! 789: idx = quick_lookup(name, &end, &k);
! 790: if (idx != -1)
! 791: Parse_Error(PARSE_FATAL, "Trying to set dynamic variable $%s",
! 792: varnames[idx]);
1.1 deraadt 793:
1.53 ! espie 794: /* We only look for a variable in the given context since anything set
1.1 deraadt 795: * here will override anything in a lower context, so there's not much
1.53 ! espie 796: * point in searching them all just to save a bit of memory... */
! 797: v = varfind(name, end, (SymTable *)ctxt, 0, idx, k);
1.38 espie 798: if (v == NULL)
1.53 ! espie 799: v = VarAdd(name, end, k, val, ctxt);
1.38 espie 800: else {
1.53 ! espie 801: if ((v->flags & VAR_READ_ONLY) == 0) {
! 802: if ((v->flags & VAR_DUMMY) == 0) {
! 803: Buf_Reset(&(v->val));
! 804: Buf_AddString(&(v->val), val);
! 805: } else {
! 806: var_init_string(v, val);
! 807: v->flags &= ~VAR_DUMMY;
! 808: }
! 809:
! 810: }
1.1 deraadt 811: }
1.37 espie 812: if (DEBUG(VAR))
1.53 ! espie 813: printf("%s:%s = %s\n", context_name(ctxt), v->name, val);
! 814: /* Any variables given on the command line are automatically exported
! 815: * to the environment (as per POSIX standard). */
! 816: if (ctxt == VAR_CMD)
! 817: esetenv(v->name, val);
1.1 deraadt 818: }
819:
820: /*-
821: *-----------------------------------------------------------------------
822: * Var_Append --
823: * The variable of the given name has the given value appended to it in
824: * the given context.
825: *
826: * Side Effects:
827: * If the variable doesn't exist, it is created. Else the strings
828: * are concatenated (with a space in between).
829: *
830: *-----------------------------------------------------------------------
831: */
832: void
1.53 ! espie 833: Var_Append_interval(name, end, val, ctxt)
1.48 espie 834: const char *name; /* Name of variable to modify */
1.53 ! espie 835: const char *end;
1.48 espie 836: const char *val; /* String to append to it */
1.37 espie 837: GSymT *ctxt; /* Context in which this should occur */
1.1 deraadt 838: {
1.53 ! espie 839: Var *v;
! 840: u_int32_t k;
! 841: int idx;
! 842:
! 843: assert(ctxt == VAR_GLOBAL || ctxt == VAR_CMD);
! 844:
! 845: idx = quick_lookup(name, &end, &k);
! 846: if (idx != -1)
! 847: Parse_Error(PARSE_FATAL, "Trying to append to dynamic variable $%s",
! 848: varnames[idx]);
1.1 deraadt 849:
1.53 ! espie 850: v = varfind(name, end, (SymTable *)ctxt, FIND_ENV, idx, k);
! 851:
! 852: if ((v->flags & VAR_READ_ONLY) == 0) {
! 853: if ((v->flags & VAR_DUMMY) == 0) {
! 854: Buf_AddSpace(&(v->val));
! 855: Buf_AddString(&(v->val), val);
! 856: } else {
! 857: var_init_string(v, val);
! 858: v->flags &= ~VAR_DUMMY;
! 859: }
1.1 deraadt 860:
861: }
1.37 espie 862: if (DEBUG(VAR))
1.53 ! espie 863: printf("%s:%s = %s\n", context_name(ctxt), v->name, VarValue(v));
1.1 deraadt 864: }
865:
866: /*-
867: *-----------------------------------------------------------------------
1.53 ! espie 868: * Var_Value --
! 869: * Return the value of a global named variable
1.1 deraadt 870: *
871: * Results:
1.53 ! espie 872: * The value if the variable exists, NULL if it doesn't
1.1 deraadt 873: *-----------------------------------------------------------------------
874: */
1.53 ! espie 875: char *
! 876: Var_Value_interval(name, end)
! 877: const char *name; /* name to find */
! 878: const char *end;
! 879: {
! 880: Var *v;
! 881:
! 882: v = VarFind_interval(name, end, NULL, FIND_ENV | FIND_MINE);
! 883: if (v != NULL && (v->flags & VAR_DUMMY) == 0)
! 884: return VarValue(v);
! 885: else
! 886: return NULL;
! 887: }
! 888:
! 889: static const char *
! 890: find_0(p)
! 891: const char *p;
1.1 deraadt 892: {
1.53 ! espie 893: while (*p != '$' && *p != '\0' && *p != ':')
! 894: p++;
! 895: return p;
! 896: }
! 897:
! 898: static const char *
! 899: find_rparen(p)
! 900: const char *p;
! 901: {
! 902: while (*p != '$' && *p != '\0' && *p != ')' && *p != ':')
! 903: p++;
! 904: return p;
! 905: }
1.1 deraadt 906:
1.53 ! espie 907: static const char *
! 908: find_ket(p)
! 909: const char *p;
! 910: {
! 911: while (*p != '$' && *p != '\0' && *p != '}' && *p != ':')
! 912: p++;
! 913: return p;
! 914: }
1.1 deraadt 915:
1.53 ! espie 916: static find_t
! 917: find_pos(c)
! 918: int c;
! 919: {
! 920: switch(c) {
! 921: case '\0':
! 922: return find_0;
! 923: case ')':
! 924: return find_rparen;
! 925: case '}':
! 926: return find_ket;
! 927: default:
! 928: return 0;
! 929: }
1.1 deraadt 930: }
931:
932: /*-
933: *-----------------------------------------------------------------------
1.53 ! espie 934: * Var_ParseSkip --
! 935: * Do whatever is needed to skip over a var specification. Since the
! 936: * result is not needed at this point, some shortcuts may be taken.
1.1 deraadt 937: *
1.53 ! espie 938: * Return value: the amount to skip
1.1 deraadt 939: *-----------------------------------------------------------------------
940: */
1.53 ! espie 941: size_t
! 942: Var_ParseSkip(str, ctxt, result)
! 943: const char *str;
! 944: SymTable *ctxt;
! 945: ReturnStatus *result;
1.1 deraadt 946: {
1.53 ! espie 947: const char *tstr; /* Pointer into str */
! 948: Var *v; /* Variable in invocation */
! 949: char endc; /* Ending character when variable in parens
! 950: * or braces */
! 951: const char *start;
! 952: size_t length;
! 953: struct Name name;
1.1 deraadt 954:
1.53 ! espie 955: v = NULL;
! 956: start = str;
! 957: str++;
! 958:
! 959: if (*str != '(' && *str != '{') {
! 960: name.tofree = FALSE;
! 961: tstr = str + 1;
! 962: length = 2;
! 963: endc = '\0';
! 964: } else {
! 965: endc = *str == '(' ? ')' : '}';
! 966: str++;
! 967:
! 968: /* Find eventual modifiers in the variable */
! 969: tstr = Var_Name_Get(str, &name, ctxt, FALSE, find_pos(endc));
! 970: Var_Name_Free(&name);
! 971: length = tstr+1 - start;
! 972: }
! 973:
! 974: if (result != NULL)
! 975: *result = SUCCESS;
! 976: if (*tstr == ':' && endc != '\0')
! 977: if (VarModifiers_Apply(NULL, NULL, ctxt, TRUE, NULL, tstr, endc,
! 978: &length) == var_Error)
! 979: *result = FAILURE;
! 980: return length;
1.1 deraadt 981: }
982:
1.53 ! espie 983: /*-
1.45 espie 984: *-----------------------------------------------------------------------
1.53 ! espie 985: * Var_ParseBuffer --
! 986: * Given the start of a variable invocation, extract the variable
! 987: * name and find its value, then modify it according to the
! 988: * specification, and add the result to the buffer.
! 989: *
! 990: * Results:
! 991: * FAILURE for invalid specifications.
! 992: *
! 993: * Side-effects:
! 994: * The length of the specification is placed in *lengthPtr
! 995: * (for invalid specifications, this is just 2...?).
1.45 espie 996: *-----------------------------------------------------------------------
997: */
1.53 ! espie 998: ReturnStatus
! 999: Var_ParseBuffer(buf, str, ctxt, err, lengthPtr)
! 1000: Buffer buf;
! 1001: const char *str;
! 1002: SymTable *ctxt;
! 1003: Boolean err;
! 1004: size_t *lengthPtr;
! 1005: {
! 1006: char *result;
! 1007: Boolean freeIt;
1.45 espie 1008:
1.53 ! espie 1009: result = Var_Parse(str, ctxt, err, lengthPtr, &freeIt);
! 1010: if (result == var_Error)
! 1011: return FAILURE;
! 1012:
! 1013: Buf_AddString(buf, result);
! 1014: if (freeIt)
! 1015: free(result);
! 1016: return SUCCESS;
1.45 espie 1017: }
1018:
1.1 deraadt 1019: /*-
1020: *-----------------------------------------------------------------------
1021: * Var_Parse --
1022: * Given the start of a variable invocation, extract the variable
1023: * name and find its value, then modify it according to the
1024: * specification.
1025: *
1026: * Results:
1027: * The (possibly-modified) value of the variable or var_Error if the
1028: * specification is invalid. The length of the specification is
1029: * placed in *lengthPtr (for invalid specifications, this is just
1030: * 2...?).
1031: * A Boolean in *freePtr telling whether the returned string should
1032: * be freed by the caller.
1033: *-----------------------------------------------------------------------
1034: */
1035: char *
1.35 espie 1036: Var_Parse(str, ctxt, err, lengthPtr, freePtr)
1.53 ! espie 1037: const char *str; /* The string to parse */
! 1038: SymTable *ctxt; /* The context for the variable */
! 1039: Boolean err; /* TRUE if undefined variables are an error */
1.44 espie 1040: size_t *lengthPtr; /* OUT: The length of the specification */
1.53 ! espie 1041: Boolean *freePtr; /* OUT: TRUE if caller should free result */
1.44 espie 1042: {
1.53 ! espie 1043: const char *tstr; /* Pointer into str */
! 1044: Var *v; /* Variable in invocation */
! 1045: char endc; /* Ending character when variable in parens
1.1 deraadt 1046: * or braces */
1.53 ! espie 1047: struct Name name;
! 1048: const char *start;
1.44 espie 1049: char *val; /* Variable value */
1050: u_int32_t k;
1.53 ! espie 1051: int idx;
1.5 millert 1052:
1.1 deraadt 1053: *freePtr = FALSE;
1.44 espie 1054: start = str++;
1.5 millert 1055:
1.44 espie 1056: val = NULL;
1.45 espie 1057: v = NULL;
1.53 ! espie 1058: idx = -1;
1.44 espie 1059:
1060: if (*str != '(' && *str != '{') {
1.53 ! espie 1061: name.s = str;
! 1062: name.e = str+1;
! 1063: name.tofree = FALSE;
! 1064: tstr = str + 1;
1.44 espie 1065: *lengthPtr = 2;
1066: endc = '\0';
1.1 deraadt 1067: } else {
1.44 espie 1068: endc = *str == '(' ? ')' : '}';
1.53 ! espie 1069: str++;
1.5 millert 1070:
1.44 espie 1071: /* Find eventual modifiers in the variable */
1.53 ! espie 1072: tstr = Var_Name_Get(str, &name, ctxt, FALSE, find_pos(endc));
1.44 espie 1073: *lengthPtr = tstr+1 - start;
1074: }
1.5 millert 1075:
1.53 ! espie 1076: idx = quick_lookup(name.s, &name.e, &k);
! 1077: v = varfind(name.s, name.e, ctxt, FIND_ENV | FIND_MINE, idx, k);
! 1078: if (v != NULL && (v->flags & VAR_DUMMY) == 0) {
1.44 espie 1079: if (v->flags & VAR_IN_USE)
1080: Fatal("Variable %s is recursive.", v->name);
1081: /*NOTREACHED*/
1082: else
1083: v->flags |= VAR_IN_USE;
1.53 ! espie 1084:
1.44 espie 1085: /* Before doing any modification, we have to make sure the value
1086: * has been fully expanded. If it looks like recursion might be
1087: * necessary (there's a dollar sign somewhere in the variable's value)
1088: * we just call Var_Subst to do any other substitutions that are
1089: * necessary. Note that the value returned by Var_Subst will have
1090: * been dynamically-allocated, so it will need freeing when we
1091: * return. */
1092: val = VarValue(v);
1.53 ! espie 1093: if (idx == -1) {
! 1094: if (strchr(val, '$') != NULL) {
! 1095: val = Var_Subst(val, ctxt, err);
! 1096: *freePtr = TRUE;
! 1097: }
! 1098: } else if (idx >= LOCAL_SIZE) {
! 1099: if (IS_EXTENDED_F(idx))
! 1100: val = Var_GetTail(val);
! 1101: else
! 1102: val = Var_GetHead(val);
1.44 espie 1103: *freePtr = TRUE;
1104: }
1105: v->flags &= ~VAR_IN_USE;
1.1 deraadt 1106: }
1.53 ! espie 1107: if (*tstr == ':' && endc != '\0')
! 1108: val = VarModifiers_Apply(val, &name, ctxt, err, freePtr, tstr, endc,
1.42 espie 1109: lengthPtr);
1.44 espie 1110: if (val == NULL) {
1.53 ! espie 1111: val = err ? var_Error : varNoError;
! 1112: /* Dynamic source */
! 1113: if (idx != -1) {
! 1114: /* can't be expanded for now: copy the var spec instead. */
! 1115: if (ctxt == NULL || ctxt == CTXT_GLOBAL || ctxt == CTXT_CMD) {
! 1116: *freePtr = TRUE;
! 1117: val = interval_dup(start, start+ *lengthPtr);
! 1118: } else {
! 1119: /* somehow, this should have been expanded already. */
! 1120: GNode *n;
! 1121:
! 1122: n = (GNode *)(((char *)ctxt) - offsetof(GNode, context));
! 1123: if (idx >= LOCAL_SIZE)
! 1124: idx = EXTENDED2SIMPLE(idx);
! 1125: switch(idx) {
! 1126: case IMPSRC_INDEX:
! 1127: Fatal("Using $< in a non-suffix rule context is a GNUmake idiom (line %lu of %s)",
! 1128: n->lineno, n->fname);
! 1129: default:
! 1130: Error("Using undefined dynamic variable $%s (line %lu of %s)",
! 1131: varnames[idx], n->lineno, n->fname);
! 1132: break;
! 1133: }
! 1134: }
! 1135: }
1.42 espie 1136: }
1.53 ! espie 1137: Var_Name_Free(&name);
1.44 espie 1138: return val;
1.42 espie 1139: }
1140:
1.1 deraadt 1141: /*-
1142: *-----------------------------------------------------------------------
1143: * Var_Subst --
1.24 espie 1144: * Substitute for all variables in a string in a context
1.1 deraadt 1145: * If undefErr is TRUE, Parse_Error will be called when an undefined
1146: * variable is encountered.
1147: *
1148: * Results:
1149: * The resulting string.
1150: *
1151: * Side Effects:
1.53 ! espie 1152: * The new string must be freed by the caller
1.1 deraadt 1153: *-----------------------------------------------------------------------
1154: */
1155: char *
1.24 espie 1156: Var_Subst(str, ctxt, undefErr)
1.53 ! espie 1157: const char *str; /* the string in which to substitute */
! 1158: SymTable *ctxt; /* the context wherein to find variables */
! 1159: Boolean undefErr; /* TRUE if undefineds are an error */
1.1 deraadt 1160: {
1.53 ! espie 1161: BUFFER buf; /* Buffer for forming things */
1.1 deraadt 1162: static Boolean errorReported; /* Set true if an error has already
1163: * been reported to prevent a plethora
1164: * of messages when recursing */
1165:
1.23 espie 1166: Buf_Init(&buf, MAKE_BSIZE);
1.1 deraadt 1167: errorReported = FALSE;
1168:
1.24 espie 1169: for (;;) {
1170: char *val; /* Value to substitute for a variable */
1.53 ! espie 1171: size_t length; /* Length of the variable invocation */
! 1172: Boolean doFree; /* Set true if val should be freed */
1.24 espie 1173: const char *cp;
1174:
1175: /* copy uninteresting stuff */
1176: for (cp = str; *str != '\0' && *str != '$'; str++)
1177: ;
1178: Buf_AddInterval(&buf, cp, str);
1179: if (*str == '\0')
1180: break;
1181: if (str[1] == '$') {
1182: /* A dollar sign may be escaped with another dollar sign. */
1183: Buf_AddChar(&buf, '$');
1184: str += 2;
1185: continue;
1186: }
1187: val = Var_Parse(str, ctxt, undefErr, &length, &doFree);
1188: /* When we come down here, val should either point to the
1189: * value of this variable, suitably modified, or be NULL.
1190: * Length should be the total length of the potential
1191: * variable invocation (from $ to end character...) */
1192: if (val == var_Error || val == varNoError) {
1193: /* If performing old-time variable substitution, skip over
1194: * the variable and continue with the substitution. Otherwise,
1195: * store the dollar sign and advance str so we continue with
1196: * the string... */
1.53 ! espie 1197: if (oldVars)
1.24 espie 1198: str += length;
1.53 ! espie 1199: else if (undefErr) {
1.24 espie 1200: /* If variable is undefined, complain and skip the
1201: * variable. The complaint will stop us from doing anything
1202: * when the file is parsed. */
1.53 ! espie 1203: if (!errorReported)
1.24 espie 1204: Parse_Error(PARSE_FATAL,
1205: "Undefined variable \"%.*s\"",length,str);
1206: str += length;
1207: errorReported = TRUE;
1208: } else {
1209: Buf_AddChar(&buf, *str);
1.53 ! espie 1210: str++;
1.24 espie 1211: }
1212: } else {
1213: /* We've now got a variable structure to store in. But first,
1214: * advance the string pointer. */
1215: str += length;
1216:
1217: /* Copy all the characters from the variable value straight
1218: * into the new string. */
1219: Buf_AddString(&buf, val);
1220: if (doFree)
1221: free(val);
1222: }
1223: }
1224: return Buf_Retrieve(&buf);
1225: }
1.1 deraadt 1226:
1.24 espie 1227: /*-
1228: *-----------------------------------------------------------------------
1229: * Var_SubstVar --
1230: * Substitute for one variable in the given string in the given context
1231: * If undefErr is TRUE, Parse_Error will be called when an undefined
1.53 ! espie 1232: * variable is encountered. Add the substituted string to buffer.
1.24 espie 1233: *-----------------------------------------------------------------------
1234: */
1.53 ! espie 1235: void
! 1236: Var_SubstVar(buf, str, var, val)
! 1237: Buffer buf;
! 1238: const char *str; /* The string in which to substitute */
1.24 espie 1239: const char *var; /* Named variable */
1.50 espie 1240: const char *val; /* Its value */
1.24 espie 1241: {
1242:
1.53 ! espie 1243: assert(*var != '\0');
! 1244:
1.24 espie 1245: for (;;) {
1.50 espie 1246: const char *start;
1247: /* Copy uninteresting stuff */
1248: for (start = str; *str != '\0' && *str != '$'; str++)
1.24 espie 1249: ;
1.53 ! espie 1250: Buf_AddInterval(buf, start, str);
1.50 espie 1251:
1252: start = str;
1253: if (*str++ == '\0')
1.24 espie 1254: break;
1.50 espie 1255: str++;
1256: /* and escaped dollars */
1257: if (start[1] == '$') {
1.53 ! espie 1258: Buf_AddInterval(buf, start, start+2);
1.24 espie 1259: continue;
1260: }
1.50 espie 1261: /* Simple variable, if it's not us, copy. */
1262: if (start[1] != '(' && start[1] != '{') {
1263: if (start[1] != *var || var[1] != '\0') {
1.53 ! espie 1264: Buf_AddChars(buf, 2, start);
1.1 deraadt 1265: continue;
1.24 espie 1266: }
1.1 deraadt 1267: } else {
1.50 espie 1268: const char *p;
1.24 espie 1269: char endc;
1.1 deraadt 1270:
1.50 espie 1271: if (start[1] == '(')
1.24 espie 1272: endc = ')';
1.53 ! espie 1273: else
1.24 espie 1274: endc = '}';
1275:
1276: /* Find the end of the variable specification. */
1.50 espie 1277: p = str;
1.24 espie 1278: while (*p != '\0' && *p != ':' && *p != endc && *p != '$')
1279: p++;
1.53 ! espie 1280: /* A variable inside the variable. We don't know how to
! 1281: * expand the external variable at this point, so we try
! 1282: * again with the nested variable. */
1.24 espie 1283: if (*p == '$') {
1.53 ! espie 1284: Buf_AddInterval(buf, start, p);
1.24 espie 1285: str = p;
1286: continue;
1.1 deraadt 1287: }
1.5 millert 1288:
1.50 espie 1289: if (strncmp(var, str, p - str) != 0 ||
1290: var[p - str] != '\0') {
1.53 ! espie 1291: /* Not the variable we want to expand. */
! 1292: Buf_AddInterval(buf, start, p);
1.24 espie 1293: str = p;
1294: continue;
1.53 ! espie 1295: }
1.50 espie 1296: if (*p == ':') {
1.53 ! espie 1297: size_t length; /* Length of the variable invocation */
! 1298: Boolean doFree; /* Set true if val should be freed */
1.50 espie 1299: char *newval; /* Value substituted for a variable */
1.53 ! espie 1300: struct Name name;
1.50 espie 1301:
1.53 ! espie 1302: length = p - str + 1;
1.50 espie 1303: doFree = FALSE;
1.53 ! espie 1304: name.s = var;
! 1305: name.e = var + (p-str);
1.50 espie 1306:
1307: /* val won't be freed since doFree == FALSE, but
1308: * VarModifiers_Apply doesn't know that, hence the cast. */
1.53 ! espie 1309: newval = VarModifiers_Apply((char *)val, &name, NULL, FALSE,
! 1310: &doFree, p, endc, &length);
! 1311: Buf_AddString(buf, newval);
1.50 espie 1312: if (doFree)
1313: free(newval);
1314: str += length;
1315: continue;
1316: } else
1.53 ! espie 1317: str = p+1;
1.1 deraadt 1318: }
1.53 ! espie 1319: Buf_AddString(buf, val);
1.1 deraadt 1320: }
1321: }
1322:
1323: /*-
1324: *-----------------------------------------------------------------------
1325: * Var_Init --
1326: * Initialize the module
1327: *
1328: * Side Effects:
1.53 ! espie 1329: * The CTXT_CMD and CTXT_GLOBAL contexts are initialized
1.1 deraadt 1330: *-----------------------------------------------------------------------
1331: */
1332: void
1.33 espie 1333: Var_Init()
1.1 deraadt 1334: {
1.53 ! espie 1335: static GSymT global_vars, cmd_vars;
1.35 espie 1336:
1337: VAR_GLOBAL = &global_vars;
1338: VAR_CMD = &cmd_vars;
1.52 espie 1339: ohash_init(VAR_GLOBAL, 10, &var_info);
1340: ohash_init(VAR_CMD, 5, &var_info);
1.37 espie 1341: CTXT_GLOBAL = (SymTable *)VAR_GLOBAL;
1342: CTXT_CMD = (SymTable *)VAR_CMD;
1.53 ! espie 1343:
! 1344: VarModifiers_Init();
1.1 deraadt 1345: }
1346:
1347:
1348: void
1.33 espie 1349: Var_End()
1.1 deraadt 1350: {
1.37 espie 1351: #ifdef CLEANUP
1.38 espie 1352: Var *v;
1353: unsigned int i;
1354:
1.53 ! espie 1355: for (v = ohash_first(VAR_GLOBAL, &i); v != NULL;
1.52 espie 1356: v = ohash_next(VAR_GLOBAL, &i))
1.38 espie 1357: VarDelete(v);
1.53 ! espie 1358: for (v = ohash_first(VAR_CMD, &i); v != NULL;
1.52 espie 1359: v = ohash_next(VAR_CMD, &i))
1.38 espie 1360: VarDelete(v);
1.37 espie 1361: #endif
1.1 deraadt 1362: }
1.5 millert 1363:
1.53 ! espie 1364: static const char *interpret(int);
! 1365:
! 1366: static const char *
! 1367: interpret(f)
! 1368: int f;
! 1369: {
! 1370: if (f & VAR_DUMMY)
! 1371: return "(D)";
! 1372: return "";
! 1373: }
! 1374:
1.1 deraadt 1375:
1376: /****************** PRINT DEBUGGING INFO *****************/
1.31 espie 1377: static void
1.53 ! espie 1378: VarPrintVar(v)
! 1379: Var *v;
1.1 deraadt 1380: {
1.53 ! espie 1381: printf("%-16s%s = %s\n", v->name, interpret(v->flags),
! 1382: (v->flags & VAR_DUMMY) == 0 ? VarValue(v) : "(none)");
1.1 deraadt 1383: }
1384:
1385: /*-
1386: *-----------------------------------------------------------------------
1387: * Var_Dump --
1.53 ! espie 1388: * print all variables
1.1 deraadt 1389: *-----------------------------------------------------------------------
1390: */
1391: void
1.53 ! espie 1392: Var_Dump()
1.1 deraadt 1393: {
1.53 ! espie 1394: Var *v;
! 1395: unsigned int i;
! 1396:
! 1397: printf("#*** Global Variables:\n");
1.38 espie 1398:
1.53 ! espie 1399: for (v = ohash_first(VAR_GLOBAL, &i); v != NULL;
! 1400: v = ohash_next(VAR_GLOBAL, &i))
! 1401: VarPrintVar(v);
1.37 espie 1402:
1.53 ! espie 1403: printf("#*** Command-line Variables:\n");
1.46 espie 1404:
1.53 ! espie 1405: for (v = ohash_first(VAR_CMD, &i); v != NULL; v = ohash_next(VAR_CMD, &i))
! 1406: VarPrintVar(v);
! 1407: }
1.46 espie 1408:
1409: static const char *quotable = " \t\n\\'\"";
1410:
1411: /* In POSIX mode, variable assignments passed on the command line are
1412: * propagated to sub makes through MAKEFLAGS.
1413: */
1414: void
1415: Var_AddCmdline(name)
1416: const char *name;
1417: {
1418: Var *v;
1419: unsigned int i;
1420: BUFFER buf;
1421: char *s;
1422:
1423: Buf_Init(&buf, MAKE_BSIZE);
1424:
1.53 ! espie 1425: for (v = ohash_first(VAR_CMD, &i); v != NULL;
! 1426: v = ohash_next(VAR_CMD, &i)) {
1.46 espie 1427: /* We assume variable names don't need quoting */
1428: Buf_AddString(&buf, v->name);
1429: Buf_AddChar(&buf, '=');
1430: for (s = VarValue(v); *s != '\0'; s++) {
1431: if (strchr(quotable, *s))
1432: Buf_AddChar(&buf, '\\');
1433: Buf_AddChar(&buf, *s);
1434: }
1435: Buf_AddSpace(&buf);
1436: }
1437: Var_Append(name, Buf_Retrieve(&buf), VAR_GLOBAL);
1438: Buf_Destroy(&buf);
1439: }