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