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