Annotation of src/usr.bin/make/var.c, Revision 1.62
1.53 espie 1: /* $OpenPackages$ */
1.62 ! espie 2: /* $OpenBSD: var.c,v 1.61 2007/01/02 13:21:31 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.62 ! espie 6: * Copyright (c) 1999,2000,2007 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.
1.57 millert 48: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 49: * may be used to endorse or promote products derived from this software
50: * without specific prior written permission.
51: *
52: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62: * SUCH DAMAGE.
63: */
64:
1.55 espie 65: #include <assert.h>
66: #include <stddef.h>
67: #include <stdio.h>
1.60 espie 68: #include <stdint.h>
1.55 espie 69: #include <stdlib.h>
70: #include <string.h>
71:
72: #include "config.h"
73: #include "defines.h"
74: #include "buf.h"
75: #include "stats.h"
76: #include "ohash.h"
1.62 ! espie 77: #include "pathnames.h"
1.55 espie 78: #include "varmodifiers.h"
79: #include "var.h"
80: #include "varname.h"
81: #include "error.h"
82: #include "str.h"
83: #include "var_int.h"
84: #include "memory.h"
85: #include "symtable.h"
86: #include "gnode.h"
87:
88: /* extended indices for System V stuff */
89: #define FTARGET_INDEX 7
90: #define DTARGET_INDEX 8
91: #define FPREFIX_INDEX 9
92: #define DPREFIX_INDEX 10
93: #define FARCHIVE_INDEX 11
94: #define DARCHIVE_INDEX 12
95: #define FMEMBER_INDEX 13
96: #define DMEMBER_INDEX 14
1.48 espie 97:
1.55 espie 98: #define EXTENDED2SIMPLE(i) (((i)-LOCAL_SIZE)/2)
99: #define IS_EXTENDED_F(i) ((i)%2 == 1)
1.34 espie 100:
1.1 deraadt 101: /*
102: * This is a harmless return value for Var_Parse that can be used by Var_Subst
103: * to determine if there was an error in parsing -- easier than returning
104: * a flag, as things outside this module don't give a hoot.
105: */
1.53 espie 106: char var_Error[] = "";
1.1 deraadt 107:
108: /*
109: * Similar to var_Error, but returned when the 'err' flag for Var_Parse is
110: * set false. Why not just use a constant? Well, gcc likes to condense
111: * identical string instances...
112: */
113: static char varNoError[] = "";
1.62 ! espie 114: bool oldVars; /* variable substitution style */
! 115: static bool checkEnvFirst; /* true if environment should be searched for
! 116: * variables before the global context */
! 117:
! 118: void
! 119: Var_setCheckEnvFirst(bool yes)
! 120: {
! 121: checkEnvFirst = yes;
! 122: }
1.1 deraadt 123:
124: /*
1.53 espie 125: * Variable values are obtained from four different contexts:
126: * 1) the process environment. The process environment itself
127: * may not be changed, but these variables may be modified,
128: * unless make is invoked with -e, in which case those variables
129: * are unmodifiable and supersede the global context.
1.1 deraadt 130: * 2) the global context. Variables set in the Makefile are located in
131: * the global context. It is the penultimate context searched when
132: * substituting.
133: * 3) the command-line context. All variables set on the command line
134: * are placed in this context. They are UNALTERABLE once placed here.
135: * 4) the local context. Each target has associated with it a context
136: * list. On this list are located the structures describing such
137: * local variables as $(@) and $(*)
138: * The four contexts are searched in the reverse order from which they are
139: * listed.
140: */
1.53 espie 141:
1.62 ! espie 142: static struct ohash global_variables;
1.53 espie 143:
144: static char *varnames[] = {
145: TARGET,
146: PREFIX,
147: ARCHIVE,
148: MEMBER,
149: OODATE,
150: ALLSRC,
151: IMPSRC,
152: FTARGET,
153: DTARGET,
154: FPREFIX,
155: DPREFIX,
156: FARCHIVE,
157: DARCHIVE,
158: FMEMBER,
159: DMEMBER
160: };
161:
1.1 deraadt 162:
1.37 espie 163: typedef struct Var_ {
1.53 espie 164: BUFFER val; /* its value */
165: unsigned int flags; /* miscellaneous status flags */
1.62 ! espie 166: #define VAR_IN_USE 1 /* Variable's value currently being used. */
! 167: /* Used to avoid recursion */
! 168: #define VAR_DUMMY 2 /* Placeholder: already looked up */
! 169: #define VAR_FROM_CMD 4 /* From the command line */
! 170: #define VAR_FROM_ENV 8 /* Read from environment */
! 171: #define VAR_SEEN_ENV 16 /* Already seen environment */
! 172: #define VAR_SHELL 32 /* magic, see posix */
! 173: #define POISONS (POISON_NORMAL | POISON_EMPTY | POISON_NOT_DEFINED)
1.53 espie 174: char name[1]; /* the variable's name */
1.1 deraadt 175: } Var;
176:
1.53 espie 177:
178: static struct ohash_info var_info = {
179: offsetof(Var, name),
1.38 espie 180: NULL, hash_alloc, hash_free, element_alloc };
1.60 espie 181: static int quick_lookup(const char *, const char **, uint32_t *);
1.23 espie 182: #define VarValue(v) Buf_Retrieve(&((v)->val))
1.62 ! espie 183: static Var *varfind(const char *, const char *, SymTable *, int, uint32_t);
! 184: static Var *find_global_var(const char *, const char *, uint32_t);
1.61 espie 185: static void VarDelete(Var *);
1.53 espie 186: static void VarPrintVar(Var *);
1.62 ! espie 187:
! 188: static Var *obtain_global_var(const char *, const char *, uint32_t);
! 189: static void fill_from_env(Var *);
1.53 espie 190: static Var *create_var(const char *, const char *);
1.62 ! espie 191: static void varq_set_append(int, const char *, GNode *, bool);
1.53 espie 192: static void var_init_string(Var *, const char *);
1.62 ! espie 193: static void var_set_string(Var *, const char *);
! 194: static void var_append_string(Var *, const char *);
! 195: static void var_set_append(const char *, const char *, const char *, int, bool);
! 196: static void set_magic_shell_variable(void);
! 197: static void poison_check(Var *);
1.53 espie 198: static const char *find_0(const char *);
199: static const char *find_rparen(const char *);
200: static const char *find_ket(const char *);
201: typedef const char * (*find_t)(const char *);
202: static find_t find_pos(int);
203:
204: /* retrieve the hashed values for well-known variables. */
205: #include "varhashconsts.h"
206:
1.37 espie 207: void
1.59 espie 208: SymTable_Init(SymTable *ctxt)
1.37 espie 209: {
1.53 espie 210: static SymTable sym_template;
1.37 espie 211: memcpy(ctxt, &sym_template, sizeof(*ctxt));
212: }
213:
1.53 espie 214: #ifdef CLEANUP
1.37 espie 215: void
1.59 espie 216: SymTable_Destroy(SymTable *ctxt)
1.37 espie 217: {
218: int i;
219:
220: for (i = 0; i < LOCAL_SIZE; i++)
221: if (ctxt->locals[i] != NULL)
222: VarDelete(ctxt->locals[i]);
223: }
1.53 espie 224: #endif
1.37 espie 225:
1.38 espie 226: static int
1.60 espie 227: quick_lookup(const char *name, const char **enamePtr, uint32_t *pk)
1.38 espie 228: {
229: size_t len;
230:
1.59 espie 231: *pk = ohash_interval(name, enamePtr);
232: len = *enamePtr - name;
1.38 espie 233: /* substitute short version for long local name */
1.53 espie 234: switch (*pk % MAGICSLOTS1) { /* MAGICSLOTS should be the */
235: case K_LONGALLSRC % MAGICSLOTS1: /* smallest constant yielding */
236: /* distinct case values */
1.56 espie 237: if (*pk == K_LONGALLSRC && len == strlen(LONGALLSRC) &&
238: strncmp(name, LONGALLSRC, len) == 0)
1.38 espie 239: return ALLSRC_INDEX;
240: break;
1.53 espie 241: case K_LONGARCHIVE % MAGICSLOTS1:
1.56 espie 242: if (*pk == K_LONGARCHIVE && len == strlen(LONGARCHIVE) &&
243: strncmp(name, LONGARCHIVE, len) == 0)
1.38 espie 244: return ARCHIVE_INDEX;
245: break;
1.53 espie 246: case K_LONGIMPSRC % MAGICSLOTS1:
1.56 espie 247: if (*pk == K_LONGIMPSRC && len == strlen(LONGIMPSRC) &&
248: strncmp(name, LONGIMPSRC, len) == 0)
1.38 espie 249: return IMPSRC_INDEX;
250: break;
1.53 espie 251: case K_LONGMEMBER % MAGICSLOTS1:
1.56 espie 252: if (*pk == K_LONGMEMBER && len == strlen(LONGMEMBER) &&
253: strncmp(name, LONGMEMBER, len) == 0)
1.38 espie 254: return MEMBER_INDEX;
255: break;
1.53 espie 256: case K_LONGOODATE % MAGICSLOTS1:
1.56 espie 257: if (*pk == K_LONGOODATE && len == strlen(LONGOODATE) &&
258: strncmp(name, LONGOODATE, len) == 0)
1.38 espie 259: return OODATE_INDEX;
260: break;
1.53 espie 261: case K_LONGPREFIX % MAGICSLOTS1:
1.56 espie 262: if (*pk == K_LONGPREFIX && len == strlen(LONGPREFIX) &&
263: strncmp(name, LONGPREFIX, len) == 0)
1.38 espie 264: return PREFIX_INDEX;
265: break;
1.53 espie 266: case K_LONGTARGET % MAGICSLOTS1:
1.56 espie 267: if (*pk == K_LONGTARGET && len == strlen(LONGTARGET) &&
268: strncmp(name, LONGTARGET, len) == 0)
1.38 espie 269: return TARGET_INDEX;
270: break;
1.53 espie 271: case K_TARGET % MAGICSLOTS1:
1.38 espie 272: if (name[0] == TARGET[0] && len == 1)
273: return TARGET_INDEX;
274: break;
1.53 espie 275: case K_OODATE % MAGICSLOTS1:
1.38 espie 276: if (name[0] == OODATE[0] && len == 1)
277: return OODATE_INDEX;
278: break;
1.53 espie 279: case K_ALLSRC % MAGICSLOTS1:
1.38 espie 280: if (name[0] == ALLSRC[0] && len == 1)
281: return ALLSRC_INDEX;
282: break;
1.53 espie 283: case K_IMPSRC % MAGICSLOTS1:
1.38 espie 284: if (name[0] == IMPSRC[0] && len == 1)
285: return IMPSRC_INDEX;
286: break;
1.53 espie 287: case K_PREFIX % MAGICSLOTS1:
1.38 espie 288: if (name[0] == PREFIX[0] && len == 1)
289: return PREFIX_INDEX;
290: break;
1.53 espie 291: case K_ARCHIVE % MAGICSLOTS1:
1.38 espie 292: if (name[0] == ARCHIVE[0] && len == 1)
293: return ARCHIVE_INDEX;
294: break;
1.53 espie 295: case K_MEMBER % MAGICSLOTS1:
1.38 espie 296: if (name[0] == MEMBER[0] && len == 1)
297: return MEMBER_INDEX;
298: break;
1.53 espie 299: case K_FTARGET % MAGICSLOTS1:
300: if (name[0] == FTARGET[0] && name[1] == FTARGET[1] && len == 2)
301: return FTARGET_INDEX;
302: break;
303: case K_DTARGET % MAGICSLOTS1:
304: if (name[0] == DTARGET[0] && name[1] == DTARGET[1] && len == 2)
305: return DTARGET_INDEX;
306: break;
307: case K_FPREFIX % MAGICSLOTS1:
308: if (name[0] == FPREFIX[0] && name[1] == FPREFIX[1] && len == 2)
309: return FPREFIX_INDEX;
310: break;
311: case K_DPREFIX % MAGICSLOTS1:
312: if (name[0] == DPREFIX[0] && name[1] == DPREFIX[1] && len == 2)
313: return DPREFIX_INDEX;
314: break;
315: case K_FARCHIVE % MAGICSLOTS1:
316: if (name[0] == FARCHIVE[0] && name[1] == FARCHIVE[1] && len == 2)
317: return FARCHIVE_INDEX;
318: break;
319: case K_DARCHIVE % MAGICSLOTS1:
320: if (name[0] == DARCHIVE[0] && name[1] == DARCHIVE[1] && len == 2)
321: return DARCHIVE_INDEX;
322: break;
323: case K_FMEMBER % MAGICSLOTS1:
324: if (name[0] == FMEMBER[0] && name[1] == FMEMBER[1] && len == 2)
325: return FMEMBER_INDEX;
326: break;
327: case K_DMEMBER % MAGICSLOTS1:
328: if (name[0] == DMEMBER[0] && name[1] == DMEMBER[1] && len == 2)
329: return DMEMBER_INDEX;
330: break;
1.38 espie 331: default:
332: break;
333: }
334: return -1;
335: }
1.37 espie 336:
1.62 ! espie 337: static void
! 338: varq_set_append(int idx, const char *val, GNode *gn, bool append)
1.37 espie 339: {
340: Var *v = gn->context.locals[idx];
341:
342: if (v == NULL) {
1.62 ! espie 343: v = create_var(varnames[idx], NULL);
! 344: #ifdef STATS_VAR_LOOKUP
! 345: STAT_VAR_CREATION++;
! 346: #endif
! 347: if (val != NULL)
! 348: var_init_string(v, val);
! 349: else
! 350: Buf_Init(&(v->val), 1);
1.37 espie 351: v->flags = 0;
352: gn->context.locals[idx] = v;
353: } else {
1.62 ! espie 354: if (append)
! 355: Buf_AddSpace(&(v->val));
! 356: else
! 357: Buf_Reset(&(v->val));
1.37 espie 358: Buf_AddString(&(v->val), val);
359: }
360: if (DEBUG(VAR))
1.62 ! espie 361: printf("%s:%s = %s\n", gn->name, varnames[idx], VarValue(v));
! 362: }
! 363:
! 364: void
! 365: Varq_Set(int idx, const char *val, GNode *gn)
! 366: {
! 367: varq_set_append(idx, val, gn, false);
1.37 espie 368: }
369:
1.53 espie 370: void
1.59 espie 371: Varq_Append(int idx, const char *val, GNode *gn)
1.37 espie 372: {
1.62 ! espie 373: varq_set_append(idx, val, gn, true);
1.37 espie 374: }
375:
376: char *
1.59 espie 377: Varq_Value(int idx, GNode *gn)
1.37 espie 378: {
379: Var *v = gn->context.locals[idx];
380:
1.53 espie 381: if (v == NULL)
382: return NULL;
1.37 espie 383: else
1.53 espie 384: return VarValue(v);
385: }
386:
387: static Var *
1.59 espie 388: create_var(const char *name, const char *ename)
1.37 espie 389: {
1.59 espie 390: return ohash_create_entry(&var_info, name, &ename);
1.37 espie 391: }
1.1 deraadt 392:
1.53 espie 393: /* Set the initial value a var should have */
394: static void
1.59 espie 395: var_init_string(Var *v, const char *val)
1.53 espie 396: {
397: size_t len;
398:
399: len = strlen(val);
400: Buf_Init(&(v->val), len+1);
401: Buf_AddChars(&(v->val), len, val);
402: }
1.35 espie 403:
1.62 ! espie 404: static void
! 405: var_set_string(Var *v, const char *val)
1.35 espie 406: {
1.62 ! espie 407: if ((v->flags & VAR_DUMMY) == 0) {
! 408: Buf_Reset(&(v->val));
! 409: Buf_AddString(&(v->val), val);
! 410: } else {
! 411: var_init_string(v, val);
! 412: v->flags &= ~VAR_DUMMY;
! 413: }
! 414: }
1.53 espie 415:
1.62 ! espie 416: static void
! 417: var_append_string(Var *v, const char *val)
! 418: {
! 419: if ((v->flags & VAR_DUMMY) == 0) {
! 420: Buf_AddSpace(&(v->val));
! 421: Buf_AddString(&(v->val), val);
! 422: } else {
! 423: var_init_string(v, val);
! 424: v->flags &= ~VAR_DUMMY;
! 425: }
1.35 espie 426: }
1.53 espie 427:
1.62 ! espie 428: static void
! 429: fill_from_env(Var *v)
1.37 espie 430: {
1.53 espie 431: char *env;
1.37 espie 432:
1.53 espie 433: env = getenv(v->name);
434: if (env == NULL)
1.62 ! espie 435: v->flags |= VAR_SEEN_ENV;
1.53 espie 436: else {
1.62 ! espie 437: var_set_string(v, env);
! 438: v->flags |= VAR_FROM_ENV | VAR_SEEN_ENV;
1.53 espie 439: }
1.37 espie 440:
1.53 espie 441: #ifdef STATS_VAR_LOOKUP
442: STAT_VAR_FROM_ENV++;
443: #endif
1.62 ! espie 444: }
1.37 espie 445:
1.62 ! espie 446: static Var *
! 447: obtain_global_var(const char *name, const char *ename, uint32_t k)
! 448: {
! 449: unsigned int slot;
! 450: Var *v;
! 451:
! 452: slot = ohash_lookup_interval(&global_variables, name, ename, k);
! 453: v = ohash_find(&global_variables, slot);
! 454: if (v == NULL) {
! 455: v = create_var(name, ename);
! 456: v->flags = VAR_DUMMY;
! 457: ohash_insert(&global_variables, slot, v);
! 458: }
! 459: return v;
1.37 espie 460: }
461:
1.62 ! espie 462: static void
! 463: poison_check(Var *v)
1.1 deraadt 464: {
1.62 ! espie 465: if (v->flags & POISON_NORMAL) {
! 466: Parse_Error(PARSE_FATAL,
! 467: "Poisoned variable %s has been referenced\n", v->name);
! 468: return;
! 469: }
! 470: if (v->flags & VAR_DUMMY) {
! 471: Parse_Error(PARSE_FATAL,
! 472: "Poisoned variable %s is not defined\n", v->name);
! 473: return;
! 474: }
! 475: if (v->flags & POISON_EMPTY)
! 476: if (strcmp(VarValue(v), "") == 0)
! 477: Parse_Error(PARSE_FATAL,
! 478: "Poisoned variable %s is empty\n", v->name);
1.37 espie 479: }
480:
1.1 deraadt 481: static Var *
1.62 ! espie 482: find_global_var(const char *name, const char *ename, uint32_t k)
1.1 deraadt 483: {
1.62 ! espie 484: Var *v;
! 485:
! 486: v = obtain_global_var(name, ename, k);
1.53 espie 487:
1.62 ! espie 488: if ((v->flags & VAR_SEEN_ENV) == 0 &&
! 489: (checkEnvFirst && (v->flags & VAR_FROM_CMD) == 0 ||
! 490: (v->flags & VAR_DUMMY) != 0))
! 491: fill_from_env(v);
1.38 espie 492:
1.62 ! espie 493: return v;
1.39 espie 494: }
495:
496: static Var *
1.62 ! espie 497: varfind(const char *name, const char *ename, SymTable *ctxt,
1.60 espie 498: int idx, uint32_t k)
1.39 espie 499: {
1.53 espie 500: /* Handle local variables first */
501: if (idx != -1) {
1.62 ! espie 502: if (ctxt != NULL) {
1.53 espie 503: if (idx < LOCAL_SIZE)
504: return ctxt->locals[idx];
505: else
506: return ctxt->locals[EXTENDED2SIMPLE(idx)];
507: } else
1.62 ! espie 508: return NULL;
! 509: } else {
! 510: return find_global_var(name, ename, k);
1.53 espie 511: }
1.1 deraadt 512: }
513:
514: /*-
515: *-----------------------------------------------------------------------
516: * VarDelete --
517: * Delete a variable and all the space associated with it.
518: *-----------------------------------------------------------------------
519: */
520: static void
1.61 espie 521: VarDelete(Var *v)
1.1 deraadt 522: {
1.53 espie 523: if ((v->flags & VAR_DUMMY) == 0)
524: Buf_Destroy(&(v->val));
1.23 espie 525: free(v);
1.1 deraadt 526: }
527:
528:
529:
530: void
1.59 espie 531: Var_Delete(const char *name)
1.1 deraadt 532: {
1.62 ! espie 533: Var *v;
! 534: uint32_t k;
! 535: unsigned int slot;
! 536: const char *ename = NULL;
! 537: int idx;
! 538:
! 539:
! 540: if (DEBUG(VAR))
! 541: printf("delete %s\n", name);
! 542:
! 543: idx = quick_lookup(name, &ename, &k);
! 544: if (idx != -1)
! 545: Parse_Error(PARSE_FATAL, "Trying to delete dynamic variable");
! 546: slot = ohash_lookup_interval(&global_variables, name, ename, k);
! 547: v = ohash_find(&global_variables, slot);
! 548:
! 549: if (v == NULL)
! 550: return;
! 551: if (checkEnvFirst && (v->flags & VAR_FROM_ENV))
! 552: return;
1.1 deraadt 553:
1.62 ! espie 554: if (v->flags & VAR_FROM_CMD)
! 555: return;
1.37 espie 556:
1.62 ! espie 557: ohash_remove(&global_variables, slot);
1.30 espie 558: VarDelete(v);
1.1 deraadt 559: }
560:
1.62 ! espie 561: static void
! 562: var_set_append(const char *name, const char *ename, const char *val, int ctxt,
! 563: bool append)
1.1 deraadt 564: {
1.62 ! espie 565: Var *v;
! 566: uint32_t k;
! 567: int idx;
1.53 espie 568:
1.62 ! espie 569: idx = quick_lookup(name, &ename, &k);
! 570: if (idx != -1) {
! 571: Parse_Error(PARSE_FATAL, "Trying to %s dynamic variable $%s",
! 572: append ? "append to" : "set", varnames[idx]);
! 573: return;
! 574: }
1.53 espie 575:
1.62 ! espie 576: v = find_global_var(name, ename, k);
! 577: if (v->flags & POISON_NORMAL)
! 578: Parse_Error(PARSE_FATAL, "Trying to %s poisoned variable %s\n",
! 579: append ? "append to" : "set", v->name);
! 580: /* so can we write to it ? */
! 581: if (ctxt == VAR_CMD) { /* always for command line */
! 582: (append ? var_append_string : var_set_string)(v, val);
! 583: v->flags |= VAR_FROM_CMD;
! 584: if ((v->flags & VAR_SHELL) == 0) {
! 585: /* Any variables given on the command line are
! 586: * automatically exported to the environment,
! 587: * except for SHELL (as per POSIX standard).
! 588: */
! 589: esetenv(v->name, val);
! 590: }
! 591: if (DEBUG(VAR))
! 592: printf("command:%s = %s\n", v->name, VarValue(v));
! 593: } else if ((v->flags & VAR_FROM_CMD) == 0 &&
! 594: (!checkEnvFirst || (v->flags & VAR_FROM_ENV) == 0)) {
! 595: (append ? var_append_string : var_set_string)(v, val);
! 596: if (DEBUG(VAR))
! 597: printf("global:%s = %s\n", v->name, VarValue(v));
! 598: } else if (DEBUG(VAR))
! 599: printf("overriden:%s = %s\n", v->name, VarValue(v));
1.1 deraadt 600: }
601:
602: void
1.62 ! espie 603: Var_Seti(const char *name, const char *ename, const char *val, int ctxt)
1.1 deraadt 604: {
1.62 ! espie 605: var_set_append(name, ename, val, ctxt, false);
! 606: }
1.53 espie 607:
1.62 ! espie 608: void
! 609: Var_Appendi(const char *name, const char *ename, const char *val, int ctxt)
! 610: {
! 611: var_set_append(name, ename, val, ctxt, true);
! 612: }
1.53 espie 613:
1.62 ! espie 614: void
! 615: Var_MarkPoisoned(const char *name, const char *ename, unsigned int type)
! 616: {
! 617: Var *v;
! 618: uint32_t k;
! 619: int idx;
! 620: idx = quick_lookup(name, &ename, &k);
1.1 deraadt 621:
1.62 ! espie 622: if (idx != -1) {
! 623: Parse_Error(PARSE_FATAL,
! 624: "Trying to poison dynamic variable $%s",
! 625: varnames[idx]);
! 626: return;
! 627: }
1.53 espie 628:
1.62 ! espie 629: v = find_global_var(name, ename, k);
! 630: v->flags |= type;
! 631: if (v->flags & POISON_NORMAL) {
! 632: if (v->flags & VAR_DUMMY)
! 633: return;
! 634: if (v->flags & VAR_FROM_ENV)
! 635: return;
! 636: Parse_Error(PARSE_FATAL,
! 637: "Poisoned variable %s is already set\n", v->name);
1.53 espie 638: }
1.1 deraadt 639: }
640:
1.53 espie 641: char *
1.59 espie 642: Var_Valuei(const char *name, const char *ename)
1.53 espie 643: {
1.62 ! espie 644: Var *v;
! 645: uint32_t k;
! 646: int idx;
! 647:
! 648: idx = quick_lookup(name, &ename, &k);
! 649: if (idx == -1) {
! 650: v = find_global_var(name, ename, k);
! 651: if (v->flags & POISONS)
! 652: poison_check(v);
! 653: if ((v->flags & VAR_DUMMY) == 0)
! 654: return VarValue(v);
! 655: }
1.53 espie 656:
657: return NULL;
658: }
659:
1.62 ! espie 660: bool
! 661: Var_Definedi(const char *name, const char *ename)
! 662: {
! 663: Var *v;
! 664: uint32_t k;
! 665: int idx;
! 666:
! 667: idx = quick_lookup(name, &ename, &k);
! 668: if (idx == -1) {
! 669: v = find_global_var(name, ename, k);
! 670: if (v->flags & POISON_NORMAL)
! 671: poison_check(v);
! 672: if ((v->flags & VAR_DUMMY) == 0)
! 673: return true;
! 674: }
! 675:
! 676: return false;
! 677: }
! 678:
1.53 espie 679: static const char *
1.59 espie 680: find_0(const char *p)
1.1 deraadt 681: {
1.53 espie 682: while (*p != '$' && *p != '\0' && *p != ':')
683: p++;
684: return p;
685: }
686:
687: static const char *
1.59 espie 688: find_rparen(const char *p)
1.53 espie 689: {
690: while (*p != '$' && *p != '\0' && *p != ')' && *p != ':')
691: p++;
692: return p;
693: }
1.1 deraadt 694:
1.53 espie 695: static const char *
1.59 espie 696: find_ket(const char *p)
1.53 espie 697: {
698: while (*p != '$' && *p != '\0' && *p != '}' && *p != ':')
699: p++;
700: return p;
701: }
1.1 deraadt 702:
1.53 espie 703: static find_t
1.59 espie 704: find_pos(int c)
1.53 espie 705: {
706: switch(c) {
707: case '\0':
708: return find_0;
709: case ')':
710: return find_rparen;
711: case '}':
712: return find_ket;
713: default:
714: return 0;
715: }
1.1 deraadt 716: }
717:
1.53 espie 718: size_t
1.59 espie 719: Var_ParseSkip(const char *str, SymTable *ctxt, bool *result)
1.1 deraadt 720: {
1.53 espie 721: const char *tstr; /* Pointer into str */
722: Var *v; /* Variable in invocation */
723: char endc; /* Ending character when variable in parens
724: * or braces */
725: const char *start;
726: size_t length;
727: struct Name name;
1.1 deraadt 728:
1.53 espie 729: v = NULL;
730: start = str;
731: str++;
732:
733: if (*str != '(' && *str != '{') {
1.55 espie 734: name.tofree = false;
1.53 espie 735: tstr = str + 1;
736: length = 2;
737: endc = '\0';
738: } else {
739: endc = *str == '(' ? ')' : '}';
740: str++;
741:
742: /* Find eventual modifiers in the variable */
1.55 espie 743: tstr = VarName_Get(str, &name, ctxt, false, find_pos(endc));
744: VarName_Free(&name);
1.54 espie 745: length = tstr - start;
1.55 espie 746: if (*tstr != 0)
747: length++;
1.53 espie 748: }
749:
750: if (result != NULL)
1.55 espie 751: *result = true;
1.53 espie 752: if (*tstr == ':' && endc != '\0')
1.55 espie 753: if (VarModifiers_Apply(NULL, NULL, ctxt, true, NULL, tstr, endc,
1.53 espie 754: &length) == var_Error)
1.58 fgsch 755: if (result != NULL)
756: *result = false;
1.53 espie 757: return length;
1.1 deraadt 758: }
759:
1.55 espie 760: /* As of now, Var_ParseBuffer is just a wrapper around Var_Parse. For
761: * speed, it may be better to revisit the implementation to do things
762: * directly. */
763: bool
1.59 espie 764: Var_ParseBuffer(Buffer buf, const char *str, SymTable *ctxt, bool err,
765: size_t *lengthPtr)
1.53 espie 766: {
767: char *result;
1.55 espie 768: bool freeIt;
1.45 espie 769:
1.53 espie 770: result = Var_Parse(str, ctxt, err, lengthPtr, &freeIt);
771: if (result == var_Error)
1.55 espie 772: return false;
1.53 espie 773:
774: Buf_AddString(buf, result);
775: if (freeIt)
776: free(result);
1.55 espie 777: return true;
1.45 espie 778: }
779:
1.1 deraadt 780: char *
1.59 espie 781: Var_Parse(const char *str, /* The string to parse */
782: SymTable *ctxt, /* The context for the variable */
783: bool err, /* true if undefined variables are an error */
784: size_t *lengthPtr, /* OUT: The length of the specification */
785: bool *freePtr) /* OUT: true if caller should free result */
1.44 espie 786: {
1.53 espie 787: const char *tstr; /* Pointer into str */
788: Var *v; /* Variable in invocation */
789: char endc; /* Ending character when variable in parens
1.1 deraadt 790: * or braces */
1.53 espie 791: struct Name name;
792: const char *start;
1.44 espie 793: char *val; /* Variable value */
1.60 espie 794: uint32_t k;
1.53 espie 795: int idx;
1.5 millert 796:
1.55 espie 797: *freePtr = false;
1.44 espie 798: start = str++;
1.5 millert 799:
1.44 espie 800: val = NULL;
1.45 espie 801: v = NULL;
1.53 espie 802: idx = -1;
1.44 espie 803:
804: if (*str != '(' && *str != '{') {
1.53 espie 805: name.s = str;
806: name.e = str+1;
1.55 espie 807: name.tofree = false;
1.53 espie 808: tstr = str + 1;
1.44 espie 809: *lengthPtr = 2;
810: endc = '\0';
1.1 deraadt 811: } else {
1.44 espie 812: endc = *str == '(' ? ')' : '}';
1.53 espie 813: str++;
1.5 millert 814:
1.44 espie 815: /* Find eventual modifiers in the variable */
1.55 espie 816: tstr = VarName_Get(str, &name, ctxt, false, find_pos(endc));
1.54 espie 817: *lengthPtr = tstr - start;
818: if (*tstr != '\0')
819: (*lengthPtr)++;
1.44 espie 820: }
1.5 millert 821:
1.53 espie 822: idx = quick_lookup(name.s, &name.e, &k);
1.62 ! espie 823: v = varfind(name.s, name.e, ctxt, idx, k);
! 824: if (v->flags & POISONS)
! 825: poison_check(v);
1.53 espie 826: if (v != NULL && (v->flags & VAR_DUMMY) == 0) {
1.44 espie 827: if (v->flags & VAR_IN_USE)
828: Fatal("Variable %s is recursive.", v->name);
829: /*NOTREACHED*/
830: else
831: v->flags |= VAR_IN_USE;
1.53 espie 832:
1.44 espie 833: /* Before doing any modification, we have to make sure the value
834: * has been fully expanded. If it looks like recursion might be
835: * necessary (there's a dollar sign somewhere in the variable's value)
836: * we just call Var_Subst to do any other substitutions that are
837: * necessary. Note that the value returned by Var_Subst will have
838: * been dynamically-allocated, so it will need freeing when we
839: * return. */
840: val = VarValue(v);
1.53 espie 841: if (idx == -1) {
842: if (strchr(val, '$') != NULL) {
843: val = Var_Subst(val, ctxt, err);
1.55 espie 844: *freePtr = true;
1.53 espie 845: }
846: } else if (idx >= LOCAL_SIZE) {
847: if (IS_EXTENDED_F(idx))
848: val = Var_GetTail(val);
849: else
850: val = Var_GetHead(val);
1.55 espie 851: *freePtr = true;
1.44 espie 852: }
853: v->flags &= ~VAR_IN_USE;
1.1 deraadt 854: }
1.53 espie 855: if (*tstr == ':' && endc != '\0')
856: val = VarModifiers_Apply(val, &name, ctxt, err, freePtr, tstr, endc,
1.42 espie 857: lengthPtr);
1.44 espie 858: if (val == NULL) {
1.53 espie 859: val = err ? var_Error : varNoError;
860: /* Dynamic source */
861: if (idx != -1) {
862: /* can't be expanded for now: copy the var spec instead. */
1.62 ! espie 863: if (ctxt == NULL) {
1.55 espie 864: *freePtr = true;
865: val = Str_dupi(start, start+ *lengthPtr);
1.53 espie 866: } else {
867: /* somehow, this should have been expanded already. */
868: GNode *n;
869:
870: n = (GNode *)(((char *)ctxt) - offsetof(GNode, context));
871: if (idx >= LOCAL_SIZE)
872: idx = EXTENDED2SIMPLE(idx);
873: switch(idx) {
874: case IMPSRC_INDEX:
875: Fatal("Using $< in a non-suffix rule context is a GNUmake idiom (line %lu of %s)",
876: n->lineno, n->fname);
877: default:
878: Error("Using undefined dynamic variable $%s (line %lu of %s)",
879: varnames[idx], n->lineno, n->fname);
880: break;
881: }
882: }
883: }
1.42 espie 884: }
1.55 espie 885: VarName_Free(&name);
1.44 espie 886: return val;
1.42 espie 887: }
888:
1.1 deraadt 889: char *
1.59 espie 890: Var_Subst(const char *str, /* the string in which to substitute */
891: SymTable *ctxt, /* the context wherein to find variables */
892: bool undefErr) /* true if undefineds are an error */
893: {
894: BUFFER buf; /* Buffer for forming things */
895: static bool errorReported; /* Set true if an error has already
896: * been reported to prevent a plethora
897: * of messages when recursing */
1.1 deraadt 898:
1.23 espie 899: Buf_Init(&buf, MAKE_BSIZE);
1.55 espie 900: errorReported = false;
1.1 deraadt 901:
1.24 espie 902: for (;;) {
1.59 espie 903: char *val; /* Value to substitute for a variable */
904: size_t length; /* Length of the variable invocation */
1.55 espie 905: bool doFree; /* Set true if val should be freed */
1.24 espie 906: const char *cp;
907:
908: /* copy uninteresting stuff */
909: for (cp = str; *str != '\0' && *str != '$'; str++)
910: ;
1.55 espie 911: Buf_Addi(&buf, cp, str);
1.24 espie 912: if (*str == '\0')
913: break;
914: if (str[1] == '$') {
915: /* A dollar sign may be escaped with another dollar sign. */
916: Buf_AddChar(&buf, '$');
917: str += 2;
918: continue;
919: }
920: val = Var_Parse(str, ctxt, undefErr, &length, &doFree);
921: /* When we come down here, val should either point to the
922: * value of this variable, suitably modified, or be NULL.
923: * Length should be the total length of the potential
924: * variable invocation (from $ to end character...) */
925: if (val == var_Error || val == varNoError) {
926: /* If performing old-time variable substitution, skip over
927: * the variable and continue with the substitution. Otherwise,
928: * store the dollar sign and advance str so we continue with
929: * the string... */
1.53 espie 930: if (oldVars)
1.24 espie 931: str += length;
1.53 espie 932: else if (undefErr) {
1.24 espie 933: /* If variable is undefined, complain and skip the
934: * variable. The complaint will stop us from doing anything
935: * when the file is parsed. */
1.53 espie 936: if (!errorReported)
1.24 espie 937: Parse_Error(PARSE_FATAL,
938: "Undefined variable \"%.*s\"",length,str);
939: str += length;
1.55 espie 940: errorReported = true;
1.24 espie 941: } else {
942: Buf_AddChar(&buf, *str);
1.53 espie 943: str++;
1.24 espie 944: }
945: } else {
946: /* We've now got a variable structure to store in. But first,
947: * advance the string pointer. */
948: str += length;
949:
950: /* Copy all the characters from the variable value straight
951: * into the new string. */
952: Buf_AddString(&buf, val);
953: if (doFree)
954: free(val);
955: }
956: }
957: return Buf_Retrieve(&buf);
958: }
1.1 deraadt 959:
1.53 espie 960: void
1.59 espie 961: Var_SubstVar(Buffer buf, /* To store result */
962: const char *str, /* The string in which to substitute */
963: const char *var, /* Named variable */
964: const char *val) /* Its value */
1.24 espie 965: {
966:
1.53 espie 967: assert(*var != '\0');
968:
1.24 espie 969: for (;;) {
1.50 espie 970: const char *start;
971: /* Copy uninteresting stuff */
972: for (start = str; *str != '\0' && *str != '$'; str++)
1.24 espie 973: ;
1.55 espie 974: Buf_Addi(buf, start, str);
1.50 espie 975:
976: start = str;
977: if (*str++ == '\0')
1.24 espie 978: break;
1.50 espie 979: str++;
980: /* and escaped dollars */
981: if (start[1] == '$') {
1.55 espie 982: Buf_Addi(buf, start, start+2);
1.24 espie 983: continue;
984: }
1.50 espie 985: /* Simple variable, if it's not us, copy. */
986: if (start[1] != '(' && start[1] != '{') {
987: if (start[1] != *var || var[1] != '\0') {
1.53 espie 988: Buf_AddChars(buf, 2, start);
1.1 deraadt 989: continue;
1.24 espie 990: }
1.1 deraadt 991: } else {
1.50 espie 992: const char *p;
1.24 espie 993: char endc;
1.1 deraadt 994:
1.50 espie 995: if (start[1] == '(')
1.24 espie 996: endc = ')';
1.53 espie 997: else
1.24 espie 998: endc = '}';
999:
1000: /* Find the end of the variable specification. */
1.50 espie 1001: p = str;
1.24 espie 1002: while (*p != '\0' && *p != ':' && *p != endc && *p != '$')
1003: p++;
1.53 espie 1004: /* A variable inside the variable. We don't know how to
1005: * expand the external variable at this point, so we try
1006: * again with the nested variable. */
1.24 espie 1007: if (*p == '$') {
1.55 espie 1008: Buf_Addi(buf, start, p);
1.24 espie 1009: str = p;
1010: continue;
1.1 deraadt 1011: }
1.5 millert 1012:
1.50 espie 1013: if (strncmp(var, str, p - str) != 0 ||
1014: var[p - str] != '\0') {
1.53 espie 1015: /* Not the variable we want to expand. */
1.55 espie 1016: Buf_Addi(buf, start, p);
1.24 espie 1017: str = p;
1018: continue;
1.53 espie 1019: }
1.50 espie 1020: if (*p == ':') {
1.53 espie 1021: size_t length; /* Length of the variable invocation */
1.55 espie 1022: bool doFree; /* Set true if val should be freed */
1.50 espie 1023: char *newval; /* Value substituted for a variable */
1.53 espie 1024: struct Name name;
1.50 espie 1025:
1.53 espie 1026: length = p - str + 1;
1.55 espie 1027: doFree = false;
1.53 espie 1028: name.s = var;
1029: name.e = var + (p-str);
1.50 espie 1030:
1.55 espie 1031: /* val won't be freed since doFree == false, but
1.50 espie 1032: * VarModifiers_Apply doesn't know that, hence the cast. */
1.55 espie 1033: newval = VarModifiers_Apply((char *)val, &name, NULL, false,
1.53 espie 1034: &doFree, p, endc, &length);
1035: Buf_AddString(buf, newval);
1.50 espie 1036: if (doFree)
1037: free(newval);
1038: str += length;
1039: continue;
1040: } else
1.53 espie 1041: str = p+1;
1.1 deraadt 1042: }
1.53 espie 1043: Buf_AddString(buf, val);
1.1 deraadt 1044: }
1045: }
1046:
1.62 ! espie 1047: static void
! 1048: set_magic_shell_variable()
! 1049: {
! 1050: const char *name = "SHELL";
! 1051: const char *ename = NULL;
! 1052: uint32_t k;
! 1053: Var *v;
! 1054: k = ohash_interval(name, &ename);
! 1055: v = create_var(name, ename);
! 1056: ohash_insert(&global_variables,
! 1057: ohash_lookup_interval(&global_variables, name, ename, k), v);
! 1058: /* the environment shall not affect it */
! 1059: v->flags = VAR_SHELL | VAR_SEEN_ENV;
! 1060: var_init_string(v, _PATH_BSHELL);
! 1061: }
! 1062:
1.1 deraadt 1063: /*-
1064: *-----------------------------------------------------------------------
1065: * Var_Init --
1066: * Initialize the module
1067: *
1068: * Side Effects:
1.53 espie 1069: * The CTXT_CMD and CTXT_GLOBAL contexts are initialized
1.1 deraadt 1070: *-----------------------------------------------------------------------
1071: */
1072: void
1.59 espie 1073: Var_Init(void)
1.1 deraadt 1074: {
1.62 ! espie 1075: ohash_init(&global_variables, 10, &var_info);
! 1076: set_magic_shell_variable();
1.35 espie 1077:
1.62 ! espie 1078:
! 1079: oldVars = true;
! 1080: Var_setCheckEnvFirst(false);
1.53 espie 1081:
1082: VarModifiers_Init();
1.1 deraadt 1083: }
1084:
1085:
1.55 espie 1086: #ifdef CLEANUP
1.1 deraadt 1087: void
1.59 espie 1088: Var_End(void)
1.1 deraadt 1089: {
1.38 espie 1090: Var *v;
1091: unsigned int i;
1092:
1.62 ! espie 1093: for (v = ohash_first(&global_variables, &i); v != NULL;
! 1094: v = ohash_next(&global_variables, &i))
1.38 espie 1095: VarDelete(v);
1.55 espie 1096: }
1.37 espie 1097: #endif
1.5 millert 1098:
1.53 espie 1099: static const char *interpret(int);
1100:
1101: static const char *
1.59 espie 1102: interpret(int f)
1.53 espie 1103: {
1104: if (f & VAR_DUMMY)
1105: return "(D)";
1106: return "";
1107: }
1108:
1.1 deraadt 1109:
1110: /****************** PRINT DEBUGGING INFO *****************/
1.31 espie 1111: static void
1.59 espie 1112: VarPrintVar(Var *v)
1.1 deraadt 1113: {
1.53 espie 1114: printf("%-16s%s = %s\n", v->name, interpret(v->flags),
1115: (v->flags & VAR_DUMMY) == 0 ? VarValue(v) : "(none)");
1.1 deraadt 1116: }
1117:
1118: void
1.59 espie 1119: Var_Dump(void)
1.1 deraadt 1120: {
1.53 espie 1121: Var *v;
1122: unsigned int i;
1123:
1124: printf("#*** Global Variables:\n");
1.38 espie 1125:
1.62 ! espie 1126: for (v = ohash_first(&global_variables, &i); v != NULL;
! 1127: v = ohash_next(&global_variables, &i))
1.53 espie 1128: VarPrintVar(v);
1.37 espie 1129:
1.53 espie 1130: }
1.46 espie 1131:
1132: static const char *quotable = " \t\n\\'\"";
1133:
1134: /* In POSIX mode, variable assignments passed on the command line are
1135: * propagated to sub makes through MAKEFLAGS.
1136: */
1137: void
1.59 espie 1138: Var_AddCmdline(const char *name)
1.46 espie 1139: {
1140: Var *v;
1141: unsigned int i;
1142: BUFFER buf;
1143: char *s;
1144:
1145: Buf_Init(&buf, MAKE_BSIZE);
1146:
1.62 ! espie 1147: for (v = ohash_first(&global_variables, &i); v != NULL;
! 1148: v = ohash_next(&global_variables, &i)) {
! 1149: if (!(v->flags & VAR_FROM_CMD)) {
! 1150: continue;
! 1151: }
1.46 espie 1152: /* We assume variable names don't need quoting */
1153: Buf_AddString(&buf, v->name);
1154: Buf_AddChar(&buf, '=');
1155: for (s = VarValue(v); *s != '\0'; s++) {
1156: if (strchr(quotable, *s))
1157: Buf_AddChar(&buf, '\\');
1158: Buf_AddChar(&buf, *s);
1159: }
1160: Buf_AddSpace(&buf);
1161: }
1162: Var_Append(name, Buf_Retrieve(&buf), VAR_GLOBAL);
1163: Buf_Destroy(&buf);
1164: }