GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: var.c,v 1.99 2015/09/27 16:58:16 guenther Exp $ */ |
||
2 |
/* $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $ */ |
||
3 |
|||
4 |
/* |
||
5 |
* Copyright (c) 1999,2000,2007 Marc Espie. |
||
6 |
* |
||
7 |
* Extensive code modifications for the OpenBSD project. |
||
8 |
* |
||
9 |
* Redistribution and use in source and binary forms, with or without |
||
10 |
* modification, are permitted provided that the following conditions |
||
11 |
* are met: |
||
12 |
* 1. Redistributions of source code must retain the above copyright |
||
13 |
* notice, this list of conditions and the following disclaimer. |
||
14 |
* 2. Redistributions in binary form must reproduce the above copyright |
||
15 |
* notice, this list of conditions and the following disclaimer in the |
||
16 |
* documentation and/or other materials provided with the distribution. |
||
17 |
* |
||
18 |
* THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS |
||
19 |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
20 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||
21 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD |
||
22 |
* PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||
23 |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||
24 |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||
25 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||
26 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
27 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||
28 |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
29 |
*/ |
||
30 |
/* |
||
31 |
* Copyright (c) 1988, 1989, 1990, 1993 |
||
32 |
* The Regents of the University of California. All rights reserved. |
||
33 |
* Copyright (c) 1989 by Berkeley Softworks |
||
34 |
* All rights reserved. |
||
35 |
* |
||
36 |
* This code is derived from software contributed to Berkeley by |
||
37 |
* Adam de Boor. |
||
38 |
* |
||
39 |
* Redistribution and use in source and binary forms, with or without |
||
40 |
* modification, are permitted provided that the following conditions |
||
41 |
* are met: |
||
42 |
* 1. Redistributions of source code must retain the above copyright |
||
43 |
* notice, this list of conditions and the following disclaimer. |
||
44 |
* 2. Redistributions in binary form must reproduce the above copyright |
||
45 |
* notice, this list of conditions and the following disclaimer in the |
||
46 |
* documentation and/or other materials provided with the distribution. |
||
47 |
* 3. Neither the name of the University nor the names of its contributors |
||
48 |
* may be used to endorse or promote products derived from this software |
||
49 |
* without specific prior written permission. |
||
50 |
* |
||
51 |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
||
52 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
53 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
54 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
||
55 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
56 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||
57 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||
58 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||
59 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||
60 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||
61 |
* SUCH DAMAGE. |
||
62 |
*/ |
||
63 |
|||
64 |
#include <assert.h> |
||
65 |
#include <stddef.h> |
||
66 |
#include <stdint.h> |
||
67 |
#include <stdio.h> |
||
68 |
#include <stdlib.h> |
||
69 |
#include <string.h> |
||
70 |
#include <ohash.h> |
||
71 |
|||
72 |
#include "config.h" |
||
73 |
#include "defines.h" |
||
74 |
#include "buf.h" |
||
75 |
#include "stats.h" |
||
76 |
#include "pathnames.h" |
||
77 |
#include "varmodifiers.h" |
||
78 |
#include "var.h" |
||
79 |
#include "varname.h" |
||
80 |
#include "error.h" |
||
81 |
#include "str.h" |
||
82 |
#include "var_int.h" |
||
83 |
#include "memory.h" |
||
84 |
#include "symtable.h" |
||
85 |
#include "gnode.h" |
||
86 |
#include "dump.h" |
||
87 |
#include "lowparse.h" |
||
88 |
|||
89 |
/* |
||
90 |
* This is a harmless return value for Var_Parse that can be used by Var_Subst |
||
91 |
* to determine if there was an error in parsing -- easier than returning |
||
92 |
* a flag, as things outside this module don't give a hoot. |
||
93 |
*/ |
||
94 |
char var_Error[] = ""; |
||
95 |
|||
96 |
GNode *current_node = NULL; |
||
97 |
/* |
||
98 |
* Similar to var_Error, but returned when the 'err' flag for Var_Parse is |
||
99 |
* set false. Why not just use a constant? Well, gcc likes to condense |
||
100 |
* identical string instances... |
||
101 |
*/ |
||
102 |
static char varNoError[] = ""; |
||
103 |
bool errorIsOkay; |
||
104 |
static bool checkEnvFirst; /* true if environment should be searched for |
||
105 |
* variables before the global context */ |
||
106 |
|||
107 |
void |
||
108 |
Var_setCheckEnvFirst(bool yes) |
||
109 |
729 |
{ |
|
110 |
729 |
checkEnvFirst = yes; |
|
111 |
729 |
} |
|
112 |
|||
113 |
/* |
||
114 |
* The rules for variable look-up are complicated. |
||
115 |
* |
||
116 |
* - Dynamic variables like $@ and $* are special. They always pertain to |
||
117 |
* a given variable. In this implementation of make, it is an error to |
||
118 |
* try to affect them manually. They are stored in a local symtable directly |
||
119 |
* inside the gnode. |
||
120 |
* |
||
121 |
* Global variables can be obtained: |
||
122 |
* - from the command line |
||
123 |
* - from the environment |
||
124 |
* - from the Makefile proper. |
||
125 |
* All of these are stored in a hash global_variables. |
||
126 |
* |
||
127 |
* Variables set on the command line override Makefile contents, are |
||
128 |
* passed to submakes (see Var_AddCmdLine), and are also exported to the |
||
129 |
* environment. |
||
130 |
* |
||
131 |
* Without -e (!checkEnvFirst), make will see variables set in the |
||
132 |
* Makefile, and default to the environment otherwise. |
||
133 |
* |
||
134 |
* With -e (checkEnvFirst), make will see the environment first, and that |
||
135 |
* will override anything that's set in the Makefile (but not set on |
||
136 |
* the command line). |
||
137 |
* |
||
138 |
* The SHELL variable is very special: it is never obtained from the |
||
139 |
* environment, and never passed to the environment. |
||
140 |
*/ |
||
141 |
|||
142 |
/* definitions pertaining to dynamic variables */ |
||
143 |
|||
144 |
/* full names of dynamic variables */ |
||
145 |
static char *varnames[] = { |
||
146 |
TARGET, |
||
147 |
PREFIX, |
||
148 |
ARCHIVE, |
||
149 |
MEMBER, |
||
150 |
OODATE, |
||
151 |
ALLSRC, |
||
152 |
IMPSRC, |
||
153 |
FTARGET, |
||
154 |
DTARGET, |
||
155 |
FPREFIX, |
||
156 |
DPREFIX, |
||
157 |
FARCHIVE, |
||
158 |
DARCHIVE, |
||
159 |
FMEMBER, |
||
160 |
DMEMBER |
||
161 |
}; |
||
162 |
|||
163 |
static bool xtlist[] = { |
||
164 |
false, /* GLOBAL_INDEX */ |
||
165 |
true, /* $@ */ |
||
166 |
false, /* $* */ |
||
167 |
false, /* $! */ |
||
168 |
true, /* $% */ |
||
169 |
false, /* $? */ |
||
170 |
false, /* $> */ |
||
171 |
true, /* $< */ |
||
172 |
true, /* ${@F} */ |
||
173 |
true, /* ${@D} */ |
||
174 |
false, /* ${*F} */ |
||
175 |
false, /* ${*D} */ |
||
176 |
false, /* ${!F} */ |
||
177 |
false, /* ${!D} */ |
||
178 |
true, /* ${%F} */ |
||
179 |
true, /* ${%D} */ |
||
180 |
}; |
||
181 |
|||
182 |
/* so that we can access tlist[-1] */ |
||
183 |
static bool *tlist = xtlist+1; |
||
184 |
|||
185 |
/* hashed names of dynamic variables */ |
||
186 |
#include "varhashconsts.h" |
||
187 |
|||
188 |
/* extended indices for System V stuff */ |
||
189 |
#define FTARGET_INDEX 7 |
||
190 |
#define DTARGET_INDEX 8 |
||
191 |
#define FPREFIX_INDEX 9 |
||
192 |
#define DPREFIX_INDEX 10 |
||
193 |
#define FARCHIVE_INDEX 11 |
||
194 |
#define DARCHIVE_INDEX 12 |
||
195 |
#define FMEMBER_INDEX 13 |
||
196 |
#define DMEMBER_INDEX 14 |
||
197 |
|||
198 |
#define GLOBAL_INDEX -1 |
||
199 |
|||
200 |
#define EXTENDED2SIMPLE(i) (((i)-LOCAL_SIZE)/2) |
||
201 |
#define IS_EXTENDED_F(i) ((i)%2 == 1) |
||
202 |
|||
203 |
|||
204 |
static struct ohash global_variables; |
||
205 |
|||
206 |
|||
207 |
typedef struct Var_ { |
||
208 |
BUFFER val; /* the variable value */ |
||
209 |
unsigned int flags; /* miscellaneous status flags */ |
||
210 |
#define VAR_IN_USE 1 /* Variable's value currently being used. */ |
||
211 |
/* (Used to avoid recursion) */ |
||
212 |
#define VAR_DUMMY 2 /* Variable is currently just a name */ |
||
213 |
/* In particular: BUFFER is invalid */ |
||
214 |
#define VAR_FROM_CMD 4 /* Special source: command line */ |
||
215 |
#define VAR_FROM_ENV 8 /* Special source: environment */ |
||
216 |
#define VAR_SEEN_ENV 16 /* No need to go look up environment again */ |
||
217 |
#define VAR_SHELL 32 /* Magic behavior */ |
||
218 |
|||
219 |
#define POISONS (POISON_NORMAL | POISON_EMPTY | POISON_NOT_DEFINED) |
||
220 |
/* Defined in var.h */ |
||
221 |
char name[1]; /* the variable's name */ |
||
222 |
} Var; |
||
223 |
|||
224 |
|||
225 |
static struct ohash_info var_info = { |
||
226 |
offsetof(Var, name), |
||
227 |
NULL, |
||
228 |
hash_calloc, hash_free, element_alloc |
||
229 |
}; |
||
230 |
|||
231 |
static int classify_var(const char *, const char **, uint32_t *); |
||
232 |
static Var *find_global_var(const char *, const char *, uint32_t); |
||
233 |
static Var *find_global_var_without_env(const char *, const char *, uint32_t); |
||
234 |
static void fill_from_env(Var *); |
||
235 |
static Var *create_var(const char *, const char *); |
||
236 |
static void var_set_initial_value(Var *, const char *); |
||
237 |
static void var_set_value(Var *, const char *); |
||
238 |
#define var_get_value(v) Buf_Retrieve(&((v)->val)) |
||
239 |
static void var_append_value(Var *, const char *); |
||
240 |
static void poison_check(Var *); |
||
241 |
static void var_set_append(const char *, const char *, const char *, int, bool); |
||
242 |
static void set_magic_shell_variable(void); |
||
243 |
|||
244 |
static void delete_var(Var *); |
||
245 |
static void print_var(Var *); |
||
246 |
|||
247 |
|||
248 |
static const char *find_rparen(const char *); |
||
249 |
static const char *find_ket(const char *); |
||
250 |
typedef const char * (*find_t)(const char *); |
||
251 |
static find_t find_pos(int); |
||
252 |
static void push_used(Var *); |
||
253 |
static void pop_used(Var *); |
||
254 |
static char *get_expanded_value(const char *, const char *, int, uint32_t, |
||
255 |
SymTable *, bool, bool *); |
||
256 |
static bool parse_base_variable_name(const char **, struct Name *, SymTable *); |
||
257 |
|||
258 |
|||
259 |
|||
260 |
/* Variable lookup function: return idx for dynamic variable, or |
||
261 |
* GLOBAL_INDEX if name is not dynamic. Set up *pk for further use. |
||
262 |
*/ |
||
263 |
static int |
||
264 |
classify_var(const char *name, const char **enamePtr, uint32_t *pk) |
||
265 |
324991 |
{ |
|
266 |
size_t len; |
||
267 |
|||
268 |
324991 |
*pk = ohash_interval(name, enamePtr); |
|
269 |
324991 |
len = *enamePtr - name; |
|
270 |
/* substitute short version for long local name */ |
||
271 |
✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓ |
324991 |
switch (*pk % MAGICSLOTS1) { /* MAGICSLOTS should be the */ |
272 |
case K_LONGALLSRC % MAGICSLOTS1:/* smallest constant yielding */ |
||
273 |
/* distinct case values */ |
||
274 |
✓✓✓✗ |
1769 |
if (*pk == K_LONGALLSRC && len == strlen(LONGALLSRC) && |
275 |
strncmp(name, LONGALLSRC, len) == 0) |
||
276 |
153 |
return ALLSRC_INDEX; |
|
277 |
break; |
||
278 |
case K_LONGARCHIVE % MAGICSLOTS1: |
||
279 |
✗✓✗✗ |
4130 |
if (*pk == K_LONGARCHIVE && len == strlen(LONGARCHIVE) && |
280 |
strncmp(name, LONGARCHIVE, len) == 0) |
||
281 |
return ARCHIVE_INDEX; |
||
282 |
break; |
||
283 |
case K_LONGIMPSRC % MAGICSLOTS1: |
||
284 |
✓✓✓✗ |
3360 |
if (*pk == K_LONGIMPSRC && len == strlen(LONGIMPSRC) && |
285 |
strncmp(name, LONGIMPSRC, len) == 0) |
||
286 |
821 |
return IMPSRC_INDEX; |
|
287 |
break; |
||
288 |
case K_LONGMEMBER % MAGICSLOTS1: |
||
289 |
✗✓✗✗ |
11744 |
if (*pk == K_LONGMEMBER && len == strlen(LONGMEMBER) && |
290 |
strncmp(name, LONGMEMBER, len) == 0) |
||
291 |
return MEMBER_INDEX; |
||
292 |
break; |
||
293 |
case K_LONGOODATE % MAGICSLOTS1: |
||
294 |
✗✓✗✗ |
2528 |
if (*pk == K_LONGOODATE && len == strlen(LONGOODATE) && |
295 |
strncmp(name, LONGOODATE, len) == 0) |
||
296 |
return OODATE_INDEX; |
||
297 |
break; |
||
298 |
case K_LONGPREFIX % MAGICSLOTS1: |
||
299 |
✗✓✗✗ |
5937 |
if (*pk == K_LONGPREFIX && len == strlen(LONGPREFIX) && |
300 |
strncmp(name, LONGPREFIX, len) == 0) |
||
301 |
return PREFIX_INDEX; |
||
302 |
break; |
||
303 |
case K_LONGTARGET % MAGICSLOTS1: |
||
304 |
✓✓✓✗ |
1993 |
if (*pk == K_LONGTARGET && len == strlen(LONGTARGET) && |
305 |
strncmp(name, LONGTARGET, len) == 0) |
||
306 |
517 |
return TARGET_INDEX; |
|
307 |
break; |
||
308 |
case K_TARGET % MAGICSLOTS1: |
||
309 |
✓✓ | 6559 |
if (name[0] == TARGET[0] && len == 1) |
310 |
184 |
return TARGET_INDEX; |
|
311 |
break; |
||
312 |
case K_OODATE % MAGICSLOTS1: |
||
313 |
✗✓ | 9507 |
if (name[0] == OODATE[0] && len == 1) |
314 |
return OODATE_INDEX; |
||
315 |
break; |
||
316 |
case K_ALLSRC % MAGICSLOTS1: |
||
317 |
✓✓ | 2373 |
if (name[0] == ALLSRC[0] && len == 1) |
318 |
3 |
return ALLSRC_INDEX; |
|
319 |
break; |
||
320 |
case K_IMPSRC % MAGICSLOTS1: |
||
321 |
✓✓ | 720 |
if (name[0] == IMPSRC[0] && len == 1) |
322 |
224 |
return IMPSRC_INDEX; |
|
323 |
break; |
||
324 |
case K_PREFIX % MAGICSLOTS1: |
||
325 |
✓✓ | 8652 |
if (name[0] == PREFIX[0] && len == 1) |
326 |
991 |
return PREFIX_INDEX; |
|
327 |
break; |
||
328 |
case K_ARCHIVE % MAGICSLOTS1: |
||
329 |
✗✓ | 1466 |
if (name[0] == ARCHIVE[0] && len == 1) |
330 |
return ARCHIVE_INDEX; |
||
331 |
break; |
||
332 |
case K_MEMBER % MAGICSLOTS1: |
||
333 |
✗✓ | 2802 |
if (name[0] == MEMBER[0] && len == 1) |
334 |
return MEMBER_INDEX; |
||
335 |
break; |
||
336 |
case K_FTARGET % MAGICSLOTS1: |
||
337 |
✗✓✗✗ |
2262 |
if (name[0] == FTARGET[0] && name[1] == FTARGET[1] && len == 2) |
338 |
return FTARGET_INDEX; |
||
339 |
break; |
||
340 |
case K_DTARGET % MAGICSLOTS1: |
||
341 |
✗✓✗✗ |
129 |
if (name[0] == DTARGET[0] && name[1] == DTARGET[1] && len == 2) |
342 |
return DTARGET_INDEX; |
||
343 |
break; |
||
344 |
case K_FPREFIX % MAGICSLOTS1: |
||
345 |
✗✓✗✗ |
8196 |
if (name[0] == FPREFIX[0] && name[1] == FPREFIX[1] && len == 2) |
346 |
return FPREFIX_INDEX; |
||
347 |
break; |
||
348 |
case K_DPREFIX % MAGICSLOTS1: |
||
349 |
✗✓✗✗ |
422 |
if (name[0] == DPREFIX[0] && name[1] == DPREFIX[1] && len == 2) |
350 |
return DPREFIX_INDEX; |
||
351 |
break; |
||
352 |
case K_FARCHIVE % MAGICSLOTS1: |
||
353 |
✗✓✗✗ |
1829 |
if (name[0] == FARCHIVE[0] && name[1] == FARCHIVE[1] && |
354 |
len == 2) |
||
355 |
return FARCHIVE_INDEX; |
||
356 |
break; |
||
357 |
case K_DARCHIVE % MAGICSLOTS1: |
||
358 |
✗✓✗✗ |
9946 |
if (name[0] == DARCHIVE[0] && name[1] == DARCHIVE[1] && |
359 |
len == 2) |
||
360 |
return DARCHIVE_INDEX; |
||
361 |
break; |
||
362 |
case K_FMEMBER % MAGICSLOTS1: |
||
363 |
✗✓✗✗ |
3879 |
if (name[0] == FMEMBER[0] && name[1] == FMEMBER[1] && len == 2) |
364 |
return FMEMBER_INDEX; |
||
365 |
break; |
||
366 |
case K_DMEMBER % MAGICSLOTS1: |
||
367 |
✗✓✗✗ |
1344 |
if (name[0] == DMEMBER[0] && name[1] == DMEMBER[1] && len == 2) |
368 |
return DMEMBER_INDEX; |
||
369 |
break; |
||
370 |
default: |
||
371 |
break; |
||
372 |
} |
||
373 |
322098 |
return GLOBAL_INDEX; |
|
374 |
} |
||
375 |
|||
376 |
|||
377 |
/*** |
||
378 |
*** Internal handling of variables. |
||
379 |
***/ |
||
380 |
|||
381 |
|||
382 |
/* Create a new variable, does not initialize anything except the name. |
||
383 |
* in particular, buffer is invalid, and flag value is invalid. Accordingly, |
||
384 |
* must either: |
||
385 |
* - set flags to VAR_DUMMY |
||
386 |
* - set flags to !VAR_DUMMY, and initialize buffer, for instance with |
||
387 |
* var_set_initial_value(). |
||
388 |
*/ |
||
389 |
static Var * |
||
390 |
create_var(const char *name, const char *ename) |
||
391 |
133765 |
{ |
|
392 |
133765 |
return ohash_create_entry(&var_info, name, &ename); |
|
393 |
} |
||
394 |
|||
395 |
/* Initial version of var_set_value(), to be called after create_var(). |
||
396 |
*/ |
||
397 |
static void |
||
398 |
var_set_initial_value(Var *v, const char *val) |
||
399 |
120454 |
{ |
|
400 |
size_t len; |
||
401 |
|||
402 |
120454 |
len = strlen(val); |
|
403 |
120454 |
Buf_Init(&(v->val), len+1); |
|
404 |
120454 |
Buf_AddChars(&(v->val), len, val); |
|
405 |
120454 |
} |
|
406 |
|||
407 |
/* Normal version of var_set_value(), to be called after variable is fully |
||
408 |
* initialized. |
||
409 |
*/ |
||
410 |
static void |
||
411 |
var_set_value(Var *v, const char *val) |
||
412 |
135683 |
{ |
|
413 |
✓✓ | 135683 |
if ((v->flags & VAR_DUMMY) == 0) { |
414 |
19554 |
Buf_Reset(&(v->val)); |
|
415 |
19554 |
Buf_AddString(&(v->val), val); |
|
416 |
} else { |
||
417 |
116129 |
var_set_initial_value(v, val); |
|
418 |
116129 |
v->flags &= ~VAR_DUMMY; |
|
419 |
} |
||
420 |
135683 |
} |
|
421 |
|||
422 |
/* Add to a variable, insert a separating space if the variable was already |
||
423 |
* defined. |
||
424 |
*/ |
||
425 |
static void |
||
426 |
var_append_value(Var *v, const char *val) |
||
427 |
17377 |
{ |
|
428 |
✓✓ | 17377 |
if ((v->flags & VAR_DUMMY) == 0) { |
429 |
✓✓ | 13052 |
Buf_AddSpace(&(v->val)); |
430 |
13052 |
Buf_AddString(&(v->val), val); |
|
431 |
} else { |
||
432 |
4325 |
var_set_initial_value(v, val); |
|
433 |
4325 |
v->flags &= ~VAR_DUMMY; |
|
434 |
} |
||
435 |
17377 |
} |
|
436 |
|||
437 |
|||
438 |
/* Delete a variable and all the space associated with it. |
||
439 |
*/ |
||
440 |
static void |
||
441 |
delete_var(Var *v) |
||
442 |
{ |
||
443 |
if ((v->flags & VAR_DUMMY) == 0) |
||
444 |
Buf_Destroy(&(v->val)); |
||
445 |
free(v); |
||
446 |
} |
||
447 |
|||
448 |
|||
449 |
|||
450 |
|||
451 |
/*** |
||
452 |
*** Dynamic variable handling. |
||
453 |
***/ |
||
454 |
|||
455 |
|||
456 |
|||
457 |
/* create empty symtable. |
||
458 |
* XXX: to save space, dynamic variables may be NULL pointers. |
||
459 |
*/ |
||
460 |
void |
||
461 |
SymTable_Init(SymTable *ctxt) |
||
462 |
84705 |
{ |
|
463 |
static SymTable sym_template; |
||
464 |
84705 |
memcpy(ctxt, &sym_template, sizeof(*ctxt)); |
|
465 |
84705 |
} |
|
466 |
|||
467 |
/*** |
||
468 |
*** Global variable handling. |
||
469 |
***/ |
||
470 |
|||
471 |
/* Create a new global var if necessary, and set it up correctly. |
||
472 |
* Do not take environment into account. |
||
473 |
*/ |
||
474 |
static Var * |
||
475 |
find_global_var_without_env(const char *name, const char *ename, uint32_t k) |
||
476 |
325162 |
{ |
|
477 |
unsigned int slot; |
||
478 |
Var *v; |
||
479 |
|||
480 |
325162 |
slot = ohash_lookup_interval(&global_variables, name, ename, k); |
|
481 |
325162 |
v = ohash_find(&global_variables, slot); |
|
482 |
✓✓ | 325162 |
if (v == NULL) { |
483 |
133765 |
v = create_var(name, ename); |
|
484 |
133765 |
v->flags = VAR_DUMMY; |
|
485 |
133765 |
ohash_insert(&global_variables, slot, v); |
|
486 |
} |
||
487 |
325162 |
return v; |
|
488 |
} |
||
489 |
|||
490 |
/* Helper for find_global_var(): grab environment value if needed. |
||
491 |
*/ |
||
492 |
static void |
||
493 |
fill_from_env(Var *v) |
||
494 |
130448 |
{ |
|
495 |
char *env; |
||
496 |
|||
497 |
130448 |
env = getenv(v->name); |
|
498 |
✓✓ | 130448 |
if (env == NULL) |
499 |
128834 |
v->flags |= VAR_SEEN_ENV; |
|
500 |
else { |
||
501 |
1614 |
var_set_value(v, env); |
|
502 |
1614 |
v->flags |= VAR_FROM_ENV | VAR_SEEN_ENV; |
|
503 |
} |
||
504 |
|||
505 |
#ifdef STATS_VAR_LOOKUP |
||
506 |
STAT_VAR_FROM_ENV++; |
||
507 |
#endif |
||
508 |
130448 |
} |
|
509 |
|||
510 |
/* Find global var, and obtain its value from the environment if needed. |
||
511 |
*/ |
||
512 |
static Var * |
||
513 |
find_global_var(const char *name, const char *ename, uint32_t k) |
||
514 |
321474 |
{ |
|
515 |
Var *v; |
||
516 |
|||
517 |
321474 |
v = find_global_var_without_env(name, ename, k); |
|
518 |
|||
519 |
✓✓ | 321474 |
if ((v->flags & VAR_SEEN_ENV) == 0) |
520 |
✗✓✗✗ ✓✗ |
130448 |
if ((checkEnvFirst && (v->flags & VAR_FROM_CMD) == 0) || |
521 |
(v->flags & VAR_DUMMY) != 0) |
||
522 |
130448 |
fill_from_env(v); |
|
523 |
|||
524 |
321474 |
return v; |
|
525 |
} |
||
526 |
|||
527 |
/* mark variable as poisoned, in a given setup. |
||
528 |
*/ |
||
529 |
void |
||
530 |
Var_MarkPoisoned(const char *name, const char *ename, unsigned int type) |
||
531 |
{ |
||
532 |
Var *v; |
||
533 |
uint32_t k; |
||
534 |
int idx; |
||
535 |
idx = classify_var(name, &ename, &k); |
||
536 |
|||
537 |
if (idx != GLOBAL_INDEX) { |
||
538 |
Parse_Error(PARSE_FATAL, |
||
539 |
"Trying to poison dynamic variable $%s", |
||
540 |
varnames[idx]); |
||
541 |
return; |
||
542 |
} |
||
543 |
|||
544 |
v = find_global_var(name, ename, k); |
||
545 |
v->flags |= type; |
||
546 |
/* POISON_NORMAL is not lazy: if the variable already exists in |
||
547 |
* the Makefile, then it's a mistake. |
||
548 |
*/ |
||
549 |
if (v->flags & POISON_NORMAL) { |
||
550 |
if (v->flags & VAR_DUMMY) |
||
551 |
return; |
||
552 |
if (v->flags & VAR_FROM_ENV) |
||
553 |
return; |
||
554 |
Parse_Error(PARSE_FATAL, |
||
555 |
"Poisoned variable %s is already set\n", v->name); |
||
556 |
} |
||
557 |
} |
||
558 |
|||
559 |
/* Check if there's any reason not to use the variable in this context. |
||
560 |
*/ |
||
561 |
static void |
||
562 |
poison_check(Var *v) |
||
563 |
{ |
||
564 |
if (v->flags & POISON_NORMAL) { |
||
565 |
Parse_Error(PARSE_FATAL, |
||
566 |
"Poisoned variable %s has been referenced\n", v->name); |
||
567 |
return; |
||
568 |
} |
||
569 |
if (v->flags & VAR_DUMMY) { |
||
570 |
Parse_Error(PARSE_FATAL, |
||
571 |
"Poisoned variable %s is not defined\n", v->name); |
||
572 |
return; |
||
573 |
} |
||
574 |
if (v->flags & POISON_EMPTY) |
||
575 |
if (strcmp(var_get_value(v), "") == 0) |
||
576 |
Parse_Error(PARSE_FATAL, |
||
577 |
"Poisoned variable %s is empty\n", v->name); |
||
578 |
} |
||
579 |
|||
580 |
/* Delete global variable. |
||
581 |
*/ |
||
582 |
void |
||
583 |
Var_Deletei(const char *name, const char *ename) |
||
584 |
{ |
||
585 |
Var *v; |
||
586 |
uint32_t k; |
||
587 |
unsigned int slot; |
||
588 |
int idx; |
||
589 |
|||
590 |
idx = classify_var(name, &ename, &k); |
||
591 |
if (idx != GLOBAL_INDEX) { |
||
592 |
Parse_Error(PARSE_FATAL, |
||
593 |
"Trying to delete dynamic variable $%s", varnames[idx]); |
||
594 |
return; |
||
595 |
} |
||
596 |
slot = ohash_lookup_interval(&global_variables, name, ename, k); |
||
597 |
v = ohash_find(&global_variables, slot); |
||
598 |
|||
599 |
if (v == NULL) |
||
600 |
return; |
||
601 |
|||
602 |
if (checkEnvFirst && (v->flags & VAR_FROM_ENV)) |
||
603 |
return; |
||
604 |
|||
605 |
if (v->flags & VAR_FROM_CMD) |
||
606 |
return; |
||
607 |
|||
608 |
ohash_remove(&global_variables, slot); |
||
609 |
delete_var(v); |
||
610 |
} |
||
611 |
|||
612 |
/* Set or add a global variable, in VAR_CMD or VAR_GLOBAL context. |
||
613 |
*/ |
||
614 |
static void |
||
615 |
var_set_append(const char *name, const char *ename, const char *val, int ctxt, |
||
616 |
bool append) |
||
617 |
136797 |
{ |
|
618 |
Var *v; |
||
619 |
uint32_t k; |
||
620 |
int idx; |
||
621 |
|||
622 |
136797 |
idx = classify_var(name, &ename, &k); |
|
623 |
✗✓ | 136797 |
if (idx != GLOBAL_INDEX) { |
624 |
Parse_Error(PARSE_FATAL, "Trying to %s dynamic variable $%s", |
||
625 |
append ? "append to" : "set", varnames[idx]); |
||
626 |
return; |
||
627 |
} |
||
628 |
|||
629 |
136797 |
v = find_global_var(name, ename, k); |
|
630 |
✗✓ | 136797 |
if (v->flags & POISON_NORMAL) |
631 |
Parse_Error(PARSE_FATAL, "Trying to %s poisoned variable %s\n", |
||
632 |
append ? "append to" : "set", v->name); |
||
633 |
/* so can we write to it ? */ |
||
634 |
✓✓ | 136797 |
if (ctxt == VAR_CMD) { /* always for command line */ |
635 |
✗✓ | 2416 |
(append ? var_append_value : var_set_value)(v, val); |
636 |
2416 |
v->flags |= VAR_FROM_CMD; |
|
637 |
✓✗ | 2416 |
if ((v->flags & VAR_SHELL) == 0) { |
638 |
/* Any variables given on the command line are |
||
639 |
* automatically exported to the environment, |
||
640 |
* except for SHELL (as per POSIX standard). |
||
641 |
*/ |
||
642 |
2416 |
esetenv(v->name, val); |
|
643 |
} |
||
644 |
✗✓ | 2416 |
if (DEBUG(VAR)) |
645 |
printf("command:%s = %s\n", v->name, var_get_value(v)); |
||
646 |
✓✓✗✓ ✗✗ |
134381 |
} else if ((v->flags & VAR_FROM_CMD) == 0 && |
647 |
(!checkEnvFirst || (v->flags & VAR_FROM_ENV) == 0)) { |
||
648 |
✓✓ | 134184 |
(append ? var_append_value : var_set_value)(v, val); |
649 |
✗✓ | 134184 |
if (DEBUG(VAR)) |
650 |
printf("global:%s = %s\n", v->name, var_get_value(v)); |
||
651 |
✗✓ | 197 |
} else if (DEBUG(VAR)) |
652 |
printf("overridden:%s = %s\n", v->name, var_get_value(v)); |
||
653 |
} |
||
654 |
|||
655 |
void |
||
656 |
Var_Seti_with_ctxt(const char *name, const char *ename, const char *val, |
||
657 |
int ctxt) |
||
658 |
119297 |
{ |
|
659 |
119297 |
var_set_append(name, ename, val, ctxt, false); |
|
660 |
119297 |
} |
|
661 |
|||
662 |
void |
||
663 |
Var_Appendi_with_ctxt(const char *name, const char *ename, const char *val, |
||
664 |
int ctxt) |
||
665 |
17500 |
{ |
|
666 |
17500 |
var_set_append(name, ename, val, ctxt, true); |
|
667 |
17500 |
} |
|
668 |
|||
669 |
/* XXX different semantics for Var_Valuei() and Var_Definedi(): |
||
670 |
* references to poisoned value variables will error out in Var_Valuei(), |
||
671 |
* but not in Var_Definedi(), so the following construct works: |
||
672 |
* .poison BINDIR |
||
673 |
* BINDIR ?= /usr/bin |
||
674 |
*/ |
||
675 |
char * |
||
676 |
Var_Valuei(const char *name, const char *ename) |
||
677 |
2831 |
{ |
|
678 |
Var *v; |
||
679 |
uint32_t k; |
||
680 |
int idx; |
||
681 |
|||
682 |
2831 |
idx = classify_var(name, &ename, &k); |
|
683 |
✗✓ | 2831 |
if (idx != GLOBAL_INDEX) { |
684 |
Parse_Error(PARSE_FATAL, |
||
685 |
"Trying to get value of dynamic variable $%s", |
||
686 |
varnames[idx]); |
||
687 |
return NULL; |
||
688 |
} |
||
689 |
2831 |
v = find_global_var(name, ename, k); |
|
690 |
✗✓ | 2831 |
if (v->flags & POISONS) |
691 |
poison_check(v); |
||
692 |
✓✓ | 2831 |
if ((v->flags & VAR_DUMMY) == 0) |
693 |
2103 |
return var_get_value(v); |
|
694 |
else |
||
695 |
728 |
return NULL; |
|
696 |
} |
||
697 |
|||
698 |
bool |
||
699 |
Var_Definedi(const char *name, const char *ename) |
||
700 |
111750 |
{ |
|
701 |
Var *v; |
||
702 |
uint32_t k; |
||
703 |
int idx; |
||
704 |
|||
705 |
111750 |
idx = classify_var(name, &ename, &k); |
|
706 |
/* We don't bother writing an error message for dynamic variables, |
||
707 |
* these will be caught when getting set later, usually. |
||
708 |
*/ |
||
709 |
✓✗ | 111750 |
if (idx == GLOBAL_INDEX) { |
710 |
111750 |
v = find_global_var(name, ename, k); |
|
711 |
✗✓ | 111750 |
if (v->flags & POISON_NORMAL) |
712 |
poison_check(v); |
||
713 |
✓✓ | 111750 |
if ((v->flags & VAR_DUMMY) == 0) |
714 |
8964 |
return true; |
|
715 |
} |
||
716 |
102786 |
return false; |
|
717 |
} |
||
718 |
|||
719 |
|||
720 |
/*** |
||
721 |
*** Substitution functions, handling both global and dynamic variables. |
||
722 |
***/ |
||
723 |
|||
724 |
|||
725 |
/* All the scanning functions needed to account for all the forms of |
||
726 |
* variable names that exist: |
||
727 |
* $A, ${AB}, $(ABC), ${A:mod}, $(A:mod) |
||
728 |
*/ |
||
729 |
|||
730 |
static const char * |
||
731 |
find_rparen(const char *p) |
||
732 |
7926 |
{ |
|
733 |
✓✗✓✓ ✓✓ |
64858 |
while (*p != '$' && *p != '\0' && *p != ')' && *p != ':') |
734 |
49006 |
p++; |
|
735 |
7926 |
return p; |
|
736 |
} |
||
737 |
|||
738 |
static const char * |
||
739 |
find_ket(const char *p) |
||
740 |
172432 |
{ |
|
741 |
✓✓✓✓ ✓✓ |
1806847 |
while (*p != '$' && *p != '\0' && *p != '}' && *p != ':') |
742 |
1461983 |
p++; |
|
743 |
172432 |
return p; |
|
744 |
} |
||
745 |
|||
746 |
/* Figure out what kind of name we're looking for from a start character. |
||
747 |
*/ |
||
748 |
static find_t |
||
749 |
find_pos(int c) |
||
750 |
180358 |
{ |
|
751 |
✓✓✗ | 180358 |
switch(c) { |
752 |
case '(': |
||
753 |
7926 |
return find_rparen; |
|
754 |
case '{': |
||
755 |
172432 |
return find_ket; |
|
756 |
default: |
||
757 |
Parse_Error(PARSE_FATAL, |
||
758 |
"Wrong character in variable spec %c (can't happen)", c); |
||
759 |
return find_rparen; |
||
760 |
} |
||
761 |
} |
||
762 |
|||
763 |
static bool |
||
764 |
parse_base_variable_name(const char **pstr, struct Name *name, SymTable *ctxt) |
||
765 |
73613 |
{ |
|
766 |
73613 |
const char *str = *pstr; |
|
767 |
const char *tstr; |
||
768 |
73613 |
bool has_modifier = false; |
|
769 |
|||
770 |
✓✓ | 73613 |
switch(str[1]) { |
771 |
case '(': |
||
772 |
case '{': |
||
773 |
/* Find eventual modifiers in the variable */ |
||
774 |
73199 |
tstr = VarName_Get(str+2, name, ctxt, false, find_pos(str[1])); |
|
775 |
✗✓ | 73199 |
if (*tstr == '\0') |
776 |
Parse_Error(PARSE_FATAL, "Unterminated variable spec in %s", *pstr); |
||
777 |
✓✓ | 73199 |
else if (*tstr == ':') |
778 |
11097 |
has_modifier = true; |
|
779 |
else |
||
780 |
62102 |
tstr++; |
|
781 |
break; |
||
782 |
default: |
||
783 |
414 |
name->s = str+1; |
|
784 |
414 |
name->e = str+2; |
|
785 |
414 |
name->tofree = false; |
|
786 |
414 |
tstr = str + 2; |
|
787 |
break; |
||
788 |
} |
||
789 |
73613 |
*pstr = tstr; |
|
790 |
73613 |
return has_modifier; |
|
791 |
} |
||
792 |
|||
793 |
bool |
||
794 |
Var_ParseSkip(const char **pstr, SymTable *ctxt) |
||
795 |
{ |
||
796 |
const char *str = *pstr; |
||
797 |
struct Name name; |
||
798 |
bool result; |
||
799 |
bool has_modifier; |
||
800 |
const char *tstr = str; |
||
801 |
|||
802 |
if (str[1] == 0) { |
||
803 |
*pstr = str+1; |
||
804 |
return false; |
||
805 |
} |
||
806 |
has_modifier = parse_base_variable_name(&tstr, &name, ctxt); |
||
807 |
VarName_Free(&name); |
||
808 |
result = true; |
||
809 |
if (has_modifier) { |
||
810 |
bool freePtr = false; |
||
811 |
char *s = VarModifiers_Apply(NULL, NULL, ctxt, true, &freePtr, |
||
812 |
&tstr, str[1]); |
||
813 |
if (s == var_Error) |
||
814 |
result = false; |
||
815 |
if (freePtr) |
||
816 |
free(s); |
||
817 |
} |
||
818 |
*pstr = tstr; |
||
819 |
return result; |
||
820 |
} |
||
821 |
|||
822 |
/* As of now, Var_ParseBuffer is just a wrapper around Var_Parse. For |
||
823 |
* speed, it may be better to revisit the implementation to do things |
||
824 |
* directly. */ |
||
825 |
bool |
||
826 |
Var_ParseBuffer(Buffer buf, const char *str, SymTable *ctxt, bool err, |
||
827 |
size_t *lengthPtr) |
||
828 |
5425 |
{ |
|
829 |
char *result; |
||
830 |
bool freeIt; |
||
831 |
|||
832 |
5425 |
result = Var_Parse(str, ctxt, err, lengthPtr, &freeIt); |
|
833 |
✓✓ | 5425 |
if (result == var_Error) |
834 |
682 |
return false; |
|
835 |
|||
836 |
4743 |
Buf_AddString(buf, result); |
|
837 |
✓✓ | 4743 |
if (freeIt) |
838 |
364 |
free(result); |
|
839 |
4743 |
return true; |
|
840 |
} |
||
841 |
|||
842 |
/* Helper function for Var_Parse: still recursive, but we tag what variables |
||
843 |
* we expand for better error messages. |
||
844 |
*/ |
||
845 |
#define MAX_DEPTH 350 |
||
846 |
static Var *call_trace[MAX_DEPTH]; |
||
847 |
static int current_depth = 0; |
||
848 |
|||
849 |
static void |
||
850 |
push_used(Var *v) |
||
851 |
14621 |
{ |
|
852 |
✗✓ | 14621 |
if (v->flags & VAR_IN_USE) { |
853 |
int i; |
||
854 |
fprintf(stderr, "Problem with variable expansion chain: "); |
||
855 |
for (i = 0; |
||
856 |
i < (current_depth > MAX_DEPTH ? MAX_DEPTH : current_depth); |
||
857 |
i++) |
||
858 |
fprintf(stderr, "%s -> ", call_trace[i]->name); |
||
859 |
fprintf(stderr, "%s\n", v->name); |
||
860 |
Fatal("\tVariable %s is recursive.", v->name); |
||
861 |
/*NOTREACHED*/ |
||
862 |
} |
||
863 |
|||
864 |
14621 |
v->flags |= VAR_IN_USE; |
|
865 |
✓✗ | 14621 |
if (current_depth < MAX_DEPTH) |
866 |
14621 |
call_trace[current_depth] = v; |
|
867 |
14621 |
current_depth++; |
|
868 |
14621 |
} |
|
869 |
|||
870 |
static void |
||
871 |
pop_used(Var *v) |
||
872 |
14621 |
{ |
|
873 |
14621 |
v->flags &= ~VAR_IN_USE; |
|
874 |
14621 |
current_depth--; |
|
875 |
14621 |
} |
|
876 |
|||
877 |
static char * |
||
878 |
get_expanded_value(const char *name, const char *ename, int idx, uint32_t k, |
||
879 |
SymTable *ctxt, bool err, bool *freePtr) |
||
880 |
72592 |
{ |
|
881 |
char *val; |
||
882 |
|||
883 |
/* Before doing any modification, we have to make sure the |
||
884 |
* value has been fully expanded. If it looks like recursion |
||
885 |
* might be necessary (there's a dollar sign somewhere in |
||
886 |
* the variable's value) we just call Var_Subst to do any |
||
887 |
* other substitutions that are necessary. Note that the |
||
888 |
* value returned by Var_Subst will have been dynamically |
||
889 |
* allocated, so it will need freeing when we return. |
||
890 |
*/ |
||
891 |
✓✓ | 72592 |
if (idx == GLOBAL_INDEX) { |
892 |
70096 |
Var *v = find_global_var(name, ename, k); |
|
893 |
|||
894 |
✗✓ | 70096 |
if (v == NULL) |
895 |
return NULL; |
||
896 |
|||
897 |
✗✓ | 70096 |
if ((v->flags & POISONS) != 0) |
898 |
poison_check(v); |
||
899 |
✓✓ | 70096 |
if ((v->flags & VAR_DUMMY) != 0) |
900 |
7540 |
return NULL; |
|
901 |
|||
902 |
62556 |
val = var_get_value(v); |
|
903 |
✓✓ | 62556 |
if (strchr(val, '$') != NULL) { |
904 |
14621 |
push_used(v); |
|
905 |
14621 |
val = Var_Subst(val, ctxt, err); |
|
906 |
14621 |
pop_used(v); |
|
907 |
14621 |
*freePtr = true; |
|
908 |
} |
||
909 |
} else { |
||
910 |
✓✗ | 2496 |
if (ctxt != NULL) { |
911 |
✓✗ | 2496 |
if (idx < LOCAL_SIZE) |
912 |
2496 |
val = ctxt->locals[idx]; |
|
913 |
else |
||
914 |
val = ctxt->locals[EXTENDED2SIMPLE(idx)]; |
||
915 |
} else |
||
916 |
val = NULL; |
||
917 |
✗✓ | 2496 |
if (val == NULL) |
918 |
return NULL; |
||
919 |
|||
920 |
✗✓ | 2496 |
if (idx >= LOCAL_SIZE) { |
921 |
if (IS_EXTENDED_F(idx)) |
||
922 |
val = Var_GetTail(val); |
||
923 |
else |
||
924 |
val = Var_GetHead(val); |
||
925 |
*freePtr = true; |
||
926 |
} |
||
927 |
} |
||
928 |
65052 |
return val; |
|
929 |
} |
||
930 |
|||
931 |
#define ERRMSG1 "Using $< in a non-suffix rule context is a GNUmake idiom " |
||
932 |
#define ERRMSG2 "Using undefined dynamic variable $%s " |
||
933 |
static void |
||
934 |
bad_dynamic_variable(int idx) |
||
935 |
{ |
||
936 |
Location origin; |
||
937 |
|||
938 |
Parse_FillLocation(&origin); |
||
939 |
if (idx >= LOCAL_SIZE) |
||
940 |
idx = EXTENDED2SIMPLE(idx); |
||
941 |
switch(idx) { |
||
942 |
case IMPSRC_INDEX: |
||
943 |
if (origin.fname) |
||
944 |
Fatal(ERRMSG1 "(%s:%lu)", |
||
945 |
origin.fname, origin.lineno); |
||
946 |
else if (current_node) |
||
947 |
Fatal(ERRMSG1 "(prereq of %s)", current_node->name); |
||
948 |
else |
||
949 |
Fatal(ERRMSG1 "(?)"); |
||
950 |
break; |
||
951 |
default: |
||
952 |
if (origin.fname) |
||
953 |
Error(ERRMSG2 "(%s:%lu)", varnames[idx], |
||
954 |
origin.fname, origin.lineno); |
||
955 |
else if (current_node) |
||
956 |
Error(ERRMSG2 "(prereq of %s)", varnames[idx], |
||
957 |
current_node->name); |
||
958 |
else |
||
959 |
Error(ERRMSG2 "(?)", varnames[idx]); |
||
960 |
break; |
||
961 |
} |
||
962 |
} |
||
963 |
|||
964 |
char * |
||
965 |
Var_Parse(const char *str, /* The string to parse */ |
||
966 |
SymTable *ctxt, /* The context for the variable */ |
||
967 |
bool err, /* true if undefined variables are an error */ |
||
968 |
size_t *lengthPtr, /* OUT: The length of the specification */ |
||
969 |
bool *freePtr) /* OUT: true if caller should free result */ |
||
970 |
72592 |
{ |
|
971 |
const char *tstr; |
||
972 |
struct Name name; |
||
973 |
char *val; |
||
974 |
uint32_t k; |
||
975 |
int idx; |
||
976 |
bool has_modifier; |
||
977 |
|||
978 |
72592 |
*freePtr = false; |
|
979 |
|||
980 |
72592 |
tstr = str; |
|
981 |
|||
982 |
✗✓ | 72592 |
if (str[1] == 0) { |
983 |
*lengthPtr = 1; |
||
984 |
*freePtr = false; |
||
985 |
return err ? var_Error : varNoError; |
||
986 |
} |
||
987 |
|||
988 |
72592 |
has_modifier = parse_base_variable_name(&tstr, &name, ctxt); |
|
989 |
|||
990 |
72592 |
idx = classify_var(name.s, &name.e, &k); |
|
991 |
72592 |
val = get_expanded_value(name.s, name.e, idx, k, ctxt, err, freePtr); |
|
992 |
✓✓ | 72592 |
if (has_modifier) { |
993 |
11097 |
val = VarModifiers_Apply(val, &name, ctxt, err, freePtr, |
|
994 |
&tstr, str[1]); |
||
995 |
} |
||
996 |
✓✓ | 72592 |
if (val == NULL) { |
997 |
✓✓ | 7540 |
val = err ? var_Error : varNoError; |
998 |
/* If it comes from a dynamic source, and it doesn't have |
||
999 |
* a context, copy the spec instead. |
||
1000 |
* Specifically, this make allows constructs like: |
||
1001 |
* target.o: $*.c |
||
1002 |
* Absence of a context means "parsing". But these can't |
||
1003 |
* be expanded during parsing, to be consistent with the |
||
1004 |
* way .SUFFIXES work. |
||
1005 |
* .SUFFIXES may be added/reset/removed during parsing, |
||
1006 |
* but in the end, the final list is what's considered for |
||
1007 |
* handling targets. So those dynamic variables must be |
||
1008 |
* handled lazily too. |
||
1009 |
*/ |
||
1010 |
✗✓ | 7540 |
if (idx != GLOBAL_INDEX) { |
1011 |
if (ctxt == NULL) { |
||
1012 |
*freePtr = true; |
||
1013 |
val = Str_dupi(str, tstr); |
||
1014 |
} else { |
||
1015 |
bad_dynamic_variable(idx); |
||
1016 |
} |
||
1017 |
} |
||
1018 |
} |
||
1019 |
72592 |
VarName_Free(&name); |
|
1020 |
72592 |
*lengthPtr = tstr - str; |
|
1021 |
72592 |
return val; |
|
1022 |
} |
||
1023 |
|||
1024 |
|||
1025 |
char * |
||
1026 |
Var_Subst(const char *str, /* the string in which to substitute */ |
||
1027 |
SymTable *ctxt, /* the context wherein to find variables */ |
||
1028 |
bool undefErr) /* true if undefineds are an error */ |
||
1029 |
81211 |
{ |
|
1030 |
BUFFER buf; /* Buffer for forming things */ |
||
1031 |
static bool errorReported; |
||
1032 |
|||
1033 |
81211 |
Buf_Init(&buf, MAKE_BSIZE); |
|
1034 |
81211 |
errorReported = false; |
|
1035 |
|||
1036 |
for (;;) { |
||
1037 |
char *val; /* Value to substitute for a variable */ |
||
1038 |
size_t length; /* Length of the variable invocation */ |
||
1039 |
bool doFree; /* Set true if val should be freed */ |
||
1040 |
const char *cp; |
||
1041 |
|||
1042 |
/* copy uninteresting stuff */ |
||
1043 |
✓✓ | 128926 |
for (cp = str; *str != '\0' && *str != '$'; str++) |
1044 |
; |
||
1045 |
128926 |
Buf_Addi(&buf, cp, str); |
|
1046 |
✓✓ | 128926 |
if (*str == '\0') |
1047 |
81211 |
break; |
|
1048 |
✓✓ | 47715 |
if (str[1] == '$') { |
1049 |
/* A $ may be escaped with another $. */ |
||
1050 |
✓✓ | 1031 |
Buf_AddChar(&buf, '$'); |
1051 |
1031 |
str += 2; |
|
1052 |
1031 |
continue; |
|
1053 |
} |
||
1054 |
46684 |
val = Var_Parse(str, ctxt, undefErr, &length, &doFree); |
|
1055 |
/* When we come down here, val should either point to the |
||
1056 |
* value of this variable, suitably modified, or be NULL. |
||
1057 |
* Length should be the total length of the potential |
||
1058 |
* variable invocation (from $ to end character...) */ |
||
1059 |
✓✓✓✓ |
46684 |
if (val == var_Error || val == varNoError) { |
1060 |
/* If errors are not an issue, skip over the variable |
||
1061 |
* and continue with the substitution. Otherwise, store |
||
1062 |
* the dollar sign and advance str so we continue with |
||
1063 |
* the string... */ |
||
1064 |
✓✗ | 5886 |
if (errorIsOkay) |
1065 |
5886 |
str += length; |
|
1066 |
else if (undefErr) { |
||
1067 |
/* If variable is undefined, complain and |
||
1068 |
* skip the variable name. The complaint |
||
1069 |
* will stop us from doing anything when |
||
1070 |
* the file is parsed. */ |
||
1071 |
if (!errorReported) |
||
1072 |
Parse_Error(PARSE_FATAL, |
||
1073 |
"Undefined variable \"%.*s\"", |
||
1074 |
(int)length, str); |
||
1075 |
str += length; |
||
1076 |
errorReported = true; |
||
1077 |
} else { |
||
1078 |
Buf_AddChar(&buf, *str); |
||
1079 |
str++; |
||
1080 |
} |
||
1081 |
} else { |
||
1082 |
/* We've now got a variable structure to store in. |
||
1083 |
* But first, advance the string pointer. */ |
||
1084 |
40798 |
str += length; |
|
1085 |
|||
1086 |
/* Copy all the characters from the variable value |
||
1087 |
* straight into the new string. */ |
||
1088 |
40798 |
Buf_AddString(&buf, val); |
|
1089 |
✓✓ | 40798 |
if (doFree) |
1090 |
13008 |
free(val); |
|
1091 |
} |
||
1092 |
} |
||
1093 |
81211 |
return Buf_Retrieve(&buf); |
|
1094 |
} |
||
1095 |
|||
1096 |
/* Very quick version of the variable scanner that just looks for target |
||
1097 |
* variables, and never ever errors out |
||
1098 |
*/ |
||
1099 |
bool |
||
1100 |
Var_Check_for_target(const char *str) |
||
1101 |
438 |
{ |
|
1102 |
438 |
bool seen_target = false; |
|
1103 |
|||
1104 |
for (;;) { |
||
1105 |
const char *tstr; |
||
1106 |
uint32_t k; |
||
1107 |
int idx; |
||
1108 |
bool has_modifier; |
||
1109 |
struct Name name; |
||
1110 |
|||
1111 |
/* skip over uninteresting stuff */ |
||
1112 |
✓✓ | 26075 |
for (; *str != '\0' && *str != '$'; str++) |
1113 |
; |
||
1114 |
✓✓ | 1896 |
if (*str == '\0') |
1115 |
438 |
break; |
|
1116 |
✓✓ | 1458 |
if (str[1] == '$') { |
1117 |
/* A $ may be escaped with another $. */ |
||
1118 |
437 |
str += 2; |
|
1119 |
437 |
continue; |
|
1120 |
} |
||
1121 |
|||
1122 |
1021 |
tstr = str; |
|
1123 |
|||
1124 |
1021 |
has_modifier = parse_base_variable_name(&tstr, &name, NULL); |
|
1125 |
1021 |
idx = classify_var(name.s, &name.e, &k); |
|
1126 |
✗✓ | 1021 |
if (has_modifier) { |
1127 |
bool doFree = false; |
||
1128 |
char *val = VarModifiers_Apply(NULL, NULL, NULL, false, |
||
1129 |
&doFree, &tstr, str[1]); |
||
1130 |
if (doFree) |
||
1131 |
free(val); |
||
1132 |
} |
||
1133 |
✓✓ | 1021 |
if (tlist[idx]) |
1134 |
228 |
seen_target = true; |
|
1135 |
1021 |
VarName_Free(&name); |
|
1136 |
1021 |
str = tstr; |
|
1137 |
} |
||
1138 |
438 |
return seen_target; |
|
1139 |
} |
||
1140 |
|||
1141 |
static BUFFER subst_buffer; |
||
1142 |
|||
1143 |
/* we would like to subst on intervals, but it's complicated, so we cheat |
||
1144 |
* by storing the interval in a static buffer. |
||
1145 |
*/ |
||
1146 |
char * |
||
1147 |
Var_Substi(const char *str, const char *estr, SymTable *ctxt, bool undefErr) |
||
1148 |
5359 |
{ |
|
1149 |
/* delimited string: no need to copy */ |
||
1150 |
✓✗✗✓ |
5359 |
if (estr == NULL || *estr == '\0') |
1151 |
return Var_Subst(str, ctxt, undefErr); |
||
1152 |
|||
1153 |
5359 |
Buf_Reset(&subst_buffer); |
|
1154 |
5359 |
Buf_Addi(&subst_buffer, str, estr); |
|
1155 |
5359 |
return Var_Subst(Buf_Retrieve(&subst_buffer), ctxt, undefErr); |
|
1156 |
} |
||
1157 |
|||
1158 |
/*** |
||
1159 |
*** Supplementary support for .for loops. |
||
1160 |
***/ |
||
1161 |
|||
1162 |
|||
1163 |
|||
1164 |
struct LoopVar |
||
1165 |
{ |
||
1166 |
Var old; /* keep old variable value (before the loop) */ |
||
1167 |
Var *me; /* the variable we're dealing with */ |
||
1168 |
}; |
||
1169 |
|||
1170 |
|||
1171 |
struct LoopVar * |
||
1172 |
Var_NewLoopVar(const char *name, const char *ename) |
||
1173 |
2959 |
{ |
|
1174 |
struct LoopVar *l; |
||
1175 |
uint32_t k; |
||
1176 |
|||
1177 |
2959 |
l = emalloc(sizeof(struct LoopVar)); |
|
1178 |
|||
1179 |
/* we obtain a new variable quickly, make a snapshot of its old |
||
1180 |
* value, and make sure the environment cannot touch us. |
||
1181 |
*/ |
||
1182 |
/* XXX: should we avoid dynamic variables ? */ |
||
1183 |
2959 |
k = ohash_interval(name, &ename); |
|
1184 |
|||
1185 |
2959 |
l->me = find_global_var_without_env(name, ename, k); |
|
1186 |
2959 |
l->old = *(l->me); |
|
1187 |
2959 |
l->me->flags = VAR_SEEN_ENV | VAR_DUMMY; |
|
1188 |
2959 |
return l; |
|
1189 |
} |
||
1190 |
|||
1191 |
char * |
||
1192 |
Var_LoopVarName(struct LoopVar *v) |
||
1193 |
{ |
||
1194 |
return v->me->name; |
||
1195 |
} |
||
1196 |
|||
1197 |
void |
||
1198 |
Var_DeleteLoopVar(struct LoopVar *l) |
||
1199 |
2959 |
{ |
|
1200 |
✓✓ | 2959 |
if ((l->me->flags & VAR_DUMMY) == 0) |
1201 |
2943 |
Buf_Destroy(&(l->me->val)); |
|
1202 |
2959 |
*(l->me) = l->old; |
|
1203 |
2959 |
free(l); |
|
1204 |
2959 |
} |
|
1205 |
|||
1206 |
void |
||
1207 |
Var_SubstVar(Buffer buf, /* To store result */ |
||
1208 |
const char *str, /* The string in which to substitute */ |
||
1209 |
struct LoopVar *l, /* Handle */ |
||
1210 |
const char *val) /* Its value */ |
||
1211 |
14117 |
{ |
|
1212 |
14117 |
const char *var = l->me->name; |
|
1213 |
|||
1214 |
14117 |
var_set_value(l->me, val); |
|
1215 |
|||
1216 |
for (;;) { |
||
1217 |
const char *start; |
||
1218 |
/* Copy uninteresting stuff */ |
||
1219 |
✓✓ | 133902 |
for (start = str; *str != '\0' && *str != '$'; str++) |
1220 |
; |
||
1221 |
133902 |
Buf_Addi(buf, start, str); |
|
1222 |
|||
1223 |
133902 |
start = str; |
|
1224 |
✓✓ | 133902 |
if (*str++ == '\0') |
1225 |
14117 |
break; |
|
1226 |
119785 |
str++; |
|
1227 |
/* and escaped dollars */ |
||
1228 |
✓✓ | 119785 |
if (start[1] == '$') { |
1229 |
406 |
Buf_Addi(buf, start, start+2); |
|
1230 |
406 |
continue; |
|
1231 |
} |
||
1232 |
/* Simple variable, if it's not us, copy. */ |
||
1233 |
✓✓ | 119379 |
if (start[1] != '(' && start[1] != '{') { |
1234 |
✓✓✗✓ |
12220 |
if (start[1] != *var || var[1] != '\0') { |
1235 |
42 |
Buf_AddChars(buf, 2, start); |
|
1236 |
42 |
continue; |
|
1237 |
} |
||
1238 |
} else { |
||
1239 |
const char *p; |
||
1240 |
107159 |
char paren = start[1]; |
|
1241 |
|||
1242 |
|||
1243 |
/* Find the end of the variable specification. */ |
||
1244 |
107159 |
p = find_pos(paren)(str); |
|
1245 |
/* A variable inside the variable. We don't know how to |
||
1246 |
* expand the external variable at this point, so we |
||
1247 |
* try again with the nested variable. */ |
||
1248 |
✓✓ | 107159 |
if (*p == '$') { |
1249 |
2702 |
Buf_Addi(buf, start, p); |
|
1250 |
2702 |
str = p; |
|
1251 |
2702 |
continue; |
|
1252 |
} |
||
1253 |
|||
1254 |
✓✓✗✓ |
104457 |
if (strncmp(var, str, p - str) != 0 || |
1255 |
var[p - str] != '\0') { |
||
1256 |
/* Not the variable we want to expand. */ |
||
1257 |
80577 |
Buf_Addi(buf, start, p); |
|
1258 |
80577 |
str = p; |
|
1259 |
80577 |
continue; |
|
1260 |
} |
||
1261 |
✓✓ | 23880 |
if (*p == ':') { |
1262 |
bool doFree; /* should val be freed ? */ |
||
1263 |
char *newval; |
||
1264 |
struct Name name; |
||
1265 |
|||
1266 |
9378 |
doFree = false; |
|
1267 |
9378 |
name.s = var; |
|
1268 |
9378 |
name.e = var + (p-str); |
|
1269 |
|||
1270 |
/* val won't be freed since !doFree, but |
||
1271 |
* VarModifiers_Apply doesn't know that, |
||
1272 |
* hence the cast. */ |
||
1273 |
9378 |
newval = VarModifiers_Apply((char *)val, |
|
1274 |
&name, NULL, false, &doFree, &p, paren); |
||
1275 |
9378 |
Buf_AddString(buf, newval); |
|
1276 |
✓✗ | 9378 |
if (doFree) |
1277 |
9378 |
free(newval); |
|
1278 |
9378 |
str = p; |
|
1279 |
9378 |
continue; |
|
1280 |
} else |
||
1281 |
14502 |
str = p+1; |
|
1282 |
} |
||
1283 |
26680 |
Buf_AddString(buf, val); |
|
1284 |
} |
||
1285 |
14117 |
} |
|
1286 |
|||
1287 |
/*** |
||
1288 |
*** Odds and ends |
||
1289 |
***/ |
||
1290 |
|||
1291 |
static void |
||
1292 |
set_magic_shell_variable() |
||
1293 |
729 |
{ |
|
1294 |
729 |
const char *name = "SHELL"; |
|
1295 |
729 |
const char *ename = NULL; |
|
1296 |
uint32_t k; |
||
1297 |
Var *v; |
||
1298 |
|||
1299 |
729 |
k = ohash_interval(name, &ename); |
|
1300 |
729 |
v = find_global_var_without_env(name, ename, k); |
|
1301 |
729 |
var_set_value(v, _PATH_BSHELL); |
|
1302 |
/* XXX the environment shall never affect it */ |
||
1303 |
729 |
v->flags = VAR_SHELL | VAR_SEEN_ENV; |
|
1304 |
729 |
} |
|
1305 |
|||
1306 |
/* |
||
1307 |
* Var_Init |
||
1308 |
* Initialize the module |
||
1309 |
*/ |
||
1310 |
void |
||
1311 |
Var_Init(void) |
||
1312 |
729 |
{ |
|
1313 |
729 |
ohash_init(&global_variables, 10, &var_info); |
|
1314 |
729 |
set_magic_shell_variable(); |
|
1315 |
|||
1316 |
|||
1317 |
729 |
errorIsOkay = true; |
|
1318 |
729 |
Var_setCheckEnvFirst(false); |
|
1319 |
|||
1320 |
729 |
VarModifiers_Init(); |
|
1321 |
729 |
Buf_Init(&subst_buffer, MAKE_BSIZE); |
|
1322 |
729 |
} |
|
1323 |
|||
1324 |
|||
1325 |
static const char *interpret(int); |
||
1326 |
|||
1327 |
static const char * |
||
1328 |
interpret(int f) |
||
1329 |
{ |
||
1330 |
if (f & VAR_DUMMY) |
||
1331 |
return "(D)"; |
||
1332 |
return ""; |
||
1333 |
} |
||
1334 |
|||
1335 |
|||
1336 |
static void |
||
1337 |
print_var(Var *v) |
||
1338 |
{ |
||
1339 |
printf("%-16s%s = %s\n", v->name, interpret(v->flags), |
||
1340 |
(v->flags & VAR_DUMMY) == 0 ? var_get_value(v) : "(none)"); |
||
1341 |
} |
||
1342 |
|||
1343 |
|||
1344 |
void |
||
1345 |
Var_Dump(void) |
||
1346 |
{ |
||
1347 |
Var **t; |
||
1348 |
|||
1349 |
unsigned int i; |
||
1350 |
const char *banner; |
||
1351 |
bool first = true; |
||
1352 |
|||
1353 |
t = sort_ohash_by_name(&global_variables); |
||
1354 |
/* somewhat dirty, but does the trick */ |
||
1355 |
|||
1356 |
#define LOOP(mask, value, do_stuff) \ |
||
1357 |
for (i = 0; t[i] != NULL; i++) \ |
||
1358 |
if ((t[i]->flags & (mask)) == (value)) { \ |
||
1359 |
if (banner) { \ |
||
1360 |
if (first) \ |
||
1361 |
first = false; \ |
||
1362 |
else \ |
||
1363 |
putchar('\n'); \ |
||
1364 |
fputs(banner, stdout); \ |
||
1365 |
banner = NULL; \ |
||
1366 |
} \ |
||
1367 |
do_stuff; \ |
||
1368 |
} |
||
1369 |
|||
1370 |
banner = "#variables from command line:\n"; |
||
1371 |
LOOP(VAR_FROM_CMD | VAR_DUMMY, VAR_FROM_CMD, print_var(t[i])); |
||
1372 |
|||
1373 |
banner = "#global variables:\n"; |
||
1374 |
LOOP(VAR_FROM_ENV| VAR_FROM_CMD | VAR_DUMMY, 0, print_var(t[i])); |
||
1375 |
|||
1376 |
banner = "#variables from env:\n"; |
||
1377 |
LOOP(VAR_FROM_ENV|VAR_DUMMY, VAR_FROM_ENV, print_var(t[i])); |
||
1378 |
|||
1379 |
banner = "#variable name seen, but not defined:"; |
||
1380 |
LOOP(VAR_DUMMY|POISONS, VAR_DUMMY, printf(" %s", t[i]->name)); |
||
1381 |
|||
1382 |
#undef LOOP |
||
1383 |
|||
1384 |
printf("\n\n"); |
||
1385 |
|||
1386 |
for (i = 0; t[i] != NULL; i++) |
||
1387 |
switch(t[i]->flags & POISONS) { |
||
1388 |
case POISON_NORMAL: |
||
1389 |
printf(".poison %s\n", t[i]->name); |
||
1390 |
break; |
||
1391 |
case POISON_EMPTY: |
||
1392 |
printf(".poison empty(%s)\n", t[i]->name); |
||
1393 |
break; |
||
1394 |
case POISON_NOT_DEFINED: |
||
1395 |
printf(".poison !defined(%s)\n", t[i]->name); |
||
1396 |
break; |
||
1397 |
default: |
||
1398 |
break; |
||
1399 |
} |
||
1400 |
free(t); |
||
1401 |
printf("\n"); |
||
1402 |
} |
||
1403 |
|||
1404 |
static const char *quotable = " \t\n\\'\""; |
||
1405 |
|||
1406 |
/* POSIX says that variable assignments passed on the command line should be |
||
1407 |
* propagated to sub makes through MAKEFLAGS. |
||
1408 |
*/ |
||
1409 |
void |
||
1410 |
Var_AddCmdline(const char *name) |
||
1411 |
729 |
{ |
|
1412 |
Var *v; |
||
1413 |
unsigned int i; |
||
1414 |
BUFFER buf; |
||
1415 |
char *s; |
||
1416 |
|||
1417 |
729 |
Buf_Init(&buf, MAKE_BSIZE); |
|
1418 |
|||
1419 |
✓✓ | 10798 |
for (v = ohash_first(&global_variables, &i); v != NULL; |
1420 |
9340 |
v = ohash_next(&global_variables, &i)) { |
|
1421 |
/* This is not as expensive as it looks: this function is |
||
1422 |
* called before parsing Makefiles, so there are just a |
||
1423 |
* few non cmdling variables in there. |
||
1424 |
*/ |
||
1425 |
✓✓ | 9340 |
if (!(v->flags & VAR_FROM_CMD)) { |
1426 |
7290 |
continue; |
|
1427 |
} |
||
1428 |
/* We assume variable names don't need quoting */ |
||
1429 |
2050 |
Buf_AddString(&buf, v->name); |
|
1430 |
✗✓ | 2050 |
Buf_AddChar(&buf, '='); |
1431 |
✓✓ | 9752 |
for (s = var_get_value(v); *s != '\0'; s++) { |
1432 |
✗✓ | 7702 |
if (strchr(quotable, *s)) |
1433 |
Buf_AddChar(&buf, '\\'); |
||
1434 |
✗✓ | 7702 |
Buf_AddChar(&buf, *s); |
1435 |
} |
||
1436 |
✗✓ | 2050 |
Buf_AddSpace(&buf); |
1437 |
} |
||
1438 |
729 |
Var_Append(name, Buf_Retrieve(&buf)); |
|
1439 |
729 |
Buf_Destroy(&buf); |
|
1440 |
729 |
} |
Generated by: GCOVR (Version 3.3) |