Annotation of src/usr.bin/make/parsevar.c, Revision 1.16
1.16 ! espie 1: /* $OpenBSD: parsevar.c,v 1.15 2013/11/22 15:47:35 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++) {
1.15 espie 49: if (ISSPACE(*p) || *p == '$' || *p == '\0')
1.6 espie 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++) {
1.15 espie 63: if (ISSPACE(*p) || *p == '$' || *p == '\0')
1.6 espie 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.16 ! espie 82: #define VAR_LAZYSHELL 16
! 83: #define VAR_SUNSHELL 32
1.11 espie 84: int type;
1.6 espie 85: struct Name name;
1.1 espie 86:
1.6 espie 87: arg = VarName_Get(line, &name, NULL, true,
88: FEATURES(FEATURE_SUNSHCMD) ? find_op1 : find_op2);
1.1 espie 89:
1.15 espie 90: while (ISSPACE(*arg))
1.6 espie 91: arg++;
1.1 espie 92:
1.6 espie 93: type = VAR_NORMAL;
94:
1.16 ! espie 95: /* double operators (except for :) are forbidden */
! 96: /* OPT and APPEND don't match */
! 97: /* APPEND and LAZYSHELL can't really work */
1.7 espie 98: while (*arg != '=') {
1.6 espie 99: /* Check operator type. */
100: switch (*arg++) {
101: case '+':
1.16 ! espie 102: if (type & (VAR_OPT|VAR_LAZYSHELL|VAR_APPEND))
1.7 espie 103: type = VAR_INVALID;
104: else
105: type |= VAR_APPEND;
1.6 espie 106: break;
107:
108: case '?':
1.7 espie 109: if (type & (VAR_OPT|VAR_APPEND))
110: type = VAR_INVALID;
1.10 espie 111: else
1.7 espie 112: type |= VAR_OPT;
1.6 espie 113: break;
114:
115: case ':':
1.10 espie 116: if (FEATURES(FEATURE_SUNSHCMD) &&
1.6 espie 117: strncmp(arg, "sh", 2) == 0) {
1.16 ! espie 118: type = VAR_SUNSHELL;
1.6 espie 119: arg += 2;
120: while (*arg != '=' && *arg != '\0')
121: arg++;
122: } else {
1.7 espie 123: if (type & VAR_SUBST)
124: type = VAR_INVALID;
125: else
126: type |= VAR_SUBST;
1.6 espie 127: }
128: break;
129:
130: case '!':
1.16 ! espie 131: if (type & VAR_SHELL) {
! 132: if (type & (VAR_APPEND))
! 133: type = VAR_INVALID;
! 134: else
! 135: type = VAR_LAZYSHELL;
! 136: } else if (type & (VAR_LAZYSHELL|VAR_SUNSHELL))
1.7 espie 137: type = VAR_INVALID;
138: else
139: type |= VAR_SHELL;
1.6 espie 140: break;
141:
142: default:
1.7 espie 143: type = VAR_INVALID;
144: break;
145: }
146: if (type == VAR_INVALID) {
1.6 espie 147: VarName_Free(&name);
148: return false;
1.1 espie 149: }
1.6 espie 150: }
151:
1.7 espie 152: arg++;
1.15 espie 153: while (ISSPACE(*arg))
1.6 espie 154: arg++;
155: /* If the variable already has a value, we don't do anything. */
156: if ((type & VAR_OPT) && Var_Definedi(name.s, name.e)) {
157: VarName_Free(&name);
158: return true;
159: }
1.16 ! espie 160: if (type & (VAR_SHELL|VAR_SUNSHELL)) {
1.6 espie 161: char *err;
162:
163: if (strchr(arg, '$') != NULL) {
164: char *sub;
165: /* There's a dollar sign in the command, so perform
166: * variable expansion on the whole thing. */
167: sub = Var_Subst(arg, NULL, true);
168: res1 = Cmd_Exec(sub, &err);
169: free(sub);
170: } else
171: res1 = Cmd_Exec(arg, &err);
172:
173: if (err)
174: Parse_Error(PARSE_WARNING, err, arg);
175: arg = res1;
176: }
1.16 ! espie 177: if (type & VAR_LAZYSHELL) {
! 178: if (strchr(arg, '$') != NULL) {
! 179: /* There's a dollar sign in the command, so perform
! 180: * variable expansion on the whole thing. */
! 181: arg = Var_Subst(arg, NULL, true);
! 182: }
! 183: }
1.6 espie 184: if (type & VAR_SUBST) {
185: /*
186: * Allow variables in the old value to be undefined, but leave
187: * their invocation alone -- this is done by forcing
1.10 espie 188: * errorIsOkay to be false.
189: * XXX: This can cause recursive variables, but that's not
1.6 espie 190: * hard to do, and this allows someone to do something like
191: *
1.10 espie 192: * CFLAGS = $(.INCLUDES)
1.6 espie 193: * CFLAGS := -I.. $(CFLAGS)
194: *
195: * And not get an error.
196: */
197: bool saved = errorIsOkay;
198:
199: errorIsOkay = false;
200: /* ensure the variable is set to something to avoid `variable
201: * is recursive' errors. */
1.7 espie 202: if (!Var_Definedi(name.s, name.e))
1.8 espie 203: Var_Seti_with_ctxt(name.s, name.e, "", ctxt);
1.6 espie 204:
205: res2 = Var_Subst(arg, NULL, false);
206: errorIsOkay = saved;
207:
208: arg = res2;
209: }
210:
211: if (type & VAR_APPEND)
1.8 espie 212: Var_Appendi_with_ctxt(name.s, name.e, arg, ctxt);
1.6 espie 213: else
1.8 espie 214: Var_Seti_with_ctxt(name.s, name.e, arg, ctxt);
1.16 ! espie 215: if (type & VAR_LAZYSHELL)
! 216: Var_Mark(name.s, name.e, VAR_EXEC_LATER);
1.1 espie 217:
218: VarName_Free(&name);
1.6 espie 219: free(res2);
220: free(res1);
1.1 espie 221: return true;
1.3 espie 222: }
223:
224: bool
1.12 espie 225: Parse_As_Var_Assignment(const char *line)
1.3 espie 226: {
227: return parse_variable_assignment(line, VAR_GLOBAL);
228: }
229:
230: bool
231: Parse_CmdlineVar(const char *line)
232: {
233: bool result;
1.4 espie 234: bool saved = errorIsOkay;
1.3 espie 235:
1.4 espie 236: errorIsOkay = false;
1.3 espie 237: result = parse_variable_assignment(line, VAR_CMD);
1.5 espie 238: errorIsOkay = saved;
1.3 espie 239: return result;
1.1 espie 240: }
241: