Annotation of src/usr.bin/make/parsevar.c, Revision 1.2
1.1 espie 1: /* $OpenPackages$ */
1.2 ! espie 2: /* $OpenBSD: parsevar.c,v 1.1 2001/05/23 12:34:48 espie Exp $ */
1.1 espie 3: /* $NetBSD: parse.c,v 1.29 1997/03/10 21:20:04 christos Exp $ */
4:
5: /*
6: * Copyright (c) 2001 Marc Espie.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
18: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
21: * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28: */
29:
30: #include <ctype.h>
31: #include <stddef.h>
32: #include <stdlib.h>
33: #include <string.h>
34: #include "config.h"
35: #include "defines.h"
36: #include "var.h"
37: #include "varname.h"
38: #include "error.h"
39: #include "cmd_exec.h"
40: #include "parsevar.h"
41:
42: static const char *find_op1(const char *);
43: static const char *find_op2(const char *);
44:
45: static const char *
1.2 ! espie 46: find_op1(const char *p)
1.1 espie 47: {
48: for(;; p++) {
49: if (isspace(*p) || *p == '$' || *p == '\0')
50: break;
51: if (p[strspn(p, "?:!+")] == '=')
52: break;
53: if (p[0] == ':' && p[1] == 's' && p[2] == 'h')
54: break;
55: }
56: return p;
57: }
58:
59: static const char *
1.2 ! espie 60: find_op2(const char *p)
1.1 espie 61: {
62: for(;; p++) {
63: if (isspace(*p) || *p == '$' || *p == '\0')
64: break;
65: if (p[strspn(p, "?:!+")] == '=')
66: break;
67: }
68: return p;
69: }
70:
71: bool
1.2 ! espie 72: Parse_DoVar(const char *line,
! 73: GSymT *ctxt) /* Context in which to do the assignment */
1.1 espie 74: {
75: const char *arg;
76: char *res1 = NULL, *res2 = NULL;
77: #define VAR_NORMAL 0
78: #define VAR_SUBST 1
79: #define VAR_APPEND 2
80: #define VAR_SHELL 4
81: #define VAR_OPT 8
82: int type; /* Type of assignment */
83: struct Name name;
84:
85: arg = VarName_Get(line, &name, (SymTable *)ctxt, true,
86: FEATURES(FEATURE_SUNSHCMD) ? find_op1 : find_op2);
87:
88: while (isspace(*arg))
89: arg++;
90:
91: type = VAR_NORMAL;
92:
93: while (*arg != '=' && !isspace(*arg)) {
94: /* Check operator type. */
95: switch (*arg++) {
96: case '+':
97: if (type & (VAR_OPT|VAR_APPEND)) {
98: VarName_Free(&name);
99: return false;
100: }
101: type |= VAR_APPEND;
102: break;
103:
104: case '?':
105: if (type & (VAR_OPT|VAR_APPEND)) {
106: VarName_Free(&name);
107: return false;
108: }
109: type |= VAR_OPT;
110: break;
111:
112: case ':':
113: if (FEATURES(FEATURE_SUNSHCMD) && strncmp(arg, "sh", 2) == 0) {
114: type = VAR_SHELL;
115: arg += 2;
116: while (*arg != '=' && *arg != '\0')
117: arg++;
118: } else {
119: if (type & VAR_SUBST) {
120: VarName_Free(&name);
121: return false;
122: }
123: type |= VAR_SUBST;
124: }
125: break;
126:
127: case '!':
128: if (type & VAR_SHELL) {
129: VarName_Free(&name);
130: return false;
131: }
132: type |= VAR_SHELL;
133: break;
134:
135: default:
136: VarName_Free(&name);
137: return false;
138: }
139: }
140:
141: /* Check validity of operator */
142: if (*arg++ != '=') {
143: VarName_Free(&name);
144: return false;
145: }
146:
147: while (isspace(*arg))
148: arg++;
149: /* If the variable already has a value, we don't do anything. */
150: if ((type & VAR_OPT) && Var_Valuei(name.s, name.e) != NULL) {
151: VarName_Free(&name);
152: return true;
153: }
154: if (type & VAR_SHELL) {
155: char *err;
156:
157: if (strchr(arg, '$') != NULL) {
158: char *sub;
159: /* There's a dollar sign in the command, so perform variable
160: * expansion on the whole thing. */
161: sub = Var_Subst(arg, NULL, true);
162: res1 = Cmd_Exec(sub, &err);
163: free(sub);
164: } else
165: res1 = Cmd_Exec(arg, &err);
166:
167: if (err)
168: Parse_Error(PARSE_WARNING, err, arg);
169: arg = res1;
170: }
171: if (type & VAR_SUBST) {
172: /*
173: * Allow variables in the old value to be undefined, but leave their
174: * invocation alone -- this is done by forcing oldVars to be false.
175: * XXX: This can cause recursive variables, but that's not hard to do,
176: * and this allows someone to do something like
177: *
178: * CFLAGS = $(.INCLUDES)
179: * CFLAGS := -I.. $(CFLAGS)
180: *
181: * And not get an error.
182: */
183: bool oldOldVars = oldVars;
184:
185: oldVars = false;
186: /* ensure the variable is set to something to avoid `variable
187: * is recursive' errors. */
188: if (Var_Valuei(name.s, name.e) == NULL)
189: Var_Seti(name.s, name.e, "", ctxt);
190:
191: res2 = Var_Subst(arg, (SymTable *)ctxt, false);
192: oldVars = oldOldVars;
193:
194: arg = res2;
195: }
196:
197: if (type & VAR_APPEND)
198: Var_Appendi(name.s, name.e, arg, ctxt);
199: else
200: Var_Seti(name.s, name.e, arg, ctxt);
201:
202: VarName_Free(&name);
203: free(res2);
204: free(res1);
205: return true;
206: }
207: