Annotation of src/usr.bin/make/var.c, Revision 1.42
1.42 ! espie 1: /* $OpenBSD: var.c,v 1.41 2000/07/17 23:01:20 espie Exp $ */
1.6 millert 2: /* $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $ */
1.1 deraadt 3:
4: /*
1.17 espie 5: * Copyright (c) 1999 Marc Espie.
6: *
7: * Extensive code modifications for the OpenBSD project.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
19: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
22: * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29: */
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: #ifndef lint
70: #if 0
1.5 millert 71: static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
1.1 deraadt 72: #else
1.42 ! espie 73: static char rcsid[] = "$OpenBSD: var.c,v 1.41 2000/07/17 23:01:20 espie Exp $";
1.1 deraadt 74: #endif
75: #endif /* not lint */
76:
77: /*-
78: * var.c --
79: * Variable-handling functions
80: *
81: * Interface:
82: * Var_Set Set the value of a variable in the given
83: * context. The variable is created if it doesn't
84: * yet exist. The value and variable name need not
85: * be preserved.
86: *
87: * Var_Append Append more characters to an existing variable
88: * in the given context. The variable needn't
89: * exist already -- it will be created if it doesn't.
90: * A space is placed between the old value and the
91: * new one.
92: *
93: * Var_Exists See if a variable exists.
94: *
95: * Var_Value Return the value of a variable in a context or
96: * NULL if the variable is undefined.
97: *
98: * Var_Subst Substitute named variable, or all variables if
99: * NULL in a string using
100: * the given context as the top-most one. If the
101: * third argument is non-zero, Parse_Error is
102: * called if any variables are undefined.
103: *
104: * Var_Parse Parse a variable expansion from a string and
105: * return the result and the number of characters
106: * consumed.
107: *
108: * Var_Delete Delete a variable in a context.
109: *
110: * Var_Init Initialize this module.
111: *
112: * Debugging:
113: * Var_Dump Print out all variables defined in the given
114: * context.
115: *
116: * XXX: There's a lot of duplication in these functions.
117: */
118:
119: #include <ctype.h>
1.6 millert 120: #ifndef MAKE_BOOTSTRAP
1.9 deraadt 121: #include <sys/types.h>
1.6 millert 122: #include <regex.h>
123: #endif
124: #include <stdlib.h>
1.35 espie 125: #include <stddef.h>
1.1 deraadt 126: #include "make.h"
127: #include "buf.h"
1.38 espie 128: #include "ohash.h"
129: #include "hashconsts.h"
1.34 espie 130:
1.37 espie 131: static SymTable *CTXT_GLOBAL, *CTXT_CMD, *CTXT_ENV;
132:
1.34 espie 133: static char *varnames[] = {
134: TARGET,
135: OODATE,
136: ALLSRC,
137: IMPSRC,
138: PREFIX,
139: ARCHIVE,
140: MEMBER };
141:
1.1 deraadt 142: /*
143: * This is a harmless return value for Var_Parse that can be used by Var_Subst
144: * to determine if there was an error in parsing -- easier than returning
145: * a flag, as things outside this module don't give a hoot.
146: */
147: char var_Error[] = "";
148:
149: /*
150: * Similar to var_Error, but returned when the 'err' flag for Var_Parse is
151: * set false. Why not just use a constant? Well, gcc likes to condense
152: * identical string instances...
153: */
154: static char varNoError[] = "";
155:
156: /*
157: * Internally, variables are contained in four different contexts.
158: * 1) the environment. They may not be changed. If an environment
159: * variable is appended-to, the result is placed in the global
160: * context.
161: * 2) the global context. Variables set in the Makefile are located in
162: * the global context. It is the penultimate context searched when
163: * substituting.
164: * 3) the command-line context. All variables set on the command line
165: * are placed in this context. They are UNALTERABLE once placed here.
166: * 4) the local context. Each target has associated with it a context
167: * list. On this list are located the structures describing such
168: * local variables as $(@) and $(*)
169: * The four contexts are searched in the reverse order from which they are
170: * listed.
171: */
1.37 espie 172: GSymT *VAR_GLOBAL; /* variables from the makefile */
173: GSymT *VAR_CMD; /* variables defined on the command-line */
174: static GSymT *VAR_ENV; /* variables read from env */
1.1 deraadt 175:
1.39 espie 176: #define FIND_MINE 0x1 /* look in CTXT_CMD and CTXT_GLOBAL */
177: #define FIND_ENV 0x2 /* look in the environment */
1.1 deraadt 178:
1.37 espie 179: typedef struct Var_ {
1.23 espie 180: BUFFER val; /* its value */
1.1 deraadt 181: int flags; /* miscellaneous status flags */
182: #define VAR_IN_USE 1 /* Variable's value currently being used.
183: * Used to avoid recursion */
184: #define VAR_JUNK 4 /* Variable is a junk variable that
185: * should be destroyed when done with
186: * it. Used by Var_Parse for undefined,
187: * modified variables */
1.38 espie 188: char name[1]; /* the variable's name */
1.1 deraadt 189: } Var;
190:
1.6 millert 191: /* Var*Pattern flags */
192: #define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */
193: #define VAR_SUB_ONE 0x02 /* Apply substitution to one word */
194: #define VAR_SUB_MATCHED 0x04 /* There was a match */
195: #define VAR_MATCH_START 0x08 /* Match at start of word */
196: #define VAR_MATCH_END 0x10 /* Match at end of word */
197:
1.1 deraadt 198: typedef struct {
199: char *lhs; /* String to match */
1.16 espie 200: size_t leftLen; /* Length of string */
1.1 deraadt 201: char *rhs; /* Replacement string (w/ &'s removed) */
1.16 espie 202: size_t rightLen; /* Length of replacement */
1.1 deraadt 203: int flags;
204: } VarPattern;
205:
1.6 millert 206: #ifndef MAKE_BOOTSTRAP
207: typedef struct {
208: regex_t re;
209: int nsub;
210: regmatch_t *matches;
211: char *replace;
212: int flags;
213: } VarREPattern;
214: #endif
215:
1.38 espie 216: static struct hash_info var_info = {
217: offsetof(Var, name),
218: NULL, hash_alloc, hash_free, element_alloc };
219: static int quick_lookup __P((const char *, const char **, u_int32_t *));
1.23 espie 220: #define VarValue(v) Buf_Retrieve(&((v)->val))
1.32 espie 221: static int VarCmp __P((void *, void *));
1.39 espie 222: static Var *varfind __P((const char *, const char *, SymTable *, int, int, u_int32_t));
223: static Var *VarFind_interval __P((const char *, const char *, SymTable *, int));
224: #define VarFind(n, ctxt, flags) VarFind_interval(n, NULL, ctxt, flags)
225: static Var *VarAdd __P((const char *, const char *, GSymT *));
1.32 espie 226: static void VarDelete __P((void *));
1.40 espie 227: static Boolean VarHead __P((const char *, Boolean, Buffer, void *));
228: static Boolean VarTail __P((const char *, Boolean, Buffer, void *));
229: static Boolean VarSuffix __P((const char *, Boolean, Buffer, void *));
230: static Boolean VarRoot __P((const char *, Boolean, Buffer, void *));
231: static Boolean VarMatch __P((const char *, Boolean, Buffer, void *));
1.4 briggs 232: #ifdef SYSVVARSUB
1.40 espie 233: static Boolean VarSYSVMatch __P((const char *, Boolean, Buffer, void *));
1.4 briggs 234: #endif
1.40 espie 235: static Boolean VarNoMatch __P((const char *, Boolean, Buffer, void *));
1.6 millert 236: #ifndef MAKE_BOOTSTRAP
237: static void VarREError __P((int, regex_t *, const char *));
1.40 espie 238: static Boolean VarRESubstitute __P((const char *, Boolean, Buffer, void *));
1.6 millert 239: #endif
1.40 espie 240: static Boolean VarSubstitute __P((const char *, Boolean, Buffer, void *));
1.35 espie 241: static char *VarGetPattern __P((SymTable *, int, char **, int, int *, size_t *,
1.6 millert 242: VarPattern *));
1.40 espie 243: static char *VarQuote __P((const char *));
244: static char *VarModify __P((const char *, Boolean (*)(const char *, Boolean, Buffer, void *), void *));
1.42 ! espie 245: char *VarModifiers_Apply __P((char *, SymTable *, Boolean,
! 246: Boolean *, char *, char, size_t *));
1.32 espie 247: static void VarPrintVar __P((void *));
1.40 espie 248: static Boolean VarUppercase __P((const char *, Boolean, Buffer, void *));
249: static Boolean VarLowercase __P((const char *, Boolean, Buffer, void *));
1.38 espie 250: static const char *context_name __P((GSymT *));
1.39 espie 251: static Var *new_var __P((const char *, const char *));
252: static Var *getvar __P((GSymT *, const char *, const char *, u_int32_t));
1.37 espie 253:
254: void
255: SymTable_Init(ctxt)
256: SymTable *ctxt;
257: {
258: static SymTable sym_template;
259: memcpy(ctxt, &sym_template, sizeof(*ctxt));
260: }
261:
262: void
263: SymTable_Destroy(ctxt)
264: SymTable *ctxt;
265: {
266: int i;
267:
268: for (i = 0; i < LOCAL_SIZE; i++)
269: if (ctxt->locals[i] != NULL)
270: VarDelete(ctxt->locals[i]);
271: }
272:
1.38 espie 273: static int
274: quick_lookup(name, end, pk)
275: const char *name;
276: const char **end;
277: u_int32_t *pk;
278: {
279: size_t len;
280:
281: *pk = hash_interval(name, end);
282: len = *end - name;
283: /* substitute short version for long local name */
284: switch (*pk % MAGICSLOTS) { /* MAGICSLOTS should be the */
285: case K_LONGALLSRC % MAGICSLOTS: /* smallest constant yielding */
286: /* distinct case values */
287: if (*pk == K_LONGALLSRC && strncmp(name, LONGALLSRC, len) == 0 &&
288: len == strlen(LONGALLSRC))
289: return ALLSRC_INDEX;
290: break;
291: case K_LONGARCHIVE % MAGICSLOTS:
292: if (*pk == K_LONGARCHIVE && strncmp(name, LONGARCHIVE, len) == 0 &&
293: len == strlen(LONGARCHIVE))
294: return ARCHIVE_INDEX;
295: break;
296: case K_LONGIMPSRC % MAGICSLOTS:
297: if (*pk == K_LONGIMPSRC && strncmp(name, LONGIMPSRC, len) == 0 &&
298: len == strlen(LONGIMPSRC))
299: return IMPSRC_INDEX;
300: break;
301: case K_LONGMEMBER % MAGICSLOTS:
302: if (*pk == K_LONGMEMBER && strncmp(name, LONGMEMBER, len) == 0 &&
303: len == strlen(LONGMEMBER))
304: return MEMBER_INDEX;
305: break;
306: case K_LONGOODATE % MAGICSLOTS:
307: if (*pk == K_LONGOODATE && strncmp(name, LONGOODATE, len) == 0 &&
308: len == strlen(LONGOODATE))
309: return OODATE_INDEX;
310: break;
311: case K_LONGPREFIX % MAGICSLOTS:
312: if (*pk == K_LONGPREFIX && strncmp(name, LONGPREFIX, len) == 0 &&
313: len == strlen(LONGPREFIX))
314: return PREFIX_INDEX;
315: break;
316: case K_LONGTARGET % MAGICSLOTS:
317: if (*pk == K_LONGTARGET && strncmp(name, LONGTARGET, len) == 0 &&
318: len == strlen(LONGTARGET))
319: return TARGET_INDEX;
320: break;
321: case K_TARGET % MAGICSLOTS:
322: if (name[0] == TARGET[0] && len == 1)
323: return TARGET_INDEX;
324: break;
325: case K_OODATE % MAGICSLOTS:
326: if (name[0] == OODATE[0] && len == 1)
327: return OODATE_INDEX;
328: break;
329: case K_ALLSRC % MAGICSLOTS:
330: if (name[0] == ALLSRC[0] && len == 1)
331: return ALLSRC_INDEX;
332: break;
333: case K_IMPSRC % MAGICSLOTS:
334: if (name[0] == IMPSRC[0] && len == 1)
335: return IMPSRC_INDEX;
336: break;
337: case K_PREFIX % MAGICSLOTS:
338: if (name[0] == PREFIX[0] && len == 1)
339: return PREFIX_INDEX;
340: break;
341: case K_ARCHIVE % MAGICSLOTS:
342: if (name[0] == ARCHIVE[0] && len == 1)
343: return ARCHIVE_INDEX;
344: break;
345: case K_MEMBER % MAGICSLOTS:
346: if (name[0] == MEMBER[0] && len == 1)
347: return MEMBER_INDEX;
348: break;
349: default:
350: break;
351: }
352: return -1;
353: }
1.37 espie 354:
355: void
356: Varq_Set(idx, val, gn)
357: int idx;
358: char *val;
359: GNode *gn;
360: {
1.38 espie 361: /* We only look for a variable in the given context since anything set
362: * here will override anything in a lower context, so there's not much
363: * point in searching them all just to save a bit of memory... */
1.37 espie 364: Var *v = gn->context.locals[idx];
365:
366: if (v == NULL) {
367: v = new_var(varnames[idx], val);
368: v->flags = 0;
369: gn->context.locals[idx] = v;
370: } else {
371: Buf_Reset(&(v->val));
372: Buf_AddString(&(v->val), val);
373:
374: }
375: if (DEBUG(VAR))
376: printf("%s:%s = %s\n", gn->name, varnames[idx], val);
377: }
378:
379: void
380: Varq_Append(idx, val, gn)
381: int idx;
382: char *val;
383: GNode *gn;
384: {
385: Var *v = gn->context.locals[idx];
386:
387: if (v == NULL) {
388: v = new_var(varnames[idx], val);
389: v->flags = 0;
390: gn->context.locals[idx] = v;
391: } else {
392: Buf_AddSpace(&(v->val));
393: Buf_AddString(&(v->val), val);
394: }
395: if (DEBUG(VAR))
396: printf("%s:%s = %s\n", gn->name, varnames[idx], VarValue(v));
397: }
398:
399: char *
400: Varq_Value(idx, gn)
401: int idx;
402: GNode *gn;
403: {
404: Var *v = gn->context.locals[idx];
405:
406: if (v != NULL)
407: return VarValue(v);
408: else
409: return NULL;
410: }
411:
412: Boolean
413: Varq_Exists(idx, gn)
414: int idx;
415: GNode *gn;
416: {
417: return gn->context.locals[idx] != NULL;
418: }
1.1 deraadt 419:
1.35 espie 420:
1.38 espie 421: static const char *
1.35 espie 422: context_name(ctxt)
1.37 espie 423: GSymT *ctxt;
1.35 espie 424: {
425: if (ctxt == VAR_GLOBAL)
426: return "Global";
1.37 espie 427: else if (ctxt == VAR_CMD)
1.35 espie 428: return "Command";
1.37 espie 429: else
1.35 espie 430: return "Environment";
431: }
432:
1.37 espie 433: /* Create a variable, to pass to VarAdd. */
434: static Var *
435: new_var(name, val)
1.39 espie 436: const char *name;
437: const char *val;
1.37 espie 438: {
439: Var *v;
1.38 espie 440: const char *end = NULL;
1.37 espie 441:
1.38 espie 442: v = hash_create_entry(&var_info, name, &end);
1.37 espie 443:
444: if (val != NULL) {
445: size_t len = strlen(val);
446: Buf_Init(&(v->val), len+1);
447: Buf_AddChars(&(v->val), len, val);
448: } else
449: Buf_Init(&(v->val), 1);
450:
451: return v;
452: }
453:
1.38 espie 454: static Var *
455: getvar(ctxt, name, end, k)
456: GSymT *ctxt;
1.39 espie 457: const char *name;
1.38 espie 458: const char *end;
459: u_int32_t k;
1.1 deraadt 460: {
1.38 espie 461: return hash_find(ctxt, hash_lookup_interval(ctxt, name, end, k));
1.37 espie 462: }
463:
1.1 deraadt 464: /*-
465: *-----------------------------------------------------------------------
1.39 espie 466: * VarFind_interval --
1.1 deraadt 467: * Find the given variable in the given context and any other contexts
1.39 espie 468: * indicated. if end is NULL, name is a string, otherwise, only
469: * the interval name - end is concerned.
1.1 deraadt 470: *
471: * Results:
472: * A pointer to the structure describing the desired variable or
1.26 espie 473: * NULL if the variable does not exist.
1.1 deraadt 474: *
475: * Side Effects:
1.17 espie 476: * Caches env variables in the VAR_ENV context.
1.1 deraadt 477: *-----------------------------------------------------------------------
478: */
479: static Var *
1.39 espie 480: VarFind_interval(name, end, ctxt, flags)
481: const char *name; /* name to find */
482: const char *end; /* end of name */
1.35 espie 483: SymTable *ctxt; /* context in which to find it */
1.39 espie 484: int flags; /* FIND_MINE set means to look in the
485: * CTXT_GLOBAL and CTXT_CMD contexts also.
1.1 deraadt 486: * FIND_ENV set means to look in the
1.39 espie 487: * environment */
1.1 deraadt 488: {
1.38 espie 489: int idx;
490: u_int32_t k;
491:
492: idx = quick_lookup(name, &end, &k);
1.39 espie 493: return varfind(name, end, ctxt, flags, idx, k);
494: }
495:
496: static Var *
497: varfind(name, end, ctxt, flags, idx, k)
498: const char *name;
499: const char *end;
500: SymTable *ctxt;
501: int flags;
502: int idx;
503: u_int32_t k;
504: {
505: Var *v;
1.1 deraadt 506:
507: /*
508: * First look for the variable in the given context. If it's not there,
509: * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
510: * depending on the FIND_* flags in 'flags'
511: */
1.37 espie 512: if (ctxt == NULL)
513: v = NULL;
514: else if (ctxt == CTXT_GLOBAL || ctxt == CTXT_CMD || ctxt == CTXT_ENV)
1.38 espie 515: v = getvar((GSymT *)ctxt, name, end, k);
1.37 espie 516: else {
1.38 espie 517: if (idx == -1)
518: v = NULL;
519: else
520: v = ctxt->locals[idx];
1.37 espie 521: }
522: if (v != NULL)
523: return v;
524:
1.39 espie 525: if ((flags & FIND_MINE) && ctxt != CTXT_CMD)
1.38 espie 526: v = getvar(VAR_CMD, name, end, k);
1.37 espie 527: if (v != NULL)
528: return v;
529:
1.39 espie 530: if (!checkEnvFirst && (flags & FIND_MINE) && ctxt != CTXT_GLOBAL)
1.38 espie 531: v = getvar(VAR_GLOBAL, name, end, k);
1.37 espie 532: if (v != NULL)
533: return v;
534:
535: if ((flags & FIND_ENV)) {
536: char *env;
1.42 ! espie 537: char *n;
1.37 espie 538:
1.38 espie 539: v = getvar(VAR_ENV, name, end, k);
1.37 espie 540: if (v != NULL)
541: return v;
1.1 deraadt 542:
1.42 ! espie 543: /* getenv requires a null-terminated name */
! 544: n = interval_dup(name, end);
! 545: env = getenv(n);
! 546: free(n);
! 547: if (env != NULL)
1.37 espie 548: return VarAdd(name, env, VAR_ENV);
549: }
1.17 espie 550:
1.39 espie 551: if (checkEnvFirst && (flags & FIND_MINE) && ctxt != CTXT_GLOBAL)
1.38 espie 552: v = getvar(VAR_GLOBAL, name, end, k);
1.37 espie 553: return v;
1.1 deraadt 554: }
555:
556: /*-
557: *-----------------------------------------------------------------------
558: * VarAdd --
559: * Add a new variable of name name and value val to the given context
560: *
561: * Results:
1.17 espie 562: * The added variable
1.1 deraadt 563: *
564: * Side Effects:
565: * The new variable is placed at the front of the given context
566: * The name and val arguments are duplicated so they may
567: * safely be freed.
568: *-----------------------------------------------------------------------
569: */
1.17 espie 570: static Var *
571: VarAdd(name, val, ctxt)
1.39 espie 572: const char *name; /* name of variable to add */
573: const char *val; /* value to set it to */
1.37 espie 574: GSymT *ctxt; /* context in which to set it */
1.1 deraadt 575: {
1.38 espie 576: Var *v;
577: const char *end = NULL;
578: int idx;
579: u_int32_t k;
1.1 deraadt 580:
1.37 espie 581: v = new_var(name, val);
1.1 deraadt 582:
583: v->flags = 0;
584:
1.38 espie 585: idx = quick_lookup(name, &end, &k);
586:
587: if (idx != -1) {
588: Parse_Error(PARSE_FATAL, "Trying to set dynamic variable %s",
589: v->name);
590: } else
591: hash_insert(ctxt, hash_lookup_interval(ctxt, name, end, k), v);
1.17 espie 592: return v;
1.1 deraadt 593: }
594:
595:
596: /*-
597: *-----------------------------------------------------------------------
598: * VarDelete --
599: * Delete a variable and all the space associated with it.
600: *
601: * Results:
602: * None
603: *
604: * Side Effects:
605: * None
606: *-----------------------------------------------------------------------
607: */
608: static void
609: VarDelete(vp)
1.32 espie 610: void *vp;
1.1 deraadt 611: {
612: Var *v = (Var *) vp;
1.23 espie 613: Buf_Destroy(&(v->val));
614: free(v);
1.1 deraadt 615: }
616:
617:
618:
619: /*-
620: *-----------------------------------------------------------------------
621: * Var_Delete --
622: * Remove a variable from a context.
623: *
624: * Results:
625: * None.
626: *
627: * Side Effects:
628: * The Var structure is removed and freed.
629: *
630: *-----------------------------------------------------------------------
631: */
632: void
633: Var_Delete(name, ctxt)
634: char *name;
1.37 espie 635: GSymT *ctxt;
1.1 deraadt 636: {
1.38 espie 637: Var *v;
638: u_int32_t k;
639: const char *end = NULL;
1.1 deraadt 640:
1.37 espie 641: if (DEBUG(VAR))
1.35 espie 642: printf("%s:delete %s\n", context_name(ctxt), name);
1.38 espie 643: (void)quick_lookup(name, &end, &k);
644: v = hash_remove(ctxt, hash_lookup_interval(ctxt, name, end, k));
1.37 espie 645:
1.38 espie 646: if (v != NULL)
1.30 espie 647: VarDelete(v);
1.1 deraadt 648: }
649:
650: /*-
651: *-----------------------------------------------------------------------
652: * Var_Set --
653: * Set the variable name to the value val in the given context.
654: *
655: * Results:
656: * None.
657: *
658: * Side Effects:
659: * If the variable doesn't yet exist, a new record is created for it.
660: * Else the old value is freed and the new one stuck in its place
661: *
662: * Notes:
663: * The variable is searched for only in its context before being
664: * created in that context. I.e. if the context is VAR_GLOBAL,
665: * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
666: * VAR_CMD->context is searched. This is done to avoid the literally
667: * thousands of unnecessary strcmp's that used to be done to
668: * set, say, $(@) or $(<).
669: *-----------------------------------------------------------------------
670: */
671: void
1.35 espie 672: Var_Set(name, val, ctxt)
1.37 espie 673: char *name; /* name of variable to set */
674: char *val; /* value to give to the variable */
675: GSymT *ctxt; /* context in which to set it */
1.1 deraadt 676: {
677: register Var *v;
678:
679: /*
680: * We only look for a variable in the given context since anything set
681: * here will override anything in a lower context, so there's not much
682: * point in searching them all just to save a bit of memory...
683: */
1.37 espie 684: v = VarFind(name, (SymTable *)ctxt, 0);
1.38 espie 685: if (v == NULL)
1.17 espie 686: (void)VarAdd(name, val, ctxt);
1.38 espie 687: else {
1.23 espie 688: Buf_Reset(&(v->val));
689: Buf_AddString(&(v->val), val);
1.1 deraadt 690:
691: }
1.37 espie 692: if (DEBUG(VAR))
693: printf("%s:%s = %s\n", context_name(ctxt), name, val);
1.1 deraadt 694: /*
695: * Any variables given on the command line are automatically exported
1.17 espie 696: * to the environment (as per POSIX standard).
697: * We put them into the env cache directly.
698: * (Note that additions to VAR_CMD occur very early, so VAR_ENV is
699: * actually empty at this point).
1.1 deraadt 700: */
701: if (ctxt == VAR_CMD) {
702: setenv(name, val, 1);
1.17 espie 703: (void)VarAdd(name, val, VAR_ENV);
1.1 deraadt 704: }
705: }
706:
707: /*-
708: *-----------------------------------------------------------------------
709: * Var_Append --
710: * The variable of the given name has the given value appended to it in
711: * the given context.
712: *
713: * Results:
714: * None
715: *
716: * Side Effects:
717: * If the variable doesn't exist, it is created. Else the strings
718: * are concatenated (with a space in between).
719: *
720: * Notes:
721: * Only if the variable is being sought in the global context is the
722: * environment searched.
723: * XXX: Knows its calling circumstances in that if called with ctxt
724: * an actual target, it will only search that context since only
725: * a local variable could be being appended to. This is actually
726: * a big win and must be tolerated.
727: *-----------------------------------------------------------------------
728: */
729: void
1.35 espie 730: Var_Append(name, val, ctxt)
1.37 espie 731: char *name; /* Name of variable to modify */
732: char *val; /* String to append to it */
733: GSymT *ctxt; /* Context in which this should occur */
1.1 deraadt 734: {
735: register Var *v;
736:
1.37 espie 737: v = VarFind(name, (SymTable *)ctxt, (ctxt == VAR_GLOBAL) ? FIND_ENV : 0);
1.1 deraadt 738:
1.26 espie 739: if (v == NULL) {
1.17 espie 740: (void)VarAdd(name, val, ctxt);
1.1 deraadt 741: } else {
1.23 espie 742: Buf_AddSpace(&(v->val));
743: Buf_AddString(&(v->val), val);
1.1 deraadt 744:
745:
746: }
1.37 espie 747: if (DEBUG(VAR))
748: printf("%s:%s = %s\n", context_name(ctxt), name, VarValue(v));
1.1 deraadt 749: }
750:
751: /*-
752: *-----------------------------------------------------------------------
753: * Var_Exists --
754: * See if the given variable exists.
755: *
756: * Results:
757: * TRUE if it does, FALSE if it doesn't
758: *
759: * Side Effects:
760: * None.
761: *
762: *-----------------------------------------------------------------------
763: */
764: Boolean
765: Var_Exists(name, ctxt)
1.37 espie 766: char *name; /* Variable to find */
767: GSymT *ctxt; /* Context in which to start search */
1.1 deraadt 768: {
769: Var *v;
770:
1.39 espie 771: v = VarFind(name, (SymTable *)ctxt, FIND_MINE|FIND_ENV);
1.1 deraadt 772:
1.26 espie 773: if (v == NULL)
1.17 espie 774: return FALSE;
775: else
776: return TRUE;
1.1 deraadt 777: }
778:
779: /*-
780: *-----------------------------------------------------------------------
781: * Var_Value --
782: * Return the value of the named variable in the given context
783: *
784: * Results:
785: * The value if the variable exists, NULL if it doesn't
786: *
787: * Side Effects:
788: * None
789: *-----------------------------------------------------------------------
790: */
791: char *
1.18 espie 792: Var_Value(name, ctxt)
1.37 espie 793: char *name; /* name to find */
794: GSymT *ctxt; /* context in which to search for it */
1.1 deraadt 795: {
796: Var *v;
797:
1.39 espie 798: v = VarFind(name, (SymTable *)ctxt, FIND_ENV | FIND_MINE);
1.26 espie 799: if (v != NULL)
1.23 espie 800: return VarValue(v);
1.21 espie 801: else
1.17 espie 802: return NULL;
1.1 deraadt 803: }
804:
805: /*-
806: *-----------------------------------------------------------------------
1.11 espie 807: * VarUppercase --
808: * Place the Upper cased word in the given buffer.
809: *
810: * Results:
811: * TRUE if characters were added to the buffer (a space needs to be
812: * added to the buffer before the next word).
813: *
814: * Side Effects:
815: * The word is added to the buffer.
816: *
817: *-----------------------------------------------------------------------
818: */
819: static Boolean
1.40 espie 820: VarUppercase(word, addSpace, buf, dummy)
821: const char *word; /* Word to Upper Case */
1.11 espie 822: Boolean addSpace; /* True if need to add a space to the buffer
823: * before sticking in the head */
824: Buffer buf; /* Buffer in which to store it */
1.32 espie 825: void *dummy;
1.11 espie 826: {
827: size_t len = strlen(word);
828:
1.19 espie 829: if (addSpace)
830: Buf_AddSpace(buf);
831: while (len--)
1.16 espie 832: Buf_AddChar(buf, toupper(*word++));
1.40 espie 833: return TRUE;
1.11 espie 834: }
835:
836: /*-
837: *-----------------------------------------------------------------------
838: * VarLowercase --
839: * Place the Lower cased word in the given buffer.
840: *
841: * Results:
842: * TRUE if characters were added to the buffer (a space needs to be
843: * added to the buffer before the next word).
844: *
845: * Side Effects:
846: * The word is added to the buffer.
847: *
848: *-----------------------------------------------------------------------
849: */
850: static Boolean
1.40 espie 851: VarLowercase(word, addSpace, buf, dummy)
852: const char *word; /* Word to Lower Case */
1.11 espie 853: Boolean addSpace; /* True if need to add a space to the buffer
854: * before sticking in the head */
855: Buffer buf; /* Buffer in which to store it */
1.32 espie 856: void *dummy;
1.11 espie 857: {
858: size_t len = strlen(word);
859:
1.19 espie 860: if (addSpace)
861: Buf_AddSpace(buf);
862: while (len--)
1.16 espie 863: Buf_AddChar(buf, tolower(*word++));
1.40 espie 864: return TRUE;
1.11 espie 865: }
866:
867: /*-
868: *-----------------------------------------------------------------------
1.1 deraadt 869: * VarHead --
870: * Remove the tail of the given word and place the result in the given
871: * buffer.
872: *
873: * Results:
874: * TRUE if characters were added to the buffer (a space needs to be
875: * added to the buffer before the next word).
876: *
877: * Side Effects:
878: * The trimmed word is added to the buffer.
879: *
880: *-----------------------------------------------------------------------
881: */
882: static Boolean
1.32 espie 883: VarHead(word, addSpace, buf, dummy)
1.40 espie 884: const char *word; /* Word to trim */
1.1 deraadt 885: Boolean addSpace; /* True if need to add a space to the buffer
886: * before sticking in the head */
887: Buffer buf; /* Buffer in which to store it */
1.32 espie 888: void *dummy;
1.1 deraadt 889: {
1.40 espie 890: const char *slash;
1.1 deraadt 891:
1.19 espie 892: slash = strrchr(word, '/');
893: if (slash != NULL) {
894: if (addSpace)
895: Buf_AddSpace(buf);
896: Buf_AddInterval(buf, word, slash);
1.40 espie 897: return TRUE;
1.1 deraadt 898: } else {
1.19 espie 899: /* If no directory part, give . (q.v. the POSIX standard) */
900: if (addSpace)
901: Buf_AddString(buf, " .");
902: else
1.16 espie 903: Buf_AddChar(buf, '.');
1.1 deraadt 904: }
905: return(dummy ? TRUE : TRUE);
906: }
907:
908: /*-
909: *-----------------------------------------------------------------------
910: * VarTail --
911: * Remove the head of the given word and place the result in the given
912: * buffer.
913: *
914: * Results:
915: * TRUE if characters were added to the buffer (a space needs to be
916: * added to the buffer before the next word).
917: *
918: * Side Effects:
919: * The trimmed word is added to the buffer.
920: *
921: *-----------------------------------------------------------------------
922: */
923: static Boolean
1.32 espie 924: VarTail(word, addSpace, buf, dummy)
1.40 espie 925: const char *word; /* Word to trim */
1.1 deraadt 926: Boolean addSpace; /* TRUE if need to stick a space in the
927: * buffer before adding the tail */
928: Buffer buf; /* Buffer in which to store it */
1.32 espie 929: void *dummy;
1.1 deraadt 930: {
1.40 espie 931: const char *slash;
1.1 deraadt 932:
1.19 espie 933: if (addSpace)
934: Buf_AddSpace(buf);
935: slash = strrchr(word, '/');
936: if (slash != NULL)
937: Buf_AddString(buf, slash+1);
938: else
939: Buf_AddString(buf, word);
1.1 deraadt 940: return (dummy ? TRUE : TRUE);
941: }
942:
943: /*-
944: *-----------------------------------------------------------------------
945: * VarSuffix --
946: * Place the suffix of the given word in the given buffer.
947: *
948: * Results:
949: * TRUE if characters were added to the buffer (a space needs to be
950: * added to the buffer before the next word).
951: *
952: * Side Effects:
953: * The suffix from the word is placed in the buffer.
954: *
955: *-----------------------------------------------------------------------
956: */
957: static Boolean
1.32 espie 958: VarSuffix(word, addSpace, buf, dummy)
1.40 espie 959: const char *word; /* Word to trim */
1.1 deraadt 960: Boolean addSpace; /* TRUE if need to add a space before placing
961: * the suffix in the buffer */
962: Buffer buf; /* Buffer in which to store it */
1.32 espie 963: void *dummy;
1.1 deraadt 964: {
1.40 espie 965: const char *dot;
1.1 deraadt 966:
1.19 espie 967: dot = strrchr(word, '.');
968: if (dot != NULL) {
969: if (addSpace)
970: Buf_AddSpace(buf);
971: Buf_AddString(buf, dot+1);
1.1 deraadt 972: addSpace = TRUE;
973: }
974: return (dummy ? addSpace : addSpace);
975: }
976:
977: /*-
978: *-----------------------------------------------------------------------
979: * VarRoot --
980: * Remove the suffix of the given word and place the result in the
981: * buffer.
982: *
983: * Results:
984: * TRUE if characters were added to the buffer (a space needs to be
985: * added to the buffer before the next word).
986: *
987: * Side Effects:
988: * The trimmed word is added to the buffer.
989: *
990: *-----------------------------------------------------------------------
991: */
992: static Boolean
1.32 espie 993: VarRoot(word, addSpace, buf, dummy)
1.40 espie 994: const char *word; /* Word to trim */
1.1 deraadt 995: Boolean addSpace; /* TRUE if need to add a space to the buffer
996: * before placing the root in it */
997: Buffer buf; /* Buffer in which to store it */
1.32 espie 998: void *dummy;
1.1 deraadt 999: {
1.40 espie 1000: const char *dot;
1.1 deraadt 1001:
1.19 espie 1002: if (addSpace)
1003: Buf_AddSpace(buf);
1.1 deraadt 1004:
1.19 espie 1005: dot = strrchr(word, '.');
1006: if (dot != NULL)
1007: Buf_AddInterval(buf, word, dot);
1008: else
1009: Buf_AddString(buf, word);
1.1 deraadt 1010: return (dummy ? TRUE : TRUE);
1011: }
1012:
1013: /*-
1014: *-----------------------------------------------------------------------
1015: * VarMatch --
1016: * Place the word in the buffer if it matches the given pattern.
1017: * Callback function for VarModify to implement the :M modifier.
1.5 millert 1018: *
1.1 deraadt 1019: * Results:
1020: * TRUE if a space should be placed in the buffer before the next
1021: * word.
1022: *
1023: * Side Effects:
1024: * The word may be copied to the buffer.
1025: *
1026: *-----------------------------------------------------------------------
1027: */
1028: static Boolean
1.32 espie 1029: VarMatch(word, addSpace, buf, pattern)
1.40 espie 1030: const char *word; /* Word to examine */
1.1 deraadt 1031: Boolean addSpace; /* TRUE if need to add a space to the
1032: * buffer before adding the word, if it
1033: * matches */
1034: Buffer buf; /* Buffer in which to store it */
1.32 espie 1035: void *pattern; /* Pattern the word must match */
1.1 deraadt 1036: {
1037: if (Str_Match(word, (char *) pattern)) {
1.19 espie 1038: if (addSpace)
1039: Buf_AddSpace(buf);
1.1 deraadt 1040: addSpace = TRUE;
1.19 espie 1041: Buf_AddString(buf, word);
1.1 deraadt 1042: }
1.40 espie 1043: return addSpace;
1.1 deraadt 1044: }
1045:
1.4 briggs 1046: #ifdef SYSVVARSUB
1.1 deraadt 1047: /*-
1048: *-----------------------------------------------------------------------
1049: * VarSYSVMatch --
1050: * Place the word in the buffer if it matches the given pattern.
1051: * Callback function for VarModify to implement the System V %
1052: * modifiers.
1.5 millert 1053: *
1.1 deraadt 1054: * Results:
1055: * TRUE if a space should be placed in the buffer before the next
1056: * word.
1057: *
1058: * Side Effects:
1059: * The word may be copied to the buffer.
1060: *
1061: *-----------------------------------------------------------------------
1062: */
1063: static Boolean
1.32 espie 1064: VarSYSVMatch(word, addSpace, buf, patp)
1.40 espie 1065: const char *word; /* Word to examine */
1.1 deraadt 1066: Boolean addSpace; /* TRUE if need to add a space to the
1067: * buffer before adding the word, if it
1068: * matches */
1069: Buffer buf; /* Buffer in which to store it */
1.32 espie 1070: void *patp; /* Pattern the word must match */
1.1 deraadt 1071: {
1.40 espie 1072: size_t len;
1073: const char *ptr;
1.1 deraadt 1074: VarPattern *pat = (VarPattern *) patp;
1075:
1.7 deraadt 1076: if (*word) {
1077: if (addSpace)
1.19 espie 1078: Buf_AddSpace(buf);
1.7 deraadt 1079:
1080: addSpace = TRUE;
1081:
1082: if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL)
1083: Str_SYSVSubst(buf, pat->rhs, ptr, len);
1084: else
1.19 espie 1085: Buf_AddString(buf, word);
1.7 deraadt 1086: }
1.40 espie 1087: return addSpace;
1.1 deraadt 1088: }
1.4 briggs 1089: #endif
1.1 deraadt 1090:
1091:
1092: /*-
1093: *-----------------------------------------------------------------------
1094: * VarNoMatch --
1095: * Place the word in the buffer if it doesn't match the given pattern.
1096: * Callback function for VarModify to implement the :N modifier.
1.5 millert 1097: *
1.1 deraadt 1098: * Results:
1099: * TRUE if a space should be placed in the buffer before the next
1100: * word.
1101: *
1102: * Side Effects:
1103: * The word may be copied to the buffer.
1104: *
1105: *-----------------------------------------------------------------------
1106: */
1107: static Boolean
1.32 espie 1108: VarNoMatch(word, addSpace, buf, pattern)
1.40 espie 1109: const char *word; /* Word to examine */
1.1 deraadt 1110: Boolean addSpace; /* TRUE if need to add a space to the
1111: * buffer before adding the word, if it
1112: * matches */
1113: Buffer buf; /* Buffer in which to store it */
1.32 espie 1114: void *pattern; /* Pattern the word must match */
1.1 deraadt 1115: {
1116: if (!Str_Match(word, (char *) pattern)) {
1.19 espie 1117: if (addSpace)
1118: Buf_AddSpace(buf);
1.1 deraadt 1119: addSpace = TRUE;
1.19 espie 1120: Buf_AddString(buf, word);
1.1 deraadt 1121: }
1122: return(addSpace);
1123: }
1124:
1125:
1126: /*-
1127: *-----------------------------------------------------------------------
1128: * VarSubstitute --
1129: * Perform a string-substitution on the given word, placing the
1130: * result in the passed buffer.
1131: *
1132: * Results:
1133: * TRUE if a space is needed before more characters are added.
1134: *
1135: * Side Effects:
1136: * None.
1137: *
1138: *-----------------------------------------------------------------------
1139: */
1140: static Boolean
1.32 espie 1141: VarSubstitute(word, addSpace, buf, patternp)
1.40 espie 1142: const char *word; /* Word to modify */
1.1 deraadt 1143: Boolean addSpace; /* True if space should be added before
1144: * other characters */
1145: Buffer buf; /* Buffer for result */
1.32 espie 1146: void *patternp; /* Pattern for substitution */
1.1 deraadt 1147: {
1.40 espie 1148: size_t wordLen; /* Length of word */
1149: const char *cp; /* General pointer */
1.1 deraadt 1150: VarPattern *pattern = (VarPattern *) patternp;
1151:
1152: wordLen = strlen(word);
1.6 millert 1153: if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) !=
1154: (VAR_SUB_ONE|VAR_SUB_MATCHED)) {
1.1 deraadt 1155: /*
1.6 millert 1156: * Still substituting -- break it down into simple anchored cases
1.1 deraadt 1157: * and if none of them fits, perform the general substitution case.
1158: */
1159: if ((pattern->flags & VAR_MATCH_START) &&
1160: (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
1161: /*
1162: * Anchored at start and beginning of word matches pattern
1163: */
1164: if ((pattern->flags & VAR_MATCH_END) &&
1165: (wordLen == pattern->leftLen)) {
1166: /*
1167: * Also anchored at end and matches to the end (word
1168: * is same length as pattern) add space and rhs only
1169: * if rhs is non-null.
1170: */
1171: if (pattern->rightLen != 0) {
1.19 espie 1172: if (addSpace)
1173: Buf_AddSpace(buf);
1.1 deraadt 1174: addSpace = TRUE;
1.16 espie 1175: Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
1.1 deraadt 1176: }
1.6 millert 1177: pattern->flags |= VAR_SUB_MATCHED;
1.1 deraadt 1178: } else if (pattern->flags & VAR_MATCH_END) {
1179: /*
1180: * Doesn't match to end -- copy word wholesale
1181: */
1182: goto nosub;
1183: } else {
1184: /*
1185: * Matches at start but need to copy in trailing characters
1186: */
1187: if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
1.19 espie 1188: if (addSpace)
1189: Buf_AddSpace(buf);
1.1 deraadt 1190: addSpace = TRUE;
1191: }
1.16 espie 1192: Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
1193: Buf_AddChars(buf, wordLen - pattern->leftLen,
1194: word + pattern->leftLen);
1.6 millert 1195: pattern->flags |= VAR_SUB_MATCHED;
1.1 deraadt 1196: }
1197: } else if (pattern->flags & VAR_MATCH_START) {
1198: /*
1199: * Had to match at start of word and didn't -- copy whole word.
1200: */
1201: goto nosub;
1202: } else if (pattern->flags & VAR_MATCH_END) {
1203: /*
1204: * Anchored at end, Find only place match could occur (leftLen
1205: * characters from the end of the word) and see if it does. Note
1206: * that because the $ will be left at the end of the lhs, we have
1207: * to use strncmp.
1208: */
1209: cp = word + (wordLen - pattern->leftLen);
1210: if ((cp >= word) &&
1211: (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
1212: /*
1213: * Match found. If we will place characters in the buffer,
1214: * add a space before hand as indicated by addSpace, then
1215: * stuff in the initial, unmatched part of the word followed
1216: * by the right-hand-side.
1217: */
1218: if (((cp - word) + pattern->rightLen) != 0) {
1.19 espie 1219: if (addSpace)
1220: Buf_AddSpace(buf);
1.1 deraadt 1221: addSpace = TRUE;
1222: }
1.19 espie 1223: Buf_AddInterval(buf, word, cp);
1.16 espie 1224: Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
1.6 millert 1225: pattern->flags |= VAR_SUB_MATCHED;
1.1 deraadt 1226: } else {
1227: /*
1228: * Had to match at end and didn't. Copy entire word.
1229: */
1230: goto nosub;
1231: }
1232: } else {
1233: /*
1234: * Pattern is unanchored: search for the pattern in the word using
1235: * String_FindSubstring, copying unmatched portions and the
1236: * right-hand-side for each match found, handling non-global
1.5 millert 1237: * substitutions correctly, etc. When the loop is done, any
1.1 deraadt 1238: * remaining part of the word (word and wordLen are adjusted
1239: * accordingly through the loop) is copied straight into the
1240: * buffer.
1241: * addSpace is set FALSE as soon as a space is added to the
1242: * buffer.
1243: */
1244: register Boolean done;
1.16 espie 1245: size_t origSize;
1.1 deraadt 1246:
1247: done = FALSE;
1248: origSize = Buf_Size(buf);
1249: while (!done) {
1.15 espie 1250: cp = strstr(word, pattern->lhs);
1.1 deraadt 1251: if (cp != (char *)NULL) {
1252: if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
1.19 espie 1253: Buf_AddSpace(buf);
1.1 deraadt 1254: addSpace = FALSE;
1255: }
1.19 espie 1256: Buf_AddInterval(buf, word, cp);
1.16 espie 1257: Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
1.1 deraadt 1258: wordLen -= (cp - word) + pattern->leftLen;
1259: word = cp + pattern->leftLen;
1.5 millert 1260: if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){
1.1 deraadt 1261: done = TRUE;
1262: }
1.6 millert 1263: pattern->flags |= VAR_SUB_MATCHED;
1.1 deraadt 1264: } else {
1265: done = TRUE;
1266: }
1267: }
1268: if (wordLen != 0) {
1.19 espie 1269: if (addSpace)
1270: Buf_AddSpace(buf);
1.16 espie 1271: Buf_AddChars(buf, wordLen, word);
1.1 deraadt 1272: }
1273: /*
1274: * If added characters to the buffer, need to add a space
1275: * before we add any more. If we didn't add any, just return
1276: * the previous value of addSpace.
1277: */
1.16 espie 1278: return (Buf_Size(buf) != origSize || addSpace);
1.1 deraadt 1279: }
1280: return (addSpace);
1281: }
1282: nosub:
1.19 espie 1283: if (addSpace)
1284: Buf_AddSpace(buf);
1.16 espie 1285: Buf_AddChars(buf, wordLen, word);
1.1 deraadt 1286: return(TRUE);
1287: }
1288:
1.6 millert 1289: #ifndef MAKE_BOOTSTRAP
1290: /*-
1291: *-----------------------------------------------------------------------
1292: * VarREError --
1293: * Print the error caused by a regcomp or regexec call.
1294: *
1295: * Results:
1296: * None.
1297: *
1298: * Side Effects:
1299: * An error gets printed.
1300: *
1301: *-----------------------------------------------------------------------
1302: */
1303: static void
1304: VarREError(err, pat, str)
1305: int err;
1306: regex_t *pat;
1307: const char *str;
1308: {
1309: char *errbuf;
1310: int errlen;
1311:
1312: errlen = regerror(err, pat, 0, 0);
1313: errbuf = emalloc(errlen);
1314: regerror(err, pat, errbuf, errlen);
1315: Error("%s: %s", str, errbuf);
1316: free(errbuf);
1317: }
1318:
1319: /*-
1320: *-----------------------------------------------------------------------
1321: * VarRESubstitute --
1322: * Perform a regex substitution on the given word, placing the
1323: * result in the passed buffer.
1324: *
1325: * Results:
1326: * TRUE if a space is needed before more characters are added.
1327: *
1328: * Side Effects:
1329: * None.
1330: *
1331: *-----------------------------------------------------------------------
1332: */
1333: static Boolean
1334: VarRESubstitute(word, addSpace, buf, patternp)
1.40 espie 1335: const char *word;
1.6 millert 1336: Boolean addSpace;
1337: Buffer buf;
1.32 espie 1338: void *patternp;
1.6 millert 1339: {
1340: VarREPattern *pat;
1341: int xrv;
1.40 espie 1342: const char *wp;
1.6 millert 1343: char *rp;
1344: int added;
1345:
1346: #define MAYBE_ADD_SPACE() \
1347: if (addSpace && !added) \
1.19 espie 1348: Buf_AddSpace(buf); \
1.6 millert 1349: added = 1
1350:
1351: added = 0;
1352: wp = word;
1353: pat = patternp;
1354:
1355: if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==
1356: (VAR_SUB_ONE|VAR_SUB_MATCHED))
1357: xrv = REG_NOMATCH;
1358: else {
1359: tryagain:
1360: xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, 0);
1361: }
1362:
1363: switch (xrv) {
1364: case 0:
1365: pat->flags |= VAR_SUB_MATCHED;
1366: if (pat->matches[0].rm_so > 0) {
1367: MAYBE_ADD_SPACE();
1.16 espie 1368: Buf_AddChars(buf, pat->matches[0].rm_so, wp);
1.6 millert 1369: }
1370:
1371: for (rp = pat->replace; *rp; rp++) {
1372: if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
1373: MAYBE_ADD_SPACE();
1.16 espie 1374: Buf_AddChar(buf, rp[1]);
1.6 millert 1375: rp++;
1376: }
1377: else if ((*rp == '&') || ((*rp == '\\') && isdigit(rp[1]))) {
1378: int n;
1.40 espie 1379: const char *subbuf;
1.6 millert 1380: int sublen;
1381: char errstr[3];
1382:
1383: if (*rp == '&') {
1384: n = 0;
1385: errstr[0] = '&';
1386: errstr[1] = '\0';
1387: } else {
1388: n = rp[1] - '0';
1389: errstr[0] = '\\';
1390: errstr[1] = rp[1];
1391: errstr[2] = '\0';
1392: rp++;
1393: }
1394:
1395: if (n > pat->nsub) {
1396: Error("No subexpression %s", &errstr[0]);
1397: subbuf = "";
1398: sublen = 0;
1399: } else if ((pat->matches[n].rm_so == -1) &&
1400: (pat->matches[n].rm_eo == -1)) {
1401: Error("No match for subexpression %s", &errstr[0]);
1402: subbuf = "";
1403: sublen = 0;
1404: } else {
1405: subbuf = wp + pat->matches[n].rm_so;
1406: sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
1407: }
1408:
1409: if (sublen > 0) {
1410: MAYBE_ADD_SPACE();
1.16 espie 1411: Buf_AddChars(buf, sublen, subbuf);
1.6 millert 1412: }
1413: } else {
1414: MAYBE_ADD_SPACE();
1.16 espie 1415: Buf_AddChar(buf, *rp);
1.6 millert 1416: }
1417: }
1418: wp += pat->matches[0].rm_eo;
1419: if (pat->flags & VAR_SUB_GLOBAL)
1420: goto tryagain;
1421: if (*wp) {
1422: MAYBE_ADD_SPACE();
1.16 espie 1423: Buf_AddChars(buf, strlen(wp), wp);
1.6 millert 1424: }
1425: break;
1426: default:
1427: VarREError(xrv, &pat->re, "Unexpected regex error");
1428: /* fall through */
1429: case REG_NOMATCH:
1430: if (*wp) {
1431: MAYBE_ADD_SPACE();
1.16 espie 1432: Buf_AddChars(buf, strlen(wp), wp);
1.6 millert 1433: }
1434: break;
1435: }
1436: return(addSpace||added);
1437: }
1438: #endif
1439:
1.1 deraadt 1440: /*-
1441: *-----------------------------------------------------------------------
1442: * VarModify --
1443: * Modify each of the words of the passed string using the given
1444: * function. Used to implement all modifiers.
1445: *
1446: * Results:
1447: * A string of all the words modified appropriately.
1448: *
1449: *-----------------------------------------------------------------------
1450: */
1451: static char *
1452: VarModify (str, modProc, datum)
1.40 espie 1453: const char *str; /* String whose words should be trimmed */
1.1 deraadt 1454: /* Function to use to modify them */
1.40 espie 1455: Boolean (*modProc) __P((const char *, Boolean, Buffer, void *));
1.32 espie 1456: void *datum; /* Datum to pass it */
1.1 deraadt 1457: {
1.23 espie 1458: BUFFER buf; /* Buffer for the new string */
1.1 deraadt 1459: Boolean addSpace; /* TRUE if need to add a space to the
1460: * buffer before adding the trimmed
1461: * word */
1.40 espie 1462: char **av; /* word list */
1463: char *as; /* word list memory */
1.1 deraadt 1464: int ac, i;
1465:
1.23 espie 1466: Buf_Init(&buf, 0);
1.1 deraadt 1467: addSpace = FALSE;
1468:
1.10 espie 1469: av = brk_string(str, &ac, FALSE, &as);
1.1 deraadt 1470:
1.10 espie 1471: for (i = 0; i < ac; i++)
1.23 espie 1472: addSpace = (*modProc)(av[i], addSpace, &buf, datum);
1.5 millert 1473:
1.10 espie 1474: free(as);
1475: free(av);
1.23 espie 1476: return Buf_Retrieve(&buf);
1.1 deraadt 1477: }
1478:
1479: /*-
1480: *-----------------------------------------------------------------------
1.6 millert 1481: * VarGetPattern --
1482: * Pass through the tstr looking for 1) escaped delimiters,
1483: * '$'s and backslashes (place the escaped character in
1484: * uninterpreted) and 2) unescaped $'s that aren't before
1485: * the delimiter (expand the variable substitution).
1486: * Return the expanded string or NULL if the delimiter was missing
1.10 espie 1487: * If pattern is specified, handle escaped ampersands, and replace
1.6 millert 1488: * unescaped ampersands with the lhs of the pattern.
1489: *
1490: * Results:
1491: * A string of all the words modified appropriately.
1492: * If length is specified, return the string length of the buffer
1493: * If flags is specified and the last character of the pattern is a
1494: * $ set the VAR_MATCH_END bit of flags.
1495: *
1496: * Side Effects:
1497: * None.
1498: *-----------------------------------------------------------------------
1499: */
1500: static char *
1501: VarGetPattern(ctxt, err, tstr, delim, flags, length, pattern)
1.35 espie 1502: SymTable *ctxt;
1.6 millert 1503: int err;
1504: char **tstr;
1505: int delim;
1506: int *flags;
1.16 espie 1507: size_t *length;
1.6 millert 1508: VarPattern *pattern;
1509: {
1510: char *cp;
1.23 espie 1511: BUFFER buf;
1.29 espie 1512: size_t junk;
1.23 espie 1513:
1514: Buf_Init(&buf, 0);
1.6 millert 1515: if (length == NULL)
1516: length = &junk;
1517:
1518: #define IS_A_MATCH(cp, delim) \
1519: ((cp[0] == '\\') && ((cp[1] == delim) || \
1520: (cp[1] == '\\') || (cp[1] == '$') || (pattern && (cp[1] == '&'))))
1521:
1522: /*
1523: * Skim through until the matching delimiter is found;
1524: * pick up variable substitutions on the way. Also allow
1525: * backslashes to quote the delimiter, $, and \, but don't
1526: * touch other backslashes.
1527: */
1528: for (cp = *tstr; *cp && (*cp != delim); cp++) {
1529: if (IS_A_MATCH(cp, delim)) {
1.23 espie 1530: Buf_AddChar(&buf, cp[1]);
1.6 millert 1531: cp++;
1532: } else if (*cp == '$') {
1533: if (cp[1] == delim) {
1534: if (flags == NULL)
1.23 espie 1535: Buf_AddChar(&buf, *cp);
1.6 millert 1536: else
1537: /*
1538: * Unescaped $ at end of pattern => anchor
1539: * pattern at end.
1540: */
1541: *flags |= VAR_MATCH_END;
1542: }
1543: else {
1544: char *cp2;
1.29 espie 1545: size_t len;
1.6 millert 1546: Boolean freeIt;
1547:
1548: /*
1549: * If unescaped dollar sign not before the
1550: * delimiter, assume it's a variable
1551: * substitution and recurse.
1552: */
1553: cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
1.23 espie 1554: Buf_AddString(&buf, cp2);
1.6 millert 1555: if (freeIt)
1556: free(cp2);
1557: cp += len - 1;
1558: }
1559: }
1560: else if (pattern && *cp == '&')
1.23 espie 1561: Buf_AddChars(&buf, pattern->leftLen, pattern->lhs);
1.6 millert 1562: else
1.23 espie 1563: Buf_AddChar(&buf, *cp);
1.6 millert 1564: }
1565:
1566: if (*cp != delim) {
1567: *tstr = cp;
1568: *length = 0;
1569: return NULL;
1570: }
1571: else {
1572: *tstr = ++cp;
1.23 espie 1573: *length = Buf_Size(&buf);
1574: return Buf_Retrieve(&buf);
1.6 millert 1575: }
1576: }
1577:
1578: /*-
1579: *-----------------------------------------------------------------------
1580: * VarQuote --
1581: * Quote shell meta-characters in the string
1582: *
1583: * Results:
1584: * The quoted string
1585: *
1586: *-----------------------------------------------------------------------
1587: */
1588: static char *
1589: VarQuote(str)
1.40 espie 1590: const char *str;
1.6 millert 1591: {
1592:
1.23 espie 1593: BUFFER buf;
1.6 millert 1594: /* This should cover most shells :-( */
1595: static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
1596:
1.23 espie 1597: Buf_Init(&buf, MAKE_BSIZE);
1.6 millert 1598: for (; *str; str++) {
1599: if (strchr(meta, *str) != NULL)
1.23 espie 1600: Buf_AddChar(&buf, '\\');
1601: Buf_AddChar(&buf, *str);
1.6 millert 1602: }
1.23 espie 1603: return Buf_Retrieve(&buf);
1.6 millert 1604: }
1605:
1606: /*-
1607: *-----------------------------------------------------------------------
1.1 deraadt 1608: * Var_Parse --
1609: * Given the start of a variable invocation, extract the variable
1610: * name and find its value, then modify it according to the
1611: * specification.
1612: *
1613: * Results:
1614: * The (possibly-modified) value of the variable or var_Error if the
1615: * specification is invalid. The length of the specification is
1616: * placed in *lengthPtr (for invalid specifications, this is just
1617: * 2...?).
1618: * A Boolean in *freePtr telling whether the returned string should
1619: * be freed by the caller.
1620: *
1621: * Side Effects:
1622: * None.
1623: *
1624: *-----------------------------------------------------------------------
1625: */
1626: char *
1.35 espie 1627: Var_Parse(str, ctxt, err, lengthPtr, freePtr)
1.1 deraadt 1628: char *str; /* The string to parse */
1.35 espie 1629: SymTable *ctxt; /* The context for the variable */
1.1 deraadt 1630: Boolean err; /* TRUE if undefined variables are an error */
1.29 espie 1631: size_t *lengthPtr; /* OUT: The length of the specification */
1.1 deraadt 1632: Boolean *freePtr; /* OUT: TRUE if caller should free result */
1633: {
1.42 ! espie 1634: char *tstr; /* Pointer into str */
1.1 deraadt 1635: Var *v; /* Variable in invocation */
1636: Boolean haveModifier;/* TRUE if have modifiers for the variable */
1.42 ! espie 1637: char endc; /* Ending character when variable in parens
1.1 deraadt 1638: * or braces */
1639: char *start;
1640: Boolean dynamic; /* TRUE if the variable is local and we're
1641: * expanding it in a non-local context. This
1642: * is done to support dynamic sources. The
1643: * result is just the invocation, unaltered */
1.5 millert 1644:
1.1 deraadt 1645: *freePtr = FALSE;
1646: dynamic = FALSE;
1647: start = str;
1.5 millert 1648:
1.1 deraadt 1649: if (str[1] != '(' && str[1] != '{') {
1650: /*
1651: * If it's not bounded by braces of some sort, life is much simpler.
1652: * We just need to check for the first character and return the
1653: * value if it exists.
1654: */
1.39 espie 1655: v = VarFind_interval(str+1, str+2, ctxt, FIND_ENV | FIND_MINE);
1.26 espie 1656: if (v == NULL) {
1.1 deraadt 1657: *lengthPtr = 2;
1.5 millert 1658:
1.37 espie 1659: if (ctxt == CTXT_CMD || ctxt == CTXT_GLOBAL || ctxt == NULL) {
1.1 deraadt 1660: /*
1661: * If substituting a local variable in a non-local context,
1662: * assume it's for dynamic source stuff. We have to handle
1663: * this specially and return the longhand for the variable
1664: * with the dollar sign escaped so it makes it back to the
1665: * caller. Only four of the local variables are treated
1666: * specially as they are the only four that will be set
1667: * when dynamic sources are expanded.
1668: */
1669: switch (str[1]) {
1670: case '@':
1.42 ! espie 1671: return "$(.TARGET)";
1.1 deraadt 1672: case '%':
1.42 ! espie 1673: return "$(.ARCHIVE)";
1.1 deraadt 1674: case '*':
1.42 ! espie 1675: return "$(.PREFIX)";
1.1 deraadt 1676: case '!':
1.42 ! espie 1677: return "$(.MEMBER)";
1.1 deraadt 1678: }
1679: }
1.42 ! espie 1680: /* Error. */
! 1681: return err ? var_Error : varNoError;
1.1 deraadt 1682: } else {
1683: haveModifier = FALSE;
1684: tstr = &str[1];
1685: endc = str[1];
1686: }
1687: } else {
1.42 ! espie 1688: endc = str[1] == '(' ? ')' : '}';
1.1 deraadt 1689:
1.42 ! espie 1690: /* Skip to the end character or a colon, whichever comes first. */
! 1691: for (tstr = str + 2; *tstr != '\0' && *tstr != endc && *tstr != ':';)
! 1692: tstr++;
! 1693: if (*tstr == ':')
1.1 deraadt 1694: haveModifier = TRUE;
1.42 ! espie 1695: else if (*tstr != '\0')
1.1 deraadt 1696: haveModifier = FALSE;
1.42 ! espie 1697: else {
1.1 deraadt 1698: /*
1699: * If we never did find the end character, return NULL
1700: * right now, setting the length to be the distance to
1701: * the end of the string, since that's what make does.
1702: */
1703: *lengthPtr = tstr - str;
1.42 ! espie 1704: return var_Error;
1.1 deraadt 1705: }
1.5 millert 1706:
1.39 espie 1707: v = VarFind_interval(str + 2, tstr, ctxt, FIND_ENV | FIND_MINE);
1.37 espie 1708: if (v == NULL && ctxt != CTXT_CMD && ctxt != CTXT_GLOBAL &&
1.36 espie 1709: ctxt != NULL &&
1710: (tstr-str) == 4 && (str[3] == 'F' || str[3] == 'D'))
1.1 deraadt 1711: {
1712: /*
1713: * Check for bogus D and F forms of local variables since we're
1714: * in a local context and the name is the right length.
1715: */
1.42 ! espie 1716: switch (str[2]) {
1.1 deraadt 1717: case '@':
1718: case '%':
1719: case '*':
1720: case '!':
1721: case '>':
1722: case '<':
1723: {
1724: char *val;
1725:
1.39 espie 1726: /* Well, it's local -- go look for it. */
1727: v = VarFind_interval(str+2, str+3, ctxt, 0);
1.5 millert 1728:
1.26 espie 1729: if (v != NULL) {
1.42 ! espie 1730: /* No need for nested expansion or anything, as we're
1.1 deraadt 1731: * the only one who sets these things and we sure don't
1.42 ! espie 1732: * but nested invocations in them... */
1.23 espie 1733: val = VarValue(v);
1.5 millert 1734:
1.42 ! espie 1735: if (str[3] == 'D')
! 1736: val = Var_GetHead(val);
! 1737: else
! 1738: val = Var_GetTail(val);
! 1739: /* Resulting string is dynamically allocated, so
! 1740: * tell caller to free it. */
1.1 deraadt 1741: *freePtr = TRUE;
1742: *lengthPtr = tstr-start+1;
1743: *tstr = endc;
1.42 ! espie 1744: return val;
1.1 deraadt 1745: }
1746: break;
1747: }
1748: }
1749: }
1.5 millert 1750:
1.26 espie 1751: if (v == NULL) {
1.36 espie 1752: if ((tstr-str == 3 ||
1.42 ! espie 1753: (tstr-str == 4 && (str[3] == 'F' ||
! 1754: str[3] == 'D'))) &&
1.37 espie 1755: (ctxt == CTXT_CMD || ctxt == CTXT_GLOBAL || ctxt == NULL))
1.1 deraadt 1756: {
1.42 ! espie 1757: /* If substituting a local variable in a non-local context,
1.1 deraadt 1758: * assume it's for dynamic source stuff. We have to handle
1759: * this specially and return the longhand for the variable
1760: * with the dollar sign escaped so it makes it back to the
1761: * caller. Only four of the local variables are treated
1762: * specially as they are the only four that will be set
1.42 ! espie 1763: * when dynamic sources are expanded. */
1.1 deraadt 1764: switch (str[2]) {
1765: case '@':
1766: case '%':
1767: case '*':
1768: case '!':
1769: dynamic = TRUE;
1770: break;
1771: }
1.42 ! espie 1772: } else if (tstr-str > 4 && str[2] == '.' &&
1.1 deraadt 1773: isupper((unsigned char) str[3]) &&
1.37 espie 1774: (ctxt == CTXT_CMD || ctxt == CTXT_GLOBAL || ctxt == NULL))
1.1 deraadt 1775: {
1776: int len;
1.5 millert 1777:
1.1 deraadt 1778: len = (tstr-str) - 3;
1779: if ((strncmp(str+2, ".TARGET", len) == 0) ||
1780: (strncmp(str+2, ".ARCHIVE", len) == 0) ||
1781: (strncmp(str+2, ".PREFIX", len) == 0) ||
1.42 ! espie 1782: (strncmp(str+2, ".MEMBER", len) == 0)) {
1.1 deraadt 1783: dynamic = TRUE;
1784: }
1785: }
1.5 millert 1786:
1.1 deraadt 1787: if (!haveModifier) {
1.42 ! espie 1788: /* No modifiers -- have specification length so we can return
! 1789: * now. */
1.1 deraadt 1790: *lengthPtr = tstr - start + 1;
1791: *tstr = endc;
1792: if (dynamic) {
1.42 ! espie 1793: char *n;
! 1794: n = emalloc(*lengthPtr + 1);
! 1795: strncpy(n, start, *lengthPtr);
! 1796: n[*lengthPtr] = '\0';
1.1 deraadt 1797: *freePtr = TRUE;
1.42 ! espie 1798: return n;
! 1799: } else
! 1800: return err ? var_Error : varNoError;
1.1 deraadt 1801: } else {
1.42 ! espie 1802: /* Still need to get to the end of the variable specification,
! 1803: * so kludge up a Var structure for the modifications */
1.37 espie 1804: v = new_var(str+1, NULL); /* junk has name, for error reports */
1.1 deraadt 1805: v->flags = VAR_JUNK;
1806: }
1807: }
1808: }
1809:
1.42 ! espie 1810: if (v->flags & VAR_IN_USE)
1.1 deraadt 1811: Fatal("Variable %s is recursive.", v->name);
1812: /*NOTREACHED*/
1.42 ! espie 1813: else
1.1 deraadt 1814: v->flags |= VAR_IN_USE;
1.42 ! espie 1815: /* Before doing any modification, we have to make sure the value
1.1 deraadt 1816: * has been fully expanded. If it looks like recursion might be
1817: * necessary (there's a dollar sign somewhere in the variable's value)
1818: * we just call Var_Subst to do any other substitutions that are
1819: * necessary. Note that the value returned by Var_Subst will have
1820: * been dynamically-allocated, so it will need freeing when we
1.42 ! espie 1821: * return. */
1.23 espie 1822: str = VarValue(v);
1.42 ! espie 1823: if (strchr(str, '$') != NULL) {
1.24 espie 1824: str = Var_Subst(str, ctxt, err);
1.1 deraadt 1825: *freePtr = TRUE;
1826: }
1.5 millert 1827:
1.1 deraadt 1828: v->flags &= ~VAR_IN_USE;
1.5 millert 1829:
1.42 ! espie 1830: *lengthPtr = tstr - start + 1;
! 1831: if (str != NULL && haveModifier)
! 1832: str = VarModifiers_Apply(str, ctxt, err, freePtr, tstr+1, endc,
! 1833: lengthPtr);
! 1834:
! 1835: if (v->flags & VAR_JUNK) {
! 1836: /* Perform any free'ing needed and set *freePtr to FALSE so the caller
! 1837: * doesn't try to free a static pointer. */
! 1838: if (*freePtr)
! 1839: free(str);
! 1840: *freePtr = FALSE;
! 1841: Buf_Destroy(&(v->val));
! 1842: free(v);
! 1843: if (dynamic) {
! 1844: str = emalloc(*lengthPtr + 1);
! 1845: strncpy(str, start, *lengthPtr);
! 1846: str[*lengthPtr] = '\0';
! 1847: *freePtr = TRUE;
! 1848: } else {
! 1849: str = err ? var_Error : varNoError;
! 1850: }
! 1851: }
! 1852: return str;
! 1853: }
! 1854:
! 1855: char *
! 1856: VarModifiers_Apply(str, ctxt, err, freePtr, start, endc, lengthPtr)
! 1857: char *str;
! 1858: SymTable *ctxt;
! 1859: Boolean err;
! 1860: Boolean *freePtr;
! 1861: char *start;
! 1862: char endc;
! 1863: size_t *lengthPtr;
! 1864: {
! 1865: char *tstr;
! 1866: char delim;
! 1867: char *cp;
! 1868:
! 1869: tstr = start;
! 1870:
1.1 deraadt 1871: /*
1872: * Now we need to apply any modifiers the user wants applied.
1873: * These are:
1874: * :M<pattern> words which match the given <pattern>.
1875: * <pattern> is of the standard file
1876: * wildcarding form.
1877: * :S<d><pat1><d><pat2><d>[g]
1878: * Substitute <pat2> for <pat1> in the value
1.6 millert 1879: * :C<d><pat1><d><pat2><d>[g]
1880: * Substitute <pat2> for regex <pat1> in the value
1.1 deraadt 1881: * :H Substitute the head of each word
1882: * :T Substitute the tail of each word
1883: * :E Substitute the extension (minus '.') of
1884: * each word
1885: * :R Substitute the root of each word
1886: * (pathname minus the suffix).
1887: * :lhs=rhs Like :S, but the rhs goes to the end of
1888: * the invocation.
1889: */
1.42 ! espie 1890: while (*tstr != endc) {
! 1891: char *newStr; /* New value to return */
! 1892: char termc; /* Character which terminated scan */
! 1893:
! 1894: if (DEBUG(VAR))
! 1895: printf("Applying :%c to \"%s\"\n", *tstr, str);
! 1896: switch (*tstr) {
! 1897: case 'N':
! 1898: case 'M':
! 1899: {
! 1900: for (cp = tstr + 1;
! 1901: *cp != '\0' && *cp != ':' && *cp != endc;
! 1902: cp++) {
! 1903: if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){
! 1904: cp++;
! 1905: }
! 1906: }
! 1907: termc = *cp;
! 1908: *cp = '\0';
! 1909: if (*tstr == 'M')
! 1910: newStr = VarModify(str, VarMatch, tstr+1);
! 1911: else
! 1912: newStr = VarModify(str, VarNoMatch, tstr+1);
! 1913: break;
! 1914: }
! 1915: case 'S':
! 1916: {
! 1917: VarPattern pattern;
! 1918:
! 1919: pattern.flags = 0;
! 1920: delim = tstr[1];
! 1921: tstr += 2;
! 1922:
! 1923: /* If pattern begins with '^', it is anchored to the
! 1924: * start of the word -- skip over it and flag pattern. */
! 1925: if (*tstr == '^') {
! 1926: pattern.flags |= VAR_MATCH_START;
! 1927: tstr++;
! 1928: }
1.5 millert 1929:
1.42 ! espie 1930: cp = tstr;
! 1931: if ((pattern.lhs = VarGetPattern(ctxt, err, &cp, delim,
! 1932: &pattern.flags, &pattern.leftLen, NULL)) == NULL)
! 1933: goto cleanup;
! 1934:
! 1935: if ((pattern.rhs = VarGetPattern(ctxt, err, &cp, delim,
! 1936: NULL, &pattern.rightLen, &pattern)) == NULL)
! 1937: goto cleanup;
! 1938:
! 1939: /* Check for global substitution. If 'g' after the final
! 1940: * delimiter, substitution is global and is marked that
! 1941: * way. */
! 1942: for (;; cp++) {
! 1943: switch (*cp) {
! 1944: case 'g':
! 1945: pattern.flags |= VAR_SUB_GLOBAL;
! 1946: continue;
! 1947: case '1':
! 1948: pattern.flags |= VAR_SUB_ONE;
! 1949: continue;
1.1 deraadt 1950: }
1951: break;
1952: }
1953:
1.42 ! espie 1954: termc = *cp;
! 1955: newStr = VarModify(str, VarSubstitute, &pattern);
! 1956:
! 1957: /* Free the two strings. */
! 1958: free(pattern.lhs);
! 1959: free(pattern.rhs);
! 1960: break;
! 1961: }
! 1962: #ifndef MAKE_BOOTSTRAP
! 1963: case 'C':
! 1964: {
! 1965: VarREPattern pattern;
! 1966: char *re;
! 1967: int error;
! 1968:
! 1969: pattern.flags = 0;
! 1970: delim = tstr[1];
! 1971: tstr += 2;
! 1972:
! 1973: cp = tstr;
! 1974:
! 1975: if ((re = VarGetPattern(ctxt, err, &cp, delim, NULL,
! 1976: NULL, NULL)) == NULL)
! 1977: goto cleanup;
1.6 millert 1978:
1.42 ! espie 1979: if ((pattern.replace = VarGetPattern(ctxt, err, &cp,
! 1980: delim, NULL, NULL, NULL)) == NULL) {
! 1981: free(re);
! 1982: goto cleanup;
! 1983: }
! 1984:
! 1985: for (;; cp++) {
! 1986: switch (*cp) {
! 1987: case 'g':
! 1988: pattern.flags |= VAR_SUB_GLOBAL;
! 1989: continue;
! 1990: case '1':
! 1991: pattern.flags |= VAR_SUB_ONE;
! 1992: continue;
1.1 deraadt 1993: }
1.42 ! espie 1994: break;
! 1995: }
1.1 deraadt 1996:
1.42 ! espie 1997: termc = *cp;
1.5 millert 1998:
1.42 ! espie 1999: error = regcomp(&pattern.re, re, REG_EXTENDED);
! 2000: free(re);
! 2001: if (error) {
! 2002: *lengthPtr = cp - start + 1;
! 2003: VarREError(error, &pattern.re, "RE substitution error");
! 2004: free(pattern.replace);
! 2005: return var_Error;
! 2006: }
1.1 deraadt 2007:
1.42 ! espie 2008: pattern.nsub = pattern.re.re_nsub + 1;
! 2009: if (pattern.nsub < 1)
! 2010: pattern.nsub = 1;
! 2011: if (pattern.nsub > 10)
! 2012: pattern.nsub = 10;
! 2013: pattern.matches = emalloc(pattern.nsub *
! 2014: sizeof(regmatch_t));
! 2015: newStr = VarModify(str, VarRESubstitute, &pattern);
! 2016: regfree(&pattern.re);
! 2017: free(pattern.replace);
! 2018: free(pattern.matches);
! 2019: break;
! 2020: }
! 2021: #endif
! 2022: case 'Q':
! 2023: if (tstr[1] == endc || tstr[1] == ':') {
! 2024: newStr = VarQuote(str);
! 2025: cp = tstr + 1;
! 2026: termc = *cp;
! 2027: break;
! 2028: }
! 2029: /*FALLTHRU*/
! 2030: case 'T':
! 2031: if (tstr[1] == endc || tstr[1] == ':') {
! 2032: newStr = VarModify(str, VarTail, NULL);
! 2033: cp = tstr + 1;
! 2034: termc = *cp;
! 2035: break;
! 2036: }
! 2037: /*FALLTHRU*/
! 2038: case 'H':
! 2039: if (tstr[1] == endc || tstr[1] == ':') {
! 2040: newStr = VarModify(str, VarHead, NULL);
! 2041: cp = tstr + 1;
! 2042: termc = *cp;
! 2043: break;
! 2044: }
! 2045: /*FALLTHRU*/
! 2046: case 'E':
! 2047: if (tstr[1] == endc || tstr[1] == ':') {
! 2048: newStr = VarModify(str, VarSuffix, NULL);
! 2049: cp = tstr + 1;
! 2050: termc = *cp;
! 2051: break;
! 2052: }
! 2053: /*FALLTHRU*/
! 2054: case 'R':
! 2055: if (tstr[1] == endc || tstr[1] == ':') {
! 2056: newStr = VarModify(str, VarRoot, NULL);
! 2057: cp = tstr + 1;
! 2058: termc = *cp;
! 2059: break;
! 2060: }
! 2061: /*FALLTHRU*/
! 2062: case 'U':
! 2063: if (tstr[1] == endc || tstr[1] == ':') {
! 2064: newStr = VarModify(str, VarUppercase, NULL);
! 2065: cp = tstr + 1;
1.6 millert 2066: termc = *cp;
2067: break;
2068: }
1.42 ! espie 2069: /*FALLTHRU*/
! 2070: case 'L':
! 2071: if (tstr[1] == endc || tstr[1] == ':') {
! 2072: newStr = VarModify(str, VarLowercase, NULL);
! 2073: cp = tstr + 1;
1.6 millert 2074: termc = *cp;
1.1 deraadt 2075: break;
2076: }
1.42 ! espie 2077: /*FALLTHRU*/
1.4 briggs 2078: #ifdef SUNSHCMD
1.42 ! espie 2079: case 's':
! 2080: if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) {
! 2081: char *err;
! 2082: newStr = Cmd_Exec(str, &err);
! 2083: if (err)
! 2084: Error(err, str);
! 2085: cp = tstr + 2;
! 2086: termc = *cp;
! 2087: break;
! 2088: }
! 2089: /*FALLTHRU*/
1.4 briggs 2090: #endif
1.42 ! espie 2091: default:
! 2092: {
1.4 briggs 2093: #ifdef SYSVVARSUB
1.42 ! espie 2094: /* This can either be a bogus modifier or a System-V
! 2095: * substitution command. */
! 2096: VarPattern pattern;
! 2097: Boolean eqFound;
! 2098: int cnt; /* Used to count brace pairs when
! 2099: * variable in in parens or braces */
! 2100: char startc;
! 2101:
! 2102: if (endc == ')')
! 2103: startc = '(';
! 2104: else
! 2105: startc = '{';
! 2106:
! 2107: pattern.flags = 0;
! 2108: eqFound = FALSE;
! 2109: /* First we make a pass through the string trying
! 2110: * to verify it is a SYSV-make-style translation:
! 2111: * it must be: <string1>=<string2>) */
! 2112: cp = tstr;
! 2113: cnt = 1;
! 2114: while (*cp != '\0' && cnt) {
! 2115: if (*cp == '=') {
! 2116: eqFound = TRUE;
! 2117: /* continue looking for endc */
! 2118: }
! 2119: else if (*cp == endc)
! 2120: cnt--;
! 2121: else if (*cp == startc)
! 2122: cnt++;
! 2123: if (cnt)
! 2124: cp++;
! 2125: }
! 2126: if (*cp == endc && eqFound) {
! 2127:
! 2128: /* Now we break this sucker into the lhs and
! 2129: * rhs. We must null terminate them of course. */
! 2130: for (cp = tstr; *cp != '='; cp++)
! 2131: continue;
! 2132: pattern.lhs = tstr;
! 2133: pattern.leftLen = cp - tstr;
! 2134: *cp++ = '\0';
1.5 millert 2135:
1.42 ! espie 2136: pattern.rhs = cp;
1.1 deraadt 2137: cnt = 1;
1.42 ! espie 2138: while (cnt) {
! 2139: if (*cp == endc)
1.1 deraadt 2140: cnt--;
2141: else if (*cp == startc)
2142: cnt++;
2143: if (cnt)
2144: cp++;
2145: }
1.42 ! espie 2146: pattern.rightLen = cp - pattern.rhs;
! 2147: *cp = '\0';
1.1 deraadt 2148:
1.42 ! espie 2149: /* SYSV modifications happen through the whole
! 2150: * string. Note the pattern is anchored at the end. */
! 2151: newStr = VarModify(str, VarSYSVMatch, &pattern);
! 2152:
! 2153: /* Restore the nulled characters */
! 2154: pattern.lhs[pattern.leftLen] = '=';
! 2155: pattern.rhs[pattern.rightLen] = endc;
! 2156: termc = endc;
! 2157: } else
1.4 briggs 2158: #endif
1.42 ! espie 2159: {
! 2160: Error ("Unknown modifier '%c'\n", *tstr);
! 2161: for (cp = tstr+1;
! 2162: *cp != ':' && *cp != endc && *cp != '\0';)
! 2163: cp++;
! 2164: termc = *cp;
! 2165: newStr = var_Error;
1.1 deraadt 2166: }
2167: }
2168: }
1.42 ! espie 2169: if (DEBUG(VAR))
! 2170: printf("Result is \"%s\"\n", newStr);
1.5 millert 2171:
1.42 ! espie 2172: if (*freePtr)
1.1 deraadt 2173: free(str);
1.42 ! espie 2174: str = newStr;
! 2175: if (str != var_Error)
1.1 deraadt 2176: *freePtr = TRUE;
1.42 ! espie 2177: else
! 2178: *freePtr = FALSE;
! 2179: if (termc == '\0')
! 2180: Error("Unclosed variable specification");
! 2181: else if (termc == ':')
! 2182: *cp++ = termc;
! 2183: else
! 2184: *cp = termc;
! 2185: tstr = cp;
1.1 deraadt 2186: }
1.42 ! espie 2187: *lengthPtr += tstr - start+1;
! 2188: return str;
1.6 millert 2189:
2190: cleanup:
1.42 ! espie 2191: *lengthPtr += cp - start +1;
1.6 millert 2192: if (*freePtr)
2193: free(str);
1.42 ! espie 2194: Error("Unclosed substitution for (%c missing)", delim);
! 2195: return var_Error;
1.1 deraadt 2196: }
2197:
2198: /*-
2199: *-----------------------------------------------------------------------
2200: * Var_Subst --
1.24 espie 2201: * Substitute for all variables in a string in a context
1.1 deraadt 2202: * If undefErr is TRUE, Parse_Error will be called when an undefined
2203: * variable is encountered.
2204: *
2205: * Results:
2206: * The resulting string.
2207: *
2208: * Side Effects:
2209: * None. The old string must be freed by the caller
2210: *-----------------------------------------------------------------------
2211: */
2212: char *
1.24 espie 2213: Var_Subst(str, ctxt, undefErr)
1.1 deraadt 2214: char *str; /* the string in which to substitute */
1.35 espie 2215: SymTable *ctxt; /* the context wherein to find variables */
1.1 deraadt 2216: Boolean undefErr; /* TRUE if undefineds are an error */
2217: {
1.24 espie 2218: BUFFER buf; /* Buffer for forming things */
1.1 deraadt 2219: static Boolean errorReported; /* Set true if an error has already
2220: * been reported to prevent a plethora
2221: * of messages when recursing */
2222:
1.23 espie 2223: Buf_Init(&buf, MAKE_BSIZE);
1.1 deraadt 2224: errorReported = FALSE;
2225:
1.24 espie 2226: for (;;) {
2227: char *val; /* Value to substitute for a variable */
2228: size_t length; /* Length of the variable invocation */
2229: Boolean doFree; /* Set true if val should be freed */
2230: const char *cp;
2231:
2232: /* copy uninteresting stuff */
2233: for (cp = str; *str != '\0' && *str != '$'; str++)
2234: ;
2235: Buf_AddInterval(&buf, cp, str);
2236: if (*str == '\0')
2237: break;
2238: if (str[1] == '$') {
2239: /* A dollar sign may be escaped with another dollar sign. */
2240: Buf_AddChar(&buf, '$');
2241: str += 2;
2242: continue;
2243: }
2244: val = Var_Parse(str, ctxt, undefErr, &length, &doFree);
2245: /* When we come down here, val should either point to the
2246: * value of this variable, suitably modified, or be NULL.
2247: * Length should be the total length of the potential
2248: * variable invocation (from $ to end character...) */
2249: if (val == var_Error || val == varNoError) {
2250: /* If performing old-time variable substitution, skip over
2251: * the variable and continue with the substitution. Otherwise,
2252: * store the dollar sign and advance str so we continue with
2253: * the string... */
2254: if (oldVars) {
2255: str += length;
2256: } else if (undefErr) {
2257: /* If variable is undefined, complain and skip the
2258: * variable. The complaint will stop us from doing anything
2259: * when the file is parsed. */
2260: if (!errorReported) {
2261: Parse_Error(PARSE_FATAL,
2262: "Undefined variable \"%.*s\"",length,str);
2263: }
2264: str += length;
2265: errorReported = TRUE;
2266: } else {
2267: Buf_AddChar(&buf, *str);
2268: str += 1;
2269: }
2270: } else {
2271: /* We've now got a variable structure to store in. But first,
2272: * advance the string pointer. */
2273: str += length;
2274:
2275: /* Copy all the characters from the variable value straight
2276: * into the new string. */
2277: Buf_AddString(&buf, val);
2278: if (doFree)
2279: free(val);
2280: }
2281: }
2282: return Buf_Retrieve(&buf);
2283: }
1.1 deraadt 2284:
1.24 espie 2285: /*-
2286: *-----------------------------------------------------------------------
2287: * Var_SubstVar --
2288: * Substitute for one variable in the given string in the given context
2289: * If undefErr is TRUE, Parse_Error will be called when an undefined
2290: * variable is encountered.
2291: *
2292: * Side Effects:
2293: * Append the result to the buffer
2294: *-----------------------------------------------------------------------
2295: */
2296: void
2297: Var_SubstVar(buf, str, var, ctxt)
2298: Buffer buf; /* Where to store the result */
2299: char *str; /* The string in which to substitute */
2300: const char *var; /* Named variable */
1.37 espie 2301: GSymT *ctxt; /* The context wherein to find variables */
1.24 espie 2302: {
2303: char *val; /* Value substituted for a variable */
2304: size_t length; /* Length of the variable invocation */
2305: Boolean doFree; /* Set true if val should be freed */
2306:
2307: for (;;) {
2308: const char *cp;
2309: /* copy uninteresting stuff */
2310: for (cp = str; *str != '\0' && *str != '$'; str++)
2311: ;
2312: Buf_AddInterval(buf, cp, str);
2313: if (*str == '\0')
2314: break;
2315: if (str[1] == '$') {
2316: Buf_AddString(buf, "$$");
2317: str += 2;
2318: continue;
2319: }
2320: if (str[1] != '(' && str[1] != '{') {
2321: if (str[1] != *var || var[1] != '\0') {
2322: Buf_AddChars(buf, 2, str);
2323: str += 2;
1.1 deraadt 2324: continue;
1.24 espie 2325: }
1.1 deraadt 2326: } else {
1.24 espie 2327: char *p;
2328: char endc;
1.1 deraadt 2329:
1.24 espie 2330: if (str[1] == '(')
2331: endc = ')';
2332: else if (str[1] == '{')
2333: endc = '}';
2334:
2335: /* Find the end of the variable specification. */
2336: p = str+2;
2337: while (*p != '\0' && *p != ':' && *p != endc && *p != '$')
2338: p++;
2339: /* A variable inside the variable. We don't know how to
2340: * expand the external variable at this point, so we try
2341: * again with the nested variable. */
2342: if (*p == '$') {
2343: Buf_AddInterval(buf, str, p);
2344: str = p;
2345: continue;
1.1 deraadt 2346: }
1.5 millert 2347:
1.24 espie 2348: if (strncmp(var, str + 2, p - str - 2) != 0 ||
2349: var[p - str - 2] != '\0') {
2350: /* Not the variable we want to expand. */
2351: Buf_AddInterval(buf, str, p);
2352: str = p;
2353: continue;
2354: }
1.1 deraadt 2355: }
1.24 espie 2356: /* okay, so we've found the variable we want to expand. */
1.37 espie 2357: val = Var_Parse(str, (SymTable *)ctxt, FALSE, &length, &doFree);
1.24 espie 2358: /* We've now got a variable structure to store in. But first,
2359: * advance the string pointer. */
2360: str += length;
2361:
2362: /* Copy all the characters from the variable value straight
2363: * into the new string. */
2364: Buf_AddString(buf, val);
2365: if (doFree)
2366: free(val);
1.1 deraadt 2367: }
2368: }
2369:
2370: /*-
2371: *-----------------------------------------------------------------------
2372: * Var_GetTail --
2373: * Return the tail from each of a list of words. Used to set the
2374: * System V local variables.
2375: *
2376: * Results:
2377: * The resulting string.
2378: *
2379: * Side Effects:
2380: * None.
2381: *
2382: *-----------------------------------------------------------------------
2383: */
2384: char *
2385: Var_GetTail(file)
2386: char *file; /* Filename to modify */
2387: {
1.30 espie 2388: return VarModify(file, VarTail, NULL);
1.1 deraadt 2389: }
2390:
2391: /*-
2392: *-----------------------------------------------------------------------
2393: * Var_GetHead --
2394: * Find the leading components of a (list of) filename(s).
2395: * XXX: VarHead does not replace foo by ., as (sun) System V make
2396: * does.
2397: *
2398: * Results:
2399: * The leading components.
2400: *
2401: * Side Effects:
2402: * None.
2403: *
2404: *-----------------------------------------------------------------------
2405: */
2406: char *
2407: Var_GetHead(file)
2408: char *file; /* Filename to manipulate */
2409: {
1.30 espie 2410: return VarModify(file, VarHead, NULL);
1.1 deraadt 2411: }
2412:
2413: /*-
2414: *-----------------------------------------------------------------------
2415: * Var_Init --
2416: * Initialize the module
2417: *
2418: * Side Effects:
1.5 millert 2419: * The VAR_CMD and VAR_GLOBAL contexts are created
1.1 deraadt 2420: *-----------------------------------------------------------------------
2421: */
2422: void
1.33 espie 2423: Var_Init()
1.1 deraadt 2424: {
1.37 espie 2425: static GSymT global_vars, cmd_vars, env_vars;
1.35 espie 2426:
2427: VAR_GLOBAL = &global_vars;
2428: VAR_CMD = &cmd_vars;
2429: VAR_ENV = &env_vars;
1.38 espie 2430: hash_init(VAR_GLOBAL, 10, &var_info);
2431: hash_init(VAR_CMD, 5, &var_info);
2432: hash_init(VAR_ENV, 5, &var_info);
1.37 espie 2433: CTXT_GLOBAL = (SymTable *)VAR_GLOBAL;
2434: CTXT_CMD = (SymTable *)VAR_CMD;
2435: CTXT_ENV = (SymTable *)VAR_ENV;
1.1 deraadt 2436: }
2437:
2438:
2439: void
1.33 espie 2440: Var_End()
1.1 deraadt 2441: {
1.37 espie 2442: #ifdef CLEANUP
1.38 espie 2443: Var *v;
2444: unsigned int i;
2445:
2446: for (v = hash_first(VAR_GLOBAL, &i); v != NULL;
2447: v = hash_next(VAR_GLOBAL, &i))
2448: VarDelete(v);
2449: for (v = hash_first(VAR_CMD, &i); v != NULL;
2450: v = hash_next(VAR_CMD, &i))
2451: VarDelete(v);
2452: for (v = hash_first(VAR_ENV, &i); v != NULL;
2453: v = hash_next(VAR_ENV, &i))
2454: VarDelete(v);
1.37 espie 2455: #endif
1.1 deraadt 2456: }
1.5 millert 2457:
1.1 deraadt 2458:
2459: /****************** PRINT DEBUGGING INFO *****************/
1.31 espie 2460: static void
2461: VarPrintVar(vp)
1.32 espie 2462: void *vp;
1.1 deraadt 2463: {
1.31 espie 2464: Var *v = (Var *)vp;
2465:
1.23 espie 2466: printf("%-16s = %s\n", v->name, VarValue(v));
1.1 deraadt 2467: }
2468:
2469: /*-
2470: *-----------------------------------------------------------------------
2471: * Var_Dump --
2472: * print all variables in a context
2473: *-----------------------------------------------------------------------
2474: */
2475: void
1.35 espie 2476: Var_Dump(ctxt)
1.37 espie 2477: GSymT *ctxt;
1.1 deraadt 2478: {
1.38 espie 2479: Var *v;
2480: unsigned int i;
2481:
2482: for (v = hash_first(ctxt, &i); v != NULL;
2483: v = hash_next(ctxt, &i))
2484: VarPrintVar(v);
1.1 deraadt 2485: }
1.37 espie 2486: