Annotation of src/usr.bin/make/parsevar.c, Revision 1.3
1.1 espie 1: /* $OpenPackages$ */
1.3 ! espie 2: /* $OpenBSD: parsevar.c,v 1.2 2004/04/07 13:11:36 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 *);
1.3 ! espie 44: static bool parse_variable_assignment(const char *, int);
1.1 espie 45:
46: static const char *
1.2 espie 47: find_op1(const char *p)
1.1 espie 48: {
49: for(;; p++) {
50: if (isspace(*p) || *p == '$' || *p == '\0')
51: break;
52: if (p[strspn(p, "?:!+")] == '=')
53: break;
54: if (p[0] == ':' && p[1] == 's' && p[2] == 'h')
55: break;
56: }
57: return p;
58: }
59:
60: static const char *
1.2 espie 61: find_op2(const char *p)
1.1 espie 62: {
63: for(;; p++) {
64: if (isspace(*p) || *p == '$' || *p == '\0')
65: break;
66: if (p[strspn(p, "?:!+")] == '=')
67: break;
68: }
69: return p;
70: }
71:
1.3 ! espie 72: static bool
! 73: parse_variable_assignment(const char *line,
! 74: int ctxt) /* Context in which to do the assignment */
1.1 espie 75: {
76: const char *arg;
77: char *res1 = NULL, *res2 = NULL;
78: #define VAR_NORMAL 0
79: #define VAR_SUBST 1
80: #define VAR_APPEND 2
81: #define VAR_SHELL 4
82: #define VAR_OPT 8
83: int type; /* Type of assignment */
84: struct Name name;
85:
1.3 ! espie 86: arg = VarName_Get(line, &name, NULL, true,
1.1 espie 87: FEATURES(FEATURE_SUNSHCMD) ? find_op1 : find_op2);
88:
89: while (isspace(*arg))
90: arg++;
91:
92: type = VAR_NORMAL;
93:
94: while (*arg != '=' && !isspace(*arg)) {
95: /* Check operator type. */
96: switch (*arg++) {
97: case '+':
98: if (type & (VAR_OPT|VAR_APPEND)) {
99: VarName_Free(&name);
100: return false;
101: }
102: type |= VAR_APPEND;
103: break;
104:
105: case '?':
106: if (type & (VAR_OPT|VAR_APPEND)) {
107: VarName_Free(&name);
108: return false;
109: }
110: type |= VAR_OPT;
111: break;
112:
113: case ':':
114: if (FEATURES(FEATURE_SUNSHCMD) && strncmp(arg, "sh", 2) == 0) {
115: type = VAR_SHELL;
116: arg += 2;
117: while (*arg != '=' && *arg != '\0')
118: arg++;
119: } else {
120: if (type & VAR_SUBST) {
121: VarName_Free(&name);
122: return false;
123: }
124: type |= VAR_SUBST;
125: }
126: break;
127:
128: case '!':
129: if (type & VAR_SHELL) {
130: VarName_Free(&name);
131: return false;
132: }
133: type |= VAR_SHELL;
134: break;
135:
136: default:
137: VarName_Free(&name);
138: return false;
139: }
140: }
141:
142: /* Check validity of operator */
143: if (*arg++ != '=') {
144: VarName_Free(&name);
145: return false;
146: }
147:
148: while (isspace(*arg))
149: arg++;
150: /* If the variable already has a value, we don't do anything. */
1.3 ! espie 151: if ((type & VAR_OPT) && Var_Definedi(name.s, name.e)) {
1.1 espie 152: VarName_Free(&name);
153: return true;
154: }
155: if (type & VAR_SHELL) {
156: char *err;
157:
158: if (strchr(arg, '$') != NULL) {
159: char *sub;
160: /* There's a dollar sign in the command, so perform variable
161: * expansion on the whole thing. */
162: sub = Var_Subst(arg, NULL, true);
163: res1 = Cmd_Exec(sub, &err);
164: free(sub);
165: } else
166: res1 = Cmd_Exec(arg, &err);
167:
168: if (err)
169: Parse_Error(PARSE_WARNING, err, arg);
170: arg = res1;
171: }
172: if (type & VAR_SUBST) {
173: /*
174: * Allow variables in the old value to be undefined, but leave their
175: * invocation alone -- this is done by forcing oldVars to be false.
176: * XXX: This can cause recursive variables, but that's not hard to do,
177: * and this allows someone to do something like
178: *
179: * CFLAGS = $(.INCLUDES)
180: * CFLAGS := -I.. $(CFLAGS)
181: *
182: * And not get an error.
183: */
184: bool oldOldVars = oldVars;
185:
186: oldVars = false;
187: /* ensure the variable is set to something to avoid `variable
188: * is recursive' errors. */
189: if (Var_Valuei(name.s, name.e) == NULL)
190: Var_Seti(name.s, name.e, "", ctxt);
191:
1.3 ! espie 192: res2 = Var_Subst(arg, NULL, false);
1.1 espie 193: oldVars = oldOldVars;
194:
195: arg = res2;
196: }
197:
198: if (type & VAR_APPEND)
199: Var_Appendi(name.s, name.e, arg, ctxt);
200: else
201: Var_Seti(name.s, name.e, arg, ctxt);
202:
203: VarName_Free(&name);
204: free(res2);
205: free(res1);
206: return true;
1.3 ! espie 207: }
! 208:
! 209: bool
! 210: Parse_DoVar(const char *line)
! 211: {
! 212: return parse_variable_assignment(line, VAR_GLOBAL);
! 213: }
! 214:
! 215: bool
! 216: Parse_CmdlineVar(const char *line)
! 217: {
! 218: bool result;
! 219:
! 220: oldVars = false;
! 221: result = parse_variable_assignment(line, VAR_CMD);
! 222: oldVars = true;
! 223: return result;
1.1 espie 224: }
225: