Sat Oct 31 11:34:30 2020 UTC ()
make(1): reduce the scope where recursive expressions are detected

Only the call to Var_Subst needs to be protected since the other
functions have nothing to do with expanding variables.


(rillig)
diff -r1.417 -r1.418 src/usr.bin/make/main.c
diff -r1.614 -r1.615 src/usr.bin/make/var.c

cvs diff -r1.417 -r1.418 src/usr.bin/make/main.c (switch to unified diff)

--- src/usr.bin/make/main.c 2020/10/31 09:35:58 1.417
+++ src/usr.bin/make/main.c 2020/10/31 11:34:30 1.418
@@ -1,2247 +1,2247 @@ @@ -1,2247 +1,2247 @@
1/* $NetBSD: main.c,v 1.417 2020/10/31 09:35:58 rillig Exp $ */ 1/* $NetBSD: main.c,v 1.418 2020/10/31 11:34:30 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1989, 1990, 1993 4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor. 8 * Adam de Boor.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35/* 35/*
36 * Copyright (c) 1989 by Berkeley Softworks 36 * Copyright (c) 1989 by Berkeley Softworks
37 * All rights reserved. 37 * All rights reserved.
38 * 38 *
39 * This code is derived from software contributed to Berkeley by 39 * This code is derived from software contributed to Berkeley by
40 * Adam de Boor. 40 * Adam de Boor.
41 * 41 *
42 * Redistribution and use in source and binary forms, with or without 42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions 43 * modification, are permitted provided that the following conditions
44 * are met: 44 * are met:
45 * 1. Redistributions of source code must retain the above copyright 45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer. 46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright 47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the 48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution. 49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software 50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement: 51 * must display the following acknowledgement:
52 * This product includes software developed by the University of 52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors. 53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors 54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software 55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission. 56 * without specific prior written permission.
57 * 57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE. 68 * SUCH DAMAGE.
69 */ 69 */
70 70
71/*- 71/*-
72 * main.c -- 72 * main.c --
73 * The main file for this entire program. Exit routines etc 73 * The main file for this entire program. Exit routines etc
74 * reside here. 74 * reside here.
75 * 75 *
76 * Utility functions defined in this file: 76 * Utility functions defined in this file:
77 * Main_ParseArgLine Takes a line of arguments, breaks them and 77 * Main_ParseArgLine Takes a line of arguments, breaks them and
78 * treats them as if they were given when first 78 * treats them as if they were given when first
79 * invoked. Used by the parse module to implement 79 * invoked. Used by the parse module to implement
80 * the .MFLAGS target. 80 * the .MFLAGS target.
81 * 81 *
82 * Error Print a tagged error message. The global 82 * Error Print a tagged error message. The global
83 * MAKE variable must have been defined. This 83 * MAKE variable must have been defined. This
84 * takes a format string and optional arguments 84 * takes a format string and optional arguments
85 * for it. 85 * for it.
86 * 86 *
87 * Fatal Print an error message and exit. Also takes 87 * Fatal Print an error message and exit. Also takes
88 * a format string and arguments for it. 88 * a format string and arguments for it.
89 * 89 *
90 * Punt Aborts all jobs and exits with a message. Also 90 * Punt Aborts all jobs and exits with a message. Also
91 * takes a format string and arguments for it. 91 * takes a format string and arguments for it.
92 * 92 *
93 * Finish Finish things up by printing the number of 93 * Finish Finish things up by printing the number of
94 * errors which occurred, as passed to it, and 94 * errors which occurred, as passed to it, and
95 * exiting. 95 * exiting.
96 */ 96 */
97 97
98#include <sys/types.h> 98#include <sys/types.h>
99#include <sys/time.h> 99#include <sys/time.h>
100#include <sys/param.h> 100#include <sys/param.h>
101#include <sys/resource.h> 101#include <sys/resource.h>
102#include <sys/stat.h> 102#include <sys/stat.h>
103#ifdef MAKE_NATIVE 103#ifdef MAKE_NATIVE
104#include <sys/sysctl.h> 104#include <sys/sysctl.h>
105#endif 105#endif
106#include <sys/utsname.h> 106#include <sys/utsname.h>
107#include <sys/wait.h> 107#include <sys/wait.h>
108 108
109#include <errno.h> 109#include <errno.h>
110#include <signal.h> 110#include <signal.h>
111#include <stdarg.h> 111#include <stdarg.h>
112#include <time.h> 112#include <time.h>
113 113
114#include "make.h" 114#include "make.h"
115#include "dir.h" 115#include "dir.h"
116#include "job.h" 116#include "job.h"
117#include "pathnames.h" 117#include "pathnames.h"
118#include "trace.h" 118#include "trace.h"
119 119
120/* "@(#)main.c 8.3 (Berkeley) 3/19/94" */ 120/* "@(#)main.c 8.3 (Berkeley) 3/19/94" */
121MAKE_RCSID("$NetBSD: main.c,v 1.417 2020/10/31 09:35:58 rillig Exp $"); 121MAKE_RCSID("$NetBSD: main.c,v 1.418 2020/10/31 11:34:30 rillig Exp $");
122#if defined(MAKE_NATIVE) && !defined(lint) 122#if defined(MAKE_NATIVE) && !defined(lint)
123__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 " 123__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
124 "The Regents of the University of California. " 124 "The Regents of the University of California. "
125 "All rights reserved."); 125 "All rights reserved.");
126#endif 126#endif
127 127
128#ifndef DEFMAXLOCAL 128#ifndef DEFMAXLOCAL
129#define DEFMAXLOCAL DEFMAXJOBS 129#define DEFMAXLOCAL DEFMAXJOBS
130#endif 130#endif
131 131
132CmdOpts opts; 132CmdOpts opts;
133time_t now; /* Time at start of make */ 133time_t now; /* Time at start of make */
134GNode *DEFAULT; /* .DEFAULT node */ 134GNode *DEFAULT; /* .DEFAULT node */
135Boolean allPrecious; /* .PRECIOUS given on line by itself */ 135Boolean allPrecious; /* .PRECIOUS given on line by itself */
136Boolean deleteOnError; /* .DELETE_ON_ERROR: set */ 136Boolean deleteOnError; /* .DELETE_ON_ERROR: set */
137 137
138static int maxJobTokens; /* -j argument */ 138static int maxJobTokens; /* -j argument */
139Boolean enterFlagObj; /* -w and objdir != srcdir */ 139Boolean enterFlagObj; /* -w and objdir != srcdir */
140 140
141Boolean oldVars; /* variable substitution style */ 141Boolean oldVars; /* variable substitution style */
142static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ 142static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
143Boolean doing_depend; /* Set while reading .depend */ 143Boolean doing_depend; /* Set while reading .depend */
144static Boolean jobsRunning; /* TRUE if the jobs might be running */ 144static Boolean jobsRunning; /* TRUE if the jobs might be running */
145static const char * tracefile; 145static const char * tracefile;
146static int ReadMakefile(const char *); 146static int ReadMakefile(const char *);
147static void usage(void) MAKE_ATTR_DEAD; 147static void usage(void) MAKE_ATTR_DEAD;
148static void purge_cached_realpaths(void); 148static void purge_cached_realpaths(void);
149 149
150static Boolean ignorePWD; /* if we use -C, PWD is meaningless */ 150static Boolean ignorePWD; /* if we use -C, PWD is meaningless */
151static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ 151static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */
152char curdir[MAXPATHLEN + 1]; /* Startup directory */ 152char curdir[MAXPATHLEN + 1]; /* Startup directory */
153char *progname; /* the program name */ 153char *progname; /* the program name */
154char *makeDependfile; 154char *makeDependfile;
155pid_t myPid; 155pid_t myPid;
156int makelevel; 156int makelevel;
157 157
158Boolean forceJobs = FALSE; 158Boolean forceJobs = FALSE;
159 159
160extern SearchPath *parseIncPath; 160extern SearchPath *parseIncPath;
161 161
162/* 162/*
163 * For compatibility with the POSIX version of MAKEFLAGS that includes 163 * For compatibility with the POSIX version of MAKEFLAGS that includes
164 * all the options with out -, convert flags to -f -l -a -g -s. 164 * all the options with out -, convert flags to -f -l -a -g -s.
165 */ 165 */
166static char * 166static char *
167explode(const char *flags) 167explode(const char *flags)
168{ 168{
169 size_t len; 169 size_t len;
170 char *nf, *st; 170 char *nf, *st;
171 const char *f; 171 const char *f;
172 172
173 if (flags == NULL) 173 if (flags == NULL)
174 return NULL; 174 return NULL;
175 175
176 for (f = flags; *f; f++) 176 for (f = flags; *f; f++)
177 if (!ch_isalpha(*f)) 177 if (!ch_isalpha(*f))
178 break; 178 break;
179 179
180 if (*f) 180 if (*f)
181 return bmake_strdup(flags); 181 return bmake_strdup(flags);
182 182
183 len = strlen(flags); 183 len = strlen(flags);
184 st = nf = bmake_malloc(len * 3 + 1); 184 st = nf = bmake_malloc(len * 3 + 1);
185 while (*flags) { 185 while (*flags) {
186 *nf++ = '-'; 186 *nf++ = '-';
187 *nf++ = *flags++; 187 *nf++ = *flags++;
188 *nf++ = ' '; 188 *nf++ = ' ';
189 } 189 }
190 *nf = '\0'; 190 *nf = '\0';
191 return st; 191 return st;
192} 192}
193 193
194static void 194static void
195parse_debug_option_F(const char *modules) 195parse_debug_option_F(const char *modules)
196{ 196{
197 const char *mode; 197 const char *mode;
198 size_t len; 198 size_t len;
199 char *fname; 199 char *fname;
200 200
201 if (opts.debug_file != stdout && opts.debug_file != stderr) 201 if (opts.debug_file != stdout && opts.debug_file != stderr)
202 fclose(opts.debug_file); 202 fclose(opts.debug_file);
203 203
204 if (*modules == '+') { 204 if (*modules == '+') {
205 modules++; 205 modules++;
206 mode = "a"; 206 mode = "a";
207 } else 207 } else
208 mode = "w"; 208 mode = "w";
209 209
210 if (strcmp(modules, "stdout") == 0) { 210 if (strcmp(modules, "stdout") == 0) {
211 opts.debug_file = stdout; 211 opts.debug_file = stdout;
212 return; 212 return;
213 } 213 }
214 if (strcmp(modules, "stderr") == 0) { 214 if (strcmp(modules, "stderr") == 0) {
215 opts.debug_file = stderr; 215 opts.debug_file = stderr;
216 return; 216 return;
217 } 217 }
218 218
219 len = strlen(modules); 219 len = strlen(modules);
220 fname = bmake_malloc(len + 20); 220 fname = bmake_malloc(len + 20);
221 memcpy(fname, modules, len + 1); 221 memcpy(fname, modules, len + 1);
222 222
223 /* Let the filename be modified by the pid */ 223 /* Let the filename be modified by the pid */
224 if (strcmp(fname + len - 3, ".%d") == 0) 224 if (strcmp(fname + len - 3, ".%d") == 0)
225 snprintf(fname + len - 2, 20, "%d", getpid()); 225 snprintf(fname + len - 2, 20, "%d", getpid());
226 226
227 opts.debug_file = fopen(fname, mode); 227 opts.debug_file = fopen(fname, mode);
228 if (!opts.debug_file) { 228 if (!opts.debug_file) {
229 fprintf(stderr, "Cannot open debug file %s\n", 229 fprintf(stderr, "Cannot open debug file %s\n",
230 fname); 230 fname);
231 usage(); 231 usage();
232 } 232 }
233 free(fname); 233 free(fname);
234} 234}
235 235
236static void 236static void
237parse_debug_options(const char *argvalue) 237parse_debug_options(const char *argvalue)
238{ 238{
239 const char *modules; 239 const char *modules;
240 240
241 for (modules = argvalue; *modules; ++modules) { 241 for (modules = argvalue; *modules; ++modules) {
242 switch (*modules) { 242 switch (*modules) {
243 case '0': /* undocumented, only intended for tests */ 243 case '0': /* undocumented, only intended for tests */
244 opts.debug &= DEBUG_LINT; 244 opts.debug &= DEBUG_LINT;
245 break; 245 break;
246 case 'A': 246 case 'A':
247 opts.debug = ~(0|DEBUG_LINT); 247 opts.debug = ~(0|DEBUG_LINT);
248 break; 248 break;
249 case 'a': 249 case 'a':
250 opts.debug |= DEBUG_ARCH; 250 opts.debug |= DEBUG_ARCH;
251 break; 251 break;
252 case 'C': 252 case 'C':
253 opts.debug |= DEBUG_CWD; 253 opts.debug |= DEBUG_CWD;
254 break; 254 break;
255 case 'c': 255 case 'c':
256 opts.debug |= DEBUG_COND; 256 opts.debug |= DEBUG_COND;
257 break; 257 break;
258 case 'd': 258 case 'd':
259 opts.debug |= DEBUG_DIR; 259 opts.debug |= DEBUG_DIR;
260 break; 260 break;
261 case 'e': 261 case 'e':
262 opts.debug |= DEBUG_ERROR; 262 opts.debug |= DEBUG_ERROR;
263 break; 263 break;
264 case 'f': 264 case 'f':
265 opts.debug |= DEBUG_FOR; 265 opts.debug |= DEBUG_FOR;
266 break; 266 break;
267 case 'g': 267 case 'g':
268 if (modules[1] == '1') { 268 if (modules[1] == '1') {
269 opts.debug |= DEBUG_GRAPH1; 269 opts.debug |= DEBUG_GRAPH1;
270 ++modules; 270 ++modules;
271 } 271 }
272 else if (modules[1] == '2') { 272 else if (modules[1] == '2') {
273 opts.debug |= DEBUG_GRAPH2; 273 opts.debug |= DEBUG_GRAPH2;
274 ++modules; 274 ++modules;
275 } 275 }
276 else if (modules[1] == '3') { 276 else if (modules[1] == '3') {
277 opts.debug |= DEBUG_GRAPH3; 277 opts.debug |= DEBUG_GRAPH3;
278 ++modules; 278 ++modules;
279 } 279 }
280 break; 280 break;
281 case 'h': 281 case 'h':
282 opts.debug |= DEBUG_HASH; 282 opts.debug |= DEBUG_HASH;
283 break; 283 break;
284 case 'j': 284 case 'j':
285 opts.debug |= DEBUG_JOB; 285 opts.debug |= DEBUG_JOB;
286 break; 286 break;
287 case 'L': 287 case 'L':
288 opts.debug |= DEBUG_LINT; 288 opts.debug |= DEBUG_LINT;
289 break; 289 break;
290 case 'l': 290 case 'l':
291 opts.debug |= DEBUG_LOUD; 291 opts.debug |= DEBUG_LOUD;
292 break; 292 break;
293 case 'M': 293 case 'M':
294 opts.debug |= DEBUG_META; 294 opts.debug |= DEBUG_META;
295 break; 295 break;
296 case 'm': 296 case 'm':
297 opts.debug |= DEBUG_MAKE; 297 opts.debug |= DEBUG_MAKE;
298 break; 298 break;
299 case 'n': 299 case 'n':
300 opts.debug |= DEBUG_SCRIPT; 300 opts.debug |= DEBUG_SCRIPT;
301 break; 301 break;
302 case 'p': 302 case 'p':
303 opts.debug |= DEBUG_PARSE; 303 opts.debug |= DEBUG_PARSE;
304 break; 304 break;
305 case 's': 305 case 's':
306 opts.debug |= DEBUG_SUFF; 306 opts.debug |= DEBUG_SUFF;
307 break; 307 break;
308 case 't': 308 case 't':
309 opts.debug |= DEBUG_TARG; 309 opts.debug |= DEBUG_TARG;
310 break; 310 break;
311 case 'V': 311 case 'V':
312 opts.debugVflag = TRUE; 312 opts.debugVflag = TRUE;
313 break; 313 break;
314 case 'v': 314 case 'v':
315 opts.debug |= DEBUG_VAR; 315 opts.debug |= DEBUG_VAR;
316 break; 316 break;
317 case 'x': 317 case 'x':
318 opts.debug |= DEBUG_SHELL; 318 opts.debug |= DEBUG_SHELL;
319 break; 319 break;
320 case 'F': 320 case 'F':
321 parse_debug_option_F(modules + 1); 321 parse_debug_option_F(modules + 1);
322 goto debug_setbuf; 322 goto debug_setbuf;
323 default: 323 default:
324 (void)fprintf(stderr, 324 (void)fprintf(stderr,
325 "%s: illegal argument to d option -- %c\n", 325 "%s: illegal argument to d option -- %c\n",
326 progname, *modules); 326 progname, *modules);
327 usage(); 327 usage();
328 } 328 }
329 } 329 }
330debug_setbuf: 330debug_setbuf:
331 /* 331 /*
332 * Make the debug_file unbuffered, and make 332 * Make the debug_file unbuffered, and make
333 * stdout line buffered (unless debugfile == stdout). 333 * stdout line buffered (unless debugfile == stdout).
334 */ 334 */
335 setvbuf(opts.debug_file, NULL, _IONBF, 0); 335 setvbuf(opts.debug_file, NULL, _IONBF, 0);
336 if (opts.debug_file != stdout) { 336 if (opts.debug_file != stdout) {
337 setvbuf(stdout, NULL, _IOLBF, 0); 337 setvbuf(stdout, NULL, _IOLBF, 0);
338 } 338 }
339} 339}
340 340
341/* 341/*
342 * does path contain any relative components 342 * does path contain any relative components
343 */ 343 */
344static Boolean 344static Boolean
345is_relpath(const char *path) 345is_relpath(const char *path)
346{ 346{
347 const char *cp; 347 const char *cp;
348 348
349 if (path[0] != '/') 349 if (path[0] != '/')
350 return TRUE; 350 return TRUE;
351 cp = path; 351 cp = path;
352 while ((cp = strstr(cp, "/.")) != NULL) { 352 while ((cp = strstr(cp, "/.")) != NULL) {
353 cp += 2; 353 cp += 2;
354 if (cp[0] == '/' || cp[0] == '\0') 354 if (cp[0] == '/' || cp[0] == '\0')
355 return TRUE; 355 return TRUE;
356 else if (cp[0] == '.') { 356 else if (cp[0] == '.') {
357 if (cp[1] == '/' || cp[1] == '\0') 357 if (cp[1] == '/' || cp[1] == '\0')
358 return TRUE; 358 return TRUE;
359 } 359 }
360 } 360 }
361 return FALSE; 361 return FALSE;
362} 362}
363 363
364static void 364static void
365MainParseArgChdir(const char *argvalue) 365MainParseArgChdir(const char *argvalue)
366{ 366{
367 struct stat sa, sb; 367 struct stat sa, sb;
368 368
369 if (chdir(argvalue) == -1) { 369 if (chdir(argvalue) == -1) {
370 (void)fprintf(stderr, "%s: chdir %s: %s\n", 370 (void)fprintf(stderr, "%s: chdir %s: %s\n",
371 progname, argvalue, strerror(errno)); 371 progname, argvalue, strerror(errno));
372 exit(1); 372 exit(1);
373 } 373 }
374 if (getcwd(curdir, MAXPATHLEN) == NULL) { 374 if (getcwd(curdir, MAXPATHLEN) == NULL) {
375 (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 375 (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
376 exit(2); 376 exit(2);
377 } 377 }
378 if (!is_relpath(argvalue) && 378 if (!is_relpath(argvalue) &&
379 stat(argvalue, &sa) != -1 && 379 stat(argvalue, &sa) != -1 &&
380 stat(curdir, &sb) != -1 && 380 stat(curdir, &sb) != -1 &&
381 sa.st_ino == sb.st_ino && 381 sa.st_ino == sb.st_ino &&
382 sa.st_dev == sb.st_dev) 382 sa.st_dev == sb.st_dev)
383 strncpy(curdir, argvalue, MAXPATHLEN); 383 strncpy(curdir, argvalue, MAXPATHLEN);
384 ignorePWD = TRUE; 384 ignorePWD = TRUE;
385} 385}
386 386
387static void 387static void
388MainParseArgJobsInternal(const char *argvalue) 388MainParseArgJobsInternal(const char *argvalue)
389{ 389{
390 if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) { 390 if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) {
391 (void)fprintf(stderr, 391 (void)fprintf(stderr,
392 "%s: internal error -- J option malformed (%s)\n", 392 "%s: internal error -- J option malformed (%s)\n",
393 progname, argvalue); 393 progname, argvalue);
394 usage(); 394 usage();
395 } 395 }
396 if ((fcntl(jp_0, F_GETFD, 0) < 0) || 396 if ((fcntl(jp_0, F_GETFD, 0) < 0) ||
397 (fcntl(jp_1, F_GETFD, 0) < 0)) { 397 (fcntl(jp_1, F_GETFD, 0) < 0)) {
398#if 0 398#if 0
399 (void)fprintf(stderr, 399 (void)fprintf(stderr,
400 "%s: ###### warning -- J descriptors were closed!\n", 400 "%s: ###### warning -- J descriptors were closed!\n",
401 progname); 401 progname);
402 exit(2); 402 exit(2);
403#endif 403#endif
404 jp_0 = -1; 404 jp_0 = -1;
405 jp_1 = -1; 405 jp_1 = -1;
406 opts.compatMake = TRUE; 406 opts.compatMake = TRUE;
407 } else { 407 } else {
408 Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); 408 Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL);
409 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 409 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
410 } 410 }
411} 411}
412 412
413static void 413static void
414MainParseArgJobs(const char *argvalue) 414MainParseArgJobs(const char *argvalue)
415{ 415{
416 char *p; 416 char *p;
417 417
418 forceJobs = TRUE; 418 forceJobs = TRUE;
419 opts.maxJobs = (int)strtol(argvalue, &p, 0); 419 opts.maxJobs = (int)strtol(argvalue, &p, 0);
420 if (*p != '\0' || opts.maxJobs < 1) { 420 if (*p != '\0' || opts.maxJobs < 1) {
421 (void)fprintf(stderr, 421 (void)fprintf(stderr,
422 "%s: illegal argument to -j -- must be positive integer!\n", 422 "%s: illegal argument to -j -- must be positive integer!\n",
423 progname); 423 progname);
424 exit(1); /* XXX: why not 2? */ 424 exit(1); /* XXX: why not 2? */
425 } 425 }
426 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 426 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
427 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 427 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
428 Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL); 428 Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL);
429 maxJobTokens = opts.maxJobs; 429 maxJobTokens = opts.maxJobs;
430} 430}
431 431
432static void 432static void
433MainParseArgSysInc(const char *argvalue) 433MainParseArgSysInc(const char *argvalue)
434{ 434{
435 /* look for magic parent directory search string */ 435 /* look for magic parent directory search string */
436 if (strncmp(".../", argvalue, 4) == 0) { 436 if (strncmp(".../", argvalue, 4) == 0) {
437 char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4); 437 char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4);
438 if (found_path == NULL) 438 if (found_path == NULL)
439 return; 439 return;
440 (void)Dir_AddDir(sysIncPath, found_path); 440 (void)Dir_AddDir(sysIncPath, found_path);
441 free(found_path); 441 free(found_path);
442 } else { 442 } else {
443 (void)Dir_AddDir(sysIncPath, argvalue); 443 (void)Dir_AddDir(sysIncPath, argvalue);
444 } 444 }
445 Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); 445 Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL);
446 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 446 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
447} 447}
448 448
449static Boolean 449static Boolean
450MainParseArg(char c, const char *argvalue) 450MainParseArg(char c, const char *argvalue)
451{ 451{
452 switch (c) { 452 switch (c) {
453 case '\0': 453 case '\0':
454 break; 454 break;
455 case 'B': 455 case 'B':
456 opts.compatMake = TRUE; 456 opts.compatMake = TRUE;
457 Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); 457 Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL);
458 Var_Set(MAKE_MODE, "compat", VAR_GLOBAL); 458 Var_Set(MAKE_MODE, "compat", VAR_GLOBAL);
459 break; 459 break;
460 case 'C': 460 case 'C':
461 MainParseArgChdir(argvalue); 461 MainParseArgChdir(argvalue);
462 break; 462 break;
463 case 'D': 463 case 'D':
464 if (argvalue[0] == '\0') return FALSE; 464 if (argvalue[0] == '\0') return FALSE;
465 Var_Set(argvalue, "1", VAR_GLOBAL); 465 Var_Set(argvalue, "1", VAR_GLOBAL);
466 Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); 466 Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL);
467 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 467 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
468 break; 468 break;
469 case 'I': 469 case 'I':
470 Parse_AddIncludeDir(argvalue); 470 Parse_AddIncludeDir(argvalue);
471 Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); 471 Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL);
472 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 472 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
473 break; 473 break;
474 case 'J': 474 case 'J':
475 MainParseArgJobsInternal(argvalue); 475 MainParseArgJobsInternal(argvalue);
476 break; 476 break;
477 case 'N': 477 case 'N':
478 opts.noExecute = TRUE; 478 opts.noExecute = TRUE;
479 opts.noRecursiveExecute = TRUE; 479 opts.noRecursiveExecute = TRUE;
480 Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL); 480 Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL);
481 break; 481 break;
482 case 'S': 482 case 'S':
483 opts.keepgoing = FALSE; 483 opts.keepgoing = FALSE;
484 Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); 484 Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL);
485 break; 485 break;
486 case 'T': 486 case 'T':
487 tracefile = bmake_strdup(argvalue); 487 tracefile = bmake_strdup(argvalue);
488 Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL); 488 Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL);
489 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 489 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
490 break; 490 break;
491 case 'V': 491 case 'V':
492 case 'v': 492 case 'v':
493 opts.printVars = c == 'v' ? EXPAND_VARS : COMPAT_VARS; 493 opts.printVars = c == 'v' ? EXPAND_VARS : COMPAT_VARS;
494 Lst_Append(opts.variables, bmake_strdup(argvalue)); 494 Lst_Append(opts.variables, bmake_strdup(argvalue));
495 /* XXX: Why always -V? */ 495 /* XXX: Why always -V? */
496 Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); 496 Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL);
497 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 497 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
498 break; 498 break;
499 case 'W': 499 case 'W':
500 opts.parseWarnFatal = TRUE; 500 opts.parseWarnFatal = TRUE;
501 break; 501 break;
502 case 'X': 502 case 'X':
503 opts.varNoExportEnv = TRUE; 503 opts.varNoExportEnv = TRUE;
504 Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL); 504 Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL);
505 break; 505 break;
506 case 'd': 506 case 'd':
507 /* If '-d-opts' don't pass to children */ 507 /* If '-d-opts' don't pass to children */
508 if (argvalue[0] == '-') 508 if (argvalue[0] == '-')
509 argvalue++; 509 argvalue++;
510 else { 510 else {
511 Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); 511 Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL);
512 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 512 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
513 } 513 }
514 parse_debug_options(argvalue); 514 parse_debug_options(argvalue);
515 break; 515 break;
516 case 'e': 516 case 'e':
517 opts.checkEnvFirst = TRUE; 517 opts.checkEnvFirst = TRUE;
518 Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); 518 Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL);
519 break; 519 break;
520 case 'f': 520 case 'f':
521 Lst_Append(opts.makefiles, bmake_strdup(argvalue)); 521 Lst_Append(opts.makefiles, bmake_strdup(argvalue));
522 break; 522 break;
523 case 'i': 523 case 'i':
524 opts.ignoreErrors = TRUE; 524 opts.ignoreErrors = TRUE;
525 Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); 525 Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL);
526 break; 526 break;
527 case 'j': 527 case 'j':
528 MainParseArgJobs(argvalue); 528 MainParseArgJobs(argvalue);
529 break; 529 break;
530 case 'k': 530 case 'k':
531 opts.keepgoing = TRUE; 531 opts.keepgoing = TRUE;
532 Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); 532 Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL);
533 break; 533 break;
534 case 'm': 534 case 'm':
535 MainParseArgSysInc(argvalue); 535 MainParseArgSysInc(argvalue);
536 break; 536 break;
537 case 'n': 537 case 'n':
538 opts.noExecute = TRUE; 538 opts.noExecute = TRUE;
539 Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); 539 Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL);
540 break; 540 break;
541 case 'q': 541 case 'q':
542 opts.queryFlag = TRUE; 542 opts.queryFlag = TRUE;
543 /* Kind of nonsensical, wot? */ 543 /* Kind of nonsensical, wot? */
544 Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); 544 Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL);
545 break; 545 break;
546 case 'r': 546 case 'r':
547 opts.noBuiltins = TRUE; 547 opts.noBuiltins = TRUE;
548 Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); 548 Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL);
549 break; 549 break;
550 case 's': 550 case 's':
551 opts.beSilent = TRUE; 551 opts.beSilent = TRUE;
552 Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); 552 Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL);
553 break; 553 break;
554 case 't': 554 case 't':
555 opts.touchFlag = TRUE; 555 opts.touchFlag = TRUE;
556 Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); 556 Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL);
557 break; 557 break;
558 case 'w': 558 case 'w':
559 opts.enterFlag = TRUE; 559 opts.enterFlag = TRUE;
560 Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL); 560 Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL);
561 break; 561 break;
562 default: 562 default:
563 case '?': 563 case '?':
564 usage(); 564 usage();
565 } 565 }
566 return TRUE; 566 return TRUE;
567} 567}
568 568
569/* Parse the given arguments. Called from main() and from 569/* Parse the given arguments. Called from main() and from
570 * Main_ParseArgLine() when the .MAKEFLAGS target is used. 570 * Main_ParseArgLine() when the .MAKEFLAGS target is used.
571 * 571 *
572 * The arguments must be treated as read-only and will be freed after the 572 * The arguments must be treated as read-only and will be freed after the
573 * call. 573 * call.
574 * 574 *
575 * XXX: Deal with command line overriding .MAKEFLAGS in makefile */ 575 * XXX: Deal with command line overriding .MAKEFLAGS in makefile */
576static void 576static void
577MainParseArgs(int argc, char **argv) 577MainParseArgs(int argc, char **argv)
578{ 578{
579 char c; 579 char c;
580 int arginc; 580 int arginc;
581 char *argvalue; 581 char *argvalue;
582 char *optscan; 582 char *optscan;
583 Boolean inOption, dashDash = FALSE; 583 Boolean inOption, dashDash = FALSE;
584 584
585 const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w"; 585 const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w";
586/* Can't actually use getopt(3) because rescanning is not portable */ 586/* Can't actually use getopt(3) because rescanning is not portable */
587 587
588rearg: 588rearg:
589 inOption = FALSE; 589 inOption = FALSE;
590 optscan = NULL; 590 optscan = NULL;
591 while (argc > 1) { 591 while (argc > 1) {
592 const char *optspec; 592 const char *optspec;
593 if (!inOption) 593 if (!inOption)
594 optscan = argv[1]; 594 optscan = argv[1];
595 c = *optscan++; 595 c = *optscan++;
596 arginc = 0; 596 arginc = 0;
597 if (inOption) { 597 if (inOption) {
598 if (c == '\0') { 598 if (c == '\0') {
599 ++argv; 599 ++argv;
600 --argc; 600 --argc;
601 inOption = FALSE; 601 inOption = FALSE;
602 continue; 602 continue;
603 } 603 }
604 } else { 604 } else {
605 if (c != '-' || dashDash) 605 if (c != '-' || dashDash)
606 break; 606 break;
607 inOption = TRUE; 607 inOption = TRUE;
608 c = *optscan++; 608 c = *optscan++;
609 } 609 }
610 /* '-' found at some earlier point */ 610 /* '-' found at some earlier point */
611 optspec = strchr(optspecs, c); 611 optspec = strchr(optspecs, c);
612 if (c != '\0' && optspec != NULL && optspec[1] == ':') { 612 if (c != '\0' && optspec != NULL && optspec[1] == ':') {
613 /* -<something> found, and <something> should have an arg */ 613 /* -<something> found, and <something> should have an arg */
614 inOption = FALSE; 614 inOption = FALSE;
615 arginc = 1; 615 arginc = 1;
616 argvalue = optscan; 616 argvalue = optscan;
617 if (*argvalue == '\0') { 617 if (*argvalue == '\0') {
618 if (argc < 3) 618 if (argc < 3)
619 goto noarg; 619 goto noarg;
620 argvalue = argv[2]; 620 argvalue = argv[2];
621 arginc = 2; 621 arginc = 2;
622 } 622 }
623 } else { 623 } else {
624 argvalue = NULL; 624 argvalue = NULL;
625 } 625 }
626 switch (c) { 626 switch (c) {
627 case '\0': 627 case '\0':
628 arginc = 1; 628 arginc = 1;
629 inOption = FALSE; 629 inOption = FALSE;
630 break; 630 break;
631 case '-': 631 case '-':
632 dashDash = TRUE; 632 dashDash = TRUE;
633 break; 633 break;
634 default: 634 default:
635 if (!MainParseArg(c, argvalue)) 635 if (!MainParseArg(c, argvalue))
636 goto noarg; 636 goto noarg;
637 } 637 }
638 argv += arginc; 638 argv += arginc;
639 argc -= arginc; 639 argc -= arginc;
640 } 640 }
641 641
642 oldVars = TRUE; 642 oldVars = TRUE;
643 643
644 /* 644 /*
645 * See if the rest of the arguments are variable assignments and 645 * See if the rest of the arguments are variable assignments and
646 * perform them if so. Else take them to be targets and stuff them 646 * perform them if so. Else take them to be targets and stuff them
647 * on the end of the "create" list. 647 * on the end of the "create" list.
648 */ 648 */
649 for (; argc > 1; ++argv, --argc) { 649 for (; argc > 1; ++argv, --argc) {
650 VarAssign var; 650 VarAssign var;
651 if (Parse_IsVar(argv[1], &var)) { 651 if (Parse_IsVar(argv[1], &var)) {
652 Parse_DoVar(&var, VAR_CMDLINE); 652 Parse_DoVar(&var, VAR_CMDLINE);
653 } else { 653 } else {
654 if (!*argv[1]) 654 if (!*argv[1])
655 Punt("illegal (null) argument."); 655 Punt("illegal (null) argument.");
656 if (*argv[1] == '-' && !dashDash) 656 if (*argv[1] == '-' && !dashDash)
657 goto rearg; 657 goto rearg;
658 Lst_Append(opts.create, bmake_strdup(argv[1])); 658 Lst_Append(opts.create, bmake_strdup(argv[1]));
659 } 659 }
660 } 660 }
661 661
662 return; 662 return;
663noarg: 663noarg:
664 (void)fprintf(stderr, "%s: option requires an argument -- %c\n", 664 (void)fprintf(stderr, "%s: option requires an argument -- %c\n",
665 progname, c); 665 progname, c);
666 usage(); 666 usage();
667} 667}
668 668
669/* Break a line of arguments into words and parse them. 669/* Break a line of arguments into words and parse them.
670 * 670 *
671 * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and 671 * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and
672 * by main() when reading the MAKEFLAGS environment variable. */ 672 * by main() when reading the MAKEFLAGS environment variable. */
673void 673void
674Main_ParseArgLine(const char *line) 674Main_ParseArgLine(const char *line)
675{ 675{
676 Words words; 676 Words words;
677 void *p1; 677 void *p1;
678 const char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); 678 const char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1);
679 char *buf; 679 char *buf;
680 680
681 if (line == NULL) 681 if (line == NULL)
682 return; 682 return;
683 for (; *line == ' '; ++line) 683 for (; *line == ' '; ++line)
684 continue; 684 continue;
685 if (!*line) 685 if (!*line)
686 return; 686 return;
687 687
688 buf = str_concat3(argv0, " ", line); 688 buf = str_concat3(argv0, " ", line);
689 free(p1); 689 free(p1);
690 690
691 words = Str_Words(buf, TRUE); 691 words = Str_Words(buf, TRUE);
692 if (words.words == NULL) { 692 if (words.words == NULL) {
693 Error("Unterminated quoted string [%s]", buf); 693 Error("Unterminated quoted string [%s]", buf);
694 free(buf); 694 free(buf);
695 return; 695 return;
696 } 696 }
697 free(buf); 697 free(buf);
698 MainParseArgs((int)words.len, words.words); 698 MainParseArgs((int)words.len, words.words);
699 699
700 Words_Free(words); 700 Words_Free(words);
701} 701}
702 702
703Boolean 703Boolean
704Main_SetObjdir(const char *fmt, ...) 704Main_SetObjdir(const char *fmt, ...)
705{ 705{
706 struct stat sb; 706 struct stat sb;
707 char *path; 707 char *path;
708 char buf[MAXPATHLEN + 1]; 708 char buf[MAXPATHLEN + 1];
709 char buf2[MAXPATHLEN + 1]; 709 char buf2[MAXPATHLEN + 1];
710 Boolean rc = FALSE; 710 Boolean rc = FALSE;
711 va_list ap; 711 va_list ap;
712 712
713 va_start(ap, fmt); 713 va_start(ap, fmt);
714 vsnprintf(path = buf, MAXPATHLEN, fmt, ap); 714 vsnprintf(path = buf, MAXPATHLEN, fmt, ap);
715 va_end(ap); 715 va_end(ap);
716 716
717 if (path[0] != '/') { 717 if (path[0] != '/') {
718 snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path); 718 snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path);
719 path = buf2; 719 path = buf2;
720 } 720 }
721 721
722 /* look for the directory and try to chdir there */ 722 /* look for the directory and try to chdir there */
723 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 723 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
724 if (access(path, W_OK) || chdir(path)) { 724 if (access(path, W_OK) || chdir(path)) {
725 (void)fprintf(stderr, "make warning: %s: %s.\n", 725 (void)fprintf(stderr, "make warning: %s: %s.\n",
726 path, strerror(errno)); 726 path, strerror(errno));
727 } else { 727 } else {
728 snprintf(objdir, sizeof objdir, "%s", path); 728 snprintf(objdir, sizeof objdir, "%s", path);
729 Var_Set(".OBJDIR", objdir, VAR_GLOBAL); 729 Var_Set(".OBJDIR", objdir, VAR_GLOBAL);
730 setenv("PWD", objdir, 1); 730 setenv("PWD", objdir, 1);
731 Dir_InitDot(); 731 Dir_InitDot();
732 purge_cached_realpaths(); 732 purge_cached_realpaths();
733 rc = TRUE; 733 rc = TRUE;
734 if (opts.enterFlag && strcmp(objdir, curdir) != 0) 734 if (opts.enterFlag && strcmp(objdir, curdir) != 0)
735 enterFlagObj = TRUE; 735 enterFlagObj = TRUE;
736 } 736 }
737 } 737 }
738 738
739 return rc; 739 return rc;
740} 740}
741 741
742static Boolean 742static Boolean
743Main_SetVarObjdir(const char *var, const char *suffix) 743Main_SetVarObjdir(const char *var, const char *suffix)
744{ 744{
745 void *path_freeIt; 745 void *path_freeIt;
746 const char *path = Var_Value(var, VAR_CMDLINE, &path_freeIt); 746 const char *path = Var_Value(var, VAR_CMDLINE, &path_freeIt);
747 const char *xpath; 747 const char *xpath;
748 char *xpath_freeIt; 748 char *xpath_freeIt;
749 749
750 if (path == NULL || path[0] == '\0') { 750 if (path == NULL || path[0] == '\0') {
751 bmake_free(path_freeIt); 751 bmake_free(path_freeIt);
752 return FALSE; 752 return FALSE;
753 } 753 }
754 754
755 /* expand variable substitutions */ 755 /* expand variable substitutions */
756 xpath = path; 756 xpath = path;
757 xpath_freeIt = NULL; 757 xpath_freeIt = NULL;
758 if (strchr(path, '$') != 0) { 758 if (strchr(path, '$') != 0) {
759 (void)Var_Subst(path, VAR_GLOBAL, VARE_WANTRES, &xpath_freeIt); 759 (void)Var_Subst(path, VAR_GLOBAL, VARE_WANTRES, &xpath_freeIt);
760 /* TODO: handle errors */ 760 /* TODO: handle errors */
761 xpath = xpath_freeIt; 761 xpath = xpath_freeIt;
762 } 762 }
763 763
764 (void)Main_SetObjdir("%s%s", xpath, suffix); 764 (void)Main_SetObjdir("%s%s", xpath, suffix);
765 765
766 bmake_free(xpath_freeIt); 766 bmake_free(xpath_freeIt);
767 bmake_free(path_freeIt); 767 bmake_free(path_freeIt);
768 return TRUE; 768 return TRUE;
769} 769}
770 770
771/* Read and parse the makefile. 771/* Read and parse the makefile.
772 * Return TRUE if reading the makefile succeeded. */ 772 * Return TRUE if reading the makefile succeeded. */
773static int 773static int
774ReadMakefileSucceeded(void *fname, void *unused) 774ReadMakefileSucceeded(void *fname, void *unused)
775{ 775{
776 return ReadMakefile(fname) == 0; 776 return ReadMakefile(fname) == 0;
777} 777}
778 778
779int 779int
780str2Lst_Append(StringList *lp, char *str, const char *sep) 780str2Lst_Append(StringList *lp, char *str, const char *sep)
781{ 781{
782 char *cp; 782 char *cp;
783 int n; 783 int n;
784 784
785 if (!sep) 785 if (!sep)
786 sep = " \t"; 786 sep = " \t";
787 787
788 for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) { 788 for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) {
789 Lst_Append(lp, cp); 789 Lst_Append(lp, cp);
790 n++; 790 n++;
791 } 791 }
792 return n; 792 return n;
793} 793}
794 794
795#ifdef SIGINFO 795#ifdef SIGINFO
796/*ARGSUSED*/ 796/*ARGSUSED*/
797static void 797static void
798siginfo(int signo MAKE_ATTR_UNUSED) 798siginfo(int signo MAKE_ATTR_UNUSED)
799{ 799{
800 char dir[MAXPATHLEN]; 800 char dir[MAXPATHLEN];
801 char str[2 * MAXPATHLEN]; 801 char str[2 * MAXPATHLEN];
802 int len; 802 int len;
803 if (getcwd(dir, sizeof(dir)) == NULL) 803 if (getcwd(dir, sizeof(dir)) == NULL)
804 return; 804 return;
805 len = snprintf(str, sizeof(str), "%s: Working in: %s\n", progname, dir); 805 len = snprintf(str, sizeof(str), "%s: Working in: %s\n", progname, dir);
806 if (len > 0) 806 if (len > 0)
807 (void)write(STDERR_FILENO, str, (size_t)len); 807 (void)write(STDERR_FILENO, str, (size_t)len);
808} 808}
809#endif 809#endif
810 810
811/* 811/*
812 * Allow makefiles some control over the mode we run in. 812 * Allow makefiles some control over the mode we run in.
813 */ 813 */
814void 814void
815MakeMode(const char *mode) 815MakeMode(const char *mode)
816{ 816{
817 char *mode_freeIt = NULL; 817 char *mode_freeIt = NULL;
818 818
819 if (mode == NULL) { 819 if (mode == NULL) {
820 (void)Var_Subst("${" MAKE_MODE ":tl}", 820 (void)Var_Subst("${" MAKE_MODE ":tl}",
821 VAR_GLOBAL, VARE_WANTRES, &mode_freeIt); 821 VAR_GLOBAL, VARE_WANTRES, &mode_freeIt);
822 /* TODO: handle errors */ 822 /* TODO: handle errors */
823 mode = mode_freeIt; 823 mode = mode_freeIt;
824 } 824 }
825 825
826 if (mode[0] != '\0') { 826 if (mode[0] != '\0') {
827 if (strstr(mode, "compat")) { 827 if (strstr(mode, "compat")) {
828 opts.compatMake = TRUE; 828 opts.compatMake = TRUE;
829 forceJobs = FALSE; 829 forceJobs = FALSE;
830 } 830 }
831#if USE_META 831#if USE_META
832 if (strstr(mode, "meta")) 832 if (strstr(mode, "meta"))
833 meta_mode_init(mode); 833 meta_mode_init(mode);
834#endif 834#endif
835 } 835 }
836 836
837 free(mode_freeIt); 837 free(mode_freeIt);
838} 838}
839 839
840static void 840static void
841PrintVar(const char *varname, Boolean expandVars) 841PrintVar(const char *varname, Boolean expandVars)
842{ 842{
843 if (strchr(varname, '$')) { 843 if (strchr(varname, '$')) {
844 char *evalue; 844 char *evalue;
845 (void)Var_Subst(varname, VAR_GLOBAL, VARE_WANTRES, &evalue); 845 (void)Var_Subst(varname, VAR_GLOBAL, VARE_WANTRES, &evalue);
846 /* TODO: handle errors */ 846 /* TODO: handle errors */
847 printf("%s\n", evalue); 847 printf("%s\n", evalue);
848 bmake_free(evalue); 848 bmake_free(evalue);
849 849
850 } else if (expandVars) { 850 } else if (expandVars) {
851 char *expr = str_concat3("${", varname, "}"); 851 char *expr = str_concat3("${", varname, "}");
852 char *evalue; 852 char *evalue;
853 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &evalue); 853 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &evalue);
854 /* TODO: handle errors */ 854 /* TODO: handle errors */
855 free(expr); 855 free(expr);
856 printf("%s\n", evalue); 856 printf("%s\n", evalue);
857 bmake_free(evalue); 857 bmake_free(evalue);
858 858
859 } else { 859 } else {
860 void *freeIt; 860 void *freeIt;
861 const char *value = Var_Value(varname, VAR_GLOBAL, &freeIt); 861 const char *value = Var_Value(varname, VAR_GLOBAL, &freeIt);
862 printf("%s\n", value ? value : ""); 862 printf("%s\n", value ? value : "");
863 bmake_free(freeIt); 863 bmake_free(freeIt);
864 } 864 }
865} 865}
866 866
867static void 867static void
868doPrintVars(void) 868doPrintVars(void)
869{ 869{
870 StringListNode *ln; 870 StringListNode *ln;
871 Boolean expandVars; 871 Boolean expandVars;
872 872
873 if (opts.printVars == EXPAND_VARS) 873 if (opts.printVars == EXPAND_VARS)
874 expandVars = TRUE; 874 expandVars = TRUE;
875 else if (opts.debugVflag) 875 else if (opts.debugVflag)
876 expandVars = FALSE; 876 expandVars = FALSE;
877 else 877 else
878 expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE); 878 expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE);
879 879
880 for (ln = opts.variables->first; ln != NULL; ln = ln->next) { 880 for (ln = opts.variables->first; ln != NULL; ln = ln->next) {
881 const char *varname = ln->datum; 881 const char *varname = ln->datum;
882 PrintVar(varname, expandVars); 882 PrintVar(varname, expandVars);
883 } 883 }
884} 884}
885 885
886static Boolean 886static Boolean
887runTargets(void) 887runTargets(void)
888{ 888{
889 GNodeList *targs; /* target nodes to create -- passed to Make_Init */ 889 GNodeList *targs; /* target nodes to create -- passed to Make_Init */
890 Boolean outOfDate; /* FALSE if all targets up to date */ 890 Boolean outOfDate; /* FALSE if all targets up to date */
891 891
892 /* 892 /*
893 * Have now read the entire graph and need to make a list of 893 * Have now read the entire graph and need to make a list of
894 * targets to create. If none was given on the command line, 894 * targets to create. If none was given on the command line,
895 * we consult the parsing module to find the main target(s) 895 * we consult the parsing module to find the main target(s)
896 * to create. 896 * to create.
897 */ 897 */
898 if (Lst_IsEmpty(opts.create)) 898 if (Lst_IsEmpty(opts.create))
899 targs = Parse_MainName(); 899 targs = Parse_MainName();
900 else 900 else
901 targs = Targ_FindList(opts.create); 901 targs = Targ_FindList(opts.create);
902 902
903 if (!opts.compatMake) { 903 if (!opts.compatMake) {
904 /* 904 /*
905 * Initialize job module before traversing the graph 905 * Initialize job module before traversing the graph
906 * now that any .BEGIN and .END targets have been read. 906 * now that any .BEGIN and .END targets have been read.
907 * This is done only if the -q flag wasn't given 907 * This is done only if the -q flag wasn't given
908 * (to prevent the .BEGIN from being executed should 908 * (to prevent the .BEGIN from being executed should
909 * it exist). 909 * it exist).
910 */ 910 */
911 if (!opts.queryFlag) { 911 if (!opts.queryFlag) {
912 Job_Init(); 912 Job_Init();
913 jobsRunning = TRUE; 913 jobsRunning = TRUE;
914 } 914 }
915 915
916 /* Traverse the graph, checking on all the targets */ 916 /* Traverse the graph, checking on all the targets */
917 outOfDate = Make_Run(targs); 917 outOfDate = Make_Run(targs);
918 } else { 918 } else {
919 /* 919 /*
920 * Compat_Init will take care of creating all the 920 * Compat_Init will take care of creating all the
921 * targets as well as initializing the module. 921 * targets as well as initializing the module.
922 */ 922 */
923 Compat_Run(targs); 923 Compat_Run(targs);
924 outOfDate = FALSE; 924 outOfDate = FALSE;
925 } 925 }
926 Lst_Free(targs); 926 Lst_Free(targs);
927 return outOfDate; 927 return outOfDate;
928} 928}
929 929
930/* 930/*
931 * Set up the .TARGETS variable to contain the list of targets to be 931 * Set up the .TARGETS variable to contain the list of targets to be
932 * created. If none specified, make the variable empty -- the parser 932 * created. If none specified, make the variable empty -- the parser
933 * will fill the thing in with the default or .MAIN target. 933 * will fill the thing in with the default or .MAIN target.
934 */ 934 */
935static void 935static void
936InitVarTargets(void) 936InitVarTargets(void)
937{ 937{
938 StringListNode *ln; 938 StringListNode *ln;
939 939
940 if (Lst_IsEmpty(opts.create)) { 940 if (Lst_IsEmpty(opts.create)) {
941 Var_Set(".TARGETS", "", VAR_GLOBAL); 941 Var_Set(".TARGETS", "", VAR_GLOBAL);
942 return; 942 return;
943 } 943 }
944 944
945 for (ln = opts.create->first; ln != NULL; ln = ln->next) { 945 for (ln = opts.create->first; ln != NULL; ln = ln->next) {
946 char *name = ln->datum; 946 char *name = ln->datum;
947 Var_Append(".TARGETS", name, VAR_GLOBAL); 947 Var_Append(".TARGETS", name, VAR_GLOBAL);
948 } 948 }
949} 949}
950 950
951static void 951static void
952InitRandom(void) 952InitRandom(void)
953{ 953{
954 struct timeval tv; 954 struct timeval tv;
955 955
956 gettimeofday(&tv, NULL); 956 gettimeofday(&tv, NULL);
957 srandom((unsigned int)(tv.tv_sec + tv.tv_usec)); 957 srandom((unsigned int)(tv.tv_sec + tv.tv_usec));
958} 958}
959 959
960static const char * 960static const char *
961init_machine(const struct utsname *utsname) 961init_machine(const struct utsname *utsname)
962{ 962{
963 const char *machine = getenv("MACHINE"); 963 const char *machine = getenv("MACHINE");
964 if (machine != NULL) 964 if (machine != NULL)
965 return machine; 965 return machine;
966 966
967#ifdef MAKE_NATIVE 967#ifdef MAKE_NATIVE
968 return utsname->machine; 968 return utsname->machine;
969#else 969#else
970#ifdef MAKE_MACHINE 970#ifdef MAKE_MACHINE
971 return MAKE_MACHINE; 971 return MAKE_MACHINE;
972#else 972#else
973 return "unknown"; 973 return "unknown";
974#endif 974#endif
975#endif 975#endif
976} 976}
977 977
978static const char * 978static const char *
979init_machine_arch(void) 979init_machine_arch(void)
980{ 980{
981 const char *env = getenv("MACHINE_ARCH"); 981 const char *env = getenv("MACHINE_ARCH");
982 if (env != NULL) 982 if (env != NULL)
983 return env; 983 return env;
984 984
985#ifdef MAKE_NATIVE 985#ifdef MAKE_NATIVE
986 { 986 {
987 struct utsname utsname; 987 struct utsname utsname;
988 static char machine_arch_buf[sizeof(utsname.machine)]; 988 static char machine_arch_buf[sizeof(utsname.machine)];
989 const int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 989 const int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
990 size_t len = sizeof(machine_arch_buf); 990 size_t len = sizeof(machine_arch_buf);
991 991
992 if (sysctl(mib, __arraycount(mib), machine_arch_buf, 992 if (sysctl(mib, __arraycount(mib), machine_arch_buf,
993 &len, NULL, 0) < 0) { 993 &len, NULL, 0) < 0) {
994 (void)fprintf(stderr, "%s: sysctl failed (%s).\n", progname, 994 (void)fprintf(stderr, "%s: sysctl failed (%s).\n", progname,
995 strerror(errno)); 995 strerror(errno));
996 exit(2); 996 exit(2);
997 } 997 }
998 998
999 return machine_arch_buf; 999 return machine_arch_buf;
1000 } 1000 }
1001#else 1001#else
1002#ifndef MACHINE_ARCH 1002#ifndef MACHINE_ARCH
1003#ifdef MAKE_MACHINE_ARCH 1003#ifdef MAKE_MACHINE_ARCH
1004 return MAKE_MACHINE_ARCH; 1004 return MAKE_MACHINE_ARCH;
1005#else 1005#else
1006 return "unknown"; 1006 return "unknown";
1007#endif 1007#endif
1008#else 1008#else
1009 return MACHINE_ARCH; 1009 return MACHINE_ARCH;
1010#endif 1010#endif
1011#endif 1011#endif
1012} 1012}
1013 1013
1014#ifndef NO_PWD_OVERRIDE 1014#ifndef NO_PWD_OVERRIDE
1015/* 1015/*
1016 * All this code is so that we know where we are when we start up 1016 * All this code is so that we know where we are when we start up
1017 * on a different machine with pmake. 1017 * on a different machine with pmake.
1018 * 1018 *
1019 * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1019 * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX
1020 * since the value of curdir can vary depending on how we got 1020 * since the value of curdir can vary depending on how we got
1021 * here. Ie sitting at a shell prompt (shell that provides $PWD) 1021 * here. Ie sitting at a shell prompt (shell that provides $PWD)
1022 * or via subdir.mk in which case its likely a shell which does 1022 * or via subdir.mk in which case its likely a shell which does
1023 * not provide it. 1023 * not provide it.
1024 * 1024 *
1025 * So, to stop it breaking this case only, we ignore PWD if 1025 * So, to stop it breaking this case only, we ignore PWD if
1026 * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression. 1026 * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression.
1027 */ 1027 */
1028static void 1028static void
1029HandlePWD(const struct stat *curdir_st) 1029HandlePWD(const struct stat *curdir_st)
1030{ 1030{
1031 char *pwd; 1031 char *pwd;
1032 void *prefix_freeIt, *makeobjdir_freeIt; 1032 void *prefix_freeIt, *makeobjdir_freeIt;
1033 const char *makeobjdir; 1033 const char *makeobjdir;
1034 struct stat pwd_st; 1034 struct stat pwd_st;
1035 1035
1036 if (ignorePWD || (pwd = getenv("PWD")) == NULL) 1036 if (ignorePWD || (pwd = getenv("PWD")) == NULL)
1037 return; 1037 return;
1038 1038
1039 if (Var_Value("MAKEOBJDIRPREFIX", VAR_CMDLINE, &prefix_freeIt) != NULL) { 1039 if (Var_Value("MAKEOBJDIRPREFIX", VAR_CMDLINE, &prefix_freeIt) != NULL) {
1040 bmake_free(prefix_freeIt); 1040 bmake_free(prefix_freeIt);
1041 return; 1041 return;
1042 } 1042 }
1043 1043
1044 makeobjdir = Var_Value("MAKEOBJDIR", VAR_CMDLINE, &makeobjdir_freeIt); 1044 makeobjdir = Var_Value("MAKEOBJDIR", VAR_CMDLINE, &makeobjdir_freeIt);
1045 if (makeobjdir != NULL && strchr(makeobjdir, '$') != NULL) 1045 if (makeobjdir != NULL && strchr(makeobjdir, '$') != NULL)
1046 goto ignore_pwd; 1046 goto ignore_pwd;
1047 1047
1048 if (stat(pwd, &pwd_st) == 0 && 1048 if (stat(pwd, &pwd_st) == 0 &&
1049 curdir_st->st_ino == pwd_st.st_ino && 1049 curdir_st->st_ino == pwd_st.st_ino &&
1050 curdir_st->st_dev == pwd_st.st_dev) 1050 curdir_st->st_dev == pwd_st.st_dev)
1051 (void)strncpy(curdir, pwd, MAXPATHLEN); 1051 (void)strncpy(curdir, pwd, MAXPATHLEN);
1052 1052
1053ignore_pwd: 1053ignore_pwd:
1054 bmake_free(makeobjdir_freeIt); 1054 bmake_free(makeobjdir_freeIt);
1055} 1055}
1056#endif 1056#endif
1057 1057
1058/* 1058/*
1059 * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 1059 * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that,
1060 * MAKEOBJDIR is set in the environment, try only that value 1060 * MAKEOBJDIR is set in the environment, try only that value
1061 * and fall back to .CURDIR if it does not exist. 1061 * and fall back to .CURDIR if it does not exist.
1062 * 1062 *
1063 * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, 1063 * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE,
1064 * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 1064 * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none
1065 * of these paths exist, just use .CURDIR. 1065 * of these paths exist, just use .CURDIR.
1066 */ 1066 */
1067static void 1067static void
1068InitObjdir(const char *machine, const char *machine_arch) 1068InitObjdir(const char *machine, const char *machine_arch)
1069{ 1069{
1070 Dir_InitDir(curdir); 1070 Dir_InitDir(curdir);
1071 (void)Main_SetObjdir("%s", curdir); 1071 (void)Main_SetObjdir("%s", curdir);
1072 1072
1073 if (!Main_SetVarObjdir("MAKEOBJDIRPREFIX", curdir) && 1073 if (!Main_SetVarObjdir("MAKEOBJDIRPREFIX", curdir) &&
1074 !Main_SetVarObjdir("MAKEOBJDIR", "") && 1074 !Main_SetVarObjdir("MAKEOBJDIR", "") &&
1075 !Main_SetObjdir("%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && 1075 !Main_SetObjdir("%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) &&
1076 !Main_SetObjdir("%s.%s", _PATH_OBJDIR, machine) && 1076 !Main_SetObjdir("%s.%s", _PATH_OBJDIR, machine) &&
1077 !Main_SetObjdir("%s", _PATH_OBJDIR)) 1077 !Main_SetObjdir("%s", _PATH_OBJDIR))
1078 (void)Main_SetObjdir("%s%s", _PATH_OBJDIRPREFIX, curdir); 1078 (void)Main_SetObjdir("%s%s", _PATH_OBJDIRPREFIX, curdir);
1079} 1079}
1080 1080
1081/* get rid of resource limit on file descriptors */ 1081/* get rid of resource limit on file descriptors */
1082static void 1082static void
1083UnlimitFiles(void) 1083UnlimitFiles(void)
1084{ 1084{
1085#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) 1085#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE))
1086 struct rlimit rl; 1086 struct rlimit rl;
1087 if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 1087 if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
1088 rl.rlim_cur != rl.rlim_max) { 1088 rl.rlim_cur != rl.rlim_max) {
1089 rl.rlim_cur = rl.rlim_max; 1089 rl.rlim_cur = rl.rlim_max;
1090 (void)setrlimit(RLIMIT_NOFILE, &rl); 1090 (void)setrlimit(RLIMIT_NOFILE, &rl);
1091 } 1091 }
1092#endif 1092#endif
1093} 1093}
1094 1094
1095static void 1095static void
1096CmdOpts_Init(void) 1096CmdOpts_Init(void)
1097{ 1097{
1098 opts.compatMake = FALSE; /* No compat mode */ 1098 opts.compatMake = FALSE; /* No compat mode */
1099 opts.debug = 0; /* No debug verbosity, please. */ 1099 opts.debug = 0; /* No debug verbosity, please. */
1100 /* opts.debug_file has been initialized earlier */ 1100 /* opts.debug_file has been initialized earlier */
1101 opts.debugVflag = FALSE; 1101 opts.debugVflag = FALSE;
1102 opts.checkEnvFirst = FALSE; 1102 opts.checkEnvFirst = FALSE;
1103 opts.makefiles = Lst_New(); 1103 opts.makefiles = Lst_New();
1104 opts.ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 1104 opts.ignoreErrors = FALSE; /* Pay attention to non-zero returns */
1105 opts.maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */ 1105 opts.maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */
1106 opts.keepgoing = FALSE; /* Stop on error */ 1106 opts.keepgoing = FALSE; /* Stop on error */
1107 opts.noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 1107 opts.noRecursiveExecute = FALSE; /* Execute all .MAKE targets */
1108 opts.noExecute = FALSE; /* Execute all commands */ 1108 opts.noExecute = FALSE; /* Execute all commands */
1109 opts.queryFlag = FALSE; /* This is not just a check-run */ 1109 opts.queryFlag = FALSE; /* This is not just a check-run */
1110 opts.noBuiltins = FALSE; /* Read the built-in rules */ 1110 opts.noBuiltins = FALSE; /* Read the built-in rules */
1111 opts.beSilent = FALSE; /* Print commands as executed */ 1111 opts.beSilent = FALSE; /* Print commands as executed */
1112 opts.touchFlag = FALSE; /* Actually update targets */ 1112 opts.touchFlag = FALSE; /* Actually update targets */
1113 opts.printVars = 0; 1113 opts.printVars = 0;
1114 opts.variables = Lst_New(); 1114 opts.variables = Lst_New();
1115 opts.parseWarnFatal = FALSE; 1115 opts.parseWarnFatal = FALSE;
1116 opts.enterFlag = FALSE; 1116 opts.enterFlag = FALSE;
1117 opts.varNoExportEnv = FALSE; 1117 opts.varNoExportEnv = FALSE;
1118 opts.create = Lst_New(); 1118 opts.create = Lst_New();
1119} 1119}
1120 1120
1121/* Initialize MAKE and .MAKE to the path of the executable, so that it can be 1121/* Initialize MAKE and .MAKE to the path of the executable, so that it can be
1122 * found by execvp(3) and the shells, even after a chdir. 1122 * found by execvp(3) and the shells, even after a chdir.
1123 * 1123 *
1124 * If it's a relative path and contains a '/', resolve it to an absolute path. 1124 * If it's a relative path and contains a '/', resolve it to an absolute path.
1125 * Otherwise keep it as is, assuming it will be found in the PATH. */ 1125 * Otherwise keep it as is, assuming it will be found in the PATH. */
1126static void 1126static void
1127InitVarMake(const char *argv0) 1127InitVarMake(const char *argv0)
1128{ 1128{
1129 const char *make = argv0; 1129 const char *make = argv0;
1130 1130
1131 if (argv0[0] != '/' && strchr(argv0, '/') != NULL) { 1131 if (argv0[0] != '/' && strchr(argv0, '/') != NULL) {
1132 char pathbuf[MAXPATHLEN]; 1132 char pathbuf[MAXPATHLEN];
1133 const char *abs = cached_realpath(argv0, pathbuf); 1133 const char *abs = cached_realpath(argv0, pathbuf);
1134 struct stat st; 1134 struct stat st;
1135 if (abs != NULL && abs[0] == '/' && stat(make, &st) == 0) 1135 if (abs != NULL && abs[0] == '/' && stat(make, &st) == 0)
1136 make = abs; 1136 make = abs;
1137 } 1137 }
1138 1138
1139 Var_Set("MAKE", make, VAR_GLOBAL); 1139 Var_Set("MAKE", make, VAR_GLOBAL);
1140 Var_Set(".MAKE", make, VAR_GLOBAL); 1140 Var_Set(".MAKE", make, VAR_GLOBAL);
1141} 1141}
1142 1142
1143static void 1143static void
1144InitDefSysIncPath(char *syspath) 1144InitDefSysIncPath(char *syspath)
1145{ 1145{
1146 static char defsyspath[] = _PATH_DEFSYSPATH; 1146 static char defsyspath[] = _PATH_DEFSYSPATH;
1147 char *start, *cp; 1147 char *start, *cp;
1148 1148
1149 /* 1149 /*
1150 * If no user-supplied system path was given (through the -m option) 1150 * If no user-supplied system path was given (through the -m option)
1151 * add the directories from the DEFSYSPATH (more than one may be given 1151 * add the directories from the DEFSYSPATH (more than one may be given
1152 * as dir1:...:dirn) to the system include path. 1152 * as dir1:...:dirn) to the system include path.
1153 */ 1153 */
1154 /* XXX: mismatch: the -m option sets sysIncPath, not syspath */ 1154 /* XXX: mismatch: the -m option sets sysIncPath, not syspath */
1155 if (syspath == NULL || syspath[0] == '\0') 1155 if (syspath == NULL || syspath[0] == '\0')
1156 syspath = defsyspath; 1156 syspath = defsyspath;
1157 else 1157 else
1158 syspath = bmake_strdup(syspath); 1158 syspath = bmake_strdup(syspath);
1159 1159
1160 for (start = syspath; *start != '\0'; start = cp) { 1160 for (start = syspath; *start != '\0'; start = cp) {
1161 for (cp = start; *cp != '\0' && *cp != ':'; cp++) 1161 for (cp = start; *cp != '\0' && *cp != ':'; cp++)
1162 continue; 1162 continue;
1163 if (*cp == ':') { 1163 if (*cp == ':') {
1164 *cp++ = '\0'; 1164 *cp++ = '\0';
1165 } 1165 }
1166 /* look for magic parent directory search string */ 1166 /* look for magic parent directory search string */
1167 if (strncmp(".../", start, 4) != 0) { 1167 if (strncmp(".../", start, 4) != 0) {
1168 (void)Dir_AddDir(defSysIncPath, start); 1168 (void)Dir_AddDir(defSysIncPath, start);
1169 } else { 1169 } else {
1170 char *dir = Dir_FindHereOrAbove(curdir, start + 4); 1170 char *dir = Dir_FindHereOrAbove(curdir, start + 4);
1171 if (dir != NULL) { 1171 if (dir != NULL) {
1172 (void)Dir_AddDir(defSysIncPath, dir); 1172 (void)Dir_AddDir(defSysIncPath, dir);
1173 free(dir); 1173 free(dir);
1174 } 1174 }
1175 } 1175 }
1176 } 1176 }
1177 1177
1178 if (syspath != defsyspath) 1178 if (syspath != defsyspath)
1179 free(syspath); 1179 free(syspath);
1180} 1180}
1181 1181
1182static void 1182static void
1183ReadBuiltinRules(void) 1183ReadBuiltinRules(void)
1184{ 1184{
1185 StringList *sysMkPath = Lst_New(); 1185 StringList *sysMkPath = Lst_New();
1186 Dir_Expand(_PATH_DEFSYSMK, 1186 Dir_Expand(_PATH_DEFSYSMK,
1187 Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath, 1187 Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath,
1188 sysMkPath); 1188 sysMkPath);
1189 if (Lst_IsEmpty(sysMkPath)) 1189 if (Lst_IsEmpty(sysMkPath))
1190 Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); 1190 Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK);
1191 if (!Lst_ForEachUntil(sysMkPath, ReadMakefileSucceeded, NULL)) 1191 if (!Lst_ForEachUntil(sysMkPath, ReadMakefileSucceeded, NULL))
1192 Fatal("%s: cannot open %s.", progname, 1192 Fatal("%s: cannot open %s.", progname,
1193 (char *)sysMkPath->first->datum); 1193 (char *)sysMkPath->first->datum);
1194 /* XXX: sysMkPath is not freed */ 1194 /* XXX: sysMkPath is not freed */
1195} 1195}
1196 1196
1197static void 1197static void
1198InitMaxJobs(void) 1198InitMaxJobs(void)
1199{ 1199{
1200 char *value; 1200 char *value;
1201 int n; 1201 int n;
1202 1202
1203 if (forceJobs || opts.compatMake || 1203 if (forceJobs || opts.compatMake ||
1204 !Var_Exists(".MAKE.JOBS", VAR_GLOBAL)) 1204 !Var_Exists(".MAKE.JOBS", VAR_GLOBAL))
1205 return; 1205 return;
1206 1206
1207 (void)Var_Subst("${.MAKE.JOBS}", VAR_GLOBAL, VARE_WANTRES, &value); 1207 (void)Var_Subst("${.MAKE.JOBS}", VAR_GLOBAL, VARE_WANTRES, &value);
1208 /* TODO: handle errors */ 1208 /* TODO: handle errors */
1209 n = (int)strtol(value, NULL, 0); 1209 n = (int)strtol(value, NULL, 0);
1210 if (n < 1) { 1210 if (n < 1) {
1211 (void)fprintf(stderr, 1211 (void)fprintf(stderr,
1212 "%s: illegal value for .MAKE.JOBS " 1212 "%s: illegal value for .MAKE.JOBS "
1213 "-- must be positive integer!\n", 1213 "-- must be positive integer!\n",
1214 progname); 1214 progname);
1215 exit(1); 1215 exit(1);
1216 } 1216 }
1217 1217
1218 if (n != opts.maxJobs) { 1218 if (n != opts.maxJobs) {
1219 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 1219 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
1220 Var_Append(MAKEFLAGS, value, VAR_GLOBAL); 1220 Var_Append(MAKEFLAGS, value, VAR_GLOBAL);
1221 } 1221 }
1222 1222
1223 opts.maxJobs = n; 1223 opts.maxJobs = n;
1224 maxJobTokens = opts.maxJobs; 1224 maxJobTokens = opts.maxJobs;
1225 forceJobs = TRUE; 1225 forceJobs = TRUE;
1226 free(value); 1226 free(value);
1227} 1227}
1228 1228
1229/* 1229/*
1230 * For compatibility, look at the directories in the VPATH variable 1230 * For compatibility, look at the directories in the VPATH variable
1231 * and add them to the search path, if the variable is defined. The 1231 * and add them to the search path, if the variable is defined. The
1232 * variable's value is in the same format as the PATH environment 1232 * variable's value is in the same format as the PATH environment
1233 * variable, i.e. <directory>:<directory>:<directory>... 1233 * variable, i.e. <directory>:<directory>:<directory>...
1234 */ 1234 */
1235static void 1235static void
1236InitVpath(void) 1236InitVpath(void)
1237{ 1237{
1238 char *vpath, savec, *path; 1238 char *vpath, savec, *path;
1239 if (!Var_Exists("VPATH", VAR_CMDLINE)) 1239 if (!Var_Exists("VPATH", VAR_CMDLINE))
1240 return; 1240 return;
1241 1241
1242 (void)Var_Subst("${VPATH}", VAR_CMDLINE, VARE_WANTRES, &vpath); 1242 (void)Var_Subst("${VPATH}", VAR_CMDLINE, VARE_WANTRES, &vpath);
1243 /* TODO: handle errors */ 1243 /* TODO: handle errors */
1244 path = vpath; 1244 path = vpath;
1245 do { 1245 do {
1246 char *cp; 1246 char *cp;
1247 /* skip to end of directory */ 1247 /* skip to end of directory */
1248 for (cp = path; *cp != ':' && *cp != '\0'; cp++) 1248 for (cp = path; *cp != ':' && *cp != '\0'; cp++)
1249 continue; 1249 continue;
1250 /* Save terminator character so know when to stop */ 1250 /* Save terminator character so know when to stop */
1251 savec = *cp; 1251 savec = *cp;
1252 *cp = '\0'; 1252 *cp = '\0';
1253 /* Add directory to search path */ 1253 /* Add directory to search path */
1254 (void)Dir_AddDir(dirSearchPath, path); 1254 (void)Dir_AddDir(dirSearchPath, path);
1255 *cp = savec; 1255 *cp = savec;
1256 path = cp + 1; 1256 path = cp + 1;
1257 } while (savec == ':'); 1257 } while (savec == ':');
1258 free(vpath); 1258 free(vpath);
1259} 1259}
1260 1260
1261static void 1261static void
1262ReadMakefiles(void) 1262ReadMakefiles(void)
1263{ 1263{
1264 if (opts.makefiles->first != NULL) { 1264 if (opts.makefiles->first != NULL) {
1265 StringListNode *ln; 1265 StringListNode *ln;
1266 1266
1267 for (ln = opts.makefiles->first; ln != NULL; ln = ln->next) { 1267 for (ln = opts.makefiles->first; ln != NULL; ln = ln->next) {
1268 if (ReadMakefile(ln->datum) != 0) 1268 if (ReadMakefile(ln->datum) != 0)
1269 Fatal("%s: cannot open %s.", 1269 Fatal("%s: cannot open %s.",
1270 progname, (char *)ln->datum); 1270 progname, (char *)ln->datum);
1271 } 1271 }
1272 } else { 1272 } else {
1273 char *p1; 1273 char *p1;
1274 (void)Var_Subst("${" MAKEFILE_PREFERENCE "}", 1274 (void)Var_Subst("${" MAKEFILE_PREFERENCE "}",
1275 VAR_CMDLINE, VARE_WANTRES, &p1); 1275 VAR_CMDLINE, VARE_WANTRES, &p1);
1276 /* TODO: handle errors */ 1276 /* TODO: handle errors */
1277 (void)str2Lst_Append(opts.makefiles, p1, NULL); 1277 (void)str2Lst_Append(opts.makefiles, p1, NULL);
1278 (void)Lst_ForEachUntil(opts.makefiles, 1278 (void)Lst_ForEachUntil(opts.makefiles,
1279 ReadMakefileSucceeded, NULL); 1279 ReadMakefileSucceeded, NULL);
1280 free(p1); 1280 free(p1);
1281 } 1281 }
1282} 1282}
1283 1283
1284static void 1284static void
1285CleanUp(void) 1285CleanUp(void)
1286{ 1286{
1287#ifdef CLEANUP 1287#ifdef CLEANUP
1288 Lst_Destroy(opts.variables, free); 1288 Lst_Destroy(opts.variables, free);
1289 Lst_Free(opts.makefiles); /* don't free, may be used in GNodes */ 1289 Lst_Free(opts.makefiles); /* don't free, may be used in GNodes */
1290 Lst_Destroy(opts.create, free); 1290 Lst_Destroy(opts.create, free);
1291#endif 1291#endif
1292 1292
1293 /* print the graph now it's been processed if the user requested it */ 1293 /* print the graph now it's been processed if the user requested it */
1294 if (DEBUG(GRAPH2)) 1294 if (DEBUG(GRAPH2))
1295 Targ_PrintGraph(2); 1295 Targ_PrintGraph(2);
1296 1296
1297 Trace_Log(MAKEEND, 0); 1297 Trace_Log(MAKEEND, 0);
1298 1298
1299 if (enterFlagObj) 1299 if (enterFlagObj)
1300 printf("%s: Leaving directory `%s'\n", progname, objdir); 1300 printf("%s: Leaving directory `%s'\n", progname, objdir);
1301 if (opts.enterFlag) 1301 if (opts.enterFlag)
1302 printf("%s: Leaving directory `%s'\n", progname, curdir); 1302 printf("%s: Leaving directory `%s'\n", progname, curdir);
1303 1303
1304#ifdef USE_META 1304#ifdef USE_META
1305 meta_finish(); 1305 meta_finish();
1306#endif 1306#endif
1307 Suff_End(); 1307 Suff_End();
1308 Targ_End(); 1308 Targ_End();
1309 Arch_End(); 1309 Arch_End();
1310 Var_End(); 1310 Var_End();
1311 Parse_End(); 1311 Parse_End();
1312 Dir_End(); 1312 Dir_End();
1313 Job_End(); 1313 Job_End();
1314 Trace_End(); 1314 Trace_End();
1315} 1315}
1316 1316
1317/*- 1317/*-
1318 * main -- 1318 * main --
1319 * The main function, for obvious reasons. Initializes variables 1319 * The main function, for obvious reasons. Initializes variables
1320 * and a few modules, then parses the arguments give it in the 1320 * and a few modules, then parses the arguments give it in the
1321 * environment and on the command line. Reads the system makefile 1321 * environment and on the command line. Reads the system makefile
1322 * followed by either Makefile, makefile or the file given by the 1322 * followed by either Makefile, makefile or the file given by the
1323 * -f argument. Sets the .MAKEFLAGS PMake variable based on all the 1323 * -f argument. Sets the .MAKEFLAGS PMake variable based on all the
1324 * flags it has received by then uses either the Make or the Compat 1324 * flags it has received by then uses either the Make or the Compat
1325 * module to create the initial list of targets. 1325 * module to create the initial list of targets.
1326 * 1326 *
1327 * Results: 1327 * Results:
1328 * If -q was given, exits -1 if anything was out-of-date. Else it exits 1328 * If -q was given, exits -1 if anything was out-of-date. Else it exits
1329 * 0. 1329 * 0.
1330 * 1330 *
1331 * Side Effects: 1331 * Side Effects:
1332 * The program exits when done. Targets are created. etc. etc. etc. 1332 * The program exits when done. Targets are created. etc. etc. etc.
1333 */ 1333 */
1334int 1334int
1335main(int argc, char **argv) 1335main(int argc, char **argv)
1336{ 1336{
1337 Boolean outOfDate; /* FALSE if all targets up to date */ 1337 Boolean outOfDate; /* FALSE if all targets up to date */
1338 struct stat sa; 1338 struct stat sa;
1339 const char *machine; 1339 const char *machine;
1340 const char *machine_arch; 1340 const char *machine_arch;
1341 char *syspath = getenv("MAKESYSPATH"); 1341 char *syspath = getenv("MAKESYSPATH");
1342 struct utsname utsname; 1342 struct utsname utsname;
1343 1343
1344 /* default to writing debug to stderr */ 1344 /* default to writing debug to stderr */
1345 opts.debug_file = stderr; 1345 opts.debug_file = stderr;
1346 1346
1347#ifdef SIGINFO 1347#ifdef SIGINFO
1348 (void)bmake_signal(SIGINFO, siginfo); 1348 (void)bmake_signal(SIGINFO, siginfo);
1349#endif 1349#endif
1350 1350
1351 InitRandom(); 1351 InitRandom();
1352 1352
1353 if ((progname = strrchr(argv[0], '/')) != NULL) 1353 if ((progname = strrchr(argv[0], '/')) != NULL)
1354 progname++; 1354 progname++;
1355 else 1355 else
1356 progname = argv[0]; 1356 progname = argv[0];
1357 1357
1358 UnlimitFiles(); 1358 UnlimitFiles();
1359 1359
1360 if (uname(&utsname) == -1) { 1360 if (uname(&utsname) == -1) {
1361 (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 1361 (void)fprintf(stderr, "%s: uname failed (%s).\n", progname,
1362 strerror(errno)); 1362 strerror(errno));
1363 exit(2); 1363 exit(2);
1364 } 1364 }
1365 1365
1366 /* 1366 /*
1367 * Get the name of this type of MACHINE from utsname 1367 * Get the name of this type of MACHINE from utsname
1368 * so we can share an executable for similar machines. 1368 * so we can share an executable for similar machines.
1369 * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 1369 * (i.e. m68k: amiga hp300, mac68k, sun3, ...)
1370 * 1370 *
1371 * Note that both MACHINE and MACHINE_ARCH are decided at 1371 * Note that both MACHINE and MACHINE_ARCH are decided at
1372 * run-time. 1372 * run-time.
1373 */ 1373 */
1374 machine = init_machine(&utsname); 1374 machine = init_machine(&utsname);
1375 machine_arch = init_machine_arch(); 1375 machine_arch = init_machine_arch();
1376 1376
1377 myPid = getpid(); /* remember this for vFork() */ 1377 myPid = getpid(); /* remember this for vFork() */
1378 1378
1379 /* 1379 /*
1380 * Just in case MAKEOBJDIR wants us to do something tricky. 1380 * Just in case MAKEOBJDIR wants us to do something tricky.
1381 */ 1381 */
1382 Var_Init(); /* Initialize the lists of variables for 1382 Var_Init(); /* Initialize the lists of variables for
1383 * parsing arguments */ 1383 * parsing arguments */
1384 Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL); 1384 Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL);
1385 Var_Set("MACHINE", machine, VAR_GLOBAL); 1385 Var_Set("MACHINE", machine, VAR_GLOBAL);
1386 Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL); 1386 Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL);
1387#ifdef MAKE_VERSION 1387#ifdef MAKE_VERSION
1388 Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL); 1388 Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL);
1389#endif 1389#endif
1390 Var_Set(".newline", "\n", VAR_GLOBAL); /* handy for :@ loops */ 1390 Var_Set(".newline", "\n", VAR_GLOBAL); /* handy for :@ loops */
1391 /* 1391 /*
1392 * This is the traditional preference for makefiles. 1392 * This is the traditional preference for makefiles.
1393 */ 1393 */
1394#ifndef MAKEFILE_PREFERENCE_LIST 1394#ifndef MAKEFILE_PREFERENCE_LIST
1395# define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 1395# define MAKEFILE_PREFERENCE_LIST "makefile Makefile"
1396#endif 1396#endif
1397 Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, 1397 Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST,
1398 VAR_GLOBAL); 1398 VAR_GLOBAL);
1399 Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL); 1399 Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL);
1400 1400
1401 CmdOpts_Init(); 1401 CmdOpts_Init();
1402 allPrecious = FALSE; /* Remove targets when interrupted */ 1402 allPrecious = FALSE; /* Remove targets when interrupted */
1403 deleteOnError = FALSE; /* Historical default behavior */ 1403 deleteOnError = FALSE; /* Historical default behavior */
1404 jobsRunning = FALSE; 1404 jobsRunning = FALSE;
1405 1405
1406 maxJobTokens = opts.maxJobs; 1406 maxJobTokens = opts.maxJobs;
1407 ignorePWD = FALSE; 1407 ignorePWD = FALSE;
1408 1408
1409 /* 1409 /*
1410 * Initialize the parsing, directory and variable modules to prepare 1410 * Initialize the parsing, directory and variable modules to prepare
1411 * for the reading of inclusion paths and variable settings on the 1411 * for the reading of inclusion paths and variable settings on the
1412 * command line 1412 * command line
1413 */ 1413 */
1414 1414
1415 /* 1415 /*
1416 * Initialize various variables. 1416 * Initialize various variables.
1417 * MAKE also gets this name, for compatibility 1417 * MAKE also gets this name, for compatibility
1418 * .MAKEFLAGS gets set to the empty string just in case. 1418 * .MAKEFLAGS gets set to the empty string just in case.
1419 * MFLAGS also gets initialized empty, for compatibility. 1419 * MFLAGS also gets initialized empty, for compatibility.
1420 */ 1420 */
1421 Parse_Init(); 1421 Parse_Init();
1422 InitVarMake(argv[0]); 1422 InitVarMake(argv[0]);
1423 Var_Set(MAKEFLAGS, "", VAR_GLOBAL); 1423 Var_Set(MAKEFLAGS, "", VAR_GLOBAL);
1424 Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL); 1424 Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL);
1425 Var_Set("MFLAGS", "", VAR_GLOBAL); 1425 Var_Set("MFLAGS", "", VAR_GLOBAL);
1426 Var_Set(".ALLTARGETS", "", VAR_GLOBAL); 1426 Var_Set(".ALLTARGETS", "", VAR_GLOBAL);
1427 /* some makefiles need to know this */ 1427 /* some makefiles need to know this */
1428 Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMDLINE); 1428 Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMDLINE);
1429 1429
1430 /* 1430 /*
1431 * Set some other useful macros 1431 * Set some other useful macros
1432 */ 1432 */
1433 { 1433 {
1434 char tmp[64], *ep; 1434 char tmp[64], *ep;
1435 1435
1436 makelevel = ((ep = getenv(MAKE_LEVEL_ENV)) && *ep) ? atoi(ep) : 0; 1436 makelevel = ((ep = getenv(MAKE_LEVEL_ENV)) && *ep) ? atoi(ep) : 0;
1437 if (makelevel < 0) 1437 if (makelevel < 0)
1438 makelevel = 0; 1438 makelevel = 0;
1439 snprintf(tmp, sizeof(tmp), "%d", makelevel); 1439 snprintf(tmp, sizeof(tmp), "%d", makelevel);
1440 Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL); 1440 Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL);
1441 snprintf(tmp, sizeof(tmp), "%u", myPid); 1441 snprintf(tmp, sizeof(tmp), "%u", myPid);
1442 Var_Set(".MAKE.PID", tmp, VAR_GLOBAL); 1442 Var_Set(".MAKE.PID", tmp, VAR_GLOBAL);
1443 snprintf(tmp, sizeof(tmp), "%u", getppid()); 1443 snprintf(tmp, sizeof(tmp), "%u", getppid());
1444 Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL); 1444 Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL);
1445 } 1445 }
1446 if (makelevel > 0) { 1446 if (makelevel > 0) {
1447 char pn[1024]; 1447 char pn[1024];
1448 snprintf(pn, sizeof(pn), "%s[%d]", progname, makelevel); 1448 snprintf(pn, sizeof(pn), "%s[%d]", progname, makelevel);
1449 progname = bmake_strdup(pn); 1449 progname = bmake_strdup(pn);
1450 } 1450 }
1451 1451
1452#ifdef USE_META 1452#ifdef USE_META
1453 meta_init(); 1453 meta_init();
1454#endif 1454#endif
1455 Dir_Init(); 1455 Dir_Init();
1456 1456
1457 /* 1457 /*
1458 * First snag any flags out of the MAKE environment variable. 1458 * First snag any flags out of the MAKE environment variable.
1459 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 1459 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
1460 * in a different format). 1460 * in a different format).
1461 */ 1461 */
1462#ifdef POSIX 1462#ifdef POSIX
1463 { 1463 {
1464 char *p1 = explode(getenv("MAKEFLAGS")); 1464 char *p1 = explode(getenv("MAKEFLAGS"));
1465 Main_ParseArgLine(p1); 1465 Main_ParseArgLine(p1);
1466 free(p1); 1466 free(p1);
1467 } 1467 }
1468#else 1468#else
1469 Main_ParseArgLine(getenv("MAKE")); 1469 Main_ParseArgLine(getenv("MAKE"));
1470#endif 1470#endif
1471 1471
1472 /* 1472 /*
1473 * Find where we are (now). 1473 * Find where we are (now).
1474 * We take care of PWD for the automounter below... 1474 * We take care of PWD for the automounter below...
1475 */ 1475 */
1476 if (getcwd(curdir, MAXPATHLEN) == NULL) { 1476 if (getcwd(curdir, MAXPATHLEN) == NULL) {
1477 (void)fprintf(stderr, "%s: getcwd: %s.\n", 1477 (void)fprintf(stderr, "%s: getcwd: %s.\n",
1478 progname, strerror(errno)); 1478 progname, strerror(errno));
1479 exit(2); 1479 exit(2);
1480 } 1480 }
1481 1481
1482 MainParseArgs(argc, argv); 1482 MainParseArgs(argc, argv);
1483 1483
1484 if (opts.enterFlag) 1484 if (opts.enterFlag)
1485 printf("%s: Entering directory `%s'\n", progname, curdir); 1485 printf("%s: Entering directory `%s'\n", progname, curdir);
1486 1486
1487 /* 1487 /*
1488 * Verify that cwd is sane. 1488 * Verify that cwd is sane.
1489 */ 1489 */
1490 if (stat(curdir, &sa) == -1) { 1490 if (stat(curdir, &sa) == -1) {
1491 (void)fprintf(stderr, "%s: %s: %s.\n", 1491 (void)fprintf(stderr, "%s: %s: %s.\n",
1492 progname, curdir, strerror(errno)); 1492 progname, curdir, strerror(errno));
1493 exit(2); 1493 exit(2);
1494 } 1494 }
1495 1495
1496#ifndef NO_PWD_OVERRIDE 1496#ifndef NO_PWD_OVERRIDE
1497 HandlePWD(&sa); 1497 HandlePWD(&sa);
1498#endif 1498#endif
1499 Var_Set(".CURDIR", curdir, VAR_GLOBAL); 1499 Var_Set(".CURDIR", curdir, VAR_GLOBAL);
1500 1500
1501 InitObjdir(machine, machine_arch); 1501 InitObjdir(machine, machine_arch);
1502 1502
1503 /* 1503 /*
1504 * Initialize archive, target and suffix modules in preparation for 1504 * Initialize archive, target and suffix modules in preparation for
1505 * parsing the makefile(s) 1505 * parsing the makefile(s)
1506 */ 1506 */
1507 Arch_Init(); 1507 Arch_Init();
1508 Targ_Init(); 1508 Targ_Init();
1509 Suff_Init(); 1509 Suff_Init();
1510 Trace_Init(tracefile); 1510 Trace_Init(tracefile);
1511 1511
1512 DEFAULT = NULL; 1512 DEFAULT = NULL;
1513 (void)time(&now); 1513 (void)time(&now);
1514 1514
1515 Trace_Log(MAKESTART, NULL); 1515 Trace_Log(MAKESTART, NULL);
1516 1516
1517 InitVarTargets(); 1517 InitVarTargets();
1518 1518
1519 InitDefSysIncPath(syspath); 1519 InitDefSysIncPath(syspath);
1520 1520
1521 /* 1521 /*
1522 * Read in the built-in rules first, followed by the specified 1522 * Read in the built-in rules first, followed by the specified
1523 * makefiles, or the default makefile and Makefile, in that order, 1523 * makefiles, or the default makefile and Makefile, in that order,
1524 * if no makefiles were given on the command line. 1524 * if no makefiles were given on the command line.
1525 */ 1525 */
1526 if (!opts.noBuiltins) 1526 if (!opts.noBuiltins)
1527 ReadBuiltinRules(); 1527 ReadBuiltinRules();
1528 ReadMakefiles(); 1528 ReadMakefiles();
1529  1529
1530 /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1530 /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
1531 if (!opts.noBuiltins || !opts.printVars) { 1531 if (!opts.noBuiltins || !opts.printVars) {
1532 /* ignore /dev/null and anything starting with "no" */ 1532 /* ignore /dev/null and anything starting with "no" */
1533 (void)Var_Subst("${.MAKE.DEPENDFILE:N/dev/null:Nno*:T}", 1533 (void)Var_Subst("${.MAKE.DEPENDFILE:N/dev/null:Nno*:T}",
1534 VAR_CMDLINE, VARE_WANTRES, &makeDependfile); 1534 VAR_CMDLINE, VARE_WANTRES, &makeDependfile);
1535 if (makeDependfile[0] != '\0') { 1535 if (makeDependfile[0] != '\0') {
1536 /* TODO: handle errors */ 1536 /* TODO: handle errors */
1537 doing_depend = TRUE; 1537 doing_depend = TRUE;
1538 (void)ReadMakefile(makeDependfile); 1538 (void)ReadMakefile(makeDependfile);
1539 doing_depend = FALSE; 1539 doing_depend = FALSE;
1540 } 1540 }
1541 } 1541 }
1542 1542
1543 if (enterFlagObj) 1543 if (enterFlagObj)
1544 printf("%s: Entering directory `%s'\n", progname, objdir); 1544 printf("%s: Entering directory `%s'\n", progname, objdir);
1545 1545
1546 MakeMode(NULL); 1546 MakeMode(NULL);
1547 1547
1548 { 1548 {
1549 void *freeIt; 1549 void *freeIt;
1550 Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &freeIt), 1550 Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &freeIt),
1551 VAR_GLOBAL); 1551 VAR_GLOBAL);
1552 bmake_free(freeIt); 1552 bmake_free(freeIt);
1553 1553
1554 } 1554 }
1555 1555
1556 InitMaxJobs(); 1556 InitMaxJobs();
1557 1557
1558 /* 1558 /*
1559 * Be compatible if user did not specify -j and did not explicitly 1559 * Be compatible if user did not specify -j and did not explicitly
1560 * turned compatibility on 1560 * turned compatibility on
1561 */ 1561 */
1562 if (!opts.compatMake && !forceJobs) { 1562 if (!opts.compatMake && !forceJobs) {
1563 opts.compatMake = TRUE; 1563 opts.compatMake = TRUE;
1564 } 1564 }
1565 1565
1566 if (!opts.compatMake) 1566 if (!opts.compatMake)
1567 Job_ServerStart(maxJobTokens, jp_0, jp_1); 1567 Job_ServerStart(maxJobTokens, jp_0, jp_1);
1568 DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1568 DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n",
1569 jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0); 1569 jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0);
1570 1570
1571 if (!opts.printVars) 1571 if (!opts.printVars)
1572 Main_ExportMAKEFLAGS(TRUE); /* initial export */ 1572 Main_ExportMAKEFLAGS(TRUE); /* initial export */
1573 1573
1574 InitVpath(); 1574 InitVpath();
1575 1575
1576 /* 1576 /*
1577 * Now that all search paths have been read for suffixes et al, it's 1577 * Now that all search paths have been read for suffixes et al, it's
1578 * time to add the default search path to their lists... 1578 * time to add the default search path to their lists...
1579 */ 1579 */
1580 Suff_DoPaths(); 1580 Suff_DoPaths();
1581 1581
1582 /* 1582 /*
1583 * Propagate attributes through :: dependency lists. 1583 * Propagate attributes through :: dependency lists.
1584 */ 1584 */
1585 Targ_Propagate(); 1585 Targ_Propagate();
1586 1586
1587 /* print the initial graph, if the user requested it */ 1587 /* print the initial graph, if the user requested it */
1588 if (DEBUG(GRAPH1)) 1588 if (DEBUG(GRAPH1))
1589 Targ_PrintGraph(1); 1589 Targ_PrintGraph(1);
1590 1590
1591 /* print the values of any variables requested by the user */ 1591 /* print the values of any variables requested by the user */
1592 if (opts.printVars) { 1592 if (opts.printVars) {
1593 doPrintVars(); 1593 doPrintVars();
1594 outOfDate = FALSE; 1594 outOfDate = FALSE;
1595 } else { 1595 } else {
1596 outOfDate = runTargets(); 1596 outOfDate = runTargets();
1597 } 1597 }
1598 1598
1599 CleanUp(); 1599 CleanUp();
1600 1600
1601 return outOfDate ? 1 : 0; 1601 return outOfDate ? 1 : 0;
1602} 1602}
1603 1603
1604/* Open and parse the given makefile, with all its side effects. 1604/* Open and parse the given makefile, with all its side effects.
1605 * 1605 *
1606 * Results: 1606 * Results:
1607 * 0 if ok. -1 if couldn't open file. 1607 * 0 if ok. -1 if couldn't open file.
1608 */ 1608 */
1609static int 1609static int
1610ReadMakefile(const char *fname) 1610ReadMakefile(const char *fname)
1611{ 1611{
1612 int fd; 1612 int fd;
1613 char *name, *path = NULL; 1613 char *name, *path = NULL;
1614 1614
1615 if (!strcmp(fname, "-")) { 1615 if (!strcmp(fname, "-")) {
1616 Parse_File(NULL /*stdin*/, -1); 1616 Parse_File(NULL /*stdin*/, -1);
1617 Var_Set("MAKEFILE", "", VAR_INTERNAL); 1617 Var_Set("MAKEFILE", "", VAR_INTERNAL);
1618 } else { 1618 } else {
1619 /* if we've chdir'd, rebuild the path name */ 1619 /* if we've chdir'd, rebuild the path name */
1620 if (strcmp(curdir, objdir) && *fname != '/') { 1620 if (strcmp(curdir, objdir) && *fname != '/') {
1621 path = str_concat3(curdir, "/", fname); 1621 path = str_concat3(curdir, "/", fname);
1622 fd = open(path, O_RDONLY); 1622 fd = open(path, O_RDONLY);
1623 if (fd != -1) { 1623 if (fd != -1) {
1624 fname = path; 1624 fname = path;
1625 goto found; 1625 goto found;
1626 } 1626 }
1627 free(path); 1627 free(path);
1628 1628
1629 /* If curdir failed, try objdir (ala .depend) */ 1629 /* If curdir failed, try objdir (ala .depend) */
1630 path = str_concat3(objdir, "/", fname); 1630 path = str_concat3(objdir, "/", fname);
1631 fd = open(path, O_RDONLY); 1631 fd = open(path, O_RDONLY);
1632 if (fd != -1) { 1632 if (fd != -1) {
1633 fname = path; 1633 fname = path;
1634 goto found; 1634 goto found;
1635 } 1635 }
1636 } else { 1636 } else {
1637 fd = open(fname, O_RDONLY); 1637 fd = open(fname, O_RDONLY);
1638 if (fd != -1) 1638 if (fd != -1)
1639 goto found; 1639 goto found;
1640 } 1640 }
1641 /* look in -I and system include directories. */ 1641 /* look in -I and system include directories. */
1642 name = Dir_FindFile(fname, parseIncPath); 1642 name = Dir_FindFile(fname, parseIncPath);
1643 if (!name) { 1643 if (!name) {
1644 SearchPath *sysInc = Lst_IsEmpty(sysIncPath) 1644 SearchPath *sysInc = Lst_IsEmpty(sysIncPath)
1645 ? defSysIncPath : sysIncPath; 1645 ? defSysIncPath : sysIncPath;
1646 name = Dir_FindFile(fname, sysInc); 1646 name = Dir_FindFile(fname, sysInc);
1647 } 1647 }
1648 if (!name || (fd = open(name, O_RDONLY)) == -1) { 1648 if (!name || (fd = open(name, O_RDONLY)) == -1) {
1649 free(name); 1649 free(name);
1650 free(path); 1650 free(path);
1651 return -1; 1651 return -1;
1652 } 1652 }
1653 fname = name; 1653 fname = name;
1654 /* 1654 /*
1655 * set the MAKEFILE variable desired by System V fans -- the 1655 * set the MAKEFILE variable desired by System V fans -- the
1656 * placement of the setting here means it gets set to the last 1656 * placement of the setting here means it gets set to the last
1657 * makefile specified, as it is set by SysV make. 1657 * makefile specified, as it is set by SysV make.
1658 */ 1658 */
1659found: 1659found:
1660 if (!doing_depend) 1660 if (!doing_depend)
1661 Var_Set("MAKEFILE", fname, VAR_INTERNAL); 1661 Var_Set("MAKEFILE", fname, VAR_INTERNAL);
1662 Parse_File(fname, fd); 1662 Parse_File(fname, fd);
1663 } 1663 }
1664 free(path); 1664 free(path);
1665 return 0; 1665 return 0;
1666} 1666}
1667 1667
1668 1668
1669 1669
1670/*- 1670/*-
1671 * Cmd_Exec -- 1671 * Cmd_Exec --
1672 * Execute the command in cmd, and return the output of that command 1672 * Execute the command in cmd, and return the output of that command
1673 * in a string. In the output, newlines are replaced with spaces. 1673 * in a string. In the output, newlines are replaced with spaces.
1674 * 1674 *
1675 * Results: 1675 * Results:
1676 * A string containing the output of the command, or the empty string. 1676 * A string containing the output of the command, or the empty string.
1677 * *errfmt returns a format string describing the command failure, 1677 * *errfmt returns a format string describing the command failure,
1678 * if any, using a single %s conversion specification. 1678 * if any, using a single %s conversion specification.
1679 * 1679 *
1680 * Side Effects: 1680 * Side Effects:
1681 * The string must be freed by the caller. 1681 * The string must be freed by the caller.
1682 */ 1682 */
1683char * 1683char *
1684Cmd_Exec(const char *cmd, const char **errfmt) 1684Cmd_Exec(const char *cmd, const char **errfmt)
1685{ 1685{
1686 const char *args[4]; /* Args for invoking the shell */ 1686 const char *args[4]; /* Args for invoking the shell */
1687 int fds[2]; /* Pipe streams */ 1687 int fds[2]; /* Pipe streams */
1688 int cpid; /* Child PID */ 1688 int cpid; /* Child PID */
1689 int pid; /* PID from wait() */ 1689 int pid; /* PID from wait() */
1690 int status; /* command exit status */ 1690 int status; /* command exit status */
1691 Buffer buf; /* buffer to store the result */ 1691 Buffer buf; /* buffer to store the result */
1692 ssize_t bytes_read; 1692 ssize_t bytes_read;
1693 char *res; /* result */ 1693 char *res; /* result */
1694 size_t res_len; 1694 size_t res_len;
1695 char *cp; 1695 char *cp;
1696 int savederr; /* saved errno */ 1696 int savederr; /* saved errno */
1697 1697
1698 *errfmt = NULL; 1698 *errfmt = NULL;
1699 1699
1700 if (!shellName) 1700 if (!shellName)
1701 Shell_Init(); 1701 Shell_Init();
1702 /* 1702 /*
1703 * Set up arguments for shell 1703 * Set up arguments for shell
1704 */ 1704 */
1705 args[0] = shellName; 1705 args[0] = shellName;
1706 args[1] = "-c"; 1706 args[1] = "-c";
1707 args[2] = cmd; 1707 args[2] = cmd;
1708 args[3] = NULL; 1708 args[3] = NULL;
1709 1709
1710 /* 1710 /*
1711 * Open a pipe for fetching its output 1711 * Open a pipe for fetching its output
1712 */ 1712 */
1713 if (pipe(fds) == -1) { 1713 if (pipe(fds) == -1) {
1714 *errfmt = "Couldn't create pipe for \"%s\""; 1714 *errfmt = "Couldn't create pipe for \"%s\"";
1715 goto bad; 1715 goto bad;
1716 } 1716 }
1717 1717
1718 /* 1718 /*
1719 * Fork 1719 * Fork
1720 */ 1720 */
1721 switch (cpid = vFork()) { 1721 switch (cpid = vFork()) {
1722 case 0: 1722 case 0:
1723 /* 1723 /*
1724 * Close input side of pipe 1724 * Close input side of pipe
1725 */ 1725 */
1726 (void)close(fds[0]); 1726 (void)close(fds[0]);
1727 1727
1728 /* 1728 /*
1729 * Duplicate the output stream to the shell's output, then 1729 * Duplicate the output stream to the shell's output, then
1730 * shut the extra thing down. Note we don't fetch the error 1730 * shut the extra thing down. Note we don't fetch the error
1731 * stream...why not? Why? 1731 * stream...why not? Why?
1732 */ 1732 */
1733 (void)dup2(fds[1], 1); 1733 (void)dup2(fds[1], 1);
1734 (void)close(fds[1]); 1734 (void)close(fds[1]);
1735 1735
1736 Var_ExportVars(); 1736 Var_ExportVars();
1737 1737
1738 (void)execv(shellPath, UNCONST(args)); 1738 (void)execv(shellPath, UNCONST(args));
1739 _exit(1); 1739 _exit(1);
1740 /*NOTREACHED*/ 1740 /*NOTREACHED*/
1741 1741
1742 case -1: 1742 case -1:
1743 *errfmt = "Couldn't exec \"%s\""; 1743 *errfmt = "Couldn't exec \"%s\"";
1744 goto bad; 1744 goto bad;
1745 1745
1746 default: 1746 default:
1747 /* 1747 /*
1748 * No need for the writing half 1748 * No need for the writing half
1749 */ 1749 */
1750 (void)close(fds[1]); 1750 (void)close(fds[1]);
1751 1751
1752 savederr = 0; 1752 savederr = 0;
1753 Buf_Init(&buf, 0); 1753 Buf_Init(&buf, 0);
1754 1754
1755 do { 1755 do {
1756 char result[BUFSIZ]; 1756 char result[BUFSIZ];
1757 bytes_read = read(fds[0], result, sizeof(result)); 1757 bytes_read = read(fds[0], result, sizeof(result));
1758 if (bytes_read > 0) 1758 if (bytes_read > 0)
1759 Buf_AddBytes(&buf, result, (size_t)bytes_read); 1759 Buf_AddBytes(&buf, result, (size_t)bytes_read);
1760 } 1760 }
1761 while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR)); 1761 while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR));
1762 if (bytes_read == -1) 1762 if (bytes_read == -1)
1763 savederr = errno; 1763 savederr = errno;
1764 1764
1765 /* 1765 /*
1766 * Close the input side of the pipe. 1766 * Close the input side of the pipe.
1767 */ 1767 */
1768 (void)close(fds[0]); 1768 (void)close(fds[0]);
1769 1769
1770 /* 1770 /*
1771 * Wait for the process to exit. 1771 * Wait for the process to exit.
1772 */ 1772 */
1773 while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) { 1773 while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) {
1774 JobReapChild(pid, status, FALSE); 1774 JobReapChild(pid, status, FALSE);
1775 continue; 1775 continue;
1776 } 1776 }
1777 res_len = Buf_Len(&buf); 1777 res_len = Buf_Len(&buf);
1778 res = Buf_Destroy(&buf, FALSE); 1778 res = Buf_Destroy(&buf, FALSE);
1779 1779
1780 if (savederr != 0) 1780 if (savederr != 0)
1781 *errfmt = "Couldn't read shell's output for \"%s\""; 1781 *errfmt = "Couldn't read shell's output for \"%s\"";
1782 1782
1783 if (WIFSIGNALED(status)) 1783 if (WIFSIGNALED(status))
1784 *errfmt = "\"%s\" exited on a signal"; 1784 *errfmt = "\"%s\" exited on a signal";
1785 else if (WEXITSTATUS(status) != 0) 1785 else if (WEXITSTATUS(status) != 0)
1786 *errfmt = "\"%s\" returned non-zero status"; 1786 *errfmt = "\"%s\" returned non-zero status";
1787 1787
1788 /* Convert newlines to spaces. A final newline is just stripped */ 1788 /* Convert newlines to spaces. A final newline is just stripped */
1789 if (res_len > 0 && res[res_len - 1] == '\n') 1789 if (res_len > 0 && res[res_len - 1] == '\n')
1790 res[res_len - 1] = '\0'; 1790 res[res_len - 1] = '\0';
1791 for (cp = res; *cp != '\0'; cp++) 1791 for (cp = res; *cp != '\0'; cp++)
1792 if (*cp == '\n') 1792 if (*cp == '\n')
1793 *cp = ' '; 1793 *cp = ' ';
1794 break; 1794 break;
1795 } 1795 }
1796 return res; 1796 return res;
1797bad: 1797bad:
1798 return bmake_strdup(""); 1798 return bmake_strdup("");
1799} 1799}
1800 1800
1801/* Print a printf-style error message. 1801/* Print a printf-style error message.
1802 * 1802 *
1803 * This error message has no consequences, in particular it does not affect 1803 * This error message has no consequences, in particular it does not affect
1804 * the exit status. */ 1804 * the exit status. */
1805void 1805void
1806Error(const char *fmt, ...) 1806Error(const char *fmt, ...)
1807{ 1807{
1808 va_list ap; 1808 va_list ap;
1809 FILE *err_file; 1809 FILE *err_file;
1810 1810
1811 err_file = opts.debug_file; 1811 err_file = opts.debug_file;
1812 if (err_file == stdout) 1812 if (err_file == stdout)
1813 err_file = stderr; 1813 err_file = stderr;
1814 (void)fflush(stdout); 1814 (void)fflush(stdout);
1815 for (;;) { 1815 for (;;) {
1816 va_start(ap, fmt); 1816 va_start(ap, fmt);
1817 fprintf(err_file, "%s: ", progname); 1817 fprintf(err_file, "%s: ", progname);
1818 (void)vfprintf(err_file, fmt, ap); 1818 (void)vfprintf(err_file, fmt, ap);
1819 va_end(ap); 1819 va_end(ap);
1820 (void)fprintf(err_file, "\n"); 1820 (void)fprintf(err_file, "\n");
1821 (void)fflush(err_file); 1821 (void)fflush(err_file);
1822 if (err_file == stderr) 1822 if (err_file == stderr)
1823 break; 1823 break;
1824 err_file = stderr; 1824 err_file = stderr;
1825 } 1825 }
1826} 1826}
1827 1827
1828/* Produce a Fatal error message, then exit immediately. 1828/* Produce a Fatal error message, then exit immediately.
1829 * 1829 *
1830 * If jobs are running, waits for them to finish. */ 1830 * If jobs are running, wait for them to finish. */
1831void 1831void
1832Fatal(const char *fmt, ...) 1832Fatal(const char *fmt, ...)
1833{ 1833{
1834 va_list ap; 1834 va_list ap;
1835 1835
1836 va_start(ap, fmt); 1836 va_start(ap, fmt);
1837 if (jobsRunning) 1837 if (jobsRunning)
1838 Job_Wait(); 1838 Job_Wait();
1839 1839
1840 (void)fflush(stdout); 1840 (void)fflush(stdout);
1841 (void)vfprintf(stderr, fmt, ap); 1841 (void)vfprintf(stderr, fmt, ap);
1842 va_end(ap); 1842 va_end(ap);
1843 (void)fprintf(stderr, "\n"); 1843 (void)fprintf(stderr, "\n");
1844 (void)fflush(stderr); 1844 (void)fflush(stderr);
1845 1845
1846 PrintOnError(NULL, NULL); 1846 PrintOnError(NULL, NULL);
1847 1847
1848 if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 1848 if (DEBUG(GRAPH2) || DEBUG(GRAPH3))
1849 Targ_PrintGraph(2); 1849 Targ_PrintGraph(2);
1850 Trace_Log(MAKEERROR, 0); 1850 Trace_Log(MAKEERROR, 0);
1851 exit(2); /* Not 1 so -q can distinguish error */ 1851 exit(2); /* Not 1 so -q can distinguish error */
1852} 1852}
1853 1853
1854/* Major exception once jobs are being created. 1854/* Major exception once jobs are being created.
1855 * Kills all jobs, prints a message and exits. */ 1855 * Kills all jobs, prints a message and exits. */
1856void 1856void
1857Punt(const char *fmt, ...) 1857Punt(const char *fmt, ...)
1858{ 1858{
1859 va_list ap; 1859 va_list ap;
1860 1860
1861 va_start(ap, fmt); 1861 va_start(ap, fmt);
1862 (void)fflush(stdout); 1862 (void)fflush(stdout);
1863 (void)fprintf(stderr, "%s: ", progname); 1863 (void)fprintf(stderr, "%s: ", progname);
1864 (void)vfprintf(stderr, fmt, ap); 1864 (void)vfprintf(stderr, fmt, ap);
1865 va_end(ap); 1865 va_end(ap);
1866 (void)fprintf(stderr, "\n"); 1866 (void)fprintf(stderr, "\n");
1867 (void)fflush(stderr); 1867 (void)fflush(stderr);
1868 1868
1869 PrintOnError(NULL, NULL); 1869 PrintOnError(NULL, NULL);
1870 1870
1871 DieHorribly(); 1871 DieHorribly();
1872} 1872}
1873 1873
1874/* Exit without giving a message. */ 1874/* Exit without giving a message. */
1875void 1875void
1876DieHorribly(void) 1876DieHorribly(void)
1877{ 1877{
1878 if (jobsRunning) 1878 if (jobsRunning)
1879 Job_AbortAll(); 1879 Job_AbortAll();
1880 if (DEBUG(GRAPH2)) 1880 if (DEBUG(GRAPH2))
1881 Targ_PrintGraph(2); 1881 Targ_PrintGraph(2);
1882 Trace_Log(MAKEERROR, 0); 1882 Trace_Log(MAKEERROR, 0);
1883 exit(2); /* Not 1, so -q can distinguish error */ 1883 exit(2); /* Not 1, so -q can distinguish error */
1884} 1884}
1885 1885
1886/* Called when aborting due to errors in child shell to signal abnormal exit. 1886/* Called when aborting due to errors in child shell to signal abnormal exit.
1887 * The program exits. 1887 * The program exits.
1888 * Errors is the number of errors encountered in Make_Make. */ 1888 * Errors is the number of errors encountered in Make_Make. */
1889void 1889void
1890Finish(int errors) 1890Finish(int errors)
1891{ 1891{
1892 if (dieQuietly(NULL, -1)) 1892 if (dieQuietly(NULL, -1))
1893 exit(2); 1893 exit(2);
1894 Fatal("%d error%s", errors, errors == 1 ? "" : "s"); 1894 Fatal("%d error%s", errors, errors == 1 ? "" : "s");
1895} 1895}
1896 1896
1897/* 1897/*
1898 * eunlink -- 1898 * eunlink --
1899 * Remove a file carefully, avoiding directories. 1899 * Remove a file carefully, avoiding directories.
1900 */ 1900 */
1901int 1901int
1902eunlink(const char *file) 1902eunlink(const char *file)
1903{ 1903{
1904 struct stat st; 1904 struct stat st;
1905 1905
1906 if (lstat(file, &st) == -1) 1906 if (lstat(file, &st) == -1)
1907 return -1; 1907 return -1;
1908 1908
1909 if (S_ISDIR(st.st_mode)) { 1909 if (S_ISDIR(st.st_mode)) {
1910 errno = EISDIR; 1910 errno = EISDIR;
1911 return -1; 1911 return -1;
1912 } 1912 }
1913 return unlink(file); 1913 return unlink(file);
1914} 1914}
1915 1915
1916static void 1916static void
1917write_all(int fd, const void *data, size_t n) 1917write_all(int fd, const void *data, size_t n)
1918{ 1918{
1919 const char *mem = data; 1919 const char *mem = data;
1920 1920
1921 while (n > 0) { 1921 while (n > 0) {
1922 ssize_t written = write(fd, mem, n); 1922 ssize_t written = write(fd, mem, n);
1923 if (written == -1 && errno == EAGAIN) 1923 if (written == -1 && errno == EAGAIN)
1924 continue; 1924 continue;
1925 if (written == -1) 1925 if (written == -1)
1926 break; 1926 break;
1927 mem += written; 1927 mem += written;
1928 n -= (size_t)written; 1928 n -= (size_t)written;
1929 } 1929 }
1930} 1930}
1931 1931
1932/* 1932/*
1933 * execDie -- 1933 * execDie --
1934 * Print why exec failed, avoiding stdio. 1934 * Print why exec failed, avoiding stdio.
1935 */ 1935 */
1936void MAKE_ATTR_DEAD 1936void MAKE_ATTR_DEAD
1937execDie(const char *af, const char *av) 1937execDie(const char *af, const char *av)
1938{ 1938{
1939 Buffer buf; 1939 Buffer buf;
1940 1940
1941 Buf_Init(&buf, 0); 1941 Buf_Init(&buf, 0);
1942 Buf_AddStr(&buf, progname); 1942 Buf_AddStr(&buf, progname);
1943 Buf_AddStr(&buf, ": "); 1943 Buf_AddStr(&buf, ": ");
1944 Buf_AddStr(&buf, af); 1944 Buf_AddStr(&buf, af);
1945 Buf_AddStr(&buf, "("); 1945 Buf_AddStr(&buf, "(");
1946 Buf_AddStr(&buf, av); 1946 Buf_AddStr(&buf, av);
1947 Buf_AddStr(&buf, ") failed ("); 1947 Buf_AddStr(&buf, ") failed (");
1948 Buf_AddStr(&buf, strerror(errno)); 1948 Buf_AddStr(&buf, strerror(errno));
1949 Buf_AddStr(&buf, ")\n"); 1949 Buf_AddStr(&buf, ")\n");
1950 1950
1951 write_all(STDERR_FILENO, Buf_GetAll(&buf, NULL), Buf_Len(&buf)); 1951 write_all(STDERR_FILENO, Buf_GetAll(&buf, NULL), Buf_Len(&buf));
1952 1952
1953 Buf_Destroy(&buf, TRUE); 1953 Buf_Destroy(&buf, TRUE);
1954 _exit(1); 1954 _exit(1);
1955} 1955}
1956 1956
1957/* 1957/*
1958 * usage -- 1958 * usage --
1959 * exit with usage message 1959 * exit with usage message
1960 */ 1960 */
1961static void 1961static void
1962usage(void) 1962usage(void)
1963{ 1963{
1964 char *p; 1964 char *p;
1965 if ((p = strchr(progname, '[')) != NULL) 1965 if ((p = strchr(progname, '[')) != NULL)
1966 *p = '\0'; 1966 *p = '\0';
1967 1967
1968 (void)fprintf(stderr, 1968 (void)fprintf(stderr,
1969"usage: %s [-BeikNnqrstWwX] \n" 1969"usage: %s [-BeikNnqrstWwX] \n"
1970" [-C directory] [-D variable] [-d flags] [-f makefile]\n" 1970" [-C directory] [-D variable] [-d flags] [-f makefile]\n"
1971" [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n" 1971" [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n"
1972" [-V variable] [-v variable] [variable=value] [target ...]\n", 1972" [-V variable] [-v variable] [variable=value] [target ...]\n",
1973 progname); 1973 progname);
1974 exit(2); 1974 exit(2);
1975} 1975}
1976 1976
1977/* 1977/*
1978 * realpath(3) can get expensive, cache results... 1978 * realpath(3) can get expensive, cache results...
1979 */ 1979 */
1980static GNode *cached_realpaths = NULL; 1980static GNode *cached_realpaths = NULL;
1981 1981
1982static GNode * 1982static GNode *
1983get_cached_realpaths(void) 1983get_cached_realpaths(void)
1984{ 1984{
1985 1985
1986 if (!cached_realpaths) { 1986 if (!cached_realpaths) {
1987 cached_realpaths = Targ_NewGN("Realpath"); 1987 cached_realpaths = Targ_NewGN("Realpath");
1988#ifndef DEBUG_REALPATH_CACHE 1988#ifndef DEBUG_REALPATH_CACHE
1989 cached_realpaths->flags = INTERNAL; 1989 cached_realpaths->flags = INTERNAL;
1990#endif 1990#endif
1991 } 1991 }
1992 1992
1993 return cached_realpaths; 1993 return cached_realpaths;
1994} 1994}
1995 1995
1996/* purge any relative paths */ 1996/* purge any relative paths */
1997static void 1997static void
1998purge_cached_realpaths(void) 1998purge_cached_realpaths(void)
1999{ 1999{
2000 GNode *cache = get_cached_realpaths(); 2000 GNode *cache = get_cached_realpaths();
2001 HashEntry *he, *nhe; 2001 HashEntry *he, *nhe;
2002 HashIter hi; 2002 HashIter hi;
2003 2003
2004 HashIter_Init(&hi, &cache->context); 2004 HashIter_Init(&hi, &cache->context);
2005 he = HashIter_Next(&hi); 2005 he = HashIter_Next(&hi);
2006 while (he != NULL) { 2006 while (he != NULL) {
2007 nhe = HashIter_Next(&hi); 2007 nhe = HashIter_Next(&hi);
2008 if (he->key[0] != '/') { 2008 if (he->key[0] != '/') {
2009 if (DEBUG(DIR)) 2009 if (DEBUG(DIR))
2010 fprintf(stderr, "cached_realpath: purging %s\n", he->key); 2010 fprintf(stderr, "cached_realpath: purging %s\n", he->key);
2011 HashTable_DeleteEntry(&cache->context, he); 2011 HashTable_DeleteEntry(&cache->context, he);
2012 } 2012 }
2013 he = nhe; 2013 he = nhe;
2014 } 2014 }
2015} 2015}
2016 2016
2017char * 2017char *
2018cached_realpath(const char *pathname, char *resolved) 2018cached_realpath(const char *pathname, char *resolved)
2019{ 2019{
2020 GNode *cache; 2020 GNode *cache;
2021 const char *rp; 2021 const char *rp;
2022 void *freeIt; 2022 void *freeIt;
2023 2023
2024 if (!pathname || !pathname[0]) 2024 if (!pathname || !pathname[0])
2025 return NULL; 2025 return NULL;
2026 2026
2027 cache = get_cached_realpaths(); 2027 cache = get_cached_realpaths();
2028 2028
2029 if ((rp = Var_Value(pathname, cache, &freeIt)) != NULL) { 2029 if ((rp = Var_Value(pathname, cache, &freeIt)) != NULL) {
2030 /* a hit */ 2030 /* a hit */
2031 strncpy(resolved, rp, MAXPATHLEN); 2031 strncpy(resolved, rp, MAXPATHLEN);
2032 resolved[MAXPATHLEN - 1] = '\0'; 2032 resolved[MAXPATHLEN - 1] = '\0';
2033 } else if ((rp = realpath(pathname, resolved)) != NULL) { 2033 } else if ((rp = realpath(pathname, resolved)) != NULL) {
2034 Var_Set(pathname, rp, cache); 2034 Var_Set(pathname, rp, cache);
2035 } /* else should we negative-cache? */ 2035 } /* else should we negative-cache? */
2036 2036
2037 bmake_free(freeIt); 2037 bmake_free(freeIt);
2038 return rp ? resolved : NULL; 2038 return rp ? resolved : NULL;
2039} 2039}
2040 2040
2041/* 2041/*
2042 * Return true if we should die without noise. 2042 * Return true if we should die without noise.
2043 * For example our failing child was a sub-make 2043 * For example our failing child was a sub-make
2044 * or failure happend elsewhere. 2044 * or failure happend elsewhere.
2045 */ 2045 */
2046int 2046int
2047dieQuietly(GNode *gn, int bf) 2047dieQuietly(GNode *gn, int bf)
2048{ 2048{
2049 static int quietly = -1; 2049 static int quietly = -1;
2050 2050
2051 if (quietly < 0) { 2051 if (quietly < 0) {
2052 if (DEBUG(JOB) || !getBoolean(".MAKE.DIE_QUIETLY", TRUE)) 2052 if (DEBUG(JOB) || !getBoolean(".MAKE.DIE_QUIETLY", TRUE))
2053 quietly = 0; 2053 quietly = 0;
2054 else if (bf >= 0) 2054 else if (bf >= 0)
2055 quietly = bf; 2055 quietly = bf;
2056 else 2056 else
2057 quietly = gn != NULL ? ((gn->type & (OP_MAKE)) != 0) : 0; 2057 quietly = gn != NULL ? ((gn->type & (OP_MAKE)) != 0) : 0;
2058 } 2058 }
2059 return quietly; 2059 return quietly;
2060} 2060}
2061 2061
2062static void 2062static void
2063SetErrorVars(GNode *gn) 2063SetErrorVars(GNode *gn)
2064{ 2064{
2065 StringListNode *ln; 2065 StringListNode *ln;
2066 2066
2067 /* 2067 /*
2068 * We can print this even if there is no .ERROR target. 2068 * We can print this even if there is no .ERROR target.
2069 */ 2069 */
2070 Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL); 2070 Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL);
2071 Var_Delete(".ERROR_CMD", VAR_GLOBAL); 2071 Var_Delete(".ERROR_CMD", VAR_GLOBAL);
2072 2072
2073 for (ln = gn->commands->first; ln != NULL; ln = ln->next) { 2073 for (ln = gn->commands->first; ln != NULL; ln = ln->next) {
2074 const char *cmd = ln->datum; 2074 const char *cmd = ln->datum;
2075 2075
2076 if (cmd == NULL) 2076 if (cmd == NULL)
2077 break; 2077 break;
2078 Var_Append(".ERROR_CMD", cmd, VAR_GLOBAL); 2078 Var_Append(".ERROR_CMD", cmd, VAR_GLOBAL);
2079 } 2079 }
2080} 2080}
2081 2081
2082void 2082void
2083PrintOnError(GNode *gn, const char *s) 2083PrintOnError(GNode *gn, const char *s)
2084{ 2084{
2085 static GNode *en = NULL; 2085 static GNode *en = NULL;
2086 const char *expr; 2086 const char *expr;
2087 char *cp; 2087 char *cp;
2088 2088
2089 if (DEBUG(HASH)) { 2089 if (DEBUG(HASH)) {
2090 Targ_Stats(); 2090 Targ_Stats();
2091 Var_Stats(); 2091 Var_Stats();
2092 } 2092 }
2093 2093
2094 /* we generally want to keep quiet if a sub-make died */ 2094 /* we generally want to keep quiet if a sub-make died */
2095 if (dieQuietly(gn, -1)) 2095 if (dieQuietly(gn, -1))
2096 return; 2096 return;
2097 2097
2098 if (s) 2098 if (s)
2099 printf("%s", s); 2099 printf("%s", s);
2100 2100
2101 printf("\n%s: stopped in %s\n", progname, curdir); 2101 printf("\n%s: stopped in %s\n", progname, curdir);
2102 2102
2103 if (en) 2103 if (en)
2104 return; /* we've been here! */ 2104 return; /* we've been here! */
2105 if (gn) 2105 if (gn)
2106 SetErrorVars(gn); 2106 SetErrorVars(gn);
2107 expr = "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}"; 2107 expr = "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}";
2108 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp); 2108 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp);
2109 /* TODO: handle errors */ 2109 /* TODO: handle errors */
2110 printf("%s", cp); 2110 printf("%s", cp);
2111 free(cp); 2111 free(cp);
2112 fflush(stdout); 2112 fflush(stdout);
2113 2113
2114 /* 2114 /*
2115 * Finally, see if there is a .ERROR target, and run it if so. 2115 * Finally, see if there is a .ERROR target, and run it if so.
2116 */ 2116 */
2117 en = Targ_FindNode(".ERROR"); 2117 en = Targ_FindNode(".ERROR");
2118 if (en) { 2118 if (en) {
2119 en->type |= OP_SPECIAL; 2119 en->type |= OP_SPECIAL;
2120 Compat_Make(en, en); 2120 Compat_Make(en, en);
2121 } 2121 }
2122} 2122}
2123 2123
2124void 2124void
2125Main_ExportMAKEFLAGS(Boolean first) 2125Main_ExportMAKEFLAGS(Boolean first)
2126{ 2126{
2127 static Boolean once = TRUE; 2127 static Boolean once = TRUE;
2128 const char *expr; 2128 const char *expr;
2129 char *s; 2129 char *s;
2130 2130
2131 if (once != first) 2131 if (once != first)
2132 return; 2132 return;
2133 once = FALSE; 2133 once = FALSE;
2134 2134
2135 expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}"; 2135 expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}";
2136 (void)Var_Subst(expr, VAR_CMDLINE, VARE_WANTRES, &s); 2136 (void)Var_Subst(expr, VAR_CMDLINE, VARE_WANTRES, &s);
2137 /* TODO: handle errors */ 2137 /* TODO: handle errors */
2138 if (s[0] != '\0') { 2138 if (s[0] != '\0') {
2139#ifdef POSIX 2139#ifdef POSIX
2140 setenv("MAKEFLAGS", s, 1); 2140 setenv("MAKEFLAGS", s, 1);
2141#else 2141#else
2142 setenv("MAKE", s, 1); 2142 setenv("MAKE", s, 1);
2143#endif 2143#endif
2144 } 2144 }
2145} 2145}
2146 2146
2147char * 2147char *
2148getTmpdir(void) 2148getTmpdir(void)
2149{ 2149{
2150 static char *tmpdir = NULL; 2150 static char *tmpdir = NULL;
2151 2151
2152 if (!tmpdir) { 2152 if (!tmpdir) {
2153 struct stat st; 2153 struct stat st;
2154 2154
2155 /* 2155 /*
2156 * Honor $TMPDIR but only if it is valid. 2156 * Honor $TMPDIR but only if it is valid.
2157 * Ensure it ends with /. 2157 * Ensure it ends with /.
2158 */ 2158 */
2159 (void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, 2159 (void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL,
2160 VARE_WANTRES, &tmpdir); 2160 VARE_WANTRES, &tmpdir);
2161 /* TODO: handle errors */ 2161 /* TODO: handle errors */
2162 if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 2162 if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) {
2163 free(tmpdir); 2163 free(tmpdir);
2164 tmpdir = bmake_strdup(_PATH_TMP); 2164 tmpdir = bmake_strdup(_PATH_TMP);
2165 } 2165 }
2166 } 2166 }
2167 return tmpdir; 2167 return tmpdir;
2168} 2168}
2169 2169
2170/* 2170/*
2171 * Create and open a temp file using "pattern". 2171 * Create and open a temp file using "pattern".
2172 * If out_fname is provided, set it to a copy of the filename created. 2172 * If out_fname is provided, set it to a copy of the filename created.
2173 * Otherwise unlink the file once open. 2173 * Otherwise unlink the file once open.
2174 */ 2174 */
2175int 2175int
2176mkTempFile(const char *pattern, char **out_fname) 2176mkTempFile(const char *pattern, char **out_fname)
2177{ 2177{
2178 static char *tmpdir = NULL; 2178 static char *tmpdir = NULL;
2179 char tfile[MAXPATHLEN]; 2179 char tfile[MAXPATHLEN];
2180 int fd; 2180 int fd;
2181 2181
2182 if (pattern != NULL) 2182 if (pattern != NULL)
2183 pattern = TMPPAT; 2183 pattern = TMPPAT;
2184 if (tmpdir == NULL) 2184 if (tmpdir == NULL)
2185 tmpdir = getTmpdir(); 2185 tmpdir = getTmpdir();
2186 if (pattern[0] == '/') { 2186 if (pattern[0] == '/') {
2187 snprintf(tfile, sizeof(tfile), "%s", pattern); 2187 snprintf(tfile, sizeof(tfile), "%s", pattern);
2188 } else { 2188 } else {
2189 snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern); 2189 snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern);
2190 } 2190 }
2191 if ((fd = mkstemp(tfile)) < 0) 2191 if ((fd = mkstemp(tfile)) < 0)
2192 Punt("Could not create temporary file %s: %s", tfile, strerror(errno)); 2192 Punt("Could not create temporary file %s: %s", tfile, strerror(errno));
2193 if (out_fname) { 2193 if (out_fname) {
2194 *out_fname = bmake_strdup(tfile); 2194 *out_fname = bmake_strdup(tfile);
2195 } else { 2195 } else {
2196 unlink(tfile); /* we just want the descriptor */ 2196 unlink(tfile); /* we just want the descriptor */
2197 } 2197 }
2198 return fd; 2198 return fd;
2199} 2199}
2200 2200
2201/* 2201/*
2202 * Convert a string representation of a boolean. 2202 * Convert a string representation of a boolean.
2203 * Anything that looks like "No", "False", "Off", "0" etc, 2203 * Anything that looks like "No", "False", "Off", "0" etc,
2204 * is FALSE, otherwise TRUE. 2204 * is FALSE, otherwise TRUE.
2205 */ 2205 */
2206Boolean 2206Boolean
2207s2Boolean(const char *s, Boolean bf) 2207s2Boolean(const char *s, Boolean bf)
2208{ 2208{
2209 switch(s[0]) { 2209 switch(s[0]) {
2210 case '\0': /* not set - the default wins */ 2210 case '\0': /* not set - the default wins */
2211 break; 2211 break;
2212 case '0': 2212 case '0':
2213 case 'F': 2213 case 'F':
2214 case 'f': 2214 case 'f':
2215 case 'N': 2215 case 'N':
2216 case 'n': 2216 case 'n':
2217 return FALSE; 2217 return FALSE;
2218 case 'O': 2218 case 'O':
2219 case 'o': 2219 case 'o':
2220 return s[1] != 'F' && s[1] != 'f'; 2220 return s[1] != 'F' && s[1] != 'f';
2221 default: 2221 default:
2222 return TRUE; 2222 return TRUE;
2223 } 2223 }
2224 return bf; 2224 return bf;
2225} 2225}
2226 2226
2227/* 2227/*
2228 * Return a Boolean based on a variable. 2228 * Return a Boolean based on a variable.
2229 * 2229 *
2230 * If the knob is not set, return the fallback. 2230 * If the knob is not set, return the fallback.
2231 * If set, anything that looks or smells like "No", "False", "Off", "0", etc. 2231 * If set, anything that looks or smells like "No", "False", "Off", "0", etc.
2232 * is FALSE, otherwise TRUE. 2232 * is FALSE, otherwise TRUE.
2233 */ 2233 */
2234Boolean 2234Boolean
2235getBoolean(const char *varname, Boolean fallback) 2235getBoolean(const char *varname, Boolean fallback)
2236{ 2236{
2237 char *expr = str_concat3("${", varname, ":U}"); 2237 char *expr = str_concat3("${", varname, ":U}");
2238 char *value; 2238 char *value;
2239 Boolean res; 2239 Boolean res;
2240 2240
2241 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &value); 2241 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &value);
2242 /* TODO: handle errors */ 2242 /* TODO: handle errors */
2243 res = s2Boolean(value, fallback); 2243 res = s2Boolean(value, fallback);
2244 free(value); 2244 free(value);
2245 free(expr); 2245 free(expr);
2246 return res; 2246 return res;
2247} 2247}

cvs diff -r1.614 -r1.615 src/usr.bin/make/var.c (switch to unified diff)

--- src/usr.bin/make/var.c 2020/10/31 09:57:47 1.614
+++ src/usr.bin/make/var.c 2020/10/31 11:34:30 1.615
@@ -1,1131 +1,1131 @@ @@ -1,1131 +1,1131 @@
1/* $NetBSD: var.c,v 1.614 2020/10/31 09:57:47 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.615 2020/10/31 11:34:30 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1989, 1990, 1993 4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor. 8 * Adam de Boor.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35/* 35/*
36 * Copyright (c) 1989 by Berkeley Softworks 36 * Copyright (c) 1989 by Berkeley Softworks
37 * All rights reserved. 37 * All rights reserved.
38 * 38 *
39 * This code is derived from software contributed to Berkeley by 39 * This code is derived from software contributed to Berkeley by
40 * Adam de Boor. 40 * Adam de Boor.
41 * 41 *
42 * Redistribution and use in source and binary forms, with or without 42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions 43 * modification, are permitted provided that the following conditions
44 * are met: 44 * are met:
45 * 1. Redistributions of source code must retain the above copyright 45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer. 46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright 47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the 48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution. 49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software 50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement: 51 * must display the following acknowledgement:
52 * This product includes software developed by the University of 52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors. 53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors 54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software 55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission. 56 * without specific prior written permission.
57 * 57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE. 68 * SUCH DAMAGE.
69 */ 69 */
70 70
71/* 71/*
72 * Handling of variables and the expressions formed from them. 72 * Handling of variables and the expressions formed from them.
73 * 73 *
74 * Variables are set using lines of the form VAR=value. Both the variable 74 * Variables are set using lines of the form VAR=value. Both the variable
75 * name and the value can contain references to other variables, by using 75 * name and the value can contain references to other variables, by using
76 * expressions like ${VAR}, ${VAR:Modifiers}, ${${VARNAME}} or ${VAR:${MODS}}. 76 * expressions like ${VAR}, ${VAR:Modifiers}, ${${VARNAME}} or ${VAR:${MODS}}.
77 * 77 *
78 * Interface: 78 * Interface:
79 * Var_Init Initialize this module. 79 * Var_Init Initialize this module.
80 * 80 *
81 * Var_End Clean up the module. 81 * Var_End Clean up the module.
82 * 82 *
83 * Var_Set Set the value of the variable, creating it if 83 * Var_Set Set the value of the variable, creating it if
84 * necessary. 84 * necessary.
85 * 85 *
86 * Var_Append Append more characters to the variable, creating it if 86 * Var_Append Append more characters to the variable, creating it if
87 * necessary. A space is placed between the old value and 87 * necessary. A space is placed between the old value and
88 * the new one. 88 * the new one.
89 * 89 *
90 * Var_Exists See if a variable exists. 90 * Var_Exists See if a variable exists.
91 * 91 *
92 * Var_Value Return the unexpanded value of a variable, or NULL if 92 * Var_Value Return the unexpanded value of a variable, or NULL if
93 * the variable is undefined. 93 * the variable is undefined.
94 * 94 *
95 * Var_Subst Substitute all variable expressions in a string. 95 * Var_Subst Substitute all variable expressions in a string.
96 * 96 *
97 * Var_Parse Parse a variable expression such as ${VAR:Mpattern}. 97 * Var_Parse Parse a variable expression such as ${VAR:Mpattern}.
98 * 98 *
99 * Var_Delete Delete a variable. 99 * Var_Delete Delete a variable.
100 * 100 *
101 * Var_ExportVars Export some or even all variables to the environment 101 * Var_ExportVars Export some or even all variables to the environment
102 * of this process and its child processes. 102 * of this process and its child processes.
103 * 103 *
104 * Var_Export Export the variable to the environment of this process 104 * Var_Export Export the variable to the environment of this process
105 * and its child processes. 105 * and its child processes.
106 * 106 *
107 * Var_UnExport Don't export the variable anymore. 107 * Var_UnExport Don't export the variable anymore.
108 * 108 *
109 * Debugging: 109 * Debugging:
110 * Var_Stats Print out hashing statistics if in -dh mode. 110 * Var_Stats Print out hashing statistics if in -dh mode.
111 * 111 *
112 * Var_Dump Print out all variables defined in the given context. 112 * Var_Dump Print out all variables defined in the given context.
113 * 113 *
114 * XXX: There's a lot of duplication in these functions. 114 * XXX: There's a lot of duplication in these functions.
115 */ 115 */
116 116
117#include <sys/stat.h> 117#include <sys/stat.h>
118#ifndef NO_REGEX 118#ifndef NO_REGEX
119#include <sys/types.h> 119#include <sys/types.h>
120#include <regex.h> 120#include <regex.h>
121#endif 121#endif
122#include <inttypes.h> 122#include <inttypes.h>
123#include <limits.h> 123#include <limits.h>
124#include <time.h> 124#include <time.h>
125 125
126#include "make.h" 126#include "make.h"
127#include "dir.h" 127#include "dir.h"
128#include "job.h" 128#include "job.h"
129#include "metachar.h" 129#include "metachar.h"
130 130
131/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ 131/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
132MAKE_RCSID("$NetBSD: var.c,v 1.614 2020/10/31 09:57:47 rillig Exp $"); 132MAKE_RCSID("$NetBSD: var.c,v 1.615 2020/10/31 11:34:30 rillig Exp $");
133 133
134#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) 134#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1)
135#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) 135#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2)
136#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) 136#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3)
137#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) 137#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4)
138 138
139ENUM_FLAGS_RTTI_3(VarEvalFlags, 139ENUM_FLAGS_RTTI_3(VarEvalFlags,
140 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); 140 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN);
141 141
142/* 142/*
143 * This lets us tell if we have replaced the original environ 143 * This lets us tell if we have replaced the original environ
144 * (which we cannot free). 144 * (which we cannot free).
145 */ 145 */
146char **savedEnv = NULL; 146char **savedEnv = NULL;
147 147
148/* Special return value for Var_Parse, indicating a parse error. It may be 148/* Special return value for Var_Parse, indicating a parse error. It may be
149 * caused by an undefined variable, a syntax error in a modifier or 149 * caused by an undefined variable, a syntax error in a modifier or
150 * something entirely different. */ 150 * something entirely different. */
151char var_Error[] = ""; 151char var_Error[] = "";
152 152
153/* Special return value for Var_Parse, indicating an undefined variable in 153/* Special return value for Var_Parse, indicating an undefined variable in
154 * a case where VARE_UNDEFERR is not set. This undefined variable is 154 * a case where VARE_UNDEFERR is not set. This undefined variable is
155 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to 155 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to
156 * be deferred until it is defined in an actual target. */ 156 * be deferred until it is defined in an actual target. */
157static char varUndefined[] = ""; 157static char varUndefined[] = "";
158 158
159/* Special return value for Var_Parse, just to avoid allocating empty strings. 159/* Special return value for Var_Parse, just to avoid allocating empty strings.
160 * In contrast to var_Error and varUndefined, this is not an error marker but 160 * In contrast to var_Error and varUndefined, this is not an error marker but
161 * just an ordinary successful return value. */ 161 * just an ordinary successful return value. */
162static char emptyString[] = ""; 162static char emptyString[] = "";
163 163
164/* 164/*
165 * Traditionally this make consumed $$ during := like any other expansion. 165 * Traditionally this make consumed $$ during := like any other expansion.
166 * Other make's do not, and this make follows straight since 2016-01-09. 166 * Other make's do not, and this make follows straight since 2016-01-09.
167 * 167 *
168 * This knob allows controlling the behavior. 168 * This knob allows controlling the behavior.
169 * FALSE to consume $$ during := assignment. 169 * FALSE to consume $$ during := assignment.
170 * TRUE to preserve $$ during := assignment. 170 * TRUE to preserve $$ during := assignment.
171 */ 171 */
172#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" 172#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
173static Boolean save_dollars = TRUE; 173static Boolean save_dollars = TRUE;
174 174
175/* 175/*
176 * Internally, variables are contained in four different contexts. 176 * Internally, variables are contained in four different contexts.
177 * 1) the environment. They cannot be changed. If an environment 177 * 1) the environment. They cannot be changed. If an environment
178 * variable is appended to, the result is placed in the global 178 * variable is appended to, the result is placed in the global
179 * context. 179 * context.
180 * 2) the global context. Variables set in the makefiles are located 180 * 2) the global context. Variables set in the makefiles are located
181 * here. 181 * here.
182 * 3) the command-line context. All variables set on the command line 182 * 3) the command-line context. All variables set on the command line
183 * are placed in this context. 183 * are placed in this context.
184 * 4) the local context. Each target has associated with it a context 184 * 4) the local context. Each target has associated with it a context
185 * list. On this list are located the structures describing such 185 * list. On this list are located the structures describing such
186 * local variables as $(@) and $(*) 186 * local variables as $(@) and $(*)
187 * The four contexts are searched in the reverse order from which they are 187 * The four contexts are searched in the reverse order from which they are
188 * listed (but see opts.checkEnvFirst). 188 * listed (but see opts.checkEnvFirst).
189 */ 189 */
190GNode *VAR_INTERNAL; /* variables from make itself */ 190GNode *VAR_INTERNAL; /* variables from make itself */
191GNode *VAR_GLOBAL; /* variables from the makefile */ 191GNode *VAR_GLOBAL; /* variables from the makefile */
192GNode *VAR_CMDLINE; /* variables defined on the command-line */ 192GNode *VAR_CMDLINE; /* variables defined on the command-line */
193 193
194typedef enum VarFlags { 194typedef enum VarFlags {
195 195
196 /* The variable's value is currently being used by Var_Parse or Var_Subst. 196 /* The variable's value is currently being used by Var_Parse or Var_Subst.
197 * This marker is used to avoid endless recursion. */ 197 * This marker is used to avoid endless recursion. */
198 VAR_IN_USE = 0x01, 198 VAR_IN_USE = 0x01,
199 199
200 /* The variable comes from the environment. 200 /* The variable comes from the environment.
201 * These variables are not registered in any GNode, therefore they must 201 * These variables are not registered in any GNode, therefore they must
202 * be freed as soon as they are not used anymore. */ 202 * be freed as soon as they are not used anymore. */
203 VAR_FROM_ENV = 0x02, 203 VAR_FROM_ENV = 0x02,
204 204
205 /* The variable is exported to the environment, to be used by child 205 /* The variable is exported to the environment, to be used by child
206 * processes. */ 206 * processes. */
207 VAR_EXPORTED = 0x10, 207 VAR_EXPORTED = 0x10,
208 208
209 /* At the point where this variable was exported, it contained an 209 /* At the point where this variable was exported, it contained an
210 * unresolved reference to another variable. Before any child process is 210 * unresolved reference to another variable. Before any child process is
211 * started, it needs to be exported again, in the hope that the referenced 211 * started, it needs to be exported again, in the hope that the referenced
212 * variable can then be resolved. */ 212 * variable can then be resolved. */
213 VAR_REEXPORT = 0x20, 213 VAR_REEXPORT = 0x20,
214 214
215 /* The variable came from the command line. */ 215 /* The variable came from the command line. */
216 VAR_FROM_CMD = 0x40, 216 VAR_FROM_CMD = 0x40,
217 217
218 /* The variable value cannot be changed anymore, and the variable cannot 218 /* The variable value cannot be changed anymore, and the variable cannot
219 * be deleted. Any attempts to do so are ignored. */ 219 * be deleted. Any attempts to do so are ignored. */
220 VAR_READONLY = 0x80 220 VAR_READONLY = 0x80
221} VarFlags; 221} VarFlags;
222 222
223ENUM_FLAGS_RTTI_6(VarFlags, 223ENUM_FLAGS_RTTI_6(VarFlags,
224 VAR_IN_USE, VAR_FROM_ENV, 224 VAR_IN_USE, VAR_FROM_ENV,
225 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY); 225 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY);
226 226
227/* Variables are defined using one of the VAR=value assignments. Their 227/* Variables are defined using one of the VAR=value assignments. Their
228 * value can be queried by expressions such as $V, ${VAR}, or with modifiers 228 * value can be queried by expressions such as $V, ${VAR}, or with modifiers
229 * such as ${VAR:S,from,to,g:Q}. 229 * such as ${VAR:S,from,to,g:Q}.
230 * 230 *
231 * There are 3 kinds of variables: context variables, environment variables, 231 * There are 3 kinds of variables: context variables, environment variables,
232 * undefined variables. 232 * undefined variables.
233 * 233 *
234 * Context variables are stored in a GNode.context. The only way to undefine 234 * Context variables are stored in a GNode.context. The only way to undefine
235 * a context variable is using the .undef directive. In particular, it must 235 * a context variable is using the .undef directive. In particular, it must
236 * not be possible to undefine a variable during the evaluation of an 236 * not be possible to undefine a variable during the evaluation of an
237 * expression, or Var.name might point nowhere. 237 * expression, or Var.name might point nowhere.
238 * 238 *
239 * Environment variables are temporary. They are returned by VarFind, and 239 * Environment variables are temporary. They are returned by VarFind, and
240 * after using them, they must be freed using VarFreeEnv. 240 * after using them, they must be freed using VarFreeEnv.
241 * 241 *
242 * Undefined variables occur during evaluation of variable expressions such 242 * Undefined variables occur during evaluation of variable expressions such
243 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers. 243 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers.
244 */ 244 */
245typedef struct Var { 245typedef struct Var {
246 /* The name of the variable, once set, doesn't change anymore. 246 /* The name of the variable, once set, doesn't change anymore.
247 * For context variables, it aliases the corresponding HashEntry name. 247 * For context variables, it aliases the corresponding HashEntry name.
248 * For environment and undefined variables, it is allocated. */ 248 * For environment and undefined variables, it is allocated. */
249 const char *name; 249 const char *name;
250 void *name_freeIt; 250 void *name_freeIt;
251 251
252 Buffer val; /* its value */ 252 Buffer val; /* its value */
253 VarFlags flags; /* miscellaneous status flags */ 253 VarFlags flags; /* miscellaneous status flags */
254} Var; 254} Var;
255 255
256/* 256/*
257 * Exporting vars is expensive so skip it if we can 257 * Exporting vars is expensive so skip it if we can
258 */ 258 */
259typedef enum VarExportedMode { 259typedef enum VarExportedMode {
260 VAR_EXPORTED_NONE, 260 VAR_EXPORTED_NONE,
261 VAR_EXPORTED_SOME, 261 VAR_EXPORTED_SOME,
262 VAR_EXPORTED_ALL 262 VAR_EXPORTED_ALL
263} VarExportedMode; 263} VarExportedMode;
264 264
265static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE; 265static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
266 266
267typedef enum VarExportFlags { 267typedef enum VarExportFlags {
268 /* 268 /*
269 * We pass this to Var_Export when doing the initial export 269 * We pass this to Var_Export when doing the initial export
270 * or after updating an exported var. 270 * or after updating an exported var.
271 */ 271 */
272 VAR_EXPORT_PARENT = 0x01, 272 VAR_EXPORT_PARENT = 0x01,
273 /* 273 /*
274 * We pass this to Var_Export1 to tell it to leave the value alone. 274 * We pass this to Var_Export1 to tell it to leave the value alone.
275 */ 275 */
276 VAR_EXPORT_LITERAL = 0x02 276 VAR_EXPORT_LITERAL = 0x02
277} VarExportFlags; 277} VarExportFlags;
278 278
279/* Flags for pattern matching in the :S and :C modifiers */ 279/* Flags for pattern matching in the :S and :C modifiers */
280typedef enum VarPatternFlags { 280typedef enum VarPatternFlags {
281 VARP_SUB_GLOBAL = 0x01, /* Replace as often as possible ('g') */ 281 VARP_SUB_GLOBAL = 0x01, /* Replace as often as possible ('g') */
282 VARP_SUB_ONE = 0x02, /* Replace only once ('1') */ 282 VARP_SUB_ONE = 0x02, /* Replace only once ('1') */
283 VARP_ANCHOR_START = 0x04, /* Match at start of word ('^') */ 283 VARP_ANCHOR_START = 0x04, /* Match at start of word ('^') */
284 VARP_ANCHOR_END = 0x08 /* Match at end of word ('$') */ 284 VARP_ANCHOR_END = 0x08 /* Match at end of word ('$') */
285} VarPatternFlags; 285} VarPatternFlags;
286 286
287static Var * 287static Var *
288VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags) 288VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags)
289{ 289{
290 size_t value_len = strlen(value); 290 size_t value_len = strlen(value);
291 Var *var = bmake_malloc(sizeof *var); 291 Var *var = bmake_malloc(sizeof *var);
292 var->name = name; 292 var->name = name;
293 var->name_freeIt = name_freeIt; 293 var->name_freeIt = name_freeIt;
294 Buf_Init(&var->val, value_len + 1); 294 Buf_Init(&var->val, value_len + 1);
295 Buf_AddBytes(&var->val, value, value_len); 295 Buf_AddBytes(&var->val, value, value_len);
296 var->flags = flags; 296 var->flags = flags;
297 return var; 297 return var;
298} 298}
299 299
300static const char * 300static const char *
301CanonicalVarname(const char *name) 301CanonicalVarname(const char *name)
302{ 302{
303 if (*name == '.' && ch_isupper(name[1])) { 303 if (*name == '.' && ch_isupper(name[1])) {
304 switch (name[1]) { 304 switch (name[1]) {
305 case 'A': 305 case 'A':
306 if (strcmp(name, ".ALLSRC") == 0) 306 if (strcmp(name, ".ALLSRC") == 0)
307 name = ALLSRC; 307 name = ALLSRC;
308 if (strcmp(name, ".ARCHIVE") == 0) 308 if (strcmp(name, ".ARCHIVE") == 0)
309 name = ARCHIVE; 309 name = ARCHIVE;
310 break; 310 break;
311 case 'I': 311 case 'I':
312 if (strcmp(name, ".IMPSRC") == 0) 312 if (strcmp(name, ".IMPSRC") == 0)
313 name = IMPSRC; 313 name = IMPSRC;
314 break; 314 break;
315 case 'M': 315 case 'M':
316 if (strcmp(name, ".MEMBER") == 0) 316 if (strcmp(name, ".MEMBER") == 0)
317 name = MEMBER; 317 name = MEMBER;
318 break; 318 break;
319 case 'O': 319 case 'O':
320 if (strcmp(name, ".OODATE") == 0) 320 if (strcmp(name, ".OODATE") == 0)
321 name = OODATE; 321 name = OODATE;
322 break; 322 break;
323 case 'P': 323 case 'P':
324 if (strcmp(name, ".PREFIX") == 0) 324 if (strcmp(name, ".PREFIX") == 0)
325 name = PREFIX; 325 name = PREFIX;
326 break; 326 break;
327 case 'S': 327 case 'S':
328 if (strcmp(name, ".SHELL") == 0) { 328 if (strcmp(name, ".SHELL") == 0) {
329 if (!shellPath) 329 if (!shellPath)
330 Shell_Init(); 330 Shell_Init();
331 } 331 }
332 break; 332 break;
333 case 'T': 333 case 'T':
334 if (strcmp(name, ".TARGET") == 0) 334 if (strcmp(name, ".TARGET") == 0)
335 name = TARGET; 335 name = TARGET;
336 break; 336 break;
337 } 337 }
338 } 338 }
339 339
340 /* GNU make has an additional alias $^ == ${.ALLSRC}. */ 340 /* GNU make has an additional alias $^ == ${.ALLSRC}. */
341 341
342 return name; 342 return name;
343} 343}
344 344
345static Var * 345static Var *
346GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash) 346GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash)
347{ 347{
348 return HashTable_FindValueHash(&ctxt->context, varname, hash); 348 return HashTable_FindValueHash(&ctxt->context, varname, hash);
349} 349}
350 350
351/* Find the variable in the context, and maybe in other contexts as well. 351/* Find the variable in the context, and maybe in other contexts as well.
352 * 352 *
353 * Input: 353 * Input:
354 * name name to find, is not expanded any further 354 * name name to find, is not expanded any further
355 * ctxt context in which to look first 355 * ctxt context in which to look first
356 * elsewhere TRUE to look in other contexts as well 356 * elsewhere TRUE to look in other contexts as well
357 * 357 *
358 * Results: 358 * Results:
359 * The found variable, or NULL if the variable does not exist. 359 * The found variable, or NULL if the variable does not exist.
360 * If the variable is an environment variable, it must be freed using 360 * If the variable is an environment variable, it must be freed using
361 * VarFreeEnv after use. 361 * VarFreeEnv after use.
362 */ 362 */
363static Var * 363static Var *
364VarFind(const char *name, GNode *ctxt, Boolean elsewhere) 364VarFind(const char *name, GNode *ctxt, Boolean elsewhere)
365{ 365{
366 Var *var; 366 Var *var;
367 unsigned int nameHash; 367 unsigned int nameHash;
368 368
369 /* 369 /*
370 * If the variable name begins with a '.', it could very well be one of 370 * If the variable name begins with a '.', it could very well be one of
371 * the local ones. We check the name against all the local variables 371 * the local ones. We check the name against all the local variables
372 * and substitute the short version in for 'name' if it matches one of 372 * and substitute the short version in for 'name' if it matches one of
373 * them. 373 * them.
374 */ 374 */
375 name = CanonicalVarname(name); 375 name = CanonicalVarname(name);
376 nameHash = Hash_Hash(name); 376 nameHash = Hash_Hash(name);
377 377
378 /* First look for the variable in the given context. */ 378 /* First look for the variable in the given context. */
379 var = GNode_FindVar(ctxt, name, nameHash); 379 var = GNode_FindVar(ctxt, name, nameHash);
380 if (!elsewhere) 380 if (!elsewhere)
381 return var; 381 return var;
382 382
383 /* The variable was not found in the given context. Now look for it in 383 /* The variable was not found in the given context. Now look for it in
384 * the other contexts as well. */ 384 * the other contexts as well. */
385 if (var == NULL && ctxt != VAR_CMDLINE) 385 if (var == NULL && ctxt != VAR_CMDLINE)
386 var = GNode_FindVar(VAR_CMDLINE, name, nameHash); 386 var = GNode_FindVar(VAR_CMDLINE, name, nameHash);
387 387
388 if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) { 388 if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) {
389 var = GNode_FindVar(VAR_GLOBAL, name, nameHash); 389 var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
390 if (var == NULL && ctxt != VAR_INTERNAL) { 390 if (var == NULL && ctxt != VAR_INTERNAL) {
391 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ 391 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
392 var = GNode_FindVar(VAR_INTERNAL, name, nameHash); 392 var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
393 } 393 }
394 } 394 }
395 395
396 if (var == NULL) { 396 if (var == NULL) {
397 char *env; 397 char *env;
398 398
399 if ((env = getenv(name)) != NULL) { 399 if ((env = getenv(name)) != NULL) {
400 char *varname = bmake_strdup(name); 400 char *varname = bmake_strdup(name);
401 return VarNew(varname, varname, env, VAR_FROM_ENV); 401 return VarNew(varname, varname, env, VAR_FROM_ENV);
402 } 402 }
403 403
404 if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) { 404 if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) {
405 var = GNode_FindVar(VAR_GLOBAL, name, nameHash); 405 var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
406 if (var == NULL && ctxt != VAR_INTERNAL) 406 if (var == NULL && ctxt != VAR_INTERNAL)
407 var = GNode_FindVar(VAR_INTERNAL, name, nameHash); 407 var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
408 return var; 408 return var;
409 } 409 }
410 410
411 return NULL; 411 return NULL;
412 } 412 }
413 413
414 return var; 414 return var;
415} 415}
416 416
417/* If the variable is an environment variable, free it. 417/* If the variable is an environment variable, free it.
418 * 418 *
419 * Input: 419 * Input:
420 * v the variable 420 * v the variable
421 * freeValue true if the variable value should be freed as well 421 * freeValue true if the variable value should be freed as well
422 * 422 *
423 * Results: 423 * Results:
424 * TRUE if it is an environment variable, FALSE otherwise. 424 * TRUE if it is an environment variable, FALSE otherwise.
425 */ 425 */
426static Boolean 426static Boolean
427VarFreeEnv(Var *v, Boolean freeValue) 427VarFreeEnv(Var *v, Boolean freeValue)
428{ 428{
429 if (!(v->flags & VAR_FROM_ENV)) 429 if (!(v->flags & VAR_FROM_ENV))
430 return FALSE; 430 return FALSE;
431 431
432 free(v->name_freeIt); 432 free(v->name_freeIt);
433 Buf_Destroy(&v->val, freeValue); 433 Buf_Destroy(&v->val, freeValue);
434 free(v); 434 free(v);
435 return TRUE; 435 return TRUE;
436} 436}
437 437
438/* Add a new variable of the given name and value to the given context. 438/* Add a new variable of the given name and value to the given context.
439 * The name and val arguments are duplicated so they may safely be freed. */ 439 * The name and val arguments are duplicated so they may safely be freed. */
440static void 440static void
441VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags) 441VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags)
442{ 442{
443 HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL); 443 HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL);
444 Var *v = VarNew(he->key /* aliased */, NULL, val, 444 Var *v = VarNew(he->key /* aliased */, NULL, val,
445 flags & VAR_SET_READONLY ? VAR_READONLY : 0); 445 flags & VAR_SET_READONLY ? VAR_READONLY : 0);
446 HashEntry_Set(he, v); 446 HashEntry_Set(he, v);
447 if (!(ctxt->flags & INTERNAL)) { 447 if (!(ctxt->flags & INTERNAL)) {
448 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); 448 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
449 } 449 }
450} 450}
451 451
452/* Remove a variable from a context, freeing all related memory as well. 452/* Remove a variable from a context, freeing all related memory as well.
453 * The variable name is expanded once. */ 453 * The variable name is expanded once. */
454void 454void
455Var_Delete(const char *name, GNode *ctxt) 455Var_Delete(const char *name, GNode *ctxt)
456{ 456{
457 char *name_freeIt = NULL; 457 char *name_freeIt = NULL;
458 HashEntry *he; 458 HashEntry *he;
459 459
460 if (strchr(name, '$') != NULL) { 460 if (strchr(name, '$') != NULL) {
461 (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt); 461 (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt);
462 /* TODO: handle errors */ 462 /* TODO: handle errors */
463 name = name_freeIt; 463 name = name_freeIt;
464 } 464 }
465 he = HashTable_FindEntry(&ctxt->context, name); 465 he = HashTable_FindEntry(&ctxt->context, name);
466 VAR_DEBUG3("%s:delete %s%s\n", 466 VAR_DEBUG3("%s:delete %s%s\n",
467 ctxt->name, name, he != NULL ? "" : " (not found)"); 467 ctxt->name, name, he != NULL ? "" : " (not found)");
468 free(name_freeIt); 468 free(name_freeIt);
469 469
470 if (he != NULL) { 470 if (he != NULL) {
471 Var *v = HashEntry_Get(he); 471 Var *v = HashEntry_Get(he);
472 if (v->flags & VAR_EXPORTED) 472 if (v->flags & VAR_EXPORTED)
473 unsetenv(v->name); 473 unsetenv(v->name);
474 if (strcmp(v->name, MAKE_EXPORTED) == 0) 474 if (strcmp(v->name, MAKE_EXPORTED) == 0)
475 var_exportedVars = VAR_EXPORTED_NONE; 475 var_exportedVars = VAR_EXPORTED_NONE;
476 assert(v->name_freeIt == NULL); 476 assert(v->name_freeIt == NULL);
477 HashTable_DeleteEntry(&ctxt->context, he); 477 HashTable_DeleteEntry(&ctxt->context, he);
478 Buf_Destroy(&v->val, TRUE); 478 Buf_Destroy(&v->val, TRUE);
479 free(v); 479 free(v);
480 } 480 }
481} 481}
482 482
483static Boolean 483static Boolean
484MayExport(const char *name) 484MayExport(const char *name)
485{ 485{
486 if (name[0] == '.') 486 if (name[0] == '.')
487 return FALSE; /* skip internals */ 487 return FALSE; /* skip internals */
488 if (name[0] == '-') 488 if (name[0] == '-')
489 return FALSE; /* skip misnamed variables */ 489 return FALSE; /* skip misnamed variables */
490 if (name[1] == '\0') { 490 if (name[1] == '\0') {
491 /* 491 /*
492 * A single char. 492 * A single char.
493 * If it is one of the vars that should only appear in 493 * If it is one of the vars that should only appear in
494 * local context, skip it, else we can get Var_Subst 494 * local context, skip it, else we can get Var_Subst
495 * into a loop. 495 * into a loop.
496 */ 496 */
497 switch (name[0]) { 497 switch (name[0]) {
498 case '@': 498 case '@':
499 case '%': 499 case '%':
500 case '*': 500 case '*':
501 case '!': 501 case '!':
502 return FALSE; 502 return FALSE;
503 } 503 }
504 } 504 }
505 return TRUE; 505 return TRUE;
506} 506}
507 507
508/* 508/*
509 * Export a single variable. 509 * Export a single variable.
510 * We ignore make internal variables (those which start with '.'). 510 * We ignore make internal variables (those which start with '.').
511 * Also we jump through some hoops to avoid calling setenv 511 * Also we jump through some hoops to avoid calling setenv
512 * more than necessary since it can leak. 512 * more than necessary since it can leak.
513 * We only manipulate flags of vars if 'parent' is set. 513 * We only manipulate flags of vars if 'parent' is set.
514 */ 514 */
515static Boolean 515static Boolean
516Var_Export1(const char *name, VarExportFlags flags) 516Var_Export1(const char *name, VarExportFlags flags)
517{ 517{
518 VarExportFlags parent = flags & VAR_EXPORT_PARENT; 518 VarExportFlags parent = flags & VAR_EXPORT_PARENT;
519 Var *v; 519 Var *v;
520 char *val; 520 char *val;
521 521
522 if (!MayExport(name)) 522 if (!MayExport(name))
523 return FALSE; 523 return FALSE;
524 524
525 v = VarFind(name, VAR_GLOBAL, 0); 525 v = VarFind(name, VAR_GLOBAL, 0);
526 if (v == NULL) 526 if (v == NULL)
527 return FALSE; 527 return FALSE;
528 528
529 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT)) 529 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
530 return FALSE; /* nothing to do */ 530 return FALSE; /* nothing to do */
531 531
532 val = Buf_GetAll(&v->val, NULL); 532 val = Buf_GetAll(&v->val, NULL);
533 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) { 533 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) {
534 char *expr; 534 char *expr;
535 535
536 if (parent) { 536 if (parent) {
537 /* 537 /*
538 * Flag the variable as something we need to re-export. 538 * Flag the variable as something we need to re-export.
539 * No point actually exporting it now though, 539 * No point actually exporting it now though,
540 * the child process can do it at the last minute. 540 * the child process can do it at the last minute.
541 */ 541 */
542 v->flags |= VAR_EXPORTED | VAR_REEXPORT; 542 v->flags |= VAR_EXPORTED | VAR_REEXPORT;
543 return TRUE; 543 return TRUE;
544 } 544 }
545 if (v->flags & VAR_IN_USE) { 545 if (v->flags & VAR_IN_USE) {
546 /* 546 /*
547 * We recursed while exporting in a child. 547 * We recursed while exporting in a child.
548 * This isn't going to end well, just skip it. 548 * This isn't going to end well, just skip it.
549 */ 549 */
550 return FALSE; 550 return FALSE;
551 } 551 }
552 552
553 /* XXX: name is injected without escaping it */ 553 /* XXX: name is injected without escaping it */
554 expr = str_concat3("${", name, "}"); 554 expr = str_concat3("${", name, "}");
555 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val); 555 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val);
556 /* TODO: handle errors */ 556 /* TODO: handle errors */
557 setenv(name, val, 1); 557 setenv(name, val, 1);
558 free(val); 558 free(val);
559 free(expr); 559 free(expr);
560 } else { 560 } else {
561 if (parent) 561 if (parent)
562 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */ 562 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */
563 if (parent || !(v->flags & VAR_EXPORTED)) 563 if (parent || !(v->flags & VAR_EXPORTED))
564 setenv(name, val, 1); 564 setenv(name, val, 1);
565 } 565 }
566 566
567 /* 567 /*
568 * This is so Var_Set knows to call Var_Export again... 568 * This is so Var_Set knows to call Var_Export again...
569 */ 569 */
570 if (parent) { 570 if (parent) {
571 v->flags |= VAR_EXPORTED; 571 v->flags |= VAR_EXPORTED;
572 } 572 }
573 return TRUE; 573 return TRUE;
574} 574}
575 575
576/* 576/*
577 * This gets called from our child processes. 577 * This gets called from our child processes.
578 */ 578 */
579void 579void
580Var_ExportVars(void) 580Var_ExportVars(void)
581{ 581{
582 char *val; 582 char *val;
583 583
584 /* 584 /*
585 * Several make's support this sort of mechanism for tracking 585 * Several make's support this sort of mechanism for tracking
586 * recursion - but each uses a different name. 586 * recursion - but each uses a different name.
587 * We allow the makefiles to update MAKELEVEL and ensure 587 * We allow the makefiles to update MAKELEVEL and ensure
588 * children see a correctly incremented value. 588 * children see a correctly incremented value.
589 */ 589 */
590 char tmp[BUFSIZ]; 590 char tmp[BUFSIZ];
591 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1); 591 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
592 setenv(MAKE_LEVEL_ENV, tmp, 1); 592 setenv(MAKE_LEVEL_ENV, tmp, 1);
593 593
594 if (var_exportedVars == VAR_EXPORTED_NONE) 594 if (var_exportedVars == VAR_EXPORTED_NONE)
595 return; 595 return;
596 596
597 if (var_exportedVars == VAR_EXPORTED_ALL) { 597 if (var_exportedVars == VAR_EXPORTED_ALL) {
598 HashIter hi; 598 HashIter hi;
599 599
600 /* Ouch! Exporting all variables at once is crazy... */ 600 /* Ouch! Exporting all variables at once is crazy... */
601 HashIter_Init(&hi, &VAR_GLOBAL->context); 601 HashIter_Init(&hi, &VAR_GLOBAL->context);
602 while (HashIter_Next(&hi) != NULL) { 602 while (HashIter_Next(&hi) != NULL) {
603 Var *var = hi.entry->value; 603 Var *var = hi.entry->value;
604 Var_Export1(var->name, 0); 604 Var_Export1(var->name, 0);
605 } 605 }
606 return; 606 return;
607 } 607 }
608 608
609 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, &val); 609 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, &val);
610 /* TODO: handle errors */ 610 /* TODO: handle errors */
611 if (*val) { 611 if (*val) {
612 Words words = Str_Words(val, FALSE); 612 Words words = Str_Words(val, FALSE);
613 size_t i; 613 size_t i;
614 614
615 for (i = 0; i < words.len; i++) 615 for (i = 0; i < words.len; i++)
616 Var_Export1(words.words[i], 0); 616 Var_Export1(words.words[i], 0);
617 Words_Free(words); 617 Words_Free(words);
618 } 618 }
619 free(val); 619 free(val);
620} 620}
621 621
622/* 622/*
623 * This is called when .export is seen or .MAKE.EXPORTED is modified. 623 * This is called when .export is seen or .MAKE.EXPORTED is modified.
624 * 624 *
625 * It is also called when any exported variable is modified. 625 * It is also called when any exported variable is modified.
626 * XXX: Is it really? 626 * XXX: Is it really?
627 * 627 *
628 * str has the format "[-env|-literal] varname...". 628 * str has the format "[-env|-literal] varname...".
629 */ 629 */
630void 630void
631Var_Export(const char *str, Boolean isExport) 631Var_Export(const char *str, Boolean isExport)
632{ 632{
633 VarExportFlags flags; 633 VarExportFlags flags;
634 char *val; 634 char *val;
635 635
636 if (isExport && str[0] == '\0') { 636 if (isExport && str[0] == '\0') {
637 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ 637 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
638 return; 638 return;
639 } 639 }
640 640
641 if (isExport && strncmp(str, "-env", 4) == 0) { 641 if (isExport && strncmp(str, "-env", 4) == 0) {
642 str += 4; 642 str += 4;
643 flags = 0; 643 flags = 0;
644 } else if (isExport && strncmp(str, "-literal", 8) == 0) { 644 } else if (isExport && strncmp(str, "-literal", 8) == 0) {
645 str += 8; 645 str += 8;
646 flags = VAR_EXPORT_LITERAL; 646 flags = VAR_EXPORT_LITERAL;
647 } else { 647 } else {
648 flags = VAR_EXPORT_PARENT; 648 flags = VAR_EXPORT_PARENT;
649 } 649 }
650 650
651 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val); 651 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val);
652 /* TODO: handle errors */ 652 /* TODO: handle errors */
653 if (val[0] != '\0') { 653 if (val[0] != '\0') {
654 Words words = Str_Words(val, FALSE); 654 Words words = Str_Words(val, FALSE);
655 655
656 size_t i; 656 size_t i;
657 for (i = 0; i < words.len; i++) { 657 for (i = 0; i < words.len; i++) {
658 const char *name = words.words[i]; 658 const char *name = words.words[i];
659 if (Var_Export1(name, flags)) { 659 if (Var_Export1(name, flags)) {
660 if (var_exportedVars == VAR_EXPORTED_NONE) 660 if (var_exportedVars == VAR_EXPORTED_NONE)
661 var_exportedVars = VAR_EXPORTED_SOME; 661 var_exportedVars = VAR_EXPORTED_SOME;
662 if (isExport && (flags & VAR_EXPORT_PARENT)) { 662 if (isExport && (flags & VAR_EXPORT_PARENT)) {
663 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); 663 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
664 } 664 }
665 } 665 }
666 } 666 }
667 Words_Free(words); 667 Words_Free(words);
668 } 668 }
669 free(val); 669 free(val);
670} 670}
671 671
672 672
673extern char **environ; 673extern char **environ;
674 674
675/* 675/*
676 * This is called when .unexport[-env] is seen. 676 * This is called when .unexport[-env] is seen.
677 * 677 *
678 * str must have the form "unexport[-env] varname...". 678 * str must have the form "unexport[-env] varname...".
679 */ 679 */
680void 680void
681Var_UnExport(const char *str) 681Var_UnExport(const char *str)
682{ 682{
683 const char *varnames; 683 const char *varnames;
684 char *varnames_freeIt; 684 char *varnames_freeIt;
685 Boolean unexport_env; 685 Boolean unexport_env;
686 686
687 varnames = NULL; 687 varnames = NULL;
688 varnames_freeIt = NULL; 688 varnames_freeIt = NULL;
689 689
690 str += strlen("unexport"); 690 str += strlen("unexport");
691 unexport_env = strncmp(str, "-env", 4) == 0; 691 unexport_env = strncmp(str, "-env", 4) == 0;
692 if (unexport_env) { 692 if (unexport_env) {
693 const char *cp; 693 const char *cp;
694 char **newenv; 694 char **newenv;
695 695
696 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ 696 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
697 if (environ == savedEnv) { 697 if (environ == savedEnv) {
698 /* we have been here before! */ 698 /* we have been here before! */
699 newenv = bmake_realloc(environ, 2 * sizeof(char *)); 699 newenv = bmake_realloc(environ, 2 * sizeof(char *));
700 } else { 700 } else {
701 if (savedEnv) { 701 if (savedEnv) {
702 free(savedEnv); 702 free(savedEnv);
703 savedEnv = NULL; 703 savedEnv = NULL;
704 } 704 }
705 newenv = bmake_malloc(2 * sizeof(char *)); 705 newenv = bmake_malloc(2 * sizeof(char *));
706 } 706 }
707 707
708 /* Note: we cannot safely free() the original environ. */ 708 /* Note: we cannot safely free() the original environ. */
709 environ = savedEnv = newenv; 709 environ = savedEnv = newenv;
710 newenv[0] = NULL; 710 newenv[0] = NULL;
711 newenv[1] = NULL; 711 newenv[1] = NULL;
712 if (cp && *cp) 712 if (cp && *cp)
713 setenv(MAKE_LEVEL_ENV, cp, 1); 713 setenv(MAKE_LEVEL_ENV, cp, 1);
714 } else { 714 } else {
715 cpp_skip_whitespace(&str); 715 cpp_skip_whitespace(&str);
716 if (str[0] != '\0') 716 if (str[0] != '\0')
717 varnames = str; 717 varnames = str;
718 } 718 }
719 719
720 if (varnames == NULL) { 720 if (varnames == NULL) {
721 /* Using .MAKE.EXPORTED */ 721 /* Using .MAKE.EXPORTED */
722 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, 722 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES,
723 &varnames_freeIt); 723 &varnames_freeIt);
724 /* TODO: handle errors */ 724 /* TODO: handle errors */
725 varnames = varnames_freeIt; 725 varnames = varnames_freeIt;
726 } 726 }
727 727
728 { 728 {
729 Var *v; 729 Var *v;
730 size_t i; 730 size_t i;
731 731
732 Words words = Str_Words(varnames, FALSE); 732 Words words = Str_Words(varnames, FALSE);
733 for (i = 0; i < words.len; i++) { 733 for (i = 0; i < words.len; i++) {
734 const char *varname = words.words[i]; 734 const char *varname = words.words[i];
735 v = VarFind(varname, VAR_GLOBAL, 0); 735 v = VarFind(varname, VAR_GLOBAL, 0);
736 if (v == NULL) { 736 if (v == NULL) {
737 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname); 737 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname);
738 continue; 738 continue;
739 } 739 }
740 740
741 VAR_DEBUG1("Unexporting \"%s\"\n", varname); 741 VAR_DEBUG1("Unexporting \"%s\"\n", varname);
742 if (!unexport_env && (v->flags & VAR_EXPORTED) && 742 if (!unexport_env && (v->flags & VAR_EXPORTED) &&
743 !(v->flags & VAR_REEXPORT)) 743 !(v->flags & VAR_REEXPORT))
744 unsetenv(v->name); 744 unsetenv(v->name);
745 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT); 745 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT);
746 746
747 /* 747 /*
748 * If we are unexporting a list, 748 * If we are unexporting a list,
749 * remove each one from .MAKE.EXPORTED. 749 * remove each one from .MAKE.EXPORTED.
750 * If we are removing them all, 750 * If we are removing them all,
751 * just delete .MAKE.EXPORTED below. 751 * just delete .MAKE.EXPORTED below.
752 */ 752 */
753 if (varnames == str) { 753 if (varnames == str) {
754 /* XXX: v->name is injected without escaping it */ 754 /* XXX: v->name is injected without escaping it */
755 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}"); 755 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}");
756 char *cp; 756 char *cp;
757 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp); 757 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp);
758 /* TODO: handle errors */ 758 /* TODO: handle errors */
759 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL); 759 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
760 free(cp); 760 free(cp);
761 free(expr); 761 free(expr);
762 } 762 }
763 } 763 }
764 Words_Free(words); 764 Words_Free(words);
765 if (varnames != str) { 765 if (varnames != str) {
766 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); 766 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
767 free(varnames_freeIt); 767 free(varnames_freeIt);
768 } 768 }
769 } 769 }
770} 770}
771 771
772/* See Var_Set for documentation. */ 772/* See Var_Set for documentation. */
773void 773void
774Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, 774Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
775 VarSet_Flags flags) 775 VarSet_Flags flags)
776{ 776{
777 const char *unexpanded_name = name; 777 const char *unexpanded_name = name;
778 char *name_freeIt = NULL; 778 char *name_freeIt = NULL;
779 Var *v; 779 Var *v;
780 780
781 assert(val != NULL); 781 assert(val != NULL);
782 782
783 if (strchr(name, '$') != NULL) { 783 if (strchr(name, '$') != NULL) {
784 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 784 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
785 /* TODO: handle errors */ 785 /* TODO: handle errors */
786 name = name_freeIt; 786 name = name_freeIt;
787 } 787 }
788 788
789 if (name[0] == '\0') { 789 if (name[0] == '\0') {
790 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) " 790 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) "
791 "name expands to empty string - ignored\n", 791 "name expands to empty string - ignored\n",
792 unexpanded_name, val); 792 unexpanded_name, val);
793 free(name_freeIt); 793 free(name_freeIt);
794 return; 794 return;
795 } 795 }
796 796
797 if (ctxt == VAR_GLOBAL) { 797 if (ctxt == VAR_GLOBAL) {
798 v = VarFind(name, VAR_CMDLINE, 0); 798 v = VarFind(name, VAR_CMDLINE, 0);
799 if (v != NULL) { 799 if (v != NULL) {
800 if (v->flags & VAR_FROM_CMD) { 800 if (v->flags & VAR_FROM_CMD) {
801 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val); 801 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val);
802 goto out; 802 goto out;
803 } 803 }
804 VarFreeEnv(v, TRUE); 804 VarFreeEnv(v, TRUE);
805 } 805 }
806 } 806 }
807 807
808 /* 808 /*
809 * We only look for a variable in the given context since anything set 809 * We only look for a variable in the given context since anything set
810 * here will override anything in a lower context, so there's not much 810 * here will override anything in a lower context, so there's not much
811 * point in searching them all just to save a bit of memory... 811 * point in searching them all just to save a bit of memory...
812 */ 812 */
813 v = VarFind(name, ctxt, 0); 813 v = VarFind(name, ctxt, 0);
814 if (v == NULL) { 814 if (v == NULL) {
815 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT)) { 815 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT)) {
816 /* 816 /*
817 * This var would normally prevent the same name being added 817 * This var would normally prevent the same name being added
818 * to VAR_GLOBAL, so delete it from there if needed. 818 * to VAR_GLOBAL, so delete it from there if needed.
819 * Otherwise -V name may show the wrong value. 819 * Otherwise -V name may show the wrong value.
820 */ 820 */
821 /* XXX: name is expanded for the second time */ 821 /* XXX: name is expanded for the second time */
822 Var_Delete(name, VAR_GLOBAL); 822 Var_Delete(name, VAR_GLOBAL);
823 } 823 }
824 VarAdd(name, val, ctxt, flags); 824 VarAdd(name, val, ctxt, flags);
825 } else { 825 } else {
826 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) { 826 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) {
827 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n", 827 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n",
828 ctxt->name, name, val); 828 ctxt->name, name, val);
829 goto out; 829 goto out;
830 } 830 }
831 Buf_Empty(&v->val); 831 Buf_Empty(&v->val);
832 Buf_AddStr(&v->val, val); 832 Buf_AddStr(&v->val, val);
833 833
834 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); 834 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
835 if (v->flags & VAR_EXPORTED) { 835 if (v->flags & VAR_EXPORTED) {
836 Var_Export1(name, VAR_EXPORT_PARENT); 836 Var_Export1(name, VAR_EXPORT_PARENT);
837 } 837 }
838 } 838 }
839 /* 839 /*
840 * Any variables given on the command line are automatically exported 840 * Any variables given on the command line are automatically exported
841 * to the environment (as per POSIX standard) 841 * to the environment (as per POSIX standard)
842 * Other than internals. 842 * Other than internals.
843 */ 843 */
844 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT) && name[0] != '.') { 844 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT) && name[0] != '.') {
845 if (v == NULL) 845 if (v == NULL)
846 v = VarFind(name, ctxt, 0); /* we just added it */ 846 v = VarFind(name, ctxt, 0); /* we just added it */
847 v->flags |= VAR_FROM_CMD; 847 v->flags |= VAR_FROM_CMD;
848 848
849 /* 849 /*
850 * If requested, don't export these in the environment 850 * If requested, don't export these in the environment
851 * individually. We still put them in MAKEOVERRIDES so 851 * individually. We still put them in MAKEOVERRIDES so
852 * that the command-line settings continue to override 852 * that the command-line settings continue to override
853 * Makefile settings. 853 * Makefile settings.
854 */ 854 */
855 if (!opts.varNoExportEnv) 855 if (!opts.varNoExportEnv)
856 setenv(name, val, 1); 856 setenv(name, val, 1);
857 857
858 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); 858 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
859 } 859 }
860 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0) 860 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0)
861 save_dollars = s2Boolean(val, save_dollars); 861 save_dollars = s2Boolean(val, save_dollars);
862 862
863out: 863out:
864 free(name_freeIt); 864 free(name_freeIt);
865 if (v != NULL) 865 if (v != NULL)
866 VarFreeEnv(v, TRUE); 866 VarFreeEnv(v, TRUE);
867} 867}
868 868
869/*- 869/*-
870 *----------------------------------------------------------------------- 870 *-----------------------------------------------------------------------
871 * Var_Set -- 871 * Var_Set --
872 * Set the variable name to the value val in the given context. 872 * Set the variable name to the value val in the given context.
873 * 873 *
874 * If the variable doesn't yet exist, it is created. 874 * If the variable doesn't yet exist, it is created.
875 * Otherwise the new value overwrites and replaces the old value. 875 * Otherwise the new value overwrites and replaces the old value.
876 * 876 *
877 * Input: 877 * Input:
878 * name name of the variable to set, is expanded once 878 * name name of the variable to set, is expanded once
879 * val value to give to the variable 879 * val value to give to the variable
880 * ctxt context in which to set it 880 * ctxt context in which to set it
881 * 881 *
882 * Notes: 882 * Notes:
883 * The variable is searched for only in its context before being 883 * The variable is searched for only in its context before being
884 * created in that context. I.e. if the context is VAR_GLOBAL, 884 * created in that context. I.e. if the context is VAR_GLOBAL,
885 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMDLINE, 885 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMDLINE,
886 * only VAR_CMDLINE->context is searched. This is done to avoid the 886 * only VAR_CMDLINE->context is searched. This is done to avoid the
887 * literally thousands of unnecessary strcmp's that used to be done to 887 * literally thousands of unnecessary strcmp's that used to be done to
888 * set, say, $(@) or $(<). 888 * set, say, $(@) or $(<).
889 * If the context is VAR_GLOBAL though, we check if the variable 889 * If the context is VAR_GLOBAL though, we check if the variable
890 * was set in VAR_CMDLINE from the command line and skip it if so. 890 * was set in VAR_CMDLINE from the command line and skip it if so.
891 *----------------------------------------------------------------------- 891 *-----------------------------------------------------------------------
892 */ 892 */
893void 893void
894Var_Set(const char *name, const char *val, GNode *ctxt) 894Var_Set(const char *name, const char *val, GNode *ctxt)
895{ 895{
896 Var_Set_with_flags(name, val, ctxt, 0); 896 Var_Set_with_flags(name, val, ctxt, 0);
897} 897}
898 898
899/*- 899/*-
900 *----------------------------------------------------------------------- 900 *-----------------------------------------------------------------------
901 * Var_Append -- 901 * Var_Append --
902 * The variable of the given name has the given value appended to it in 902 * The variable of the given name has the given value appended to it in
903 * the given context. 903 * the given context.
904 * 904 *
905 * If the variable doesn't exist, it is created. Otherwise the strings 905 * If the variable doesn't exist, it is created. Otherwise the strings
906 * are concatenated, with a space in between. 906 * are concatenated, with a space in between.
907 * 907 *
908 * Input: 908 * Input:
909 * name name of the variable to modify, is expanded once 909 * name name of the variable to modify, is expanded once
910 * val string to append to it 910 * val string to append to it
911 * ctxt context in which this should occur 911 * ctxt context in which this should occur
912 * 912 *
913 * Notes: 913 * Notes:
914 * Only if the variable is being sought in the global context is the 914 * Only if the variable is being sought in the global context is the
915 * environment searched. 915 * environment searched.
916 * XXX: Knows its calling circumstances in that if called with ctxt 916 * XXX: Knows its calling circumstances in that if called with ctxt
917 * an actual target, it will only search that context since only 917 * an actual target, it will only search that context since only
918 * a local variable could be being appended to. This is actually 918 * a local variable could be being appended to. This is actually
919 * a big win and must be tolerated. 919 * a big win and must be tolerated.
920 *----------------------------------------------------------------------- 920 *-----------------------------------------------------------------------
921 */ 921 */
922void 922void
923Var_Append(const char *name, const char *val, GNode *ctxt) 923Var_Append(const char *name, const char *val, GNode *ctxt)
924{ 924{
925 char *name_freeIt = NULL; 925 char *name_freeIt = NULL;
926 Var *v; 926 Var *v;
927 927
928 assert(val != NULL); 928 assert(val != NULL);
929 929
930 if (strchr(name, '$') != NULL) { 930 if (strchr(name, '$') != NULL) {
931 const char *unexpanded_name = name; 931 const char *unexpanded_name = name;
932 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 932 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
933 /* TODO: handle errors */ 933 /* TODO: handle errors */
934 name = name_freeIt; 934 name = name_freeIt;
935 if (name[0] == '\0') { 935 if (name[0] == '\0') {
936 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) " 936 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) "
937 "name expands to empty string - ignored\n", 937 "name expands to empty string - ignored\n",
938 unexpanded_name, val); 938 unexpanded_name, val);
939 free(name_freeIt); 939 free(name_freeIt);
940 return; 940 return;
941 } 941 }
942 } 942 }
943 943
944 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL); 944 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL);
945 945
946 if (v == NULL) { 946 if (v == NULL) {
947 /* XXX: name is expanded for the second time */ 947 /* XXX: name is expanded for the second time */
948 Var_Set(name, val, ctxt); 948 Var_Set(name, val, ctxt);
949 } else if (v->flags & VAR_READONLY) { 949 } else if (v->flags & VAR_READONLY) {
950 VAR_DEBUG1("Ignoring append to %s since it is read-only\n", name); 950 VAR_DEBUG1("Ignoring append to %s since it is read-only\n", name);
951 } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) { 951 } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) {
952 Buf_AddByte(&v->val, ' '); 952 Buf_AddByte(&v->val, ' ');
953 Buf_AddStr(&v->val, val); 953 Buf_AddStr(&v->val, val);
954 954
955 VAR_DEBUG3("%s:%s = %s\n", 955 VAR_DEBUG3("%s:%s = %s\n",
956 ctxt->name, name, Buf_GetAll(&v->val, NULL)); 956 ctxt->name, name, Buf_GetAll(&v->val, NULL));
957 957
958 if (v->flags & VAR_FROM_ENV) { 958 if (v->flags & VAR_FROM_ENV) {
959 HashEntry *h; 959 HashEntry *h;
960 960
961 /* 961 /*
962 * If the original variable came from the environment, we 962 * If the original variable came from the environment, we
963 * have to install it in the global context (we could place 963 * have to install it in the global context (we could place
964 * it in the environment, but then we should provide a way to 964 * it in the environment, but then we should provide a way to
965 * export other variables...) 965 * export other variables...)
966 */ 966 */
967 v->flags &= ~(unsigned)VAR_FROM_ENV; 967 v->flags &= ~(unsigned)VAR_FROM_ENV;
968 h = HashTable_CreateEntry(&ctxt->context, name, NULL); 968 h = HashTable_CreateEntry(&ctxt->context, name, NULL);
969 HashEntry_Set(h, v); 969 HashEntry_Set(h, v);
970 } 970 }
971 } 971 }
972 free(name_freeIt); 972 free(name_freeIt);
973} 973}
974 974
975/* See if the given variable exists, in the given context or in other 975/* See if the given variable exists, in the given context or in other
976 * fallback contexts. 976 * fallback contexts.
977 * 977 *
978 * Input: 978 * Input:
979 * name Variable to find, is expanded once 979 * name Variable to find, is expanded once
980 * ctxt Context in which to start search 980 * ctxt Context in which to start search
981 */ 981 */
982Boolean 982Boolean
983Var_Exists(const char *name, GNode *ctxt) 983Var_Exists(const char *name, GNode *ctxt)
984{ 984{
985 char *name_freeIt = NULL; 985 char *name_freeIt = NULL;
986 Var *v; 986 Var *v;
987 987
988 if (strchr(name, '$') != NULL) { 988 if (strchr(name, '$') != NULL) {
989 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 989 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
990 /* TODO: handle errors */ 990 /* TODO: handle errors */
991 name = name_freeIt; 991 name = name_freeIt;
992 } 992 }
993 993
994 v = VarFind(name, ctxt, TRUE); 994 v = VarFind(name, ctxt, TRUE);
995 free(name_freeIt); 995 free(name_freeIt);
996 if (v == NULL) 996 if (v == NULL)
997 return FALSE; 997 return FALSE;
998 998
999 (void)VarFreeEnv(v, TRUE); 999 (void)VarFreeEnv(v, TRUE);
1000 return TRUE; 1000 return TRUE;
1001} 1001}
1002 1002
1003/*- 1003/*-
1004 *----------------------------------------------------------------------- 1004 *-----------------------------------------------------------------------
1005 * Var_Value -- 1005 * Var_Value --
1006 * Return the unexpanded value of the given variable in the given 1006 * Return the unexpanded value of the given variable in the given
1007 * context, or the usual contexts. 1007 * context, or the usual contexts.
1008 * 1008 *
1009 * Input: 1009 * Input:
1010 * name name to find, is not expanded any further 1010 * name name to find, is not expanded any further
1011 * ctxt context in which to search for it 1011 * ctxt context in which to search for it
1012 * 1012 *
1013 * Results: 1013 * Results:
1014 * The value if the variable exists, NULL if it doesn't. 1014 * The value if the variable exists, NULL if it doesn't.
1015 * If the returned value is not NULL, the caller must free *freeIt 1015 * If the returned value is not NULL, the caller must free *freeIt
1016 * as soon as the returned value is no longer needed. 1016 * as soon as the returned value is no longer needed.
1017 *----------------------------------------------------------------------- 1017 *-----------------------------------------------------------------------
1018 */ 1018 */
1019const char * 1019const char *
1020Var_Value(const char *name, GNode *ctxt, void **freeIt) 1020Var_Value(const char *name, GNode *ctxt, void **freeIt)
1021{ 1021{
1022 Var *v = VarFind(name, ctxt, TRUE); 1022 Var *v = VarFind(name, ctxt, TRUE);
1023 char *value; 1023 char *value;
1024 1024
1025 *freeIt = NULL; 1025 *freeIt = NULL;
1026 if (v == NULL) 1026 if (v == NULL)
1027 return NULL; 1027 return NULL;
1028 1028
1029 value = Buf_GetAll(&v->val, NULL); 1029 value = Buf_GetAll(&v->val, NULL);
1030 if (VarFreeEnv(v, FALSE)) 1030 if (VarFreeEnv(v, FALSE))
1031 *freeIt = value; 1031 *freeIt = value;
1032 return value; 1032 return value;
1033} 1033}
1034 1034
1035 1035
1036/* SepBuf is a string being built from words, interleaved with separators. */ 1036/* SepBuf is a string being built from words, interleaved with separators. */
1037typedef struct SepBuf { 1037typedef struct SepBuf {
1038 Buffer buf; 1038 Buffer buf;
1039 Boolean needSep; 1039 Boolean needSep;
1040 char sep; /* usually ' ', but see the :ts modifier */ 1040 char sep; /* usually ' ', but see the :ts modifier */
1041} SepBuf; 1041} SepBuf;
1042 1042
1043static void 1043static void
1044SepBuf_Init(SepBuf *buf, char sep) 1044SepBuf_Init(SepBuf *buf, char sep)
1045{ 1045{
1046 Buf_Init(&buf->buf, 32 /* bytes */); 1046 Buf_Init(&buf->buf, 32 /* bytes */);
1047 buf->needSep = FALSE; 1047 buf->needSep = FALSE;
1048 buf->sep = sep; 1048 buf->sep = sep;
1049} 1049}
1050 1050
1051static void 1051static void
1052SepBuf_Sep(SepBuf *buf) 1052SepBuf_Sep(SepBuf *buf)
1053{ 1053{
1054 buf->needSep = TRUE; 1054 buf->needSep = TRUE;
1055} 1055}
1056 1056
1057static void 1057static void
1058SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size) 1058SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1059{ 1059{
1060 if (mem_size == 0) 1060 if (mem_size == 0)
1061 return; 1061 return;
1062 if (buf->needSep && buf->sep != '\0') { 1062 if (buf->needSep && buf->sep != '\0') {
1063 Buf_AddByte(&buf->buf, buf->sep); 1063 Buf_AddByte(&buf->buf, buf->sep);
1064 buf->needSep = FALSE; 1064 buf->needSep = FALSE;
1065 } 1065 }
1066 Buf_AddBytes(&buf->buf, mem, mem_size); 1066 Buf_AddBytes(&buf->buf, mem, mem_size);
1067} 1067}
1068 1068
1069static void 1069static void
1070SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end) 1070SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1071{ 1071{
1072 SepBuf_AddBytes(buf, start, (size_t)(end - start)); 1072 SepBuf_AddBytes(buf, start, (size_t)(end - start));
1073} 1073}
1074 1074
1075static void 1075static void
1076SepBuf_AddStr(SepBuf *buf, const char *str) 1076SepBuf_AddStr(SepBuf *buf, const char *str)
1077{ 1077{
1078 SepBuf_AddBytes(buf, str, strlen(str)); 1078 SepBuf_AddBytes(buf, str, strlen(str));
1079} 1079}
1080 1080
1081static char * 1081static char *
1082SepBuf_Destroy(SepBuf *buf, Boolean free_buf) 1082SepBuf_Destroy(SepBuf *buf, Boolean free_buf)
1083{ 1083{
1084 return Buf_Destroy(&buf->buf, free_buf); 1084 return Buf_Destroy(&buf->buf, free_buf);
1085} 1085}
1086 1086
1087 1087
1088/* This callback for ModifyWords gets a single word from a variable expression 1088/* This callback for ModifyWords gets a single word from a variable expression
1089 * and typically adds a modification of this word to the buffer. It may also 1089 * and typically adds a modification of this word to the buffer. It may also
1090 * do nothing or add several words. 1090 * do nothing or add several words.
1091 * 1091 *
1092 * For example, in ${:Ua b c:M*2}, the callback is called 3 times, once for 1092 * For example, in ${:Ua b c:M*2}, the callback is called 3 times, once for
1093 * each word of "a b c". */ 1093 * each word of "a b c". */
1094typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data); 1094typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data);
1095 1095
1096 1096
1097/* Callback for ModifyWords to implement the :H modifier. 1097/* Callback for ModifyWords to implement the :H modifier.
1098 * Add the dirname of the given word to the buffer. */ 1098 * Add the dirname of the given word to the buffer. */
1099static void 1099static void
1100ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1100ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1101{ 1101{
1102 const char *slash = strrchr(word, '/'); 1102 const char *slash = strrchr(word, '/');
1103 if (slash != NULL) 1103 if (slash != NULL)
1104 SepBuf_AddBytesBetween(buf, word, slash); 1104 SepBuf_AddBytesBetween(buf, word, slash);
1105 else 1105 else
1106 SepBuf_AddStr(buf, "."); 1106 SepBuf_AddStr(buf, ".");
1107} 1107}
1108 1108
1109/* Callback for ModifyWords to implement the :T modifier. 1109/* Callback for ModifyWords to implement the :T modifier.
1110 * Add the basename of the given word to the buffer. */ 1110 * Add the basename of the given word to the buffer. */
1111static void 1111static void
1112ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1112ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1113{ 1113{
1114 const char *slash = strrchr(word, '/'); 1114 const char *slash = strrchr(word, '/');
1115 const char *base = slash != NULL ? slash + 1 : word; 1115 const char *base = slash != NULL ? slash + 1 : word;
1116 SepBuf_AddStr(buf, base); 1116 SepBuf_AddStr(buf, base);
1117} 1117}
1118 1118
1119/* Callback for ModifyWords to implement the :E modifier. 1119/* Callback for ModifyWords to implement the :E modifier.
1120 * Add the filename suffix of the given word to the buffer, if it exists. */ 1120 * Add the filename suffix of the given word to the buffer, if it exists. */
1121static void 1121static void
1122ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1122ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1123{ 1123{
1124 const char *dot = strrchr(word, '.'); 1124 const char *dot = strrchr(word, '.');
1125 if (dot != NULL) 1125 if (dot != NULL)
1126 SepBuf_AddStr(buf, dot + 1); 1126 SepBuf_AddStr(buf, dot + 1);
1127} 1127}
1128 1128
1129/* Callback for ModifyWords to implement the :R modifier. 1129/* Callback for ModifyWords to implement the :R modifier.
1130 * Add the basename of the given word to the buffer. */ 1130 * Add the basename of the given word to the buffer. */
1131static void 1131static void
@@ -2666,1231 +2666,1227 @@ ApplyModifier_Words(const char **pp, App @@ -2666,1231 +2666,1227 @@ ApplyModifier_Words(const char **pp, App
2666 } 2666 }
2667 2667
2668 /* 2668 /*
2669 * We expect estr to contain a single integer for :[N], or two integers 2669 * We expect estr to contain a single integer for :[N], or two integers
2670 * separated by ".." for :[start..end]. 2670 * separated by ".." for :[start..end].
2671 */ 2671 */
2672 first = (int)strtol(estr, &ep, 0); 2672 first = (int)strtol(estr, &ep, 0);
2673 if (ep == estr) /* Found junk instead of a number */ 2673 if (ep == estr) /* Found junk instead of a number */
2674 goto bad_modifier; 2674 goto bad_modifier;
2675 2675
2676 if (ep[0] == '\0') { /* Found only one integer in :[N] */ 2676 if (ep[0] == '\0') { /* Found only one integer in :[N] */
2677 last = first; 2677 last = first;
2678 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') { 2678 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') {
2679 /* Expecting another integer after ".." */ 2679 /* Expecting another integer after ".." */
2680 ep += 2; 2680 ep += 2;
2681 last = (int)strtol(ep, &ep, 0); 2681 last = (int)strtol(ep, &ep, 0);
2682 if (ep[0] != '\0') /* Found junk after ".." */ 2682 if (ep[0] != '\0') /* Found junk after ".." */
2683 goto bad_modifier; 2683 goto bad_modifier;
2684 } else 2684 } else
2685 goto bad_modifier; /* Found junk instead of ".." */ 2685 goto bad_modifier; /* Found junk instead of ".." */
2686 2686
2687 /* 2687 /*
2688 * Now seldata is properly filled in, but we still have to check for 0 as 2688 * Now seldata is properly filled in, but we still have to check for 0 as
2689 * a special case. 2689 * a special case.
2690 */ 2690 */
2691 if (first == 0 && last == 0) { 2691 if (first == 0 && last == 0) {
2692 /* ":[0]" or perhaps ":[0..0]" */ 2692 /* ":[0]" or perhaps ":[0..0]" */
2693 st->oneBigWord = TRUE; 2693 st->oneBigWord = TRUE;
2694 st->newVal = st->val; 2694 st->newVal = st->val;
2695 goto ok; 2695 goto ok;
2696 } 2696 }
2697 2697
2698 /* ":[0..N]" or ":[N..0]" */ 2698 /* ":[0..N]" or ":[N..0]" */
2699 if (first == 0 || last == 0) 2699 if (first == 0 || last == 0)
2700 goto bad_modifier; 2700 goto bad_modifier;
2701 2701
2702 /* Normal case: select the words described by seldata. */ 2702 /* Normal case: select the words described by seldata. */
2703 st->newVal = VarSelectWords(st->sep, st->oneBigWord, st->val, first, last); 2703 st->newVal = VarSelectWords(st->sep, st->oneBigWord, st->val, first, last);
2704 2704
2705ok: 2705ok:
2706 free(estr); 2706 free(estr);
2707 return AMR_OK; 2707 return AMR_OK;
2708 2708
2709bad_modifier: 2709bad_modifier:
2710 free(estr); 2710 free(estr);
2711 return AMR_BAD; 2711 return AMR_BAD;
2712} 2712}
2713 2713
2714static int 2714static int
2715str_cmp_asc(const void *a, const void *b) 2715str_cmp_asc(const void *a, const void *b)
2716{ 2716{
2717 return strcmp(*(const char * const *)a, *(const char * const *)b); 2717 return strcmp(*(const char * const *)a, *(const char * const *)b);
2718} 2718}
2719 2719
2720static int 2720static int
2721str_cmp_desc(const void *a, const void *b) 2721str_cmp_desc(const void *a, const void *b)
2722{ 2722{
2723 return strcmp(*(const char * const *)b, *(const char * const *)a); 2723 return strcmp(*(const char * const *)b, *(const char * const *)a);
2724} 2724}
2725 2725
2726/* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */ 2726/* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */
2727static ApplyModifierResult 2727static ApplyModifierResult
2728ApplyModifier_Order(const char **pp, ApplyModifiersState *st) 2728ApplyModifier_Order(const char **pp, ApplyModifiersState *st)
2729{ 2729{
2730 const char *mod = (*pp)++; /* skip past the 'O' in any case */ 2730 const char *mod = (*pp)++; /* skip past the 'O' in any case */
2731 2731
2732 Words words = Str_Words(st->val, FALSE); 2732 Words words = Str_Words(st->val, FALSE);
2733 2733
2734 if (mod[1] == st->endc || mod[1] == ':') { 2734 if (mod[1] == st->endc || mod[1] == ':') {
2735 /* :O sorts ascending */ 2735 /* :O sorts ascending */
2736 qsort(words.words, words.len, sizeof(char *), str_cmp_asc); 2736 qsort(words.words, words.len, sizeof(char *), str_cmp_asc);
2737 2737
2738 } else if ((mod[1] == 'r' || mod[1] == 'x') && 2738 } else if ((mod[1] == 'r' || mod[1] == 'x') &&
2739 (mod[2] == st->endc || mod[2] == ':')) { 2739 (mod[2] == st->endc || mod[2] == ':')) {
2740 (*pp)++; 2740 (*pp)++;
2741 2741
2742 if (mod[1] == 'r') { 2742 if (mod[1] == 'r') {
2743 /* :Or sorts descending */ 2743 /* :Or sorts descending */
2744 qsort(words.words, words.len, sizeof(char *), str_cmp_desc); 2744 qsort(words.words, words.len, sizeof(char *), str_cmp_desc);
2745 2745
2746 } else { 2746 } else {
2747 /* :Ox shuffles 2747 /* :Ox shuffles
2748 * 2748 *
2749 * We will use [ac..2] range for mod factors. This will produce 2749 * We will use [ac..2] range for mod factors. This will produce
2750 * random numbers in [(ac-1)..0] interval, and minimal 2750 * random numbers in [(ac-1)..0] interval, and minimal
2751 * reasonable value for mod factor is 2 (the mod 1 will produce 2751 * reasonable value for mod factor is 2 (the mod 1 will produce
2752 * 0 with probability 1). 2752 * 0 with probability 1).
2753 */ 2753 */
2754 size_t i; 2754 size_t i;
2755 for (i = words.len - 1; i > 0; i--) { 2755 for (i = words.len - 1; i > 0; i--) {
2756 size_t rndidx = (size_t)random() % (i + 1); 2756 size_t rndidx = (size_t)random() % (i + 1);
2757 char *t = words.words[i]; 2757 char *t = words.words[i];
2758 words.words[i] = words.words[rndidx]; 2758 words.words[i] = words.words[rndidx];
2759 words.words[rndidx] = t; 2759 words.words[rndidx] = t;
2760 } 2760 }
2761 } 2761 }
2762 } else { 2762 } else {
2763 Words_Free(words); 2763 Words_Free(words);
2764 return AMR_BAD; 2764 return AMR_BAD;
2765 } 2765 }
2766 2766
2767 st->newVal = Words_JoinFree(words); 2767 st->newVal = Words_JoinFree(words);
2768 return AMR_OK; 2768 return AMR_OK;
2769} 2769}
2770 2770
2771/* :? then : else */ 2771/* :? then : else */
2772static ApplyModifierResult 2772static ApplyModifierResult
2773ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st) 2773ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st)
2774{ 2774{
2775 char *then_expr, *else_expr; 2775 char *then_expr, *else_expr;
2776 VarParseResult res; 2776 VarParseResult res;
2777 2777
2778 Boolean value = FALSE; 2778 Boolean value = FALSE;
2779 VarEvalFlags then_eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2779 VarEvalFlags then_eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2780 VarEvalFlags else_eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2780 VarEvalFlags else_eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2781 2781
2782 int cond_rc = COND_PARSE; /* anything other than COND_INVALID */ 2782 int cond_rc = COND_PARSE; /* anything other than COND_INVALID */
2783 if (st->eflags & VARE_WANTRES) { 2783 if (st->eflags & VARE_WANTRES) {
2784 cond_rc = Cond_EvalCondition(st->v->name, &value); 2784 cond_rc = Cond_EvalCondition(st->v->name, &value);
2785 if (cond_rc != COND_INVALID && value) 2785 if (cond_rc != COND_INVALID && value)
2786 then_eflags |= VARE_WANTRES; 2786 then_eflags |= VARE_WANTRES;
2787 if (cond_rc != COND_INVALID && !value) 2787 if (cond_rc != COND_INVALID && !value)
2788 else_eflags |= VARE_WANTRES; 2788 else_eflags |= VARE_WANTRES;
2789 } 2789 }
2790 2790
2791 (*pp)++; /* skip past the '?' */ 2791 (*pp)++; /* skip past the '?' */
2792 res = ParseModifierPart(pp, ':', then_eflags, st, 2792 res = ParseModifierPart(pp, ':', then_eflags, st,
2793 &then_expr, NULL, NULL, NULL); 2793 &then_expr, NULL, NULL, NULL);
2794 if (res != VPR_OK) 2794 if (res != VPR_OK)
2795 return AMR_CLEANUP; 2795 return AMR_CLEANUP;
2796 2796
2797 res = ParseModifierPart(pp, st->endc, else_eflags, st, 2797 res = ParseModifierPart(pp, st->endc, else_eflags, st,
2798 &else_expr, NULL, NULL, NULL); 2798 &else_expr, NULL, NULL, NULL);
2799 if (res != VPR_OK) 2799 if (res != VPR_OK)
2800 return AMR_CLEANUP; 2800 return AMR_CLEANUP;
2801 2801
2802 (*pp)--; 2802 (*pp)--;
2803 if (cond_rc == COND_INVALID) { 2803 if (cond_rc == COND_INVALID) {
2804 Error("Bad conditional expression `%s' in %s?%s:%s", 2804 Error("Bad conditional expression `%s' in %s?%s:%s",
2805 st->v->name, st->v->name, then_expr, else_expr); 2805 st->v->name, st->v->name, then_expr, else_expr);
2806 return AMR_CLEANUP; 2806 return AMR_CLEANUP;
2807 } 2807 }
2808 2808
2809 if (value) { 2809 if (value) {
2810 st->newVal = then_expr; 2810 st->newVal = then_expr;
2811 free(else_expr); 2811 free(else_expr);
2812 } else { 2812 } else {
2813 st->newVal = else_expr; 2813 st->newVal = else_expr;
2814 free(then_expr); 2814 free(then_expr);
2815 } 2815 }
2816 ApplyModifiersState_Define(st); 2816 ApplyModifiersState_Define(st);
2817 return AMR_OK; 2817 return AMR_OK;
2818} 2818}
2819 2819
2820/* 2820/*
2821 * The ::= modifiers actually assign a value to the variable. 2821 * The ::= modifiers actually assign a value to the variable.
2822 * Their main purpose is in supporting modifiers of .for loop 2822 * Their main purpose is in supporting modifiers of .for loop
2823 * iterators and other obscure uses. They always expand to 2823 * iterators and other obscure uses. They always expand to
2824 * nothing. In a target rule that would otherwise expand to an 2824 * nothing. In a target rule that would otherwise expand to an
2825 * empty line they can be preceded with @: to keep make happy. 2825 * empty line they can be preceded with @: to keep make happy.
2826 * Eg. 2826 * Eg.
2827 * 2827 *
2828 * foo: .USE 2828 * foo: .USE
2829 * .for i in ${.TARGET} ${.TARGET:R}.gz 2829 * .for i in ${.TARGET} ${.TARGET:R}.gz
2830 * @: ${t::=$i} 2830 * @: ${t::=$i}
2831 * @echo blah ${t:T} 2831 * @echo blah ${t:T}
2832 * .endfor 2832 * .endfor
2833 * 2833 *
2834 * ::=<str> Assigns <str> as the new value of variable. 2834 * ::=<str> Assigns <str> as the new value of variable.
2835 * ::?=<str> Assigns <str> as value of variable if 2835 * ::?=<str> Assigns <str> as value of variable if
2836 * it was not already set. 2836 * it was not already set.
2837 * ::+=<str> Appends <str> to variable. 2837 * ::+=<str> Appends <str> to variable.
2838 * ::!=<cmd> Assigns output of <cmd> as the new value of 2838 * ::!=<cmd> Assigns output of <cmd> as the new value of
2839 * variable. 2839 * variable.
2840 */ 2840 */
2841static ApplyModifierResult 2841static ApplyModifierResult
2842ApplyModifier_Assign(const char **pp, ApplyModifiersState *st) 2842ApplyModifier_Assign(const char **pp, ApplyModifiersState *st)
2843{ 2843{
2844 GNode *v_ctxt; 2844 GNode *v_ctxt;
2845 char delim; 2845 char delim;
2846 char *val; 2846 char *val;
2847 VarParseResult res; 2847 VarParseResult res;
2848 2848
2849 const char *mod = *pp; 2849 const char *mod = *pp;
2850 const char *op = mod + 1; 2850 const char *op = mod + 1;
2851 if (!(op[0] == '=' || 2851 if (!(op[0] == '=' ||
2852 (op[1] == '=' && 2852 (op[1] == '=' &&
2853 (op[0] == '!' || op[0] == '+' || op[0] == '?')))) 2853 (op[0] == '!' || op[0] == '+' || op[0] == '?'))))
2854 return AMR_UNKNOWN; /* "::<unrecognised>" */ 2854 return AMR_UNKNOWN; /* "::<unrecognised>" */
2855 2855
2856 2856
2857 if (st->v->name[0] == '\0') { 2857 if (st->v->name[0] == '\0') {
2858 *pp = mod + 1; 2858 *pp = mod + 1;
2859 return AMR_BAD; 2859 return AMR_BAD;
2860 } 2860 }
2861 2861
2862 v_ctxt = st->ctxt; /* context where v belongs */ 2862 v_ctxt = st->ctxt; /* context where v belongs */
2863 if (!(st->exprFlags & VEF_UNDEF) && st->ctxt != VAR_GLOBAL) { 2863 if (!(st->exprFlags & VEF_UNDEF) && st->ctxt != VAR_GLOBAL) {
2864 Var *gv = VarFind(st->v->name, st->ctxt, 0); 2864 Var *gv = VarFind(st->v->name, st->ctxt, 0);
2865 if (gv == NULL) 2865 if (gv == NULL)
2866 v_ctxt = VAR_GLOBAL; 2866 v_ctxt = VAR_GLOBAL;
2867 else 2867 else
2868 VarFreeEnv(gv, TRUE); 2868 VarFreeEnv(gv, TRUE);
2869 } 2869 }
2870 2870
2871 switch (op[0]) { 2871 switch (op[0]) {
2872 case '+': 2872 case '+':
2873 case '?': 2873 case '?':
2874 case '!': 2874 case '!':
2875 *pp = mod + 3; 2875 *pp = mod + 3;
2876 break; 2876 break;
2877 default: 2877 default:
2878 *pp = mod + 2; 2878 *pp = mod + 2;
2879 break; 2879 break;
2880 } 2880 }
2881 2881
2882 delim = st->startc == '(' ? ')' : '}'; 2882 delim = st->startc == '(' ? ')' : '}';
2883 res = ParseModifierPart(pp, delim, st->eflags, st, &val, NULL, NULL, NULL); 2883 res = ParseModifierPart(pp, delim, st->eflags, st, &val, NULL, NULL, NULL);
2884 if (res != VPR_OK) 2884 if (res != VPR_OK)
2885 return AMR_CLEANUP; 2885 return AMR_CLEANUP;
2886 2886
2887 (*pp)--; 2887 (*pp)--;
2888 2888
2889 if (st->eflags & VARE_WANTRES) { 2889 if (st->eflags & VARE_WANTRES) {
2890 switch (op[0]) { 2890 switch (op[0]) {
2891 case '+': 2891 case '+':
2892 Var_Append(st->v->name, val, v_ctxt); 2892 Var_Append(st->v->name, val, v_ctxt);
2893 break; 2893 break;
2894 case '!': { 2894 case '!': {
2895 const char *errfmt; 2895 const char *errfmt;
2896 char *cmd_output = Cmd_Exec(val, &errfmt); 2896 char *cmd_output = Cmd_Exec(val, &errfmt);
2897 if (errfmt) 2897 if (errfmt)
2898 Error(errfmt, val); 2898 Error(errfmt, val);
2899 else 2899 else
2900 Var_Set(st->v->name, cmd_output, v_ctxt); 2900 Var_Set(st->v->name, cmd_output, v_ctxt);
2901 free(cmd_output); 2901 free(cmd_output);
2902 break; 2902 break;
2903 } 2903 }
2904 case '?': 2904 case '?':
2905 if (!(st->exprFlags & VEF_UNDEF)) 2905 if (!(st->exprFlags & VEF_UNDEF))
2906 break; 2906 break;
2907 /* FALLTHROUGH */ 2907 /* FALLTHROUGH */
2908 default: 2908 default:
2909 Var_Set(st->v->name, val, v_ctxt); 2909 Var_Set(st->v->name, val, v_ctxt);
2910 break; 2910 break;
2911 } 2911 }
2912 } 2912 }
2913 free(val); 2913 free(val);
2914 st->newVal = emptyString; 2914 st->newVal = emptyString;
2915 return AMR_OK; 2915 return AMR_OK;
2916} 2916}
2917 2917
2918/* remember current value */ 2918/* remember current value */
2919static ApplyModifierResult 2919static ApplyModifierResult
2920ApplyModifier_Remember(const char **pp, ApplyModifiersState *st) 2920ApplyModifier_Remember(const char **pp, ApplyModifiersState *st)
2921{ 2921{
2922 const char *mod = *pp; 2922 const char *mod = *pp;
2923 if (!ModMatchEq(mod, "_", st->endc)) 2923 if (!ModMatchEq(mod, "_", st->endc))
2924 return AMR_UNKNOWN; 2924 return AMR_UNKNOWN;
2925 2925
2926 if (mod[1] == '=') { 2926 if (mod[1] == '=') {
2927 size_t n = strcspn(mod + 2, ":)}"); 2927 size_t n = strcspn(mod + 2, ":)}");
2928 char *name = bmake_strldup(mod + 2, n); 2928 char *name = bmake_strldup(mod + 2, n);
2929 Var_Set(name, st->val, st->ctxt); 2929 Var_Set(name, st->val, st->ctxt);
2930 free(name); 2930 free(name);
2931 *pp = mod + 2 + n; 2931 *pp = mod + 2 + n;
2932 } else { 2932 } else {
2933 Var_Set("_", st->val, st->ctxt); 2933 Var_Set("_", st->val, st->ctxt);
2934 *pp = mod + 1; 2934 *pp = mod + 1;
2935 } 2935 }
2936 st->newVal = st->val; 2936 st->newVal = st->val;
2937 return AMR_OK; 2937 return AMR_OK;
2938} 2938}
2939 2939
2940/* Apply the given function to each word of the variable value. */ 2940/* Apply the given function to each word of the variable value. */
2941static ApplyModifierResult 2941static ApplyModifierResult
2942ApplyModifier_WordFunc(const char **pp, ApplyModifiersState *st, 2942ApplyModifier_WordFunc(const char **pp, ApplyModifiersState *st,
2943 ModifyWordsCallback modifyWord) 2943 ModifyWordsCallback modifyWord)
2944{ 2944{
2945 char delim = (*pp)[1]; 2945 char delim = (*pp)[1];
2946 if (delim != st->endc && delim != ':') 2946 if (delim != st->endc && delim != ':')
2947 return AMR_UNKNOWN; 2947 return AMR_UNKNOWN;
2948 2948
2949 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, 2949 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord,
2950 st->val, modifyWord, NULL); 2950 st->val, modifyWord, NULL);
2951 (*pp)++; 2951 (*pp)++;
2952 return AMR_OK; 2952 return AMR_OK;
2953} 2953}
2954 2954
2955static ApplyModifierResult 2955static ApplyModifierResult
2956ApplyModifier_Unique(const char **pp, ApplyModifiersState *st) 2956ApplyModifier_Unique(const char **pp, ApplyModifiersState *st)
2957{ 2957{
2958 if ((*pp)[1] == st->endc || (*pp)[1] == ':') { 2958 if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
2959 st->newVal = VarUniq(st->val); 2959 st->newVal = VarUniq(st->val);
2960 (*pp)++; 2960 (*pp)++;
2961 return AMR_OK; 2961 return AMR_OK;
2962 } else 2962 } else
2963 return AMR_UNKNOWN; 2963 return AMR_UNKNOWN;
2964} 2964}
2965 2965
2966#ifdef SYSVVARSUB 2966#ifdef SYSVVARSUB
2967/* :from=to */ 2967/* :from=to */
2968static ApplyModifierResult 2968static ApplyModifierResult
2969ApplyModifier_SysV(const char **pp, ApplyModifiersState *st) 2969ApplyModifier_SysV(const char **pp, ApplyModifiersState *st)
2970{ 2970{
2971 char *lhs, *rhs; 2971 char *lhs, *rhs;
2972 VarParseResult res; 2972 VarParseResult res;
2973 2973
2974 const char *mod = *pp; 2974 const char *mod = *pp;
2975 Boolean eqFound = FALSE; 2975 Boolean eqFound = FALSE;
2976 2976
2977 /* 2977 /*
2978 * First we make a pass through the string trying 2978 * First we make a pass through the string trying
2979 * to verify it is a SYSV-make-style translation: 2979 * to verify it is a SYSV-make-style translation:
2980 * it must be: <string1>=<string2>) 2980 * it must be: <string1>=<string2>)
2981 */ 2981 */
2982 int nest = 1; 2982 int nest = 1;
2983 const char *next = mod; 2983 const char *next = mod;
2984 while (*next != '\0' && nest > 0) { 2984 while (*next != '\0' && nest > 0) {
2985 if (*next == '=') { 2985 if (*next == '=') {
2986 eqFound = TRUE; 2986 eqFound = TRUE;
2987 /* continue looking for st->endc */ 2987 /* continue looking for st->endc */
2988 } else if (*next == st->endc) 2988 } else if (*next == st->endc)
2989 nest--; 2989 nest--;
2990 else if (*next == st->startc) 2990 else if (*next == st->startc)
2991 nest++; 2991 nest++;
2992 if (nest > 0) 2992 if (nest > 0)
2993 next++; 2993 next++;
2994 } 2994 }
2995 if (*next != st->endc || !eqFound) 2995 if (*next != st->endc || !eqFound)
2996 return AMR_UNKNOWN; 2996 return AMR_UNKNOWN;
2997 2997
2998 *pp = mod; 2998 *pp = mod;
2999 res = ParseModifierPart(pp, '=', st->eflags, st, 2999 res = ParseModifierPart(pp, '=', st->eflags, st,
3000 &lhs, NULL, NULL, NULL); 3000 &lhs, NULL, NULL, NULL);
3001 if (res != VPR_OK) 3001 if (res != VPR_OK)
3002 return AMR_CLEANUP; 3002 return AMR_CLEANUP;
3003 3003
3004 res = ParseModifierPart(pp, st->endc, st->eflags, st, 3004 res = ParseModifierPart(pp, st->endc, st->eflags, st,
3005 &rhs, NULL, NULL, NULL); 3005 &rhs, NULL, NULL, NULL);
3006 if (res != VPR_OK) 3006 if (res != VPR_OK)
3007 return AMR_CLEANUP; 3007 return AMR_CLEANUP;
3008 3008
3009 /* 3009 /*
3010 * SYSV modifications happen through the whole 3010 * SYSV modifications happen through the whole
3011 * string. Note the pattern is anchored at the end. 3011 * string. Note the pattern is anchored at the end.
3012 */ 3012 */
3013 (*pp)--; 3013 (*pp)--;
3014 if (lhs[0] == '\0' && st->val[0] == '\0') { 3014 if (lhs[0] == '\0' && st->val[0] == '\0') {
3015 st->newVal = st->val; /* special case */ 3015 st->newVal = st->val; /* special case */
3016 } else { 3016 } else {
3017 struct ModifyWord_SYSVSubstArgs args = {st->ctxt, lhs, rhs}; 3017 struct ModifyWord_SYSVSubstArgs args = {st->ctxt, lhs, rhs};
3018 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val, 3018 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val,
3019 ModifyWord_SYSVSubst, &args); 3019 ModifyWord_SYSVSubst, &args);
3020 } 3020 }
3021 free(lhs); 3021 free(lhs);
3022 free(rhs); 3022 free(rhs);
3023 return AMR_OK; 3023 return AMR_OK;
3024} 3024}
3025#endif 3025#endif
3026 3026
3027#ifdef SUNSHCMD 3027#ifdef SUNSHCMD
3028/* :sh */ 3028/* :sh */
3029static ApplyModifierResult 3029static ApplyModifierResult
3030ApplyModifier_SunShell(const char **pp, ApplyModifiersState *st) 3030ApplyModifier_SunShell(const char **pp, ApplyModifiersState *st)
3031{ 3031{
3032 const char *p = *pp; 3032 const char *p = *pp;
3033 if (p[1] == 'h' && (p[2] == st->endc || p[2] == ':')) { 3033 if (p[1] == 'h' && (p[2] == st->endc || p[2] == ':')) {
3034 if (st->eflags & VARE_WANTRES) { 3034 if (st->eflags & VARE_WANTRES) {
3035 const char *errfmt; 3035 const char *errfmt;
3036 st->newVal = Cmd_Exec(st->val, &errfmt); 3036 st->newVal = Cmd_Exec(st->val, &errfmt);
3037 if (errfmt) 3037 if (errfmt)
3038 Error(errfmt, st->val); 3038 Error(errfmt, st->val);
3039 } else 3039 } else
3040 st->newVal = emptyString; 3040 st->newVal = emptyString;
3041 *pp = p + 2; 3041 *pp = p + 2;
3042 return AMR_OK; 3042 return AMR_OK;
3043 } else 3043 } else
3044 return AMR_UNKNOWN; 3044 return AMR_UNKNOWN;
3045} 3045}
3046#endif 3046#endif
3047 3047
3048static void 3048static void
3049LogBeforeApply(const ApplyModifiersState *st, const char *mod, const char endc) 3049LogBeforeApply(const ApplyModifiersState *st, const char *mod, const char endc)
3050{ 3050{
3051 char eflags_str[VarEvalFlags_ToStringSize]; 3051 char eflags_str[VarEvalFlags_ToStringSize];
3052 char vflags_str[VarFlags_ToStringSize]; 3052 char vflags_str[VarFlags_ToStringSize];
3053 char exprflags_str[VarExprFlags_ToStringSize]; 3053 char exprflags_str[VarExprFlags_ToStringSize];
3054 Boolean is_single_char = mod[0] != '\0' && 3054 Boolean is_single_char = mod[0] != '\0' &&
3055 (mod[1] == endc || mod[1] == ':'); 3055 (mod[1] == endc || mod[1] == ':');
3056 3056
3057 /* At this point, only the first character of the modifier can 3057 /* At this point, only the first character of the modifier can
3058 * be used since the end of the modifier is not yet known. */ 3058 * be used since the end of the modifier is not yet known. */
3059 debug_printf("Applying ${%s:%c%s} to \"%s\" (%s, %s, %s)\n", 3059 debug_printf("Applying ${%s:%c%s} to \"%s\" (%s, %s, %s)\n",
3060 st->v->name, mod[0], is_single_char ? "" : "...", st->val, 3060 st->v->name, mod[0], is_single_char ? "" : "...", st->val,
3061 Enum_FlagsToString(eflags_str, sizeof eflags_str, 3061 Enum_FlagsToString(eflags_str, sizeof eflags_str,
3062 st->eflags, VarEvalFlags_ToStringSpecs), 3062 st->eflags, VarEvalFlags_ToStringSpecs),
3063 Enum_FlagsToString(vflags_str, sizeof vflags_str, 3063 Enum_FlagsToString(vflags_str, sizeof vflags_str,
3064 st->v->flags, VarFlags_ToStringSpecs), 3064 st->v->flags, VarFlags_ToStringSpecs),
3065 Enum_FlagsToString(exprflags_str, sizeof exprflags_str, 3065 Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
3066 st->exprFlags, 3066 st->exprFlags,
3067 VarExprFlags_ToStringSpecs)); 3067 VarExprFlags_ToStringSpecs));
3068} 3068}
3069 3069
3070static void 3070static void
3071LogAfterApply(ApplyModifiersState *st, const char *p, const char *mod) 3071LogAfterApply(ApplyModifiersState *st, const char *p, const char *mod)
3072{ 3072{
3073 char eflags_str[VarEvalFlags_ToStringSize]; 3073 char eflags_str[VarEvalFlags_ToStringSize];
3074 char vflags_str[VarFlags_ToStringSize]; 3074 char vflags_str[VarFlags_ToStringSize];
3075 char exprflags_str[VarExprFlags_ToStringSize]; 3075 char exprflags_str[VarExprFlags_ToStringSize];
3076 const char *quot = st->newVal == var_Error ? "" : "\""; 3076 const char *quot = st->newVal == var_Error ? "" : "\"";
3077 const char *newVal = st->newVal == var_Error ? "error" : st->newVal; 3077 const char *newVal = st->newVal == var_Error ? "error" : st->newVal;
3078 3078
3079 debug_printf("Result of ${%s:%.*s} is %s%s%s (%s, %s, %s)\n", 3079 debug_printf("Result of ${%s:%.*s} is %s%s%s (%s, %s, %s)\n",
3080 st->v->name, (int)(p - mod), mod, quot, newVal, quot, 3080 st->v->name, (int)(p - mod), mod, quot, newVal, quot,
3081 Enum_FlagsToString(eflags_str, sizeof eflags_str, 3081 Enum_FlagsToString(eflags_str, sizeof eflags_str,
3082 st->eflags, VarEvalFlags_ToStringSpecs), 3082 st->eflags, VarEvalFlags_ToStringSpecs),
3083 Enum_FlagsToString(vflags_str, sizeof vflags_str, 3083 Enum_FlagsToString(vflags_str, sizeof vflags_str,
3084 st->v->flags, VarFlags_ToStringSpecs), 3084 st->v->flags, VarFlags_ToStringSpecs),
3085 Enum_FlagsToString(exprflags_str, sizeof exprflags_str, 3085 Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
3086 st->exprFlags, 3086 st->exprFlags,
3087 VarExprFlags_ToStringSpecs)); 3087 VarExprFlags_ToStringSpecs));
3088} 3088}
3089 3089
3090static ApplyModifierResult 3090static ApplyModifierResult
3091ApplyModifier(const char **pp, ApplyModifiersState *st) 3091ApplyModifier(const char **pp, ApplyModifiersState *st)
3092{ 3092{
3093 switch (**pp) { 3093 switch (**pp) {
3094 case ':': 3094 case ':':
3095 return ApplyModifier_Assign(pp, st); 3095 return ApplyModifier_Assign(pp, st);
3096 case '@': 3096 case '@':
3097 return ApplyModifier_Loop(pp, st); 3097 return ApplyModifier_Loop(pp, st);
3098 case '_': 3098 case '_':
3099 return ApplyModifier_Remember(pp, st); 3099 return ApplyModifier_Remember(pp, st);
3100 case 'D': 3100 case 'D':
3101 case 'U': 3101 case 'U':
3102 return ApplyModifier_Defined(pp, st); 3102 return ApplyModifier_Defined(pp, st);
3103 case 'L': 3103 case 'L':
3104 return ApplyModifier_Literal(pp, st); 3104 return ApplyModifier_Literal(pp, st);
3105 case 'P': 3105 case 'P':
3106 return ApplyModifier_Path(pp, st); 3106 return ApplyModifier_Path(pp, st);
3107 case '!': 3107 case '!':
3108 return ApplyModifier_ShellCommand(pp, st); 3108 return ApplyModifier_ShellCommand(pp, st);
3109 case '[': 3109 case '[':
3110 return ApplyModifier_Words(pp, st); 3110 return ApplyModifier_Words(pp, st);
3111 case 'g': 3111 case 'g':
3112 return ApplyModifier_Gmtime(pp, st); 3112 return ApplyModifier_Gmtime(pp, st);
3113 case 'h': 3113 case 'h':
3114 return ApplyModifier_Hash(pp, st); 3114 return ApplyModifier_Hash(pp, st);
3115 case 'l': 3115 case 'l':
3116 return ApplyModifier_Localtime(pp, st); 3116 return ApplyModifier_Localtime(pp, st);
3117 case 't': 3117 case 't':
3118 return ApplyModifier_To(pp, st); 3118 return ApplyModifier_To(pp, st);
3119 case 'N': 3119 case 'N':
3120 case 'M': 3120 case 'M':
3121 return ApplyModifier_Match(pp, st); 3121 return ApplyModifier_Match(pp, st);
3122 case 'S': 3122 case 'S':
3123 return ApplyModifier_Subst(pp, st); 3123 return ApplyModifier_Subst(pp, st);
3124 case '?': 3124 case '?':
3125 return ApplyModifier_IfElse(pp, st); 3125 return ApplyModifier_IfElse(pp, st);
3126#ifndef NO_REGEX 3126#ifndef NO_REGEX
3127 case 'C': 3127 case 'C':
3128 return ApplyModifier_Regex(pp, st); 3128 return ApplyModifier_Regex(pp, st);
3129#endif 3129#endif
3130 case 'q': 3130 case 'q':
3131 case 'Q': 3131 case 'Q':
3132 return ApplyModifier_Quote(pp, st); 3132 return ApplyModifier_Quote(pp, st);
3133 case 'T': 3133 case 'T':
3134 return ApplyModifier_WordFunc(pp, st, ModifyWord_Tail); 3134 return ApplyModifier_WordFunc(pp, st, ModifyWord_Tail);
3135 case 'H': 3135 case 'H':
3136 return ApplyModifier_WordFunc(pp, st, ModifyWord_Head); 3136 return ApplyModifier_WordFunc(pp, st, ModifyWord_Head);
3137 case 'E': 3137 case 'E':
3138 return ApplyModifier_WordFunc(pp, st, ModifyWord_Suffix); 3138 return ApplyModifier_WordFunc(pp, st, ModifyWord_Suffix);
3139 case 'R': 3139 case 'R':
3140 return ApplyModifier_WordFunc(pp, st, ModifyWord_Root); 3140 return ApplyModifier_WordFunc(pp, st, ModifyWord_Root);
3141 case 'r': 3141 case 'r':
3142 return ApplyModifier_Range(pp, st); 3142 return ApplyModifier_Range(pp, st);
3143 case 'O': 3143 case 'O':
3144 return ApplyModifier_Order(pp, st); 3144 return ApplyModifier_Order(pp, st);
3145 case 'u': 3145 case 'u':
3146 return ApplyModifier_Unique(pp, st); 3146 return ApplyModifier_Unique(pp, st);
3147#ifdef SUNSHCMD 3147#ifdef SUNSHCMD
3148 case 's': 3148 case 's':
3149 return ApplyModifier_SunShell(pp, st); 3149 return ApplyModifier_SunShell(pp, st);
3150#endif 3150#endif
3151 default: 3151 default:
3152 return AMR_UNKNOWN; 3152 return AMR_UNKNOWN;
3153 } 3153 }
3154} 3154}
3155 3155
3156/* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */ 3156/* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */
3157static char * 3157static char *
3158ApplyModifiers( 3158ApplyModifiers(
3159 const char **pp, /* the parsing position, updated upon return */ 3159 const char **pp, /* the parsing position, updated upon return */
3160 char *val, /* the current value of the variable */ 3160 char *val, /* the current value of the variable */
3161 char const startc, /* '(' or '{', or '\0' for indirect modifiers */ 3161 char const startc, /* '(' or '{', or '\0' for indirect modifiers */
3162 char const endc, /* ')' or '}', or '\0' for indirect modifiers */ 3162 char const endc, /* ')' or '}', or '\0' for indirect modifiers */
3163 Var * const v, 3163 Var * const v,
3164 VarExprFlags *exprFlags, 3164 VarExprFlags *exprFlags,
3165 GNode * const ctxt, /* for looking up and modifying variables */ 3165 GNode * const ctxt, /* for looking up and modifying variables */
3166 VarEvalFlags const eflags, 3166 VarEvalFlags const eflags,
3167 void ** const freePtr /* free this after using the return value */ 3167 void ** const freePtr /* free this after using the return value */
3168) { 3168) {
3169 ApplyModifiersState st = { 3169 ApplyModifiersState st = {
3170 startc, endc, v, ctxt, eflags, val, 3170 startc, endc, v, ctxt, eflags, val,
3171 var_Error, /* .newVal */ 3171 var_Error, /* .newVal */
3172 ' ', /* .sep */ 3172 ' ', /* .sep */
3173 FALSE, /* .oneBigWord */ 3173 FALSE, /* .oneBigWord */
3174 *exprFlags /* .exprFlags */ 3174 *exprFlags /* .exprFlags */
3175 }; 3175 };
3176 const char *p; 3176 const char *p;
3177 const char *mod; 3177 const char *mod;
3178 ApplyModifierResult res; 3178 ApplyModifierResult res;
3179 3179
3180 assert(startc == '(' || startc == '{' || startc == '\0'); 3180 assert(startc == '(' || startc == '{' || startc == '\0');
3181 assert(endc == ')' || endc == '}' || endc == '\0'); 3181 assert(endc == ')' || endc == '}' || endc == '\0');
3182 assert(val != NULL); 3182 assert(val != NULL);
3183 3183
3184 p = *pp; 3184 p = *pp;
3185 while (*p != '\0' && *p != endc) { 3185 while (*p != '\0' && *p != endc) {
3186 3186
3187 if (*p == '$') { 3187 if (*p == '$') {
3188 /* 3188 /*
3189 * We may have some complex modifiers in a variable. 3189 * We may have some complex modifiers in a variable.
3190 */ 3190 */
3191 const char *nested_p = p; 3191 const char *nested_p = p;
3192 void *freeIt; 3192 void *freeIt;
3193 const char *rval; 3193 const char *rval;
3194 char c; 3194 char c;
3195 3195
3196 (void)Var_Parse(&nested_p, st.ctxt, st.eflags, &rval, &freeIt); 3196 (void)Var_Parse(&nested_p, st.ctxt, st.eflags, &rval, &freeIt);
3197 /* TODO: handle errors */ 3197 /* TODO: handle errors */
3198 3198
3199 /* 3199 /*
3200 * If we have not parsed up to st.endc or ':', we are not 3200 * If we have not parsed up to st.endc or ':', we are not
3201 * interested. This means the expression ${VAR:${M_1}${M_2}} 3201 * interested. This means the expression ${VAR:${M_1}${M_2}}
3202 * is not accepted, but ${VAR:${M_1}:${M_2}} is. 3202 * is not accepted, but ${VAR:${M_1}:${M_2}} is.
3203 */ 3203 */
3204 if (rval[0] != '\0' && 3204 if (rval[0] != '\0' &&
3205 (c = *nested_p) != '\0' && c != ':' && c != st.endc) { 3205 (c = *nested_p) != '\0' && c != ':' && c != st.endc) {
3206 if (DEBUG(LINT)) 3206 if (DEBUG(LINT))
3207 Parse_Error(PARSE_FATAL, 3207 Parse_Error(PARSE_FATAL,
3208 "Missing delimiter ':' after indirect modifier \"%.*s\"", 3208 "Missing delimiter ':' after indirect modifier \"%.*s\"",
3209 (int)(nested_p - p), p); 3209 (int)(nested_p - p), p);
3210 3210
3211 free(freeIt); 3211 free(freeIt);
3212 /* XXX: apply_mods doesn't sound like "not interested". */ 3212 /* XXX: apply_mods doesn't sound like "not interested". */
3213 /* XXX: Why is the indirect modifier parsed again by 3213 /* XXX: Why is the indirect modifier parsed again by
3214 * apply_mods? If any, p should be advanced to nested_p. */ 3214 * apply_mods? If any, p should be advanced to nested_p. */
3215 goto apply_mods; 3215 goto apply_mods;
3216 } 3216 }
3217 3217
3218 VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n", 3218 VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n",
3219 rval, (int)(size_t)(nested_p - p), p); 3219 rval, (int)(size_t)(nested_p - p), p);
3220 3220
3221 p = nested_p; 3221 p = nested_p;
3222 3222
3223 if (rval[0] != '\0') { 3223 if (rval[0] != '\0') {
3224 const char *rval_pp = rval; 3224 const char *rval_pp = rval;
3225 st.val = ApplyModifiers(&rval_pp, st.val, '\0', '\0', v, 3225 st.val = ApplyModifiers(&rval_pp, st.val, '\0', '\0', v,
3226 &st.exprFlags, ctxt, eflags, freePtr); 3226 &st.exprFlags, ctxt, eflags, freePtr);
3227 if (st.val == var_Error 3227 if (st.val == var_Error
3228 || (st.val == varUndefined && !(st.eflags & VARE_UNDEFERR)) 3228 || (st.val == varUndefined && !(st.eflags & VARE_UNDEFERR))
3229 || *rval_pp != '\0') { 3229 || *rval_pp != '\0') {
3230 free(freeIt); 3230 free(freeIt);
3231 goto out; /* error already reported */ 3231 goto out; /* error already reported */
3232 } 3232 }
3233 } 3233 }
3234 free(freeIt); 3234 free(freeIt);
3235 3235
3236 if (*p == ':') 3236 if (*p == ':')
3237 p++; 3237 p++;
3238 else if (*p == '\0' && endc != '\0') { 3238 else if (*p == '\0' && endc != '\0') {
3239 Error("Unclosed variable specification after complex " 3239 Error("Unclosed variable specification after complex "
3240 "modifier (expecting '%c') for %s", st.endc, st.v->name); 3240 "modifier (expecting '%c') for %s", st.endc, st.v->name);
3241 goto out; 3241 goto out;
3242 } 3242 }
3243 continue; 3243 continue;
3244 } 3244 }
3245 apply_mods: 3245 apply_mods:
3246 st.newVal = var_Error; /* default value, in case of errors */ 3246 st.newVal = var_Error; /* default value, in case of errors */
3247 mod = p; 3247 mod = p;
3248 3248
3249 if (DEBUG(VAR)) 3249 if (DEBUG(VAR))
3250 LogBeforeApply(&st, mod, endc); 3250 LogBeforeApply(&st, mod, endc);
3251 3251
3252 res = ApplyModifier(&p, &st); 3252 res = ApplyModifier(&p, &st);
3253 3253
3254#ifdef SYSVVARSUB 3254#ifdef SYSVVARSUB
3255 if (res == AMR_UNKNOWN) { 3255 if (res == AMR_UNKNOWN) {
3256 assert(p == mod); 3256 assert(p == mod);
3257 res = ApplyModifier_SysV(&p, &st); 3257 res = ApplyModifier_SysV(&p, &st);
3258 } 3258 }
3259#endif 3259#endif
3260 3260
3261 if (res == AMR_UNKNOWN) { 3261 if (res == AMR_UNKNOWN) {
3262 Error("Unknown modifier '%c'", *mod); 3262 Error("Unknown modifier '%c'", *mod);
3263 for (p++; *p != ':' && *p != st.endc && *p != '\0'; p++) 3263 for (p++; *p != ':' && *p != st.endc && *p != '\0'; p++)
3264 continue; 3264 continue;
3265 st.newVal = var_Error; 3265 st.newVal = var_Error;
3266 } 3266 }
3267 if (res == AMR_CLEANUP) 3267 if (res == AMR_CLEANUP)
3268 goto cleanup; 3268 goto cleanup;
3269 if (res == AMR_BAD) 3269 if (res == AMR_BAD)
3270 goto bad_modifier; 3270 goto bad_modifier;
3271 3271
3272 if (DEBUG(VAR)) 3272 if (DEBUG(VAR))
3273 LogAfterApply(&st, p, mod); 3273 LogAfterApply(&st, p, mod);
3274 3274
3275 if (st.newVal != st.val) { 3275 if (st.newVal != st.val) {
3276 if (*freePtr) { 3276 if (*freePtr) {
3277 free(st.val); 3277 free(st.val);
3278 *freePtr = NULL; 3278 *freePtr = NULL;
3279 } 3279 }
3280 st.val = st.newVal; 3280 st.val = st.newVal;
3281 if (st.val != var_Error && st.val != varUndefined && 3281 if (st.val != var_Error && st.val != varUndefined &&
3282 st.val != emptyString) { 3282 st.val != emptyString) {
3283 *freePtr = st.val; 3283 *freePtr = st.val;
3284 } 3284 }
3285 } 3285 }
3286 if (*p == '\0' && st.endc != '\0') { 3286 if (*p == '\0' && st.endc != '\0') {
3287 Error("Unclosed variable specification (expecting '%c') " 3287 Error("Unclosed variable specification (expecting '%c') "
3288 "for \"%s\" (value \"%s\") modifier %c", 3288 "for \"%s\" (value \"%s\") modifier %c",
3289 st.endc, st.v->name, st.val, *mod); 3289 st.endc, st.v->name, st.val, *mod);
3290 } else if (*p == ':') { 3290 } else if (*p == ':') {
3291 p++; 3291 p++;
3292 } else if (DEBUG(LINT) && *p != '\0' && *p != endc) { 3292 } else if (DEBUG(LINT) && *p != '\0' && *p != endc) {
3293 Parse_Error(PARSE_FATAL, 3293 Parse_Error(PARSE_FATAL,
3294 "Missing delimiter ':' after modifier \"%.*s\"", 3294 "Missing delimiter ':' after modifier \"%.*s\"",
3295 (int)(p - mod), mod); 3295 (int)(p - mod), mod);
3296 } 3296 }
3297 } 3297 }
3298out: 3298out:
3299 *pp = p; 3299 *pp = p;
3300 assert(st.val != NULL); /* Use var_Error or varUndefined instead. */ 3300 assert(st.val != NULL); /* Use var_Error or varUndefined instead. */
3301 *exprFlags = st.exprFlags; 3301 *exprFlags = st.exprFlags;
3302 return st.val; 3302 return st.val;
3303 3303
3304bad_modifier: 3304bad_modifier:
3305 Error("Bad modifier `:%.*s' for %s", 3305 Error("Bad modifier `:%.*s' for %s",
3306 (int)strcspn(mod, ":)}"), mod, st.v->name); 3306 (int)strcspn(mod, ":)}"), mod, st.v->name);
3307 3307
3308cleanup: 3308cleanup:
3309 *pp = p; 3309 *pp = p;
3310 free(*freePtr); 3310 free(*freePtr);
3311 *freePtr = NULL; 3311 *freePtr = NULL;
3312 *exprFlags = st.exprFlags; 3312 *exprFlags = st.exprFlags;
3313 return var_Error; 3313 return var_Error;
3314} 3314}
3315 3315
3316static Boolean 3316static Boolean
3317VarIsDynamic(GNode *ctxt, const char *varname, size_t namelen) 3317VarIsDynamic(GNode *ctxt, const char *varname, size_t namelen)
3318{ 3318{
3319 if ((namelen == 1 || 3319 if ((namelen == 1 ||
3320 (namelen == 2 && (varname[1] == 'F' || varname[1] == 'D'))) && 3320 (namelen == 2 && (varname[1] == 'F' || varname[1] == 'D'))) &&
3321 (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL)) 3321 (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL))
3322 { 3322 {
3323 /* 3323 /*
3324 * If substituting a local variable in a non-local context, 3324 * If substituting a local variable in a non-local context,
3325 * assume it's for dynamic source stuff. We have to handle 3325 * assume it's for dynamic source stuff. We have to handle
3326 * this specially and return the longhand for the variable 3326 * this specially and return the longhand for the variable
3327 * with the dollar sign escaped so it makes it back to the 3327 * with the dollar sign escaped so it makes it back to the
3328 * caller. Only four of the local variables are treated 3328 * caller. Only four of the local variables are treated
3329 * specially as they are the only four that will be set 3329 * specially as they are the only four that will be set
3330 * when dynamic sources are expanded. 3330 * when dynamic sources are expanded.
3331 */ 3331 */
3332 switch (varname[0]) { 3332 switch (varname[0]) {
3333 case '@': 3333 case '@':
3334 case '%': 3334 case '%':
3335 case '*': 3335 case '*':
3336 case '!': 3336 case '!':
3337 return TRUE; 3337 return TRUE;
3338 } 3338 }
3339 return FALSE; 3339 return FALSE;
3340 } 3340 }
3341 3341
3342 if ((namelen == 7 || namelen == 8) && varname[0] == '.' && 3342 if ((namelen == 7 || namelen == 8) && varname[0] == '.' &&
3343 ch_isupper(varname[1]) && (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL)) 3343 ch_isupper(varname[1]) && (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL))
3344 { 3344 {
3345 return strcmp(varname, ".TARGET") == 0 || 3345 return strcmp(varname, ".TARGET") == 0 ||
3346 strcmp(varname, ".ARCHIVE") == 0 || 3346 strcmp(varname, ".ARCHIVE") == 0 ||
3347 strcmp(varname, ".PREFIX") == 0 || 3347 strcmp(varname, ".PREFIX") == 0 ||
3348 strcmp(varname, ".MEMBER") == 0; 3348 strcmp(varname, ".MEMBER") == 0;
3349 } 3349 }
3350 3350
3351 return FALSE; 3351 return FALSE;
3352} 3352}
3353 3353
3354static const char * 3354static const char *
3355UndefinedShortVarValue(char varname, const GNode *ctxt, VarEvalFlags eflags) 3355UndefinedShortVarValue(char varname, const GNode *ctxt, VarEvalFlags eflags)
3356{ 3356{
3357 if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) { 3357 if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) {
3358 /* 3358 /*
3359 * If substituting a local variable in a non-local context, 3359 * If substituting a local variable in a non-local context,
3360 * assume it's for dynamic source stuff. We have to handle 3360 * assume it's for dynamic source stuff. We have to handle
3361 * this specially and return the longhand for the variable 3361 * this specially and return the longhand for the variable
3362 * with the dollar sign escaped so it makes it back to the 3362 * with the dollar sign escaped so it makes it back to the
3363 * caller. Only four of the local variables are treated 3363 * caller. Only four of the local variables are treated
3364 * specially as they are the only four that will be set 3364 * specially as they are the only four that will be set
3365 * when dynamic sources are expanded. 3365 * when dynamic sources are expanded.
3366 */ 3366 */
3367 switch (varname) { 3367 switch (varname) {
3368 case '@': 3368 case '@':
3369 return "$(.TARGET)"; 3369 return "$(.TARGET)";
3370 case '%': 3370 case '%':
3371 return "$(.MEMBER)"; 3371 return "$(.MEMBER)";
3372 case '*': 3372 case '*':
3373 return "$(.PREFIX)"; 3373 return "$(.PREFIX)";
3374 case '!': 3374 case '!':
3375 return "$(.ARCHIVE)"; 3375 return "$(.ARCHIVE)";
3376 } 3376 }
3377 } 3377 }
3378 return eflags & VARE_UNDEFERR ? var_Error : varUndefined; 3378 return eflags & VARE_UNDEFERR ? var_Error : varUndefined;
3379} 3379}
3380 3380
3381/* Parse a variable name, until the end character or a colon, whichever 3381/* Parse a variable name, until the end character or a colon, whichever
3382 * comes first. */ 3382 * comes first. */
3383static char * 3383static char *
3384ParseVarname(const char **pp, char startc, char endc, 3384ParseVarname(const char **pp, char startc, char endc,
3385 GNode *ctxt, VarEvalFlags eflags, 3385 GNode *ctxt, VarEvalFlags eflags,
3386 size_t *out_varname_len) 3386 size_t *out_varname_len)
3387{ 3387{
3388 Buffer buf; 3388 Buffer buf;
3389 const char *p = *pp; 3389 const char *p = *pp;
3390 int depth = 1; 3390 int depth = 1;
3391 3391
3392 Buf_Init(&buf, 0); 3392 Buf_Init(&buf, 0);
3393 3393
3394 while (*p != '\0') { 3394 while (*p != '\0') {
3395 /* Track depth so we can spot parse errors. */ 3395 /* Track depth so we can spot parse errors. */
3396 if (*p == startc) 3396 if (*p == startc)
3397 depth++; 3397 depth++;
3398 if (*p == endc) { 3398 if (*p == endc) {
3399 if (--depth == 0) 3399 if (--depth == 0)
3400 break; 3400 break;
3401 } 3401 }
3402 if (*p == ':' && depth == 1) 3402 if (*p == ':' && depth == 1)
3403 break; 3403 break;
3404 3404
3405 /* A variable inside a variable, expand. */ 3405 /* A variable inside a variable, expand. */
3406 if (*p == '$') { 3406 if (*p == '$') {
3407 void *freeIt; 3407 void *freeIt;
3408 const char *rval; 3408 const char *rval;
3409 (void)Var_Parse(&p, ctxt, eflags, &rval, &freeIt); 3409 (void)Var_Parse(&p, ctxt, eflags, &rval, &freeIt);
3410 /* TODO: handle errors */ 3410 /* TODO: handle errors */
3411 Buf_AddStr(&buf, rval); 3411 Buf_AddStr(&buf, rval);
3412 free(freeIt); 3412 free(freeIt);
3413 } else { 3413 } else {
3414 Buf_AddByte(&buf, *p); 3414 Buf_AddByte(&buf, *p);
3415 p++; 3415 p++;
3416 } 3416 }
3417 } 3417 }
3418 *pp = p; 3418 *pp = p;
3419 *out_varname_len = Buf_Len(&buf); 3419 *out_varname_len = Buf_Len(&buf);
3420 return Buf_Destroy(&buf, FALSE); 3420 return Buf_Destroy(&buf, FALSE);
3421} 3421}
3422 3422
3423static Boolean 3423static Boolean
3424ValidShortVarname(char varname, const char *start) 3424ValidShortVarname(char varname, const char *start)
3425{ 3425{
3426 switch (varname) { 3426 switch (varname) {
3427 case '\0': 3427 case '\0':
3428 case ')': 3428 case ')':
3429 case '}': 3429 case '}':
3430 case ':': 3430 case ':':
3431 case '$': 3431 case '$':
3432 break; /* and continue below */ 3432 break; /* and continue below */
3433 default: 3433 default:
3434 return TRUE; 3434 return TRUE;
3435 } 3435 }
3436 3436
3437 if (!DEBUG(LINT)) 3437 if (!DEBUG(LINT))
3438 return FALSE; 3438 return FALSE;
3439 3439
3440 if (varname == '$') 3440 if (varname == '$')
3441 Parse_Error(PARSE_FATAL, 3441 Parse_Error(PARSE_FATAL,
3442 "To escape a dollar, use \\$, not $$, at \"%s\"", start); 3442 "To escape a dollar, use \\$, not $$, at \"%s\"", start);
3443 else if (varname == '\0') 3443 else if (varname == '\0')
3444 Parse_Error(PARSE_FATAL, "Dollar followed by nothing"); 3444 Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
3445 else 3445 else
3446 Parse_Error(PARSE_FATAL, 3446 Parse_Error(PARSE_FATAL,
3447 "Invalid variable name '%c', at \"%s\"", varname, start); 3447 "Invalid variable name '%c', at \"%s\"", varname, start);
3448 3448
3449 return FALSE; 3449 return FALSE;
3450} 3450}
3451 3451
3452/*- 3452/*-
3453 *----------------------------------------------------------------------- 3453 *-----------------------------------------------------------------------
3454 * Var_Parse -- 3454 * Var_Parse --
3455 * Given the start of a variable expression (such as $v, $(VAR), 3455 * Given the start of a variable expression (such as $v, $(VAR),
3456 * ${VAR:Mpattern}), extract the variable name, possibly some 3456 * ${VAR:Mpattern}), extract the variable name, possibly some
3457 * modifiers and find its value by applying the modifiers to the 3457 * modifiers and find its value by applying the modifiers to the
3458 * original value. 3458 * original value.
3459 * 3459 *
3460 * When parsing a condition in ParseEmptyArg, pp may also point to 3460 * When parsing a condition in ParseEmptyArg, pp may also point to
3461 * the "y" of "empty(VARNAME:Modifiers)", which is syntactically 3461 * the "y" of "empty(VARNAME:Modifiers)", which is syntactically
3462 * identical. 3462 * identical.
3463 * 3463 *
3464 * Input: 3464 * Input:
3465 * str The string to parse 3465 * str The string to parse
3466 * ctxt The context for the variable 3466 * ctxt The context for the variable
3467 * flags VARE_UNDEFERR if undefineds are an error 3467 * flags VARE_UNDEFERR if undefineds are an error
3468 * VARE_WANTRES if we actually want the result 3468 * VARE_WANTRES if we actually want the result
3469 * VARE_ASSIGN if we are in a := assignment 3469 * VARE_ASSIGN if we are in a := assignment
3470 * lengthPtr OUT: The length of the specification 3470 * lengthPtr OUT: The length of the specification
3471 * freePtr OUT: Non-NULL if caller should free *freePtr 3471 * freePtr OUT: Non-NULL if caller should free *freePtr
3472 * 3472 *
3473 * Results: 3473 * Results:
3474 * Returns the value of the variable expression, never NULL. 3474 * Returns the value of the variable expression, never NULL.
3475 * Returns var_Error if there was a parse error and VARE_UNDEFERR was 3475 * Returns var_Error if there was a parse error and VARE_UNDEFERR was
3476 * set. 3476 * set.
3477 * Returns varUndefined if there was an undefined variable and 3477 * Returns varUndefined if there was an undefined variable and
3478 * VARE_UNDEFERR was not set. 3478 * VARE_UNDEFERR was not set.
3479 * 3479 *
3480 * Parsing should continue at *pp. 3480 * Parsing should continue at *pp.
3481 * TODO: Document the value of *pp on parse errors. It might be advanced 3481 * TODO: Document the value of *pp on parse errors. It might be advanced
3482 * by 0, or +1, or the index of the parse error, or the guessed end of the 3482 * by 0, or +1, or the index of the parse error, or the guessed end of the
3483 * variable expression. 3483 * variable expression.
3484 * 3484 *
3485 * If var_Error is returned, a diagnostic may or may not have been 3485 * If var_Error is returned, a diagnostic may or may not have been
3486 * printed. XXX: This is inconsistent. 3486 * printed. XXX: This is inconsistent.
3487 * 3487 *
3488 * If varUndefined is returned, a diagnostic may or may not have been 3488 * If varUndefined is returned, a diagnostic may or may not have been
3489 * printed. XXX: This is inconsistent. 3489 * printed. XXX: This is inconsistent.
3490 * 3490 *
3491 * After using the returned value, *freePtr must be freed, preferably 3491 * After using the returned value, *freePtr must be freed, preferably
3492 * using bmake_free since it is NULL in most cases. 3492 * using bmake_free since it is NULL in most cases.
3493 * 3493 *
3494 * Side Effects: 3494 * Side Effects:
3495 * Any effects from the modifiers, such as :!cmd! or ::=value. 3495 * Any effects from the modifiers, such as :!cmd! or ::=value.
3496 *----------------------------------------------------------------------- 3496 *-----------------------------------------------------------------------
3497 */ 3497 */
3498/* coverity[+alloc : arg-*4] */ 3498/* coverity[+alloc : arg-*4] */
3499VarParseResult 3499VarParseResult
3500Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags, 3500Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags,
3501 const char **out_val, void **freePtr) 3501 const char **out_val, void **freePtr)
3502{ 3502{
3503 const char *const start = *pp; 3503 const char *const start = *pp;
3504 const char *p; 3504 const char *p;
3505 Boolean haveModifier; /* TRUE if have modifiers for the variable */ 3505 Boolean haveModifier; /* TRUE if have modifiers for the variable */
3506 char startc; /* Starting character if variable in parens 3506 char startc; /* Starting character if variable in parens
3507 * or braces */ 3507 * or braces */
3508 char endc; /* Ending character if variable in parens 3508 char endc; /* Ending character if variable in parens
3509 * or braces */ 3509 * or braces */
3510 Boolean dynamic; /* TRUE if the variable is local and we're 3510 Boolean dynamic; /* TRUE if the variable is local and we're
3511 * expanding it in a non-local context. This 3511 * expanding it in a non-local context. This
3512 * is done to support dynamic sources. The 3512 * is done to support dynamic sources. The
3513 * result is just the expression, unaltered */ 3513 * result is just the expression, unaltered */
3514 const char *extramodifiers; 3514 const char *extramodifiers;
3515 Var *v; 3515 Var *v;
3516 char *nstr; 3516 char *nstr;
3517 char eflags_str[VarEvalFlags_ToStringSize]; 3517 char eflags_str[VarEvalFlags_ToStringSize];
3518 VarExprFlags exprFlags = 0; 3518 VarExprFlags exprFlags = 0;
3519 3519
3520 VAR_DEBUG3("%s: %s with %s\n", __func__, start, 3520 VAR_DEBUG3("%s: %s with %s\n", __func__, start,
3521 Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags, 3521 Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags,
3522 VarEvalFlags_ToStringSpecs)); 3522 VarEvalFlags_ToStringSpecs));
3523 3523
3524 *freePtr = NULL; 3524 *freePtr = NULL;
3525 extramodifiers = NULL; /* extra modifiers to apply first */ 3525 extramodifiers = NULL; /* extra modifiers to apply first */
3526 dynamic = FALSE; 3526 dynamic = FALSE;
3527 3527
3528 /* Appease GCC, which thinks that the variable might not be 3528 /* Appease GCC, which thinks that the variable might not be
3529 * initialized. */ 3529 * initialized. */
3530 endc = '\0'; 3530 endc = '\0';
3531 3531
3532 startc = start[1]; 3532 startc = start[1];
3533 if (startc != '(' && startc != '{') { 3533 if (startc != '(' && startc != '{') {
3534 char name[2]; 3534 char name[2];
3535 3535
3536 /* 3536 /*
3537 * If it's not bounded by braces of some sort, life is much simpler. 3537 * If it's not bounded by braces of some sort, life is much simpler.
3538 * We just need to check for the first character and return the 3538 * We just need to check for the first character and return the
3539 * value if it exists. 3539 * value if it exists.
3540 */ 3540 */
3541 3541
3542 if (!ValidShortVarname(startc, start)) { 3542 if (!ValidShortVarname(startc, start)) {
3543 (*pp)++; 3543 (*pp)++;
3544 *out_val = var_Error; 3544 *out_val = var_Error;
3545 return VPR_PARSE_MSG; 3545 return VPR_PARSE_MSG;
3546 } 3546 }
3547 3547
3548 name[0] = startc; 3548 name[0] = startc;
3549 name[1] = '\0'; 3549 name[1] = '\0';
3550 v = VarFind(name, ctxt, TRUE); 3550 v = VarFind(name, ctxt, TRUE);
3551 if (v == NULL) { 3551 if (v == NULL) {
3552 *pp += 2; 3552 *pp += 2;
3553 3553
3554 *out_val = UndefinedShortVarValue(startc, ctxt, eflags); 3554 *out_val = UndefinedShortVarValue(startc, ctxt, eflags);
3555 if (DEBUG(LINT) && *out_val == var_Error) { 3555 if (DEBUG(LINT) && *out_val == var_Error) {
3556 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name); 3556 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name);
3557 return VPR_UNDEF_MSG; 3557 return VPR_UNDEF_MSG;
3558 } 3558 }
3559 return eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK; 3559 return eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK;
3560 } else { 3560 } else {
3561 haveModifier = FALSE; 3561 haveModifier = FALSE;
3562 p = start + 1; 3562 p = start + 1;
3563 } 3563 }
3564 } else { 3564 } else {
3565 size_t namelen; 3565 size_t namelen;
3566 char *varname; 3566 char *varname;
3567 3567
3568 endc = startc == '(' ? ')' : '}'; 3568 endc = startc == '(' ? ')' : '}';
3569 3569
3570 p = start + 2; 3570 p = start + 2;
3571 varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen); 3571 varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen);
3572 3572
3573 if (*p == ':') { 3573 if (*p == ':') {
3574 haveModifier = TRUE; 3574 haveModifier = TRUE;
3575 } else if (*p == endc) { 3575 } else if (*p == endc) {
3576 haveModifier = FALSE; 3576 haveModifier = FALSE;
3577 } else { 3577 } else {
3578 Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname); 3578 Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname);
3579 *pp = p; 3579 *pp = p;
3580 free(varname); 3580 free(varname);
3581 *out_val = var_Error; 3581 *out_val = var_Error;
3582 return VPR_PARSE_MSG; 3582 return VPR_PARSE_MSG;
3583 } 3583 }
3584 3584
3585 v = VarFind(varname, ctxt, TRUE); 3585 v = VarFind(varname, ctxt, TRUE);
3586 3586
3587 /* At this point, p points just after the variable name, 3587 /* At this point, p points just after the variable name,
3588 * either at ':' or at endc. */ 3588 * either at ':' or at endc. */
3589 3589
3590 /* 3590 /*
3591 * Check also for bogus D and F forms of local variables since we're 3591 * Check also for bogus D and F forms of local variables since we're
3592 * in a local context and the name is the right length. 3592 * in a local context and the name is the right length.
3593 */ 3593 */
3594 if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL && 3594 if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL &&
3595 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') && 3595 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') &&
3596 strchr("@%?*!<>", varname[0]) != NULL) 3596 strchr("@%?*!<>", varname[0]) != NULL)
3597 { 3597 {
3598 /* 3598 /*
3599 * Well, it's local -- go look for it. 3599 * Well, it's local -- go look for it.
3600 */ 3600 */
3601 char name[] = { varname[0], '\0' }; 3601 char name[] = { varname[0], '\0' };
3602 v = VarFind(name, ctxt, 0); 3602 v = VarFind(name, ctxt, 0);
3603 3603
3604 if (v != NULL) { 3604 if (v != NULL) {
3605 if (varname[1] == 'D') { 3605 if (varname[1] == 'D') {
3606 extramodifiers = "H:"; 3606 extramodifiers = "H:";
3607 } else { /* F */ 3607 } else { /* F */
3608 extramodifiers = "T:"; 3608 extramodifiers = "T:";
3609 } 3609 }
3610 } 3610 }
3611 } 3611 }
3612 3612
3613 if (v == NULL) { 3613 if (v == NULL) {
3614 dynamic = VarIsDynamic(ctxt, varname, namelen); 3614 dynamic = VarIsDynamic(ctxt, varname, namelen);
3615 3615
3616 if (!haveModifier) { 3616 if (!haveModifier) {
3617 p++; /* skip endc */ 3617 p++; /* skip endc */
3618 *pp = p; 3618 *pp = p;
3619 if (dynamic) { 3619 if (dynamic) {
3620 char *pstr = bmake_strsedup(start, p); 3620 char *pstr = bmake_strsedup(start, p);
3621 *freePtr = pstr; 3621 *freePtr = pstr;
3622 free(varname); 3622 free(varname);
3623 *out_val = pstr; 3623 *out_val = pstr;
3624 return VPR_OK; 3624 return VPR_OK;
3625 } 3625 }
3626 3626
3627 if ((eflags & VARE_UNDEFERR) && (eflags & VARE_WANTRES) && 3627 if ((eflags & VARE_UNDEFERR) && (eflags & VARE_WANTRES) &&
3628 DEBUG(LINT)) 3628 DEBUG(LINT))
3629 { 3629 {
3630 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", 3630 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined",
3631 varname); 3631 varname);
3632 free(varname); 3632 free(varname);
3633 *out_val = var_Error; 3633 *out_val = var_Error;
3634 return VPR_UNDEF_MSG; 3634 return VPR_UNDEF_MSG;
3635 } 3635 }
3636 3636
3637 if (eflags & VARE_UNDEFERR) { 3637 if (eflags & VARE_UNDEFERR) {
3638 free(varname); 3638 free(varname);
3639 *out_val = var_Error; 3639 *out_val = var_Error;
3640 return VPR_UNDEF_SILENT; 3640 return VPR_UNDEF_SILENT;
3641 } 3641 }
3642 3642
3643 free(varname); 3643 free(varname);
3644 *out_val = varUndefined; 3644 *out_val = varUndefined;
3645 return VPR_OK; 3645 return VPR_OK;
3646 } 3646 }
3647 3647
3648 /* The variable expression is based on an undefined variable. 3648 /* The variable expression is based on an undefined variable.
3649 * Nevertheless it needs a Var, for modifiers that access the 3649 * Nevertheless it needs a Var, for modifiers that access the
3650 * variable name, such as :L or :?. 3650 * variable name, such as :L or :?.
3651 * 3651 *
3652 * Most modifiers leave this expression in the "undefined" state 3652 * Most modifiers leave this expression in the "undefined" state
3653 * (VEF_UNDEF), only a few modifiers like :D, :U, :L, :P turn this 3653 * (VEF_UNDEF), only a few modifiers like :D, :U, :L, :P turn this
3654 * undefined expression into a defined expression (VEF_DEF). 3654 * undefined expression into a defined expression (VEF_DEF).
3655 * 3655 *
3656 * At the end, after applying all modifiers, if the expression 3656 * At the end, after applying all modifiers, if the expression
3657 * is still undefined, Var_Parse will return an empty string 3657 * is still undefined, Var_Parse will return an empty string
3658 * instead of the actually computed value. */ 3658 * instead of the actually computed value. */
3659 v = VarNew(varname, varname, "", 0); 3659 v = VarNew(varname, varname, "", 0);
3660 exprFlags = VEF_UNDEF; 3660 exprFlags = VEF_UNDEF;
3661 } else 3661 } else
3662 free(varname); 3662 free(varname);
3663 } 3663 }
3664 3664
3665 if (v->flags & VAR_IN_USE) { 3665 if (v->flags & VAR_IN_USE)
3666 Fatal("Variable %s is recursive.", v->name); 3666 Fatal("Variable %s is recursive.", v->name);
3667 /*NOTREACHED*/ 
3668 } else { 
3669 v->flags |= VAR_IN_USE; 
3670 } 
3671 3667
3672 /* 3668 /*
3673 * Before doing any modification, we have to make sure the value 3669 * Before doing any modification, we have to make sure the value
3674 * has been fully expanded. If it looks like recursion might be 3670 * has been fully expanded. If it looks like recursion might be
3675 * necessary (there's a dollar sign somewhere in the variable's value) 3671 * necessary (there's a dollar sign somewhere in the variable's value)
3676 * we just call Var_Subst to do any other substitutions that are 3672 * we just call Var_Subst to do any other substitutions that are
3677 * necessary. Note that the value returned by Var_Subst will have 3673 * necessary. Note that the value returned by Var_Subst will have
3678 * been dynamically-allocated, so it will need freeing when we 3674 * been dynamically-allocated, so it will need freeing when we
3679 * return. 3675 * return.
3680 */ 3676 */
3681 nstr = Buf_GetAll(&v->val, NULL); 3677 nstr = Buf_GetAll(&v->val, NULL);
3682 if (strchr(nstr, '$') != NULL && (eflags & VARE_WANTRES)) { 3678 if (strchr(nstr, '$') != NULL && (eflags & VARE_WANTRES)) {
3683 VarEvalFlags nested_eflags = eflags; 3679 VarEvalFlags nested_eflags = eflags;
3684 if (DEBUG(LINT)) 3680 if (DEBUG(LINT))
3685 nested_eflags &= ~(unsigned)VARE_UNDEFERR; 3681 nested_eflags &= ~(unsigned)VARE_UNDEFERR;
 3682 v->flags |= VAR_IN_USE;
3686 (void)Var_Subst(nstr, ctxt, nested_eflags, &nstr); 3683 (void)Var_Subst(nstr, ctxt, nested_eflags, &nstr);
 3684 v->flags &= ~(unsigned)VAR_IN_USE;
3687 /* TODO: handle errors */ 3685 /* TODO: handle errors */
3688 *freePtr = nstr; 3686 *freePtr = nstr;
3689 } 3687 }
3690 3688
3691 v->flags &= ~(unsigned)VAR_IN_USE; 
3692 
3693 if (haveModifier || extramodifiers != NULL) { 3689 if (haveModifier || extramodifiers != NULL) {
3694 void *extraFree; 3690 void *extraFree;
3695 3691
3696 extraFree = NULL; 3692 extraFree = NULL;
3697 if (extramodifiers != NULL) { 3693 if (extramodifiers != NULL) {
3698 const char *em = extramodifiers; 3694 const char *em = extramodifiers;
3699 nstr = ApplyModifiers(&em, nstr, '(', ')', 3695 nstr = ApplyModifiers(&em, nstr, '(', ')',
3700 v, &exprFlags, ctxt, eflags, &extraFree); 3696 v, &exprFlags, ctxt, eflags, &extraFree);
3701 } 3697 }
3702 3698
3703 if (haveModifier) { 3699 if (haveModifier) {
3704 /* Skip initial colon. */ 3700 /* Skip initial colon. */
3705 p++; 3701 p++;
3706 3702
3707 nstr = ApplyModifiers(&p, nstr, startc, endc, 3703 nstr = ApplyModifiers(&p, nstr, startc, endc,
3708 v, &exprFlags, ctxt, eflags, freePtr); 3704 v, &exprFlags, ctxt, eflags, freePtr);
3709 free(extraFree); 3705 free(extraFree);
3710 } else { 3706 } else {
3711 *freePtr = extraFree; 3707 *freePtr = extraFree;
3712 } 3708 }
3713 } 3709 }
3714 3710
3715 if (*p != '\0') /* Skip past endc if possible. */ 3711 if (*p != '\0') /* Skip past endc if possible. */
3716 p++; 3712 p++;
3717 3713
3718 *pp = p; 3714 *pp = p;
3719 3715
3720 if (v->flags & VAR_FROM_ENV) { 3716 if (v->flags & VAR_FROM_ENV) {
3721 /* Free the environment variable now since we own it, 3717 /* Free the environment variable now since we own it,
3722 * but don't free the variable value if it will be returned. */ 3718 * but don't free the variable value if it will be returned. */
3723 Boolean keepValue = nstr == Buf_GetAll(&v->val, NULL); 3719 Boolean keepValue = nstr == Buf_GetAll(&v->val, NULL);
3724 if (keepValue) 3720 if (keepValue)
3725 *freePtr = nstr; 3721 *freePtr = nstr;
3726 (void)VarFreeEnv(v, !keepValue); 3722 (void)VarFreeEnv(v, !keepValue);
3727 3723
3728 } else if (exprFlags & VEF_UNDEF) { 3724 } else if (exprFlags & VEF_UNDEF) {
3729 if (!(exprFlags & VEF_DEF)) { 3725 if (!(exprFlags & VEF_DEF)) {
3730 if (*freePtr != NULL) { 3726 if (*freePtr != NULL) {
3731 free(*freePtr); 3727 free(*freePtr);
3732 *freePtr = NULL; 3728 *freePtr = NULL;
3733 } 3729 }
3734 if (dynamic) { 3730 if (dynamic) {
3735 nstr = bmake_strsedup(start, p); 3731 nstr = bmake_strsedup(start, p);
3736 *freePtr = nstr; 3732 *freePtr = nstr;
3737 } else { 3733 } else {
3738 /* The expression is still undefined, therefore discard the 3734 /* The expression is still undefined, therefore discard the
3739 * actual value and return an error marker instead. */ 3735 * actual value and return an error marker instead. */
3740 nstr = (eflags & VARE_UNDEFERR) ? var_Error : varUndefined; 3736 nstr = (eflags & VARE_UNDEFERR) ? var_Error : varUndefined;
3741 } 3737 }
3742 } 3738 }
3743 if (nstr != Buf_GetAll(&v->val, NULL)) 3739 if (nstr != Buf_GetAll(&v->val, NULL))
3744 Buf_Destroy(&v->val, TRUE); 3740 Buf_Destroy(&v->val, TRUE);
3745 free(v->name_freeIt); 3741 free(v->name_freeIt);
3746 free(v); 3742 free(v);
3747 } 3743 }
3748 *out_val = nstr; 3744 *out_val = nstr;
3749 return VPR_UNKNOWN; 3745 return VPR_UNKNOWN;
3750} 3746}
3751 3747
3752/* Substitute for all variables in the given string in the given context. 3748/* Substitute for all variables in the given string in the given context.
3753 * 3749 *
3754 * If eflags & VARE_UNDEFERR, Parse_Error will be called when an undefined 3750 * If eflags & VARE_UNDEFERR, Parse_Error will be called when an undefined
3755 * variable is encountered. 3751 * variable is encountered.
3756 * 3752 *
3757 * If eflags & VARE_WANTRES, any effects from the modifiers, such as ::=, 3753 * If eflags & VARE_WANTRES, any effects from the modifiers, such as ::=,
3758 * :sh or !cmd! take place. 3754 * :sh or !cmd! take place.
3759 * 3755 *
3760 * Input: 3756 * Input:
3761 * str the string which to substitute 3757 * str the string which to substitute
3762 * ctxt the context wherein to find variables 3758 * ctxt the context wherein to find variables
3763 * eflags VARE_UNDEFERR if undefineds are an error 3759 * eflags VARE_UNDEFERR if undefineds are an error
3764 * VARE_WANTRES if we actually want the result 3760 * VARE_WANTRES if we actually want the result
3765 * VARE_ASSIGN if we are in a := assignment 3761 * VARE_ASSIGN if we are in a := assignment
3766 * 3762 *
3767 * Results: 3763 * Results:
3768 * The resulting string. 3764 * The resulting string.
3769 */ 3765 */
3770VarParseResult 3766VarParseResult
3771Var_Subst(const char *str, GNode *ctxt, VarEvalFlags eflags, char **out_res) 3767Var_Subst(const char *str, GNode *ctxt, VarEvalFlags eflags, char **out_res)
3772{ 3768{
3773 const char *p = str; 3769 const char *p = str;
3774 Buffer buf; /* Buffer for forming things */ 3770 Buffer buf; /* Buffer for forming things */
3775 3771
3776 /* Set true if an error has already been reported, 3772 /* Set true if an error has already been reported,
3777 * to prevent a plethora of messages when recursing */ 3773 * to prevent a plethora of messages when recursing */
3778 static Boolean errorReported; 3774 static Boolean errorReported;
3779 3775
3780 Buf_Init(&buf, 0); 3776 Buf_Init(&buf, 0);
3781 errorReported = FALSE; 3777 errorReported = FALSE;
3782 3778
3783 while (*p != '\0') { 3779 while (*p != '\0') {
3784 if (p[0] == '$' && p[1] == '$') { 3780 if (p[0] == '$' && p[1] == '$') {
3785 /* A dollar sign may be escaped with another dollar sign. */ 3781 /* A dollar sign may be escaped with another dollar sign. */
3786 if (save_dollars && (eflags & VARE_ASSIGN)) 3782 if (save_dollars && (eflags & VARE_ASSIGN))
3787 Buf_AddByte(&buf, '$'); 3783 Buf_AddByte(&buf, '$');
3788 Buf_AddByte(&buf, '$'); 3784 Buf_AddByte(&buf, '$');
3789 p += 2; 3785 p += 2;
3790 } else if (*p != '$') { 3786 } else if (*p != '$') {
3791 /* 3787 /*
3792 * Skip as many characters as possible -- either to the end of 3788 * Skip as many characters as possible -- either to the end of
3793 * the string or to the next dollar sign (variable expression). 3789 * the string or to the next dollar sign (variable expression).
3794 */ 3790 */
3795 const char *plainStart = p; 3791 const char *plainStart = p;
3796 3792
3797 for (p++; *p != '$' && *p != '\0'; p++) 3793 for (p++; *p != '$' && *p != '\0'; p++)
3798 continue; 3794 continue;
3799 Buf_AddBytesBetween(&buf, plainStart, p); 3795 Buf_AddBytesBetween(&buf, plainStart, p);
3800 } else { 3796 } else {
3801 const char *nested_p = p; 3797 const char *nested_p = p;
3802 void *freeIt; 3798 void *freeIt;
3803 const char *val; 3799 const char *val;
3804 (void)Var_Parse(&nested_p, ctxt, eflags, &val, &freeIt); 3800 (void)Var_Parse(&nested_p, ctxt, eflags, &val, &freeIt);
3805 /* TODO: handle errors */ 3801 /* TODO: handle errors */
3806 3802
3807 if (val == var_Error || val == varUndefined) { 3803 if (val == var_Error || val == varUndefined) {
3808 /* 3804 /*
3809 * If performing old-time variable substitution, skip over 3805 * If performing old-time variable substitution, skip over
3810 * the variable and continue with the substitution. Otherwise, 3806 * the variable and continue with the substitution. Otherwise,
3811 * store the dollar sign and advance str so we continue with 3807 * store the dollar sign and advance str so we continue with
3812 * the string... 3808 * the string...
3813 */ 3809 */
3814 if (oldVars) { 3810 if (oldVars) {
3815 p = nested_p; 3811 p = nested_p;
3816 } else if ((eflags & VARE_UNDEFERR) || val == var_Error) { 3812 } else if ((eflags & VARE_UNDEFERR) || val == var_Error) {
3817 /* 3813 /*
3818 * If variable is undefined, complain and skip the 3814 * If variable is undefined, complain and skip the
3819 * variable. The complaint will stop us from doing anything 3815 * variable. The complaint will stop us from doing anything
3820 * when the file is parsed. 3816 * when the file is parsed.
3821 */ 3817 */
3822 if (!errorReported) { 3818 if (!errorReported) {
3823 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"", 3819 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"",
3824 (int)(size_t)(nested_p - p), p); 3820 (int)(size_t)(nested_p - p), p);
3825 } 3821 }
3826 p = nested_p; 3822 p = nested_p;
3827 errorReported = TRUE; 3823 errorReported = TRUE;
3828 } else { 3824 } else {
3829 /* Copy the initial '$' of the undefined expression, 3825 /* Copy the initial '$' of the undefined expression,
3830 * thereby deferring expansion of the expression, but 3826 * thereby deferring expansion of the expression, but
3831 * expand nested expressions if already possible. 3827 * expand nested expressions if already possible.
3832 * See unit-tests/varparse-undef-partial.mk. */ 3828 * See unit-tests/varparse-undef-partial.mk. */
3833 Buf_AddByte(&buf, *p); 3829 Buf_AddByte(&buf, *p);
3834 p++; 3830 p++;
3835 } 3831 }
3836 } else { 3832 } else {
3837 p = nested_p; 3833 p = nested_p;
3838 Buf_AddStr(&buf, val); 3834 Buf_AddStr(&buf, val);
3839 } 3835 }
3840 free(freeIt); 3836 free(freeIt);
3841 freeIt = NULL; 3837 freeIt = NULL;
3842 } 3838 }
3843 } 3839 }
3844 3840
3845 *out_res = Buf_DestroyCompact(&buf); 3841 *out_res = Buf_DestroyCompact(&buf);
3846 return VPR_OK; 3842 return VPR_OK;
3847} 3843}
3848 3844
3849/* Initialize the variables module. */ 3845/* Initialize the variables module. */
3850void 3846void
3851Var_Init(void) 3847Var_Init(void)
3852{ 3848{
3853 VAR_INTERNAL = Targ_NewGN("Internal"); 3849 VAR_INTERNAL = Targ_NewGN("Internal");
3854 VAR_GLOBAL = Targ_NewGN("Global"); 3850 VAR_GLOBAL = Targ_NewGN("Global");
3855 VAR_CMDLINE = Targ_NewGN("Command"); 3851 VAR_CMDLINE = Targ_NewGN("Command");
3856} 3852}
3857 3853
3858/* Clean up the variables module. */ 3854/* Clean up the variables module. */
3859void 3855void
3860Var_End(void) 3856Var_End(void)
3861{ 3857{
3862 Var_Stats(); 3858 Var_Stats();
3863} 3859}
3864 3860
3865void 3861void
3866Var_Stats(void) 3862Var_Stats(void)
3867{ 3863{
3868 HashTable_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL"); 3864 HashTable_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL");
3869} 3865}
3870 3866
3871/* Print all variables in a context, sorted by name. */ 3867/* Print all variables in a context, sorted by name. */
3872void 3868void
3873Var_Dump(GNode *ctxt) 3869Var_Dump(GNode *ctxt)
3874{ 3870{
3875 Vector /* of const char * */ vec; 3871 Vector /* of const char * */ vec;
3876 HashIter hi; 3872 HashIter hi;
3877 size_t i; 3873 size_t i;
3878 const char **varnames; 3874 const char **varnames;
3879 3875
3880 Vector_Init(&vec, sizeof(const char *)); 3876 Vector_Init(&vec, sizeof(const char *));
3881 3877
3882 HashIter_Init(&hi, &ctxt->context); 3878 HashIter_Init(&hi, &ctxt->context);
3883 while (HashIter_Next(&hi) != NULL) 3879 while (HashIter_Next(&hi) != NULL)
3884 *(const char **)Vector_Push(&vec) = hi.entry->key; 3880 *(const char **)Vector_Push(&vec) = hi.entry->key;
3885 varnames = vec.items; 3881 varnames = vec.items;
3886 3882
3887 qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc); 3883 qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc);
3888 3884
3889 for (i = 0; i < vec.len; i++) { 3885 for (i = 0; i < vec.len; i++) {
3890 const char *varname = varnames[i]; 3886 const char *varname = varnames[i];
3891 Var *var = HashTable_FindValue(&ctxt->context, varname); 3887 Var *var = HashTable_FindValue(&ctxt->context, varname);
3892 debug_printf("%-16s = %s\n", varname, Buf_GetAll(&var->val, NULL)); 3888 debug_printf("%-16s = %s\n", varname, Buf_GetAll(&var->val, NULL));
3893 } 3889 }
3894 3890
3895 Vector_Done(&vec); 3891 Vector_Done(&vec);
3896} 3892}