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