Annotation of src/usr.bin/make/var.c, Revision 1.40
1.40 ! espie 1: /* $OpenBSD: var.c,v 1.39 2000/07/17 22:55:12 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.40 ! espie 73: static char rcsid[] = "$OpenBSD: var.c,v 1.39 2000/07/17 22:55:12 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: char *pattern;
1891: char *cp2;
1892: Boolean copy;
1893:
1894: copy = FALSE;
1895: for (cp = tstr + 1;
1896: *cp != '\0' && *cp != ':' && *cp != endc;
1897: cp++)
1898: {
1899: if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){
1900: copy = TRUE;
1901: cp++;
1902: }
1903: }
1904: termc = *cp;
1905: *cp = '\0';
1906: if (copy) {
1907: /*
1908: * Need to compress the \:'s out of the pattern, so
1909: * allocate enough room to hold the uncompressed
1910: * pattern (note that cp started at tstr+1, so
1911: * cp - tstr takes the null byte into account) and
1912: * compress the pattern into the space.
1913: */
1914: pattern = emalloc(cp - tstr);
1915: for (cp2 = pattern, cp = tstr + 1;
1916: *cp != '\0';
1917: cp++, cp2++)
1918: {
1919: if ((*cp == '\\') &&
1920: (cp[1] == ':' || cp[1] == endc)) {
1921: cp++;
1922: }
1923: *cp2 = *cp;
1924: }
1925: *cp2 = '\0';
1926: } else {
1927: pattern = &tstr[1];
1928: }
1929: if (*tstr == 'M' || *tstr == 'm') {
1.30 espie 1930: newStr = VarModify(str, VarMatch, pattern);
1.1 deraadt 1931: } else {
1.30 espie 1932: newStr = VarModify(str, VarNoMatch, pattern);
1.1 deraadt 1933: }
1934: if (copy) {
1935: free(pattern);
1936: }
1937: break;
1938: }
1939: case 'S':
1940: {
1941: VarPattern pattern;
1942:
1943: pattern.flags = 0;
1944: delim = tstr[1];
1945: tstr += 2;
1.6 millert 1946:
1.1 deraadt 1947: /*
1948: * If pattern begins with '^', it is anchored to the
1949: * start of the word -- skip over it and flag pattern.
1950: */
1951: if (*tstr == '^') {
1952: pattern.flags |= VAR_MATCH_START;
1953: tstr += 1;
1954: }
1955:
1.6 millert 1956: cp = tstr;
1957: if ((pattern.lhs = VarGetPattern(ctxt, err, &cp, delim,
1958: &pattern.flags, &pattern.leftLen, NULL)) == NULL)
1959: goto cleanup;
1960:
1961: if ((pattern.rhs = VarGetPattern(ctxt, err, &cp, delim,
1962: NULL, &pattern.rightLen, &pattern)) == NULL)
1963: goto cleanup;
1.5 millert 1964:
1.1 deraadt 1965: /*
1.6 millert 1966: * Check for global substitution. If 'g' after the final
1967: * delimiter, substitution is global and is marked that
1968: * way.
1.1 deraadt 1969: */
1.6 millert 1970: for (;; cp++) {
1971: switch (*cp) {
1972: case 'g':
1973: pattern.flags |= VAR_SUB_GLOBAL;
1974: continue;
1975: case '1':
1976: pattern.flags |= VAR_SUB_ONE;
1977: continue;
1.1 deraadt 1978: }
1.6 millert 1979: break;
1.1 deraadt 1980: }
1981:
1.6 millert 1982: termc = *cp;
1.30 espie 1983: newStr = VarModify(str, VarSubstitute, &pattern);
1.5 millert 1984:
1.1 deraadt 1985: /*
1.6 millert 1986: * Free the two strings.
1.1 deraadt 1987: */
1.6 millert 1988: free(pattern.lhs);
1989: free(pattern.rhs);
1990: break;
1991: }
1992: #ifndef MAKE_BOOTSTRAP
1993: case 'C':
1994: {
1995: VarREPattern pattern;
1996: char *re;
1997: int error;
1998:
1999: pattern.flags = 0;
2000: delim = tstr[1];
2001: tstr += 2;
1.1 deraadt 2002:
1.6 millert 2003: cp = tstr;
1.1 deraadt 2004:
1.6 millert 2005: if ((re = VarGetPattern(ctxt, err, &cp, delim, NULL,
2006: NULL, NULL)) == NULL)
2007: goto cleanup;
2008:
2009: if ((pattern.replace = VarGetPattern(ctxt, err, &cp,
2010: delim, NULL, NULL, NULL)) == NULL) {
2011: free(re);
2012: goto cleanup;
2013: }
1.5 millert 2014:
1.6 millert 2015: for (;; cp++) {
2016: switch (*cp) {
2017: case 'g':
2018: pattern.flags |= VAR_SUB_GLOBAL;
2019: continue;
2020: case '1':
2021: pattern.flags |= VAR_SUB_ONE;
2022: continue;
1.1 deraadt 2023: }
1.6 millert 2024: break;
1.1 deraadt 2025: }
2026:
1.6 millert 2027: termc = *cp;
1.5 millert 2028:
1.6 millert 2029: error = regcomp(&pattern.re, re, REG_EXTENDED);
2030: free(re);
2031: if (error) {
1.1 deraadt 2032: *lengthPtr = cp - start + 1;
1.6 millert 2033: VarREError(error, &pattern.re, "RE substitution error");
2034: free(pattern.replace);
1.1 deraadt 2035: return (var_Error);
2036: }
2037:
1.6 millert 2038: pattern.nsub = pattern.re.re_nsub + 1;
2039: if (pattern.nsub < 1)
2040: pattern.nsub = 1;
2041: if (pattern.nsub > 10)
2042: pattern.nsub = 10;
2043: pattern.matches = emalloc(pattern.nsub *
2044: sizeof(regmatch_t));
1.30 espie 2045: newStr = VarModify(str, VarRESubstitute, &pattern);
1.6 millert 2046: regfree(&pattern.re);
2047: free(pattern.replace);
2048: free(pattern.matches);
1.1 deraadt 2049: break;
2050: }
1.6 millert 2051: #endif
2052: case 'Q':
2053: if (tstr[1] == endc || tstr[1] == ':') {
2054: newStr = VarQuote (str);
2055: cp = tstr + 1;
2056: termc = *cp;
2057: break;
2058: }
2059: /*FALLTHRU*/
1.1 deraadt 2060: case 'T':
2061: if (tstr[1] == endc || tstr[1] == ':') {
1.30 espie 2062: newStr = VarModify(str, VarTail, NULL);
1.1 deraadt 2063: cp = tstr + 1;
2064: termc = *cp;
2065: break;
2066: }
2067: /*FALLTHRU*/
2068: case 'H':
2069: if (tstr[1] == endc || tstr[1] == ':') {
1.30 espie 2070: newStr = VarModify(str, VarHead, NULL);
1.1 deraadt 2071: cp = tstr + 1;
2072: termc = *cp;
2073: break;
2074: }
2075: /*FALLTHRU*/
2076: case 'E':
2077: if (tstr[1] == endc || tstr[1] == ':') {
1.30 espie 2078: newStr = VarModify(str, VarSuffix, NULL);
1.1 deraadt 2079: cp = tstr + 1;
2080: termc = *cp;
2081: break;
2082: }
2083: /*FALLTHRU*/
2084: case 'R':
2085: if (tstr[1] == endc || tstr[1] == ':') {
1.30 espie 2086: newStr = VarModify(str, VarRoot, NULL);
1.11 espie 2087: cp = tstr + 1;
2088: termc = *cp;
2089: break;
2090: }
2091: /*FALLTHRU*/
2092: case 'U':
2093: if (tstr[1] == endc || tstr[1] == ':') {
1.30 espie 2094: newStr = VarModify(str, VarUppercase, NULL);
1.11 espie 2095: cp = tstr + 1;
2096: termc = *cp;
2097: break;
2098: }
2099: /*FALLTHRU*/
2100: case 'L':
2101: if (tstr[1] == endc || tstr[1] == ':') {
1.30 espie 2102: newStr = VarModify(str, VarLowercase, NULL);
1.1 deraadt 2103: cp = tstr + 1;
2104: termc = *cp;
2105: break;
2106: }
2107: /*FALLTHRU*/
1.4 briggs 2108: #ifdef SUNSHCMD
2109: case 's':
2110: if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) {
2111: char *err;
2112: newStr = Cmd_Exec (str, &err);
2113: if (err)
2114: Error (err, str);
2115: cp = tstr + 2;
2116: termc = *cp;
2117: break;
2118: }
2119: /*FALLTHRU*/
2120: #endif
2121: default:
2122: {
2123: #ifdef SYSVVARSUB
1.1 deraadt 2124: /*
2125: * This can either be a bogus modifier or a System-V
2126: * substitution command.
2127: */
2128: VarPattern pattern;
2129: Boolean eqFound;
1.5 millert 2130:
1.1 deraadt 2131: pattern.flags = 0;
2132: eqFound = FALSE;
2133: /*
2134: * First we make a pass through the string trying
2135: * to verify it is a SYSV-make-style translation:
2136: * it must be: <string1>=<string2>)
2137: */
2138: cp = tstr;
2139: cnt = 1;
2140: while (*cp != '\0' && cnt) {
2141: if (*cp == '=') {
2142: eqFound = TRUE;
2143: /* continue looking for endc */
2144: }
2145: else if (*cp == endc)
2146: cnt--;
2147: else if (*cp == startc)
2148: cnt++;
2149: if (cnt)
2150: cp++;
2151: }
2152: if (*cp == endc && eqFound) {
1.5 millert 2153:
1.1 deraadt 2154: /*
2155: * Now we break this sucker into the lhs and
2156: * rhs. We must null terminate them of course.
2157: */
2158: for (cp = tstr; *cp != '='; cp++)
2159: continue;
2160: pattern.lhs = tstr;
2161: pattern.leftLen = cp - tstr;
2162: *cp++ = '\0';
1.5 millert 2163:
1.1 deraadt 2164: pattern.rhs = cp;
2165: cnt = 1;
2166: while (cnt) {
2167: if (*cp == endc)
2168: cnt--;
2169: else if (*cp == startc)
2170: cnt++;
2171: if (cnt)
2172: cp++;
2173: }
2174: pattern.rightLen = cp - pattern.rhs;
2175: *cp = '\0';
1.5 millert 2176:
1.1 deraadt 2177: /*
2178: * SYSV modifications happen through the whole
2179: * string. Note the pattern is anchored at the end.
2180: */
1.30 espie 2181: newStr = VarModify(str, VarSYSVMatch, &pattern);
1.1 deraadt 2182:
2183: /*
2184: * Restore the nulled characters
2185: */
2186: pattern.lhs[pattern.leftLen] = '=';
2187: pattern.rhs[pattern.rightLen] = endc;
2188: termc = endc;
1.4 briggs 2189: } else
2190: #endif
2191: {
1.1 deraadt 2192: Error ("Unknown modifier '%c'\n", *tstr);
2193: for (cp = tstr+1;
2194: *cp != ':' && *cp != endc && *cp != '\0';
1.5 millert 2195: cp++)
1.1 deraadt 2196: continue;
2197: termc = *cp;
2198: newStr = var_Error;
2199: }
2200: }
2201: }
2202: if (DEBUG(VAR)) {
2203: printf("Result is \"%s\"\n", newStr);
2204: }
1.5 millert 2205:
1.1 deraadt 2206: if (*freePtr) {
2207: free (str);
2208: }
2209: str = newStr;
2210: if (str != var_Error) {
2211: *freePtr = TRUE;
2212: } else {
2213: *freePtr = FALSE;
2214: }
2215: if (termc == '\0') {
2216: Error("Unclosed variable specification for %s", v->name);
2217: } else if (termc == ':') {
2218: *cp++ = termc;
2219: } else {
2220: *cp = termc;
2221: }
2222: tstr = cp;
2223: }
2224: *lengthPtr = tstr - start + 1;
2225: } else {
2226: *lengthPtr = tstr - start + 1;
2227: *tstr = endc;
2228: }
1.5 millert 2229:
1.17 espie 2230: if (v->flags & VAR_JUNK) {
1.1 deraadt 2231: /*
2232: * Perform any free'ing needed and set *freePtr to FALSE so the caller
2233: * doesn't try to free a static pointer.
2234: */
2235: if (*freePtr) {
2236: free(str);
2237: }
2238: *freePtr = FALSE;
1.23 espie 2239: Buf_Destroy(&(v->val));
2240: free(v);
1.1 deraadt 2241: if (dynamic) {
2242: str = emalloc(*lengthPtr + 1);
2243: strncpy(str, start, *lengthPtr);
2244: str[*lengthPtr] = '\0';
2245: *freePtr = TRUE;
2246: } else {
1.12 espie 2247: str = err ? var_Error : varNoError;
1.1 deraadt 2248: }
2249: }
2250: return (str);
1.6 millert 2251:
2252: cleanup:
2253: *lengthPtr = cp - start + 1;
2254: if (*freePtr)
2255: free(str);
2256: Error("Unclosed substitution for %s (%c missing)",
2257: v->name, delim);
2258: return (var_Error);
1.1 deraadt 2259: }
2260:
2261: /*-
2262: *-----------------------------------------------------------------------
2263: * Var_Subst --
1.24 espie 2264: * Substitute for all variables in a string in a context
1.1 deraadt 2265: * If undefErr is TRUE, Parse_Error will be called when an undefined
2266: * variable is encountered.
2267: *
2268: * Results:
2269: * The resulting string.
2270: *
2271: * Side Effects:
2272: * None. The old string must be freed by the caller
2273: *-----------------------------------------------------------------------
2274: */
2275: char *
1.24 espie 2276: Var_Subst(str, ctxt, undefErr)
1.1 deraadt 2277: char *str; /* the string in which to substitute */
1.35 espie 2278: SymTable *ctxt; /* the context wherein to find variables */
1.1 deraadt 2279: Boolean undefErr; /* TRUE if undefineds are an error */
2280: {
1.24 espie 2281: BUFFER buf; /* Buffer for forming things */
1.1 deraadt 2282: static Boolean errorReported; /* Set true if an error has already
2283: * been reported to prevent a plethora
2284: * of messages when recursing */
2285:
1.23 espie 2286: Buf_Init(&buf, MAKE_BSIZE);
1.1 deraadt 2287: errorReported = FALSE;
2288:
1.24 espie 2289: for (;;) {
2290: char *val; /* Value to substitute for a variable */
2291: size_t length; /* Length of the variable invocation */
2292: Boolean doFree; /* Set true if val should be freed */
2293: const char *cp;
2294:
2295: /* copy uninteresting stuff */
2296: for (cp = str; *str != '\0' && *str != '$'; str++)
2297: ;
2298: Buf_AddInterval(&buf, cp, str);
2299: if (*str == '\0')
2300: break;
2301: if (str[1] == '$') {
2302: /* A dollar sign may be escaped with another dollar sign. */
2303: Buf_AddChar(&buf, '$');
2304: str += 2;
2305: continue;
2306: }
2307: val = Var_Parse(str, ctxt, undefErr, &length, &doFree);
2308: /* When we come down here, val should either point to the
2309: * value of this variable, suitably modified, or be NULL.
2310: * Length should be the total length of the potential
2311: * variable invocation (from $ to end character...) */
2312: if (val == var_Error || val == varNoError) {
2313: /* If performing old-time variable substitution, skip over
2314: * the variable and continue with the substitution. Otherwise,
2315: * store the dollar sign and advance str so we continue with
2316: * the string... */
2317: if (oldVars) {
2318: str += length;
2319: } else if (undefErr) {
2320: /* If variable is undefined, complain and skip the
2321: * variable. The complaint will stop us from doing anything
2322: * when the file is parsed. */
2323: if (!errorReported) {
2324: Parse_Error(PARSE_FATAL,
2325: "Undefined variable \"%.*s\"",length,str);
2326: }
2327: str += length;
2328: errorReported = TRUE;
2329: } else {
2330: Buf_AddChar(&buf, *str);
2331: str += 1;
2332: }
2333: } else {
2334: /* We've now got a variable structure to store in. But first,
2335: * advance the string pointer. */
2336: str += length;
2337:
2338: /* Copy all the characters from the variable value straight
2339: * into the new string. */
2340: Buf_AddString(&buf, val);
2341: if (doFree)
2342: free(val);
2343: }
2344: }
2345: return Buf_Retrieve(&buf);
2346: }
1.1 deraadt 2347:
1.24 espie 2348: /*-
2349: *-----------------------------------------------------------------------
2350: * Var_SubstVar --
2351: * Substitute for one variable in the given string in the given context
2352: * If undefErr is TRUE, Parse_Error will be called when an undefined
2353: * variable is encountered.
2354: *
2355: * Side Effects:
2356: * Append the result to the buffer
2357: *-----------------------------------------------------------------------
2358: */
2359: void
2360: Var_SubstVar(buf, str, var, ctxt)
2361: Buffer buf; /* Where to store the result */
2362: char *str; /* The string in which to substitute */
2363: const char *var; /* Named variable */
1.37 espie 2364: GSymT *ctxt; /* The context wherein to find variables */
1.24 espie 2365: {
2366: char *val; /* Value substituted for a variable */
2367: size_t length; /* Length of the variable invocation */
2368: Boolean doFree; /* Set true if val should be freed */
2369:
2370: for (;;) {
2371: const char *cp;
2372: /* copy uninteresting stuff */
2373: for (cp = str; *str != '\0' && *str != '$'; str++)
2374: ;
2375: Buf_AddInterval(buf, cp, str);
2376: if (*str == '\0')
2377: break;
2378: if (str[1] == '$') {
2379: Buf_AddString(buf, "$$");
2380: str += 2;
2381: continue;
2382: }
2383: if (str[1] != '(' && str[1] != '{') {
2384: if (str[1] != *var || var[1] != '\0') {
2385: Buf_AddChars(buf, 2, str);
2386: str += 2;
1.1 deraadt 2387: continue;
1.24 espie 2388: }
1.1 deraadt 2389: } else {
1.24 espie 2390: char *p;
2391: char endc;
1.1 deraadt 2392:
1.24 espie 2393: if (str[1] == '(')
2394: endc = ')';
2395: else if (str[1] == '{')
2396: endc = '}';
2397:
2398: /* Find the end of the variable specification. */
2399: p = str+2;
2400: while (*p != '\0' && *p != ':' && *p != endc && *p != '$')
2401: p++;
2402: /* A variable inside the variable. We don't know how to
2403: * expand the external variable at this point, so we try
2404: * again with the nested variable. */
2405: if (*p == '$') {
2406: Buf_AddInterval(buf, str, p);
2407: str = p;
2408: continue;
1.1 deraadt 2409: }
1.5 millert 2410:
1.24 espie 2411: if (strncmp(var, str + 2, p - str - 2) != 0 ||
2412: var[p - str - 2] != '\0') {
2413: /* Not the variable we want to expand. */
2414: Buf_AddInterval(buf, str, p);
2415: str = p;
2416: continue;
2417: }
1.1 deraadt 2418: }
1.24 espie 2419: /* okay, so we've found the variable we want to expand. */
1.37 espie 2420: val = Var_Parse(str, (SymTable *)ctxt, FALSE, &length, &doFree);
1.24 espie 2421: /* We've now got a variable structure to store in. But first,
2422: * advance the string pointer. */
2423: str += length;
2424:
2425: /* Copy all the characters from the variable value straight
2426: * into the new string. */
2427: Buf_AddString(buf, val);
2428: if (doFree)
2429: free(val);
1.1 deraadt 2430: }
2431: }
2432:
2433: /*-
2434: *-----------------------------------------------------------------------
2435: * Var_GetTail --
2436: * Return the tail from each of a list of words. Used to set the
2437: * System V local variables.
2438: *
2439: * Results:
2440: * The resulting string.
2441: *
2442: * Side Effects:
2443: * None.
2444: *
2445: *-----------------------------------------------------------------------
2446: */
2447: char *
2448: Var_GetTail(file)
2449: char *file; /* Filename to modify */
2450: {
1.30 espie 2451: return VarModify(file, VarTail, NULL);
1.1 deraadt 2452: }
2453:
2454: /*-
2455: *-----------------------------------------------------------------------
2456: * Var_GetHead --
2457: * Find the leading components of a (list of) filename(s).
2458: * XXX: VarHead does not replace foo by ., as (sun) System V make
2459: * does.
2460: *
2461: * Results:
2462: * The leading components.
2463: *
2464: * Side Effects:
2465: * None.
2466: *
2467: *-----------------------------------------------------------------------
2468: */
2469: char *
2470: Var_GetHead(file)
2471: char *file; /* Filename to manipulate */
2472: {
1.30 espie 2473: return VarModify(file, VarHead, NULL);
1.1 deraadt 2474: }
2475:
2476: /*-
2477: *-----------------------------------------------------------------------
2478: * Var_Init --
2479: * Initialize the module
2480: *
2481: * Side Effects:
1.5 millert 2482: * The VAR_CMD and VAR_GLOBAL contexts are created
1.1 deraadt 2483: *-----------------------------------------------------------------------
2484: */
2485: void
1.33 espie 2486: Var_Init()
1.1 deraadt 2487: {
1.37 espie 2488: static GSymT global_vars, cmd_vars, env_vars;
1.35 espie 2489:
2490: VAR_GLOBAL = &global_vars;
2491: VAR_CMD = &cmd_vars;
2492: VAR_ENV = &env_vars;
1.38 espie 2493: hash_init(VAR_GLOBAL, 10, &var_info);
2494: hash_init(VAR_CMD, 5, &var_info);
2495: hash_init(VAR_ENV, 5, &var_info);
1.37 espie 2496: CTXT_GLOBAL = (SymTable *)VAR_GLOBAL;
2497: CTXT_CMD = (SymTable *)VAR_CMD;
2498: CTXT_ENV = (SymTable *)VAR_ENV;
1.1 deraadt 2499: }
2500:
2501:
2502: void
1.33 espie 2503: Var_End()
1.1 deraadt 2504: {
1.37 espie 2505: #ifdef CLEANUP
1.38 espie 2506: Var *v;
2507: unsigned int i;
2508:
2509: for (v = hash_first(VAR_GLOBAL, &i); v != NULL;
2510: v = hash_next(VAR_GLOBAL, &i))
2511: VarDelete(v);
2512: for (v = hash_first(VAR_CMD, &i); v != NULL;
2513: v = hash_next(VAR_CMD, &i))
2514: VarDelete(v);
2515: for (v = hash_first(VAR_ENV, &i); v != NULL;
2516: v = hash_next(VAR_ENV, &i))
2517: VarDelete(v);
1.37 espie 2518: #endif
1.1 deraadt 2519: }
1.5 millert 2520:
1.1 deraadt 2521:
2522: /****************** PRINT DEBUGGING INFO *****************/
1.31 espie 2523: static void
2524: VarPrintVar(vp)
1.32 espie 2525: void *vp;
1.1 deraadt 2526: {
1.31 espie 2527: Var *v = (Var *)vp;
2528:
1.23 espie 2529: printf("%-16s = %s\n", v->name, VarValue(v));
1.1 deraadt 2530: }
2531:
2532: /*-
2533: *-----------------------------------------------------------------------
2534: * Var_Dump --
2535: * print all variables in a context
2536: *-----------------------------------------------------------------------
2537: */
2538: void
1.35 espie 2539: Var_Dump(ctxt)
1.37 espie 2540: GSymT *ctxt;
1.1 deraadt 2541: {
1.38 espie 2542: Var *v;
2543: unsigned int i;
2544:
2545: for (v = hash_first(ctxt, &i); v != NULL;
2546: v = hash_next(ctxt, &i))
2547: VarPrintVar(v);
1.1 deraadt 2548: }
1.37 espie 2549: