Tue Oct 27 07:44:43 2020 UTC ()
make(1): extract InitVpath from main


(rillig)
diff -r1.399 -r1.400 src/usr.bin/make/main.c

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

--- src/usr.bin/make/main.c 2020/10/27 07:38:08 1.399
+++ src/usr.bin/make/main.c 2020/10/27 07:44:43 1.400
@@ -1,2211 +1,2216 @@ @@ -1,2211 +1,2216 @@
1/* $NetBSD: main.c,v 1.399 2020/10/27 07:38:08 rillig Exp $ */ 1/* $NetBSD: main.c,v 1.400 2020/10/27 07:44:43 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.399 2020/10/27 07:38:08 rillig Exp $"); 121MAKE_RCSID("$NetBSD: main.c,v 1.400 2020/10/27 07:44:43 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_CMD); 652 Parse_DoVar(&var, VAR_CMD);
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 char *p1; 677 char *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 (chdir(path)) { 724 if (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 char *path_freeIt; 745 char *path_freeIt;
746 const char *path = Var_Value(var, VAR_CMD, &path_freeIt); 746 const char *path = Var_Value(var, VAR_CMD, &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 char *freeIt; 860 char *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 const char * 951static const char *
952init_machine(const struct utsname *utsname) 952init_machine(const struct utsname *utsname)
953{ 953{
954 const char *machine = getenv("MACHINE"); 954 const char *machine = getenv("MACHINE");
955 if (machine != NULL) 955 if (machine != NULL)
956 return machine; 956 return machine;
957 957
958#ifdef MAKE_NATIVE 958#ifdef MAKE_NATIVE
959 return utsname->machine; 959 return utsname->machine;
960#else 960#else
961#ifdef MAKE_MACHINE 961#ifdef MAKE_MACHINE
962 return MAKE_MACHINE; 962 return MAKE_MACHINE;
963#else 963#else
964 return "unknown"; 964 return "unknown";
965#endif 965#endif
966#endif 966#endif
967} 967}
968 968
969static const char * 969static const char *
970init_machine_arch(void) 970init_machine_arch(void)
971{ 971{
972 const char *env = getenv("MACHINE_ARCH"); 972 const char *env = getenv("MACHINE_ARCH");
973 if (env != NULL) 973 if (env != NULL)
974 return env; 974 return env;
975 975
976#ifdef MAKE_NATIVE 976#ifdef MAKE_NATIVE
977 { 977 {
978 struct utsname utsname; 978 struct utsname utsname;
979 static char machine_arch_buf[sizeof(utsname.machine)]; 979 static char machine_arch_buf[sizeof(utsname.machine)];
980 const int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 980 const int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
981 size_t len = sizeof(machine_arch_buf); 981 size_t len = sizeof(machine_arch_buf);
982 982
983 if (sysctl(mib, __arraycount(mib), machine_arch_buf, 983 if (sysctl(mib, __arraycount(mib), machine_arch_buf,
984 &len, NULL, 0) < 0) { 984 &len, NULL, 0) < 0) {
985 (void)fprintf(stderr, "%s: sysctl failed (%s).\n", progname, 985 (void)fprintf(stderr, "%s: sysctl failed (%s).\n", progname,
986 strerror(errno)); 986 strerror(errno));
987 exit(2); 987 exit(2);
988 } 988 }
989 989
990 return machine_arch_buf; 990 return machine_arch_buf;
991 } 991 }
992#else 992#else
993#ifndef MACHINE_ARCH 993#ifndef MACHINE_ARCH
994#ifdef MAKE_MACHINE_ARCH 994#ifdef MAKE_MACHINE_ARCH
995 return MAKE_MACHINE_ARCH; 995 return MAKE_MACHINE_ARCH;
996#else 996#else
997 return "unknown"; 997 return "unknown";
998#endif 998#endif
999#else 999#else
1000 return MACHINE_ARCH; 1000 return MACHINE_ARCH;
1001#endif 1001#endif
1002#endif 1002#endif
1003} 1003}
1004 1004
1005#ifndef NO_PWD_OVERRIDE 1005#ifndef NO_PWD_OVERRIDE
1006/* 1006/*
1007 * All this code is so that we know where we are when we start up 1007 * All this code is so that we know where we are when we start up
1008 * on a different machine with pmake. 1008 * on a different machine with pmake.
1009 * 1009 *
1010 * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1010 * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX
1011 * since the value of curdir can vary depending on how we got 1011 * since the value of curdir can vary depending on how we got
1012 * here. Ie sitting at a shell prompt (shell that provides $PWD) 1012 * here. Ie sitting at a shell prompt (shell that provides $PWD)
1013 * or via subdir.mk in which case its likely a shell which does 1013 * or via subdir.mk in which case its likely a shell which does
1014 * not provide it. 1014 * not provide it.
1015 * 1015 *
1016 * So, to stop it breaking this case only, we ignore PWD if 1016 * So, to stop it breaking this case only, we ignore PWD if
1017 * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression. 1017 * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression.
1018 */ 1018 */
1019static void 1019static void
1020HandlePWD(const struct stat *curdir_st) 1020HandlePWD(const struct stat *curdir_st)
1021{ 1021{
1022 char *pwd; 1022 char *pwd;
1023 char *prefix_freeIt, *makeobjdir_freeIt; 1023 char *prefix_freeIt, *makeobjdir_freeIt;
1024 const char *makeobjdir; 1024 const char *makeobjdir;
1025 struct stat pwd_st; 1025 struct stat pwd_st;
1026 1026
1027 if (ignorePWD || (pwd = getenv("PWD")) == NULL) 1027 if (ignorePWD || (pwd = getenv("PWD")) == NULL)
1028 return; 1028 return;
1029 1029
1030 if (Var_Value("MAKEOBJDIRPREFIX", VAR_CMD, &prefix_freeIt) != NULL) { 1030 if (Var_Value("MAKEOBJDIRPREFIX", VAR_CMD, &prefix_freeIt) != NULL) {
1031 bmake_free(prefix_freeIt); 1031 bmake_free(prefix_freeIt);
1032 return; 1032 return;
1033 } 1033 }
1034 1034
1035 makeobjdir = Var_Value("MAKEOBJDIR", VAR_CMD, &makeobjdir_freeIt); 1035 makeobjdir = Var_Value("MAKEOBJDIR", VAR_CMD, &makeobjdir_freeIt);
1036 if (makeobjdir != NULL && strchr(makeobjdir, '$') != NULL) 1036 if (makeobjdir != NULL && strchr(makeobjdir, '$') != NULL)
1037 goto ignore_pwd; 1037 goto ignore_pwd;
1038 1038
1039 if (stat(pwd, &pwd_st) == 0 && 1039 if (stat(pwd, &pwd_st) == 0 &&
1040 curdir_st->st_ino == pwd_st.st_ino && 1040 curdir_st->st_ino == pwd_st.st_ino &&
1041 curdir_st->st_dev == pwd_st.st_dev) 1041 curdir_st->st_dev == pwd_st.st_dev)
1042 (void)strncpy(curdir, pwd, MAXPATHLEN); 1042 (void)strncpy(curdir, pwd, MAXPATHLEN);
1043 1043
1044ignore_pwd: 1044ignore_pwd:
1045 bmake_free(makeobjdir_freeIt); 1045 bmake_free(makeobjdir_freeIt);
1046} 1046}
1047#endif 1047#endif
1048 1048
1049/* get rid of resource limit on file descriptors */ 1049/* get rid of resource limit on file descriptors */
1050static void 1050static void
1051UnlimitFiles(void) 1051UnlimitFiles(void)
1052{ 1052{
1053#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) 1053#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE))
1054 struct rlimit rl; 1054 struct rlimit rl;
1055 if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 1055 if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
1056 rl.rlim_cur != rl.rlim_max) { 1056 rl.rlim_cur != rl.rlim_max) {
1057 rl.rlim_cur = rl.rlim_max; 1057 rl.rlim_cur = rl.rlim_max;
1058 (void)setrlimit(RLIMIT_NOFILE, &rl); 1058 (void)setrlimit(RLIMIT_NOFILE, &rl);
1059 } 1059 }
1060#endif 1060#endif
1061} 1061}
1062 1062
1063static void 1063static void
1064CmdOpts_Init(void) 1064CmdOpts_Init(void)
1065{ 1065{
1066 opts.compatMake = FALSE; /* No compat mode */ 1066 opts.compatMake = FALSE; /* No compat mode */
1067 opts.debug = 0; /* No debug verbosity, please. */ 1067 opts.debug = 0; /* No debug verbosity, please. */
1068 /* opts.debug_file has been initialized earlier */ 1068 /* opts.debug_file has been initialized earlier */
1069 opts.debugVflag = FALSE; 1069 opts.debugVflag = FALSE;
1070 opts.checkEnvFirst = FALSE; 1070 opts.checkEnvFirst = FALSE;
1071 opts.makefiles = Lst_New(); 1071 opts.makefiles = Lst_New();
1072 opts.ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 1072 opts.ignoreErrors = FALSE; /* Pay attention to non-zero returns */
1073 opts.maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */ 1073 opts.maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */
1074 opts.keepgoing = FALSE; /* Stop on error */ 1074 opts.keepgoing = FALSE; /* Stop on error */
1075 opts.noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 1075 opts.noRecursiveExecute = FALSE; /* Execute all .MAKE targets */
1076 opts.noExecute = FALSE; /* Execute all commands */ 1076 opts.noExecute = FALSE; /* Execute all commands */
1077 opts.queryFlag = FALSE; /* This is not just a check-run */ 1077 opts.queryFlag = FALSE; /* This is not just a check-run */
1078 opts.noBuiltins = FALSE; /* Read the built-in rules */ 1078 opts.noBuiltins = FALSE; /* Read the built-in rules */
1079 opts.beSilent = FALSE; /* Print commands as executed */ 1079 opts.beSilent = FALSE; /* Print commands as executed */
1080 opts.touchFlag = FALSE; /* Actually update targets */ 1080 opts.touchFlag = FALSE; /* Actually update targets */
1081 opts.printVars = 0; 1081 opts.printVars = 0;
1082 opts.variables = Lst_New(); 1082 opts.variables = Lst_New();
1083 opts.parseWarnFatal = FALSE; 1083 opts.parseWarnFatal = FALSE;
1084 opts.enterFlag = FALSE; 1084 opts.enterFlag = FALSE;
1085 opts.varNoExportEnv = FALSE; 1085 opts.varNoExportEnv = FALSE;
1086 opts.create = Lst_New(); 1086 opts.create = Lst_New();
1087} 1087}
1088 1088
1089static void 1089static void
1090InitDefIncPath(char *syspath) 1090InitDefIncPath(char *syspath)
1091{ 1091{
1092 static char defsyspath[] = _PATH_DEFSYSPATH; 1092 static char defsyspath[] = _PATH_DEFSYSPATH;
1093 char *start, *cp; 1093 char *start, *cp;
1094 1094
1095 /* 1095 /*
1096 * If no user-supplied system path was given (through the -m option) 1096 * If no user-supplied system path was given (through the -m option)
1097 * add the directories from the DEFSYSPATH (more than one may be given 1097 * add the directories from the DEFSYSPATH (more than one may be given
1098 * as dir1:...:dirn) to the system include path. 1098 * as dir1:...:dirn) to the system include path.
1099 */ 1099 */
1100 /* XXX: mismatch: the -m option sets sysIncPath, not syspath */ 1100 /* XXX: mismatch: the -m option sets sysIncPath, not syspath */
1101 if (syspath == NULL || syspath[0] == '\0') 1101 if (syspath == NULL || syspath[0] == '\0')
1102 syspath = defsyspath; 1102 syspath = defsyspath;
1103 else 1103 else
1104 syspath = bmake_strdup(syspath); 1104 syspath = bmake_strdup(syspath);
1105 1105
1106 for (start = syspath; *start != '\0'; start = cp) { 1106 for (start = syspath; *start != '\0'; start = cp) {
1107 for (cp = start; *cp != '\0' && *cp != ':'; cp++) 1107 for (cp = start; *cp != '\0' && *cp != ':'; cp++)
1108 continue; 1108 continue;
1109 if (*cp == ':') { 1109 if (*cp == ':') {
1110 *cp++ = '\0'; 1110 *cp++ = '\0';
1111 } 1111 }
1112 /* look for magic parent directory search string */ 1112 /* look for magic parent directory search string */
1113 if (strncmp(".../", start, 4) != 0) { 1113 if (strncmp(".../", start, 4) != 0) {
1114 (void)Dir_AddDir(defIncPath, start); 1114 (void)Dir_AddDir(defIncPath, start);
1115 } else { 1115 } else {
1116 char *dir = Dir_FindHereOrAbove(curdir, start + 4); 1116 char *dir = Dir_FindHereOrAbove(curdir, start + 4);
1117 if (dir != NULL) { 1117 if (dir != NULL) {
1118 (void)Dir_AddDir(defIncPath, dir); 1118 (void)Dir_AddDir(defIncPath, dir);
1119 free(dir); 1119 free(dir);
1120 } 1120 }
1121 } 1121 }
1122 } 1122 }
1123 1123
1124 if (syspath != defsyspath) 1124 if (syspath != defsyspath)
1125 free(syspath); 1125 free(syspath);
1126} 1126}
1127 1127
1128static void 1128static void
1129ReadBuiltinRules(void) 1129ReadBuiltinRules(void)
1130{ 1130{
1131 StringList *sysMkPath = Lst_New(); 1131 StringList *sysMkPath = Lst_New();
1132 Dir_Expand(_PATH_DEFSYSMK, 1132 Dir_Expand(_PATH_DEFSYSMK,
1133 Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath, 1133 Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath,
1134 sysMkPath); 1134 sysMkPath);
1135 if (Lst_IsEmpty(sysMkPath)) 1135 if (Lst_IsEmpty(sysMkPath))
1136 Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); 1136 Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK);
1137 if (!Lst_ForEachUntil(sysMkPath, ReadMakefileSucceeded, NULL)) 1137 if (!Lst_ForEachUntil(sysMkPath, ReadMakefileSucceeded, NULL))
1138 Fatal("%s: cannot open %s.", progname, 1138 Fatal("%s: cannot open %s.", progname,
1139 (char *)sysMkPath->first->datum); 1139 (char *)sysMkPath->first->datum);
1140 /* XXX: sysMkPath is not freed */ 1140 /* XXX: sysMkPath is not freed */
1141} 1141}
1142 1142
 1143/*
 1144 * For compatibility, look at the directories in the VPATH variable
 1145 * and add them to the search path, if the variable is defined. The
 1146 * variable's value is in the same format as the PATH environment
 1147 * variable, i.e. <directory>:<directory>:<directory>...
 1148 */
 1149static void
 1150InitVpath(void)
 1151{
 1152 char *vpath, savec, *path;
 1153 if (!Var_Exists("VPATH", VAR_CMD))
 1154 return;
 1155
 1156 (void)Var_Subst("${VPATH}", VAR_CMD, VARE_WANTRES, &vpath);
 1157 /* TODO: handle errors */
 1158 path = vpath;
 1159 do {
 1160 char *cp;
 1161 /* skip to end of directory */
 1162 for (cp = path; *cp != ':' && *cp != '\0'; cp++)
 1163 continue;
 1164 /* Save terminator character so know when to stop */
 1165 savec = *cp;
 1166 *cp = '\0';
 1167 /* Add directory to search path */
 1168 (void)Dir_AddDir(dirSearchPath, path);
 1169 *cp = savec;
 1170 path = cp + 1;
 1171 } while (savec == ':');
 1172 free(vpath);
 1173}
 1174
1143/*- 1175/*-
1144 * main -- 1176 * main --
1145 * The main function, for obvious reasons. Initializes variables 1177 * The main function, for obvious reasons. Initializes variables
1146 * and a few modules, then parses the arguments give it in the 1178 * and a few modules, then parses the arguments give it in the
1147 * environment and on the command line. Reads the system makefile 1179 * environment and on the command line. Reads the system makefile
1148 * followed by either Makefile, makefile or the file given by the 1180 * followed by either Makefile, makefile or the file given by the
1149 * -f argument. Sets the .MAKEFLAGS PMake variable based on all the 1181 * -f argument. Sets the .MAKEFLAGS PMake variable based on all the
1150 * flags it has received by then uses either the Make or the Compat 1182 * flags it has received by then uses either the Make or the Compat
1151 * module to create the initial list of targets. 1183 * module to create the initial list of targets.
1152 * 1184 *
1153 * Results: 1185 * Results:
1154 * If -q was given, exits -1 if anything was out-of-date. Else it exits 1186 * If -q was given, exits -1 if anything was out-of-date. Else it exits
1155 * 0. 1187 * 0.
1156 * 1188 *
1157 * Side Effects: 1189 * Side Effects:
1158 * The program exits when done. Targets are created. etc. etc. etc. 1190 * The program exits when done. Targets are created. etc. etc. etc.
1159 */ 1191 */
1160int 1192int
1161main(int argc, char **argv) 1193main(int argc, char **argv)
1162{ 1194{
1163 Boolean outOfDate; /* FALSE if all targets up to date */ 1195 Boolean outOfDate; /* FALSE if all targets up to date */
1164 struct stat sa; 1196 struct stat sa;
1165 char *p1, *path; 1197 char *p1;
1166 char mdpath[MAXPATHLEN]; 1198 char mdpath[MAXPATHLEN];
1167 const char *machine; 1199 const char *machine;
1168 const char *machine_arch; 1200 const char *machine_arch;
1169 char *syspath = getenv("MAKESYSPATH"); 1201 char *syspath = getenv("MAKESYSPATH");
1170 struct timeval rightnow; /* to initialize random seed */ 1202 struct timeval rightnow; /* to initialize random seed */
1171 struct utsname utsname; 1203 struct utsname utsname;
1172 1204
1173 /* default to writing debug to stderr */ 1205 /* default to writing debug to stderr */
1174 opts.debug_file = stderr; 1206 opts.debug_file = stderr;
1175 1207
1176#ifdef SIGINFO 1208#ifdef SIGINFO
1177 (void)bmake_signal(SIGINFO, siginfo); 1209 (void)bmake_signal(SIGINFO, siginfo);
1178#endif 1210#endif
1179 /* 1211 /*
1180 * Set the seed to produce a different random sequence 1212 * Set the seed to produce a different random sequence
1181 * on each program execution. 1213 * on each program execution.
1182 */ 1214 */
1183 gettimeofday(&rightnow, NULL); 1215 gettimeofday(&rightnow, NULL);
1184 srandom((unsigned int)(rightnow.tv_sec + rightnow.tv_usec)); 1216 srandom((unsigned int)(rightnow.tv_sec + rightnow.tv_usec));
1185 1217
1186 if ((progname = strrchr(argv[0], '/')) != NULL) 1218 if ((progname = strrchr(argv[0], '/')) != NULL)
1187 progname++; 1219 progname++;
1188 else 1220 else
1189 progname = argv[0]; 1221 progname = argv[0];
1190 1222
1191 UnlimitFiles(); 1223 UnlimitFiles();
1192 1224
1193 if (uname(&utsname) == -1) { 1225 if (uname(&utsname) == -1) {
1194 (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 1226 (void)fprintf(stderr, "%s: uname failed (%s).\n", progname,
1195 strerror(errno)); 1227 strerror(errno));
1196 exit(2); 1228 exit(2);
1197 } 1229 }
1198 1230
1199 /* 1231 /*
1200 * Get the name of this type of MACHINE from utsname 1232 * Get the name of this type of MACHINE from utsname
1201 * so we can share an executable for similar machines. 1233 * so we can share an executable for similar machines.
1202 * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 1234 * (i.e. m68k: amiga hp300, mac68k, sun3, ...)
1203 * 1235 *
1204 * Note that both MACHINE and MACHINE_ARCH are decided at 1236 * Note that both MACHINE and MACHINE_ARCH are decided at
1205 * run-time. 1237 * run-time.
1206 */ 1238 */
1207 machine = init_machine(&utsname); 1239 machine = init_machine(&utsname);
1208 machine_arch = init_machine_arch(); 1240 machine_arch = init_machine_arch();
1209 1241
1210 myPid = getpid(); /* remember this for vFork() */ 1242 myPid = getpid(); /* remember this for vFork() */
1211 1243
1212 /* 1244 /*
1213 * Just in case MAKEOBJDIR wants us to do something tricky. 1245 * Just in case MAKEOBJDIR wants us to do something tricky.
1214 */ 1246 */
1215 Var_Init(); /* Initialize the lists of variables for 1247 Var_Init(); /* Initialize the lists of variables for
1216 * parsing arguments */ 1248 * parsing arguments */
1217 Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL); 1249 Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL);
1218 Var_Set("MACHINE", machine, VAR_GLOBAL); 1250 Var_Set("MACHINE", machine, VAR_GLOBAL);
1219 Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL); 1251 Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL);
1220#ifdef MAKE_VERSION 1252#ifdef MAKE_VERSION
1221 Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL); 1253 Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL);
1222#endif 1254#endif
1223 Var_Set(".newline", "\n", VAR_GLOBAL); /* handy for :@ loops */ 1255 Var_Set(".newline", "\n", VAR_GLOBAL); /* handy for :@ loops */
1224 /* 1256 /*
1225 * This is the traditional preference for makefiles. 1257 * This is the traditional preference for makefiles.
1226 */ 1258 */
1227#ifndef MAKEFILE_PREFERENCE_LIST 1259#ifndef MAKEFILE_PREFERENCE_LIST
1228# define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 1260# define MAKEFILE_PREFERENCE_LIST "makefile Makefile"
1229#endif 1261#endif
1230 Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, 1262 Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST,
1231 VAR_GLOBAL); 1263 VAR_GLOBAL);
1232 Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL); 1264 Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL);
1233 1265
1234 CmdOpts_Init(); 1266 CmdOpts_Init();
1235 allPrecious = FALSE; /* Remove targets when interrupted */ 1267 allPrecious = FALSE; /* Remove targets when interrupted */
1236 deleteOnError = FALSE; /* Historical default behavior */ 1268 deleteOnError = FALSE; /* Historical default behavior */
1237 jobsRunning = FALSE; 1269 jobsRunning = FALSE;
1238 1270
1239 maxJobTokens = opts.maxJobs; 1271 maxJobTokens = opts.maxJobs;
1240 ignorePWD = FALSE; 1272 ignorePWD = FALSE;
1241 1273
1242 /* 1274 /*
1243 * Initialize the parsing, directory and variable modules to prepare 1275 * Initialize the parsing, directory and variable modules to prepare
1244 * for the reading of inclusion paths and variable settings on the 1276 * for the reading of inclusion paths and variable settings on the
1245 * command line 1277 * command line
1246 */ 1278 */
1247 1279
1248 /* 1280 /*
1249 * Initialize various variables. 1281 * Initialize various variables.
1250 * MAKE also gets this name, for compatibility 1282 * MAKE also gets this name, for compatibility
1251 * .MAKEFLAGS gets set to the empty string just in case. 1283 * .MAKEFLAGS gets set to the empty string just in case.
1252 * MFLAGS also gets initialized empty, for compatibility. 1284 * MFLAGS also gets initialized empty, for compatibility.
1253 */ 1285 */
1254 Parse_Init(); 1286 Parse_Init();
1255 if (argv[0][0] == '/' || strchr(argv[0], '/') == NULL) { 1287 if (argv[0][0] == '/' || strchr(argv[0], '/') == NULL) {
1256 /* 1288 /*
1257 * Leave alone if it is an absolute path, or if it does 1289 * Leave alone if it is an absolute path, or if it does
1258 * not contain a '/' in which case we need to find it in 1290 * not contain a '/' in which case we need to find it in
1259 * the path, like execvp(3) and the shells do. 1291 * the path, like execvp(3) and the shells do.
1260 */ 1292 */
1261 p1 = argv[0]; 1293 p1 = argv[0];
1262 } else { 1294 } else {
1263 struct stat sb; 1295 struct stat sb;
1264 /* 1296 /*
1265 * A relative path, canonicalize it. 1297 * A relative path, canonicalize it.
1266 */ 1298 */
1267 p1 = cached_realpath(argv[0], mdpath); 1299 p1 = cached_realpath(argv[0], mdpath);
1268 if (!p1 || *p1 != '/' || stat(p1, &sb) < 0) { 1300 if (!p1 || *p1 != '/' || stat(p1, &sb) < 0) {
1269 p1 = argv[0]; /* realpath failed */ 1301 p1 = argv[0]; /* realpath failed */
1270 } 1302 }
1271 } 1303 }
1272 Var_Set("MAKE", p1, VAR_GLOBAL); 1304 Var_Set("MAKE", p1, VAR_GLOBAL);
1273 Var_Set(".MAKE", p1, VAR_GLOBAL); 1305 Var_Set(".MAKE", p1, VAR_GLOBAL);
1274 Var_Set(MAKEFLAGS, "", VAR_GLOBAL); 1306 Var_Set(MAKEFLAGS, "", VAR_GLOBAL);
1275 Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL); 1307 Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL);
1276 Var_Set("MFLAGS", "", VAR_GLOBAL); 1308 Var_Set("MFLAGS", "", VAR_GLOBAL);
1277 Var_Set(".ALLTARGETS", "", VAR_GLOBAL); 1309 Var_Set(".ALLTARGETS", "", VAR_GLOBAL);
1278 /* some makefiles need to know this */ 1310 /* some makefiles need to know this */
1279 Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMD); 1311 Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMD);
1280 1312
1281 /* 1313 /*
1282 * Set some other useful macros 1314 * Set some other useful macros
1283 */ 1315 */
1284 { 1316 {
1285 char tmp[64], *ep; 1317 char tmp[64], *ep;
1286 1318
1287 makelevel = ((ep = getenv(MAKE_LEVEL_ENV)) && *ep) ? atoi(ep) : 0; 1319 makelevel = ((ep = getenv(MAKE_LEVEL_ENV)) && *ep) ? atoi(ep) : 0;
1288 if (makelevel < 0) 1320 if (makelevel < 0)
1289 makelevel = 0; 1321 makelevel = 0;
1290 snprintf(tmp, sizeof(tmp), "%d", makelevel); 1322 snprintf(tmp, sizeof(tmp), "%d", makelevel);
1291 Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL); 1323 Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL);
1292 snprintf(tmp, sizeof(tmp), "%u", myPid); 1324 snprintf(tmp, sizeof(tmp), "%u", myPid);
1293 Var_Set(".MAKE.PID", tmp, VAR_GLOBAL); 1325 Var_Set(".MAKE.PID", tmp, VAR_GLOBAL);
1294 snprintf(tmp, sizeof(tmp), "%u", getppid()); 1326 snprintf(tmp, sizeof(tmp), "%u", getppid());
1295 Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL); 1327 Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL);
1296 } 1328 }
1297 if (makelevel > 0) { 1329 if (makelevel > 0) {
1298 char pn[1024]; 1330 char pn[1024];
1299 snprintf(pn, sizeof(pn), "%s[%d]", progname, makelevel); 1331 snprintf(pn, sizeof(pn), "%s[%d]", progname, makelevel);
1300 progname = bmake_strdup(pn); 1332 progname = bmake_strdup(pn);
1301 } 1333 }
1302 1334
1303#ifdef USE_META 1335#ifdef USE_META
1304 meta_init(); 1336 meta_init();
1305#endif 1337#endif
1306 Dir_Init(); 1338 Dir_Init();
1307 1339
1308 /* 1340 /*
1309 * First snag any flags out of the MAKE environment variable. 1341 * First snag any flags out of the MAKE environment variable.
1310 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 1342 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
1311 * in a different format). 1343 * in a different format).
1312 */ 1344 */
1313#ifdef POSIX 1345#ifdef POSIX
1314 p1 = explode(getenv("MAKEFLAGS")); 1346 p1 = explode(getenv("MAKEFLAGS"));
1315 Main_ParseArgLine(p1); 1347 Main_ParseArgLine(p1);
1316 free(p1); 1348 free(p1);
1317#else 1349#else
1318 Main_ParseArgLine(getenv("MAKE")); 1350 Main_ParseArgLine(getenv("MAKE"));
1319#endif 1351#endif
1320 1352
1321 /* 1353 /*
1322 * Find where we are (now). 1354 * Find where we are (now).
1323 * We take care of PWD for the automounter below... 1355 * We take care of PWD for the automounter below...
1324 */ 1356 */
1325 if (getcwd(curdir, MAXPATHLEN) == NULL) { 1357 if (getcwd(curdir, MAXPATHLEN) == NULL) {
1326 (void)fprintf(stderr, "%s: getcwd: %s.\n", 1358 (void)fprintf(stderr, "%s: getcwd: %s.\n",
1327 progname, strerror(errno)); 1359 progname, strerror(errno));
1328 exit(2); 1360 exit(2);
1329 } 1361 }
1330 1362
1331 MainParseArgs(argc, argv); 1363 MainParseArgs(argc, argv);
1332 1364
1333 if (opts.enterFlag) 1365 if (opts.enterFlag)
1334 printf("%s: Entering directory `%s'\n", progname, curdir); 1366 printf("%s: Entering directory `%s'\n", progname, curdir);
1335 1367
1336 /* 1368 /*
1337 * Verify that cwd is sane. 1369 * Verify that cwd is sane.
1338 */ 1370 */
1339 if (stat(curdir, &sa) == -1) { 1371 if (stat(curdir, &sa) == -1) {
1340 (void)fprintf(stderr, "%s: %s: %s.\n", 1372 (void)fprintf(stderr, "%s: %s: %s.\n",
1341 progname, curdir, strerror(errno)); 1373 progname, curdir, strerror(errno));
1342 exit(2); 1374 exit(2);
1343 } 1375 }
1344 1376
1345#ifndef NO_PWD_OVERRIDE 1377#ifndef NO_PWD_OVERRIDE
1346 HandlePWD(&sa); 1378 HandlePWD(&sa);
1347#endif 1379#endif
1348 Var_Set(".CURDIR", curdir, VAR_GLOBAL); 1380 Var_Set(".CURDIR", curdir, VAR_GLOBAL);
1349 1381
1350 /* 1382 /*
1351 * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 1383 * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that,
1352 * MAKEOBJDIR is set in the environment, try only that value 1384 * MAKEOBJDIR is set in the environment, try only that value
1353 * and fall back to .CURDIR if it does not exist. 1385 * and fall back to .CURDIR if it does not exist.
1354 * 1386 *
1355 * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, 1387 * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE,
1356 * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 1388 * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none
1357 * of these paths exist, just use .CURDIR. 1389 * of these paths exist, just use .CURDIR.
1358 */ 1390 */
1359 Dir_InitDir(curdir); 1391 Dir_InitDir(curdir);
1360 (void)Main_SetObjdir("%s", curdir); 1392 (void)Main_SetObjdir("%s", curdir);
1361 1393
1362 if (!Main_SetVarObjdir("MAKEOBJDIRPREFIX", curdir) && 1394 if (!Main_SetVarObjdir("MAKEOBJDIRPREFIX", curdir) &&
1363 !Main_SetVarObjdir("MAKEOBJDIR", "") && 1395 !Main_SetVarObjdir("MAKEOBJDIR", "") &&
1364 !Main_SetObjdir("%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && 1396 !Main_SetObjdir("%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) &&
1365 !Main_SetObjdir("%s.%s", _PATH_OBJDIR, machine) && 1397 !Main_SetObjdir("%s.%s", _PATH_OBJDIR, machine) &&
1366 !Main_SetObjdir("%s", _PATH_OBJDIR)) 1398 !Main_SetObjdir("%s", _PATH_OBJDIR))
1367 (void)Main_SetObjdir("%s%s", _PATH_OBJDIRPREFIX, curdir); 1399 (void)Main_SetObjdir("%s%s", _PATH_OBJDIRPREFIX, curdir);
1368 1400
1369 /* 1401 /*
1370 * Initialize archive, target and suffix modules in preparation for 1402 * Initialize archive, target and suffix modules in preparation for
1371 * parsing the makefile(s) 1403 * parsing the makefile(s)
1372 */ 1404 */
1373 Arch_Init(); 1405 Arch_Init();
1374 Targ_Init(); 1406 Targ_Init();
1375 Suff_Init(); 1407 Suff_Init();
1376 Trace_Init(tracefile); 1408 Trace_Init(tracefile);
1377 1409
1378 DEFAULT = NULL; 1410 DEFAULT = NULL;
1379 (void)time(&now); 1411 (void)time(&now);
1380 1412
1381 Trace_Log(MAKESTART, NULL); 1413 Trace_Log(MAKESTART, NULL);
1382 1414
1383 InitVarTargets(); 1415 InitVarTargets();
1384 1416
1385 InitDefIncPath(syspath); 1417 InitDefIncPath(syspath);
1386 1418
1387 /* 1419 /*
1388 * Read in the built-in rules first, followed by the specified 1420 * Read in the built-in rules first, followed by the specified
1389 * makefiles, or the default makefile and Makefile, in that order, 1421 * makefiles, or the default makefile and Makefile, in that order,
1390 * if no makefiles were given on the command line. 1422 * if no makefiles were given on the command line.
1391 */ 1423 */
1392 if (!opts.noBuiltins) 1424 if (!opts.noBuiltins)
1393 ReadBuiltinRules(); 1425 ReadBuiltinRules();
1394 1426
1395 if (opts.makefiles->first != NULL) { 1427 if (opts.makefiles->first != NULL) {
1396 StringListNode *ln; 1428 StringListNode *ln;
1397 1429
1398 for (ln = opts.makefiles->first; ln != NULL; ln = ln->next) { 1430 for (ln = opts.makefiles->first; ln != NULL; ln = ln->next) {
1399 if (ReadMakefile(ln->datum) != 0) 1431 if (ReadMakefile(ln->datum) != 0)
1400 Fatal("%s: cannot open %s.", 1432 Fatal("%s: cannot open %s.",
1401 progname, (char *)ln->datum); 1433 progname, (char *)ln->datum);
1402 } 1434 }
1403 } else { 1435 } else {
1404 (void)Var_Subst("${" MAKEFILE_PREFERENCE "}", 1436 (void)Var_Subst("${" MAKEFILE_PREFERENCE "}",
1405 VAR_CMD, VARE_WANTRES, &p1); 1437 VAR_CMD, VARE_WANTRES, &p1);
1406 /* TODO: handle errors */ 1438 /* TODO: handle errors */
1407 (void)str2Lst_Append(opts.makefiles, p1, NULL); 1439 (void)str2Lst_Append(opts.makefiles, p1, NULL);
1408 (void)Lst_ForEachUntil(opts.makefiles, 1440 (void)Lst_ForEachUntil(opts.makefiles,
1409 ReadMakefileSucceeded, NULL); 1441 ReadMakefileSucceeded, NULL);
1410 free(p1); 1442 free(p1);
1411 } 1443 }
1412 1444
1413 /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1445 /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
1414 if (!opts.noBuiltins || !opts.printVars) { 1446 if (!opts.noBuiltins || !opts.printVars) {
1415 /* ignore /dev/null and anything starting with "no" */ 1447 /* ignore /dev/null and anything starting with "no" */
1416 (void)Var_Subst("${.MAKE.DEPENDFILE:N/dev/null:Nno*:T}", 1448 (void)Var_Subst("${.MAKE.DEPENDFILE:N/dev/null:Nno*:T}",
1417 VAR_CMD, VARE_WANTRES, &makeDependfile); 1449 VAR_CMD, VARE_WANTRES, &makeDependfile);
1418 if (makeDependfile[0] != '\0') { 1450 if (makeDependfile[0] != '\0') {
1419 /* TODO: handle errors */ 1451 /* TODO: handle errors */
1420 doing_depend = TRUE; 1452 doing_depend = TRUE;
1421 (void)ReadMakefile(makeDependfile); 1453 (void)ReadMakefile(makeDependfile);
1422 doing_depend = FALSE; 1454 doing_depend = FALSE;
1423 } 1455 }
1424 } 1456 }
1425 1457
1426 if (enterFlagObj) 1458 if (enterFlagObj)
1427 printf("%s: Entering directory `%s'\n", progname, objdir); 1459 printf("%s: Entering directory `%s'\n", progname, objdir);
1428 1460
1429 MakeMode(NULL); 1461 MakeMode(NULL);
1430 1462
1431 Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); 1463 Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL);
1432 bmake_free(p1); 1464 bmake_free(p1);
1433 1465
1434 if (!forceJobs && !opts.compatMake && 1466 if (!forceJobs && !opts.compatMake &&
1435 Var_Exists(".MAKE.JOBS", VAR_GLOBAL)) { 1467 Var_Exists(".MAKE.JOBS", VAR_GLOBAL)) {
1436 char *value; 1468 char *value;
1437 int n; 1469 int n;
1438 1470
1439 (void)Var_Subst("${.MAKE.JOBS}", VAR_GLOBAL, VARE_WANTRES, &value); 1471 (void)Var_Subst("${.MAKE.JOBS}", VAR_GLOBAL, VARE_WANTRES, &value);
1440 /* TODO: handle errors */ 1472 /* TODO: handle errors */
1441 n = (int)strtol(value, NULL, 0); 1473 n = (int)strtol(value, NULL, 0);
1442 if (n < 1) { 1474 if (n < 1) {
1443 (void)fprintf(stderr, "%s: illegal value for .MAKE.JOBS -- must be positive integer!\n", 1475 (void)fprintf(stderr, "%s: illegal value for .MAKE.JOBS -- must be positive integer!\n",
1444 progname); 1476 progname);
1445 exit(1); 1477 exit(1);
1446 } 1478 }
1447 if (n != opts.maxJobs) { 1479 if (n != opts.maxJobs) {
1448 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 1480 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
1449 Var_Append(MAKEFLAGS, value, VAR_GLOBAL); 1481 Var_Append(MAKEFLAGS, value, VAR_GLOBAL);
1450 } 1482 }
1451 opts.maxJobs = n; 1483 opts.maxJobs = n;
1452 maxJobTokens = opts.maxJobs; 1484 maxJobTokens = opts.maxJobs;
1453 forceJobs = TRUE; 1485 forceJobs = TRUE;
1454 free(value); 1486 free(value);
1455 } 1487 }
1456 1488
1457 /* 1489 /*
1458 * Be compatible if user did not specify -j and did not explicitly 1490 * Be compatible if user did not specify -j and did not explicitly
1459 * turned compatibility on 1491 * turned compatibility on
1460 */ 1492 */
1461 if (!opts.compatMake && !forceJobs) { 1493 if (!opts.compatMake && !forceJobs) {
1462 opts.compatMake = TRUE; 1494 opts.compatMake = TRUE;
1463 } 1495 }
1464 1496
1465 if (!opts.compatMake) 1497 if (!opts.compatMake)
1466 Job_ServerStart(maxJobTokens, jp_0, jp_1); 1498 Job_ServerStart(maxJobTokens, jp_0, jp_1);
1467 DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1499 DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n",
1468 jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0); 1500 jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0);
1469 1501
1470 if (!opts.printVars) 1502 if (!opts.printVars)
1471 Main_ExportMAKEFLAGS(TRUE); /* initial export */ 1503 Main_ExportMAKEFLAGS(TRUE); /* initial export */
1472 1504
1473 1505 InitVpath();
1474 /* 
1475 * For compatibility, look at the directories in the VPATH variable 
1476 * and add them to the search path, if the variable is defined. The 
1477 * variable's value is in the same format as the PATH envariable, i.e. 
1478 * <directory>:<directory>:<directory>... 
1479 */ 
1480 if (Var_Exists("VPATH", VAR_CMD)) { 
1481 char *vpath, savec; 
1482 
1483 (void)Var_Subst("${VPATH}", VAR_CMD, VARE_WANTRES, &vpath); 
1484 /* TODO: handle errors */ 
1485 path = vpath; 
1486 do { 
1487 char *cp; 
1488 /* skip to end of directory */ 
1489 for (cp = path; *cp != ':' && *cp != '\0'; cp++) 
1490 continue; 
1491 /* Save terminator character so know when to stop */ 
1492 savec = *cp; 
1493 *cp = '\0'; 
1494 /* Add directory to search path */ 
1495 (void)Dir_AddDir(dirSearchPath, path); 
1496 *cp = savec; 
1497 path = cp + 1; 
1498 } while (savec == ':'); 
1499 free(vpath); 
1500 } 
1501 1506
1502 /* 1507 /*
1503 * Now that all search paths have been read for suffixes et al, it's 1508 * Now that all search paths have been read for suffixes et al, it's
1504 * time to add the default search path to their lists... 1509 * time to add the default search path to their lists...
1505 */ 1510 */
1506 Suff_DoPaths(); 1511 Suff_DoPaths();
1507 1512
1508 /* 1513 /*
1509 * Propagate attributes through :: dependency lists. 1514 * Propagate attributes through :: dependency lists.
1510 */ 1515 */
1511 Targ_Propagate(); 1516 Targ_Propagate();
1512 1517
1513 /* print the initial graph, if the user requested it */ 1518 /* print the initial graph, if the user requested it */
1514 if (DEBUG(GRAPH1)) 1519 if (DEBUG(GRAPH1))
1515 Targ_PrintGraph(1); 1520 Targ_PrintGraph(1);
1516 1521
1517 /* print the values of any variables requested by the user */ 1522 /* print the values of any variables requested by the user */
1518 if (opts.printVars) { 1523 if (opts.printVars) {
1519 doPrintVars(); 1524 doPrintVars();
1520 outOfDate = FALSE; 1525 outOfDate = FALSE;
1521 } else { 1526 } else {
1522 outOfDate = runTargets(); 1527 outOfDate = runTargets();
1523 } 1528 }
1524 1529
1525#ifdef CLEANUP 1530#ifdef CLEANUP
1526 Lst_Free(opts.variables); 1531 Lst_Free(opts.variables);
1527 Lst_Free(opts.makefiles); 1532 Lst_Free(opts.makefiles);
1528 Lst_Destroy(opts.create, free); 1533 Lst_Destroy(opts.create, free);
1529#endif 1534#endif
1530 1535
1531 /* print the graph now it's been processed if the user requested it */ 1536 /* print the graph now it's been processed if the user requested it */
1532 if (DEBUG(GRAPH2)) 1537 if (DEBUG(GRAPH2))
1533 Targ_PrintGraph(2); 1538 Targ_PrintGraph(2);
1534 1539
1535 Trace_Log(MAKEEND, 0); 1540 Trace_Log(MAKEEND, 0);
1536 1541
1537 if (enterFlagObj) 1542 if (enterFlagObj)
1538 printf("%s: Leaving directory `%s'\n", progname, objdir); 1543 printf("%s: Leaving directory `%s'\n", progname, objdir);
1539 if (opts.enterFlag) 1544 if (opts.enterFlag)
1540 printf("%s: Leaving directory `%s'\n", progname, curdir); 1545 printf("%s: Leaving directory `%s'\n", progname, curdir);
1541 1546
1542#ifdef USE_META 1547#ifdef USE_META
1543 meta_finish(); 1548 meta_finish();
1544#endif 1549#endif
1545 Suff_End(); 1550 Suff_End();
1546 Targ_End(); 1551 Targ_End();
1547 Arch_End(); 1552 Arch_End();
1548 Var_End(); 1553 Var_End();
1549 Parse_End(); 1554 Parse_End();
1550 Dir_End(); 1555 Dir_End();
1551 Job_End(); 1556 Job_End();
1552 Trace_End(); 1557 Trace_End();
1553 1558
1554 return outOfDate ? 1 : 0; 1559 return outOfDate ? 1 : 0;
1555} 1560}
1556 1561
1557/* Open and parse the given makefile, with all its side effects. 1562/* Open and parse the given makefile, with all its side effects.
1558 * 1563 *
1559 * Results: 1564 * Results:
1560 * 0 if ok. -1 if couldn't open file. 1565 * 0 if ok. -1 if couldn't open file.
1561 */ 1566 */
1562static int 1567static int
1563ReadMakefile(const char *fname) 1568ReadMakefile(const char *fname)
1564{ 1569{
1565 int fd; 1570 int fd;
1566 char *name, *path = NULL; 1571 char *name, *path = NULL;
1567 1572
1568 if (!strcmp(fname, "-")) { 1573 if (!strcmp(fname, "-")) {
1569 Parse_File(NULL /*stdin*/, -1); 1574 Parse_File(NULL /*stdin*/, -1);
1570 Var_Set("MAKEFILE", "", VAR_INTERNAL); 1575 Var_Set("MAKEFILE", "", VAR_INTERNAL);
1571 } else { 1576 } else {
1572 /* if we've chdir'd, rebuild the path name */ 1577 /* if we've chdir'd, rebuild the path name */
1573 if (strcmp(curdir, objdir) && *fname != '/') { 1578 if (strcmp(curdir, objdir) && *fname != '/') {
1574 path = str_concat3(curdir, "/", fname); 1579 path = str_concat3(curdir, "/", fname);
1575 fd = open(path, O_RDONLY); 1580 fd = open(path, O_RDONLY);
1576 if (fd != -1) { 1581 if (fd != -1) {
1577 fname = path; 1582 fname = path;
1578 goto found; 1583 goto found;
1579 } 1584 }
1580 free(path); 1585 free(path);
1581 1586
1582 /* If curdir failed, try objdir (ala .depend) */ 1587 /* If curdir failed, try objdir (ala .depend) */
1583 path = str_concat3(objdir, "/", fname); 1588 path = str_concat3(objdir, "/", fname);
1584 fd = open(path, O_RDONLY); 1589 fd = open(path, O_RDONLY);
1585 if (fd != -1) { 1590 if (fd != -1) {
1586 fname = path; 1591 fname = path;
1587 goto found; 1592 goto found;
1588 } 1593 }
1589 } else { 1594 } else {
1590 fd = open(fname, O_RDONLY); 1595 fd = open(fname, O_RDONLY);
1591 if (fd != -1) 1596 if (fd != -1)
1592 goto found; 1597 goto found;
1593 } 1598 }
1594 /* look in -I and system include directories. */ 1599 /* look in -I and system include directories. */
1595 name = Dir_FindFile(fname, parseIncPath); 1600 name = Dir_FindFile(fname, parseIncPath);
1596 if (!name) 1601 if (!name)
1597 name = Dir_FindFile(fname, 1602 name = Dir_FindFile(fname,
1598 Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath); 1603 Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath);
1599 if (!name || (fd = open(name, O_RDONLY)) == -1) { 1604 if (!name || (fd = open(name, O_RDONLY)) == -1) {
1600 free(name); 1605 free(name);
1601 free(path); 1606 free(path);
1602 return -1; 1607 return -1;
1603 } 1608 }
1604 fname = name; 1609 fname = name;
1605 /* 1610 /*
1606 * set the MAKEFILE variable desired by System V fans -- the 1611 * set the MAKEFILE variable desired by System V fans -- the
1607 * placement of the setting here means it gets set to the last 1612 * placement of the setting here means it gets set to the last
1608 * makefile specified, as it is set by SysV make. 1613 * makefile specified, as it is set by SysV make.
1609 */ 1614 */
1610found: 1615found:
1611 if (!doing_depend) 1616 if (!doing_depend)
1612 Var_Set("MAKEFILE", fname, VAR_INTERNAL); 1617 Var_Set("MAKEFILE", fname, VAR_INTERNAL);
1613 Parse_File(fname, fd); 1618 Parse_File(fname, fd);
1614 } 1619 }
1615 free(path); 1620 free(path);
1616 return 0; 1621 return 0;
1617} 1622}
1618 1623
1619 1624
1620 1625
1621/*- 1626/*-
1622 * Cmd_Exec -- 1627 * Cmd_Exec --
1623 * Execute the command in cmd, and return the output of that command 1628 * Execute the command in cmd, and return the output of that command
1624 * in a string. In the output, newlines are replaced with spaces. 1629 * in a string. In the output, newlines are replaced with spaces.
1625 * 1630 *
1626 * Results: 1631 * Results:
1627 * A string containing the output of the command, or the empty string. 1632 * A string containing the output of the command, or the empty string.
1628 * *errfmt returns a format string describing the command failure, 1633 * *errfmt returns a format string describing the command failure,
1629 * if any, using a single %s conversion specification. 1634 * if any, using a single %s conversion specification.
1630 * 1635 *
1631 * Side Effects: 1636 * Side Effects:
1632 * The string must be freed by the caller. 1637 * The string must be freed by the caller.
1633 */ 1638 */
1634char * 1639char *
1635Cmd_Exec(const char *cmd, const char **errfmt) 1640Cmd_Exec(const char *cmd, const char **errfmt)
1636{ 1641{
1637 const char *args[4]; /* Args for invoking the shell */ 1642 const char *args[4]; /* Args for invoking the shell */
1638 int fds[2]; /* Pipe streams */ 1643 int fds[2]; /* Pipe streams */
1639 int cpid; /* Child PID */ 1644 int cpid; /* Child PID */
1640 int pid; /* PID from wait() */ 1645 int pid; /* PID from wait() */
1641 int status; /* command exit status */ 1646 int status; /* command exit status */
1642 Buffer buf; /* buffer to store the result */ 1647 Buffer buf; /* buffer to store the result */
1643 ssize_t bytes_read; 1648 ssize_t bytes_read;
1644 char *res; /* result */ 1649 char *res; /* result */
1645 size_t res_len; 1650 size_t res_len;
1646 char *cp; 1651 char *cp;
1647 int savederr; /* saved errno */ 1652 int savederr; /* saved errno */
1648 1653
1649 *errfmt = NULL; 1654 *errfmt = NULL;
1650 1655
1651 if (!shellName) 1656 if (!shellName)
1652 Shell_Init(); 1657 Shell_Init();
1653 /* 1658 /*
1654 * Set up arguments for shell 1659 * Set up arguments for shell
1655 */ 1660 */
1656 args[0] = shellName; 1661 args[0] = shellName;
1657 args[1] = "-c"; 1662 args[1] = "-c";
1658 args[2] = cmd; 1663 args[2] = cmd;
1659 args[3] = NULL; 1664 args[3] = NULL;
1660 1665
1661 /* 1666 /*
1662 * Open a pipe for fetching its output 1667 * Open a pipe for fetching its output
1663 */ 1668 */
1664 if (pipe(fds) == -1) { 1669 if (pipe(fds) == -1) {
1665 *errfmt = "Couldn't create pipe for \"%s\""; 1670 *errfmt = "Couldn't create pipe for \"%s\"";
1666 goto bad; 1671 goto bad;
1667 } 1672 }
1668 1673
1669 /* 1674 /*
1670 * Fork 1675 * Fork
1671 */ 1676 */
1672 switch (cpid = vFork()) { 1677 switch (cpid = vFork()) {
1673 case 0: 1678 case 0:
1674 /* 1679 /*
1675 * Close input side of pipe 1680 * Close input side of pipe
1676 */ 1681 */
1677 (void)close(fds[0]); 1682 (void)close(fds[0]);
1678 1683
1679 /* 1684 /*
1680 * Duplicate the output stream to the shell's output, then 1685 * Duplicate the output stream to the shell's output, then
1681 * shut the extra thing down. Note we don't fetch the error 1686 * shut the extra thing down. Note we don't fetch the error
1682 * stream...why not? Why? 1687 * stream...why not? Why?
1683 */ 1688 */
1684 (void)dup2(fds[1], 1); 1689 (void)dup2(fds[1], 1);
1685 (void)close(fds[1]); 1690 (void)close(fds[1]);
1686 1691
1687 Var_ExportVars(); 1692 Var_ExportVars();
1688 1693
1689 (void)execv(shellPath, UNCONST(args)); 1694 (void)execv(shellPath, UNCONST(args));
1690 _exit(1); 1695 _exit(1);
1691 /*NOTREACHED*/ 1696 /*NOTREACHED*/
1692 1697
1693 case -1: 1698 case -1:
1694 *errfmt = "Couldn't exec \"%s\""; 1699 *errfmt = "Couldn't exec \"%s\"";
1695 goto bad; 1700 goto bad;
1696 1701
1697 default: 1702 default:
1698 /* 1703 /*
1699 * No need for the writing half 1704 * No need for the writing half
1700 */ 1705 */
1701 (void)close(fds[1]); 1706 (void)close(fds[1]);
1702 1707
1703 savederr = 0; 1708 savederr = 0;
1704 Buf_Init(&buf, 0); 1709 Buf_Init(&buf, 0);
1705 1710
1706 do { 1711 do {
1707 char result[BUFSIZ]; 1712 char result[BUFSIZ];
1708 bytes_read = read(fds[0], result, sizeof(result)); 1713 bytes_read = read(fds[0], result, sizeof(result));
1709 if (bytes_read > 0) 1714 if (bytes_read > 0)
1710 Buf_AddBytes(&buf, result, (size_t)bytes_read); 1715 Buf_AddBytes(&buf, result, (size_t)bytes_read);
1711 } 1716 }
1712 while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR)); 1717 while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR));
1713 if (bytes_read == -1) 1718 if (bytes_read == -1)
1714 savederr = errno; 1719 savederr = errno;
1715 1720
1716 /* 1721 /*
1717 * Close the input side of the pipe. 1722 * Close the input side of the pipe.
1718 */ 1723 */
1719 (void)close(fds[0]); 1724 (void)close(fds[0]);
1720 1725
1721 /* 1726 /*
1722 * Wait for the process to exit. 1727 * Wait for the process to exit.
1723 */ 1728 */
1724 while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) { 1729 while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) {
1725 JobReapChild(pid, status, FALSE); 1730 JobReapChild(pid, status, FALSE);
1726 continue; 1731 continue;
1727 } 1732 }
1728 res_len = Buf_Len(&buf); 1733 res_len = Buf_Len(&buf);
1729 res = Buf_Destroy(&buf, FALSE); 1734 res = Buf_Destroy(&buf, FALSE);
1730 1735
1731 if (savederr != 0) 1736 if (savederr != 0)
1732 *errfmt = "Couldn't read shell's output for \"%s\""; 1737 *errfmt = "Couldn't read shell's output for \"%s\"";
1733 1738
1734 if (WIFSIGNALED(status)) 1739 if (WIFSIGNALED(status))
1735 *errfmt = "\"%s\" exited on a signal"; 1740 *errfmt = "\"%s\" exited on a signal";
1736 else if (WEXITSTATUS(status) != 0) 1741 else if (WEXITSTATUS(status) != 0)
1737 *errfmt = "\"%s\" returned non-zero status"; 1742 *errfmt = "\"%s\" returned non-zero status";
1738 1743
1739 /* Convert newlines to spaces. A final newline is just stripped */ 1744 /* Convert newlines to spaces. A final newline is just stripped */
1740 if (res_len > 0 && res[res_len - 1] == '\n') 1745 if (res_len > 0 && res[res_len - 1] == '\n')
1741 res[res_len - 1] = '\0'; 1746 res[res_len - 1] = '\0';
1742 for (cp = res; *cp != '\0'; cp++) 1747 for (cp = res; *cp != '\0'; cp++)
1743 if (*cp == '\n') 1748 if (*cp == '\n')
1744 *cp = ' '; 1749 *cp = ' ';
1745 break; 1750 break;
1746 } 1751 }
1747 return res; 1752 return res;
1748bad: 1753bad:
1749 return bmake_strdup(""); 1754 return bmake_strdup("");
1750} 1755}
1751 1756
1752/* Print a printf-style error message. 1757/* Print a printf-style error message.
1753 * 1758 *
1754 * This error message has no consequences, in particular it does not affect 1759 * This error message has no consequences, in particular it does not affect
1755 * the exit status. */ 1760 * the exit status. */
1756void 1761void
1757Error(const char *fmt, ...) 1762Error(const char *fmt, ...)
1758{ 1763{
1759 va_list ap; 1764 va_list ap;
1760 FILE *err_file; 1765 FILE *err_file;
1761 1766
1762 err_file = opts.debug_file; 1767 err_file = opts.debug_file;
1763 if (err_file == stdout) 1768 if (err_file == stdout)
1764 err_file = stderr; 1769 err_file = stderr;
1765 (void)fflush(stdout); 1770 (void)fflush(stdout);
1766 for (;;) { 1771 for (;;) {
1767 va_start(ap, fmt); 1772 va_start(ap, fmt);
1768 fprintf(err_file, "%s: ", progname); 1773 fprintf(err_file, "%s: ", progname);
1769 (void)vfprintf(err_file, fmt, ap); 1774 (void)vfprintf(err_file, fmt, ap);
1770 va_end(ap); 1775 va_end(ap);
1771 (void)fprintf(err_file, "\n"); 1776 (void)fprintf(err_file, "\n");
1772 (void)fflush(err_file); 1777 (void)fflush(err_file);
1773 if (err_file == stderr) 1778 if (err_file == stderr)
1774 break; 1779 break;
1775 err_file = stderr; 1780 err_file = stderr;
1776 } 1781 }
1777} 1782}
1778 1783
1779/* Produce a Fatal error message, then exit immediately. 1784/* Produce a Fatal error message, then exit immediately.
1780 * 1785 *
1781 * If jobs are running, waits for them to finish. */ 1786 * If jobs are running, waits for them to finish. */
1782void 1787void
1783Fatal(const char *fmt, ...) 1788Fatal(const char *fmt, ...)
1784{ 1789{
1785 va_list ap; 1790 va_list ap;
1786 1791
1787 va_start(ap, fmt); 1792 va_start(ap, fmt);
1788 if (jobsRunning) 1793 if (jobsRunning)
1789 Job_Wait(); 1794 Job_Wait();
1790 1795
1791 (void)fflush(stdout); 1796 (void)fflush(stdout);
1792 (void)vfprintf(stderr, fmt, ap); 1797 (void)vfprintf(stderr, fmt, ap);
1793 va_end(ap); 1798 va_end(ap);
1794 (void)fprintf(stderr, "\n"); 1799 (void)fprintf(stderr, "\n");
1795 (void)fflush(stderr); 1800 (void)fflush(stderr);
1796 1801
1797 PrintOnError(NULL, NULL); 1802 PrintOnError(NULL, NULL);
1798 1803
1799 if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 1804 if (DEBUG(GRAPH2) || DEBUG(GRAPH3))
1800 Targ_PrintGraph(2); 1805 Targ_PrintGraph(2);
1801 Trace_Log(MAKEERROR, 0); 1806 Trace_Log(MAKEERROR, 0);
1802 exit(2); /* Not 1 so -q can distinguish error */ 1807 exit(2); /* Not 1 so -q can distinguish error */
1803} 1808}
1804 1809
1805/* Major exception once jobs are being created. 1810/* Major exception once jobs are being created.
1806 * Kills all jobs, prints a message and exits. */ 1811 * Kills all jobs, prints a message and exits. */
1807void 1812void
1808Punt(const char *fmt, ...) 1813Punt(const char *fmt, ...)
1809{ 1814{
1810 va_list ap; 1815 va_list ap;
1811 1816
1812 va_start(ap, fmt); 1817 va_start(ap, fmt);
1813 (void)fflush(stdout); 1818 (void)fflush(stdout);
1814 (void)fprintf(stderr, "%s: ", progname); 1819 (void)fprintf(stderr, "%s: ", progname);
1815 (void)vfprintf(stderr, fmt, ap); 1820 (void)vfprintf(stderr, fmt, ap);
1816 va_end(ap); 1821 va_end(ap);
1817 (void)fprintf(stderr, "\n"); 1822 (void)fprintf(stderr, "\n");
1818 (void)fflush(stderr); 1823 (void)fflush(stderr);
1819 1824
1820 PrintOnError(NULL, NULL); 1825 PrintOnError(NULL, NULL);
1821 1826
1822 DieHorribly(); 1827 DieHorribly();
1823} 1828}
1824 1829
1825/* Exit without giving a message. */ 1830/* Exit without giving a message. */
1826void 1831void
1827DieHorribly(void) 1832DieHorribly(void)
1828{ 1833{
1829 if (jobsRunning) 1834 if (jobsRunning)
1830 Job_AbortAll(); 1835 Job_AbortAll();
1831 if (DEBUG(GRAPH2)) 1836 if (DEBUG(GRAPH2))
1832 Targ_PrintGraph(2); 1837 Targ_PrintGraph(2);
1833 Trace_Log(MAKEERROR, 0); 1838 Trace_Log(MAKEERROR, 0);
1834 exit(2); /* Not 1, so -q can distinguish error */ 1839 exit(2); /* Not 1, so -q can distinguish error */
1835} 1840}
1836 1841
1837/* Called when aborting due to errors in child shell to signal abnormal exit. 1842/* Called when aborting due to errors in child shell to signal abnormal exit.
1838 * The program exits. 1843 * The program exits.
1839 * Errors is the number of errors encountered in Make_Make. */ 1844 * Errors is the number of errors encountered in Make_Make. */
1840void 1845void
1841Finish(int errors) 1846Finish(int errors)
1842{ 1847{
1843 if (dieQuietly(NULL, -1)) 1848 if (dieQuietly(NULL, -1))
1844 exit(2); 1849 exit(2);
1845 Fatal("%d error%s", errors, errors == 1 ? "" : "s"); 1850 Fatal("%d error%s", errors, errors == 1 ? "" : "s");
1846} 1851}
1847 1852
1848/* 1853/*
1849 * eunlink -- 1854 * eunlink --
1850 * Remove a file carefully, avoiding directories. 1855 * Remove a file carefully, avoiding directories.
1851 */ 1856 */
1852int 1857int
1853eunlink(const char *file) 1858eunlink(const char *file)
1854{ 1859{
1855 struct stat st; 1860 struct stat st;
1856 1861
1857 if (lstat(file, &st) == -1) 1862 if (lstat(file, &st) == -1)
1858 return -1; 1863 return -1;
1859 1864
1860 if (S_ISDIR(st.st_mode)) { 1865 if (S_ISDIR(st.st_mode)) {
1861 errno = EISDIR; 1866 errno = EISDIR;
1862 return -1; 1867 return -1;
1863 } 1868 }
1864 return unlink(file); 1869 return unlink(file);
1865} 1870}
1866 1871
1867static void 1872static void
1868write_all(int fd, const void *data, size_t n) 1873write_all(int fd, const void *data, size_t n)
1869{ 1874{
1870 const char *mem = data; 1875 const char *mem = data;
1871 1876
1872 while (n > 0) { 1877 while (n > 0) {
1873 ssize_t written = write(fd, mem, n); 1878 ssize_t written = write(fd, mem, n);
1874 if (written == -1 && errno == EAGAIN) 1879 if (written == -1 && errno == EAGAIN)
1875 continue; 1880 continue;
1876 if (written == -1) 1881 if (written == -1)
1877 break; 1882 break;
1878 mem += written; 1883 mem += written;
1879 n -= (size_t)written; 1884 n -= (size_t)written;
1880 } 1885 }
1881} 1886}
1882 1887
1883/* 1888/*
1884 * execDie -- 1889 * execDie --
1885 * Print why exec failed, avoiding stdio. 1890 * Print why exec failed, avoiding stdio.
1886 */ 1891 */
1887void MAKE_ATTR_DEAD 1892void MAKE_ATTR_DEAD
1888execDie(const char *af, const char *av) 1893execDie(const char *af, const char *av)
1889{ 1894{
1890 Buffer buf; 1895 Buffer buf;
1891 1896
1892 Buf_Init(&buf, 0); 1897 Buf_Init(&buf, 0);
1893 Buf_AddStr(&buf, progname); 1898 Buf_AddStr(&buf, progname);
1894 Buf_AddStr(&buf, ": "); 1899 Buf_AddStr(&buf, ": ");
1895 Buf_AddStr(&buf, af); 1900 Buf_AddStr(&buf, af);
1896 Buf_AddStr(&buf, "("); 1901 Buf_AddStr(&buf, "(");
1897 Buf_AddStr(&buf, av); 1902 Buf_AddStr(&buf, av);
1898 Buf_AddStr(&buf, ") failed ("); 1903 Buf_AddStr(&buf, ") failed (");
1899 Buf_AddStr(&buf, strerror(errno)); 1904 Buf_AddStr(&buf, strerror(errno));
1900 Buf_AddStr(&buf, ")\n"); 1905 Buf_AddStr(&buf, ")\n");
1901 1906
1902 write_all(STDERR_FILENO, Buf_GetAll(&buf, NULL), Buf_Len(&buf)); 1907 write_all(STDERR_FILENO, Buf_GetAll(&buf, NULL), Buf_Len(&buf));
1903 1908
1904 Buf_Destroy(&buf, TRUE); 1909 Buf_Destroy(&buf, TRUE);
1905 _exit(1); 1910 _exit(1);
1906} 1911}
1907 1912
1908/* 1913/*
1909 * usage -- 1914 * usage --
1910 * exit with usage message 1915 * exit with usage message
1911 */ 1916 */
1912static void 1917static void
1913usage(void) 1918usage(void)
1914{ 1919{
1915 char *p; 1920 char *p;
1916 if ((p = strchr(progname, '[')) != NULL) 1921 if ((p = strchr(progname, '[')) != NULL)
1917 *p = '\0'; 1922 *p = '\0';
1918 1923
1919 (void)fprintf(stderr, 1924 (void)fprintf(stderr,
1920"usage: %s [-BeikNnqrstWwX] \n" 1925"usage: %s [-BeikNnqrstWwX] \n"
1921" [-C directory] [-D variable] [-d flags] [-f makefile]\n" 1926" [-C directory] [-D variable] [-d flags] [-f makefile]\n"
1922" [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n" 1927" [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n"
1923" [-V variable] [-v variable] [variable=value] [target ...]\n", 1928" [-V variable] [-v variable] [variable=value] [target ...]\n",
1924 progname); 1929 progname);
1925 exit(2); 1930 exit(2);
1926} 1931}
1927 1932
1928/* 1933/*
1929 * realpath(3) can get expensive, cache results... 1934 * realpath(3) can get expensive, cache results...
1930 */ 1935 */
1931static GNode *cached_realpaths = NULL; 1936static GNode *cached_realpaths = NULL;
1932 1937
1933static GNode * 1938static GNode *
1934get_cached_realpaths(void) 1939get_cached_realpaths(void)
1935{ 1940{
1936 1941
1937 if (!cached_realpaths) { 1942 if (!cached_realpaths) {
1938 cached_realpaths = Targ_NewGN("Realpath"); 1943 cached_realpaths = Targ_NewGN("Realpath");
1939#ifndef DEBUG_REALPATH_CACHE 1944#ifndef DEBUG_REALPATH_CACHE
1940 cached_realpaths->flags = INTERNAL; 1945 cached_realpaths->flags = INTERNAL;
1941#endif 1946#endif
1942 } 1947 }
1943 1948
1944 return cached_realpaths; 1949 return cached_realpaths;
1945} 1950}
1946 1951
1947/* purge any relative paths */ 1952/* purge any relative paths */
1948static void 1953static void
1949purge_cached_realpaths(void) 1954purge_cached_realpaths(void)
1950{ 1955{
1951 GNode *cache = get_cached_realpaths(); 1956 GNode *cache = get_cached_realpaths();
1952 HashEntry *he, *nhe; 1957 HashEntry *he, *nhe;
1953 HashIter hi; 1958 HashIter hi;
1954 1959
1955 HashIter_Init(&hi, &cache->context); 1960 HashIter_Init(&hi, &cache->context);
1956 he = HashIter_Next(&hi); 1961 he = HashIter_Next(&hi);
1957 while (he != NULL) { 1962 while (he != NULL) {
1958 nhe = HashIter_Next(&hi); 1963 nhe = HashIter_Next(&hi);
1959 if (he->key[0] != '/') { 1964 if (he->key[0] != '/') {
1960 if (DEBUG(DIR)) 1965 if (DEBUG(DIR))
1961 fprintf(stderr, "cached_realpath: purging %s\n", he->key); 1966 fprintf(stderr, "cached_realpath: purging %s\n", he->key);
1962 HashTable_DeleteEntry(&cache->context, he); 1967 HashTable_DeleteEntry(&cache->context, he);
1963 } 1968 }
1964 he = nhe; 1969 he = nhe;
1965 } 1970 }
1966} 1971}
1967 1972
1968char * 1973char *
1969cached_realpath(const char *pathname, char *resolved) 1974cached_realpath(const char *pathname, char *resolved)
1970{ 1975{
1971 GNode *cache; 1976 GNode *cache;
1972 const char *rp; 1977 const char *rp;
1973 char *cp; 1978 char *cp;
1974 1979
1975 if (!pathname || !pathname[0]) 1980 if (!pathname || !pathname[0])
1976 return NULL; 1981 return NULL;
1977 1982
1978 cache = get_cached_realpaths(); 1983 cache = get_cached_realpaths();
1979 1984
1980 if ((rp = Var_Value(pathname, cache, &cp)) != NULL) { 1985 if ((rp = Var_Value(pathname, cache, &cp)) != NULL) {
1981 /* a hit */ 1986 /* a hit */
1982 strncpy(resolved, rp, MAXPATHLEN); 1987 strncpy(resolved, rp, MAXPATHLEN);
1983 resolved[MAXPATHLEN - 1] = '\0'; 1988 resolved[MAXPATHLEN - 1] = '\0';
1984 } else if ((rp = realpath(pathname, resolved)) != NULL) { 1989 } else if ((rp = realpath(pathname, resolved)) != NULL) {
1985 Var_Set(pathname, rp, cache); 1990 Var_Set(pathname, rp, cache);
1986 } /* else should we negative-cache? */ 1991 } /* else should we negative-cache? */
1987 1992
1988 bmake_free(cp); 1993 bmake_free(cp);
1989 return rp ? resolved : NULL; 1994 return rp ? resolved : NULL;
1990} 1995}
1991 1996
1992/* 1997/*
1993 * Return true if we should die without noise. 1998 * Return true if we should die without noise.
1994 * For example our failing child was a sub-make 1999 * For example our failing child was a sub-make
1995 * or failure happend elsewhere. 2000 * or failure happend elsewhere.
1996 */ 2001 */
1997int 2002int
1998dieQuietly(GNode *gn, int bf) 2003dieQuietly(GNode *gn, int bf)
1999{ 2004{
2000 static int quietly = -1; 2005 static int quietly = -1;
2001 2006
2002 if (quietly < 0) { 2007 if (quietly < 0) {
2003 if (DEBUG(JOB) || getBoolean(".MAKE.DIE_QUIETLY", 1) == 0) 2008 if (DEBUG(JOB) || getBoolean(".MAKE.DIE_QUIETLY", 1) == 0)
2004 quietly = 0; 2009 quietly = 0;
2005 else if (bf >= 0) 2010 else if (bf >= 0)
2006 quietly = bf; 2011 quietly = bf;
2007 else 2012 else
2008 quietly = gn != NULL ? ((gn->type & (OP_MAKE)) != 0) : 0; 2013 quietly = gn != NULL ? ((gn->type & (OP_MAKE)) != 0) : 0;
2009 } 2014 }
2010 return quietly; 2015 return quietly;
2011} 2016}
2012 2017
2013static void 2018static void
2014SetErrorVars(GNode *gn) 2019SetErrorVars(GNode *gn)
2015{ 2020{
2016 StringListNode *ln; 2021 StringListNode *ln;
2017 2022
2018 /* 2023 /*
2019 * We can print this even if there is no .ERROR target. 2024 * We can print this even if there is no .ERROR target.
2020 */ 2025 */
2021 Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL); 2026 Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL);
2022 Var_Delete(".ERROR_CMD", VAR_GLOBAL); 2027 Var_Delete(".ERROR_CMD", VAR_GLOBAL);
2023 2028
2024 for (ln = gn->commands->first; ln != NULL; ln = ln->next) { 2029 for (ln = gn->commands->first; ln != NULL; ln = ln->next) {
2025 const char *cmd = ln->datum; 2030 const char *cmd = ln->datum;
2026 2031
2027 if (cmd == NULL) 2032 if (cmd == NULL)
2028 break; 2033 break;
2029 Var_Append(".ERROR_CMD", cmd, VAR_GLOBAL); 2034 Var_Append(".ERROR_CMD", cmd, VAR_GLOBAL);
2030 } 2035 }
2031} 2036}
2032 2037
2033void 2038void
2034PrintOnError(GNode *gn, const char *s) 2039PrintOnError(GNode *gn, const char *s)
2035{ 2040{
2036 static GNode *en = NULL; 2041 static GNode *en = NULL;
2037 const char *expr; 2042 const char *expr;
2038 char *cp; 2043 char *cp;
2039 2044
2040 if (DEBUG(HASH)) { 2045 if (DEBUG(HASH)) {
2041 Targ_Stats(); 2046 Targ_Stats();
2042 Var_Stats(); 2047 Var_Stats();
2043 } 2048 }
2044 2049
2045 /* we generally want to keep quiet if a sub-make died */ 2050 /* we generally want to keep quiet if a sub-make died */
2046 if (dieQuietly(gn, -1)) 2051 if (dieQuietly(gn, -1))
2047 return; 2052 return;
2048 2053
2049 if (s) 2054 if (s)
2050 printf("%s", s); 2055 printf("%s", s);
2051 2056
2052 printf("\n%s: stopped in %s\n", progname, curdir); 2057 printf("\n%s: stopped in %s\n", progname, curdir);
2053 2058
2054 if (en) 2059 if (en)
2055 return; /* we've been here! */ 2060 return; /* we've been here! */
2056 if (gn) 2061 if (gn)
2057 SetErrorVars(gn); 2062 SetErrorVars(gn);
2058 expr = "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}"; 2063 expr = "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}";
2059 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp); 2064 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp);
2060 /* TODO: handle errors */ 2065 /* TODO: handle errors */
2061 printf("%s", cp); 2066 printf("%s", cp);
2062 free(cp); 2067 free(cp);
2063 fflush(stdout); 2068 fflush(stdout);
2064 2069
2065 /* 2070 /*
2066 * Finally, see if there is a .ERROR target, and run it if so. 2071 * Finally, see if there is a .ERROR target, and run it if so.
2067 */ 2072 */
2068 en = Targ_FindNode(".ERROR"); 2073 en = Targ_FindNode(".ERROR");
2069 if (en) { 2074 if (en) {
2070 en->type |= OP_SPECIAL; 2075 en->type |= OP_SPECIAL;
2071 Compat_Make(en, en); 2076 Compat_Make(en, en);
2072 } 2077 }
2073} 2078}
2074 2079
2075void 2080void
2076Main_ExportMAKEFLAGS(Boolean first) 2081Main_ExportMAKEFLAGS(Boolean first)
2077{ 2082{
2078 static Boolean once = TRUE; 2083 static Boolean once = TRUE;
2079 const char *expr; 2084 const char *expr;
2080 char *s; 2085 char *s;
2081 2086
2082 if (once != first) 2087 if (once != first)
2083 return; 2088 return;
2084 once = FALSE; 2089 once = FALSE;
2085 2090
2086 expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}"; 2091 expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}";
2087 (void)Var_Subst(expr, VAR_CMD, VARE_WANTRES, &s); 2092 (void)Var_Subst(expr, VAR_CMD, VARE_WANTRES, &s);
2088 /* TODO: handle errors */ 2093 /* TODO: handle errors */
2089 if (s[0] != '\0') { 2094 if (s[0] != '\0') {
2090#ifdef POSIX 2095#ifdef POSIX
2091 setenv("MAKEFLAGS", s, 1); 2096 setenv("MAKEFLAGS", s, 1);
2092#else 2097#else
2093 setenv("MAKE", s, 1); 2098 setenv("MAKE", s, 1);
2094#endif 2099#endif
2095 } 2100 }
2096} 2101}
2097 2102
2098char * 2103char *
2099getTmpdir(void) 2104getTmpdir(void)
2100{ 2105{
2101 static char *tmpdir = NULL; 2106 static char *tmpdir = NULL;
2102 2107
2103 if (!tmpdir) { 2108 if (!tmpdir) {
2104 struct stat st; 2109 struct stat st;
2105 2110
2106 /* 2111 /*
2107 * Honor $TMPDIR but only if it is valid. 2112 * Honor $TMPDIR but only if it is valid.
2108 * Ensure it ends with /. 2113 * Ensure it ends with /.
2109 */ 2114 */
2110 (void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, 2115 (void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL,
2111 VARE_WANTRES, &tmpdir); 2116 VARE_WANTRES, &tmpdir);
2112 /* TODO: handle errors */ 2117 /* TODO: handle errors */
2113 if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 2118 if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) {
2114 free(tmpdir); 2119 free(tmpdir);
2115 tmpdir = bmake_strdup(_PATH_TMP); 2120 tmpdir = bmake_strdup(_PATH_TMP);
2116 } 2121 }
2117 } 2122 }
2118 return tmpdir; 2123 return tmpdir;
2119} 2124}
2120 2125
2121/* 2126/*
2122 * Create and open a temp file using "pattern". 2127 * Create and open a temp file using "pattern".
2123 * If "fnamep" is provided set it to a copy of the filename created. 2128 * If "fnamep" is provided set it to a copy of the filename created.
2124 * Otherwise unlink the file once open. 2129 * Otherwise unlink the file once open.
2125 */ 2130 */
2126int 2131int
2127mkTempFile(const char *pattern, char **fnamep) 2132mkTempFile(const char *pattern, char **fnamep)
2128{ 2133{
2129 static char *tmpdir = NULL; 2134 static char *tmpdir = NULL;
2130 char tfile[MAXPATHLEN]; 2135 char tfile[MAXPATHLEN];
2131 int fd; 2136 int fd;
2132 2137
2133 if (!pattern) 2138 if (!pattern)
2134 pattern = TMPPAT; 2139 pattern = TMPPAT;
2135 if (!tmpdir) 2140 if (!tmpdir)
2136 tmpdir = getTmpdir(); 2141 tmpdir = getTmpdir();
2137 if (pattern[0] == '/') { 2142 if (pattern[0] == '/') {
2138 snprintf(tfile, sizeof(tfile), "%s", pattern); 2143 snprintf(tfile, sizeof(tfile), "%s", pattern);
2139 } else { 2144 } else {
2140 snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern); 2145 snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern);
2141 } 2146 }
2142 if ((fd = mkstemp(tfile)) < 0) 2147 if ((fd = mkstemp(tfile)) < 0)
2143 Punt("Could not create temporary file %s: %s", tfile, strerror(errno)); 2148 Punt("Could not create temporary file %s: %s", tfile, strerror(errno));
2144 if (fnamep) { 2149 if (fnamep) {
2145 *fnamep = bmake_strdup(tfile); 2150 *fnamep = bmake_strdup(tfile);
2146 } else { 2151 } else {
2147 unlink(tfile); /* we just want the descriptor */ 2152 unlink(tfile); /* we just want the descriptor */
2148 } 2153 }
2149 return fd; 2154 return fd;
2150} 2155}
2151 2156
2152/* 2157/*
2153 * Convert a string representation of a boolean. 2158 * Convert a string representation of a boolean.
2154 * Anything that looks like "No", "False", "Off", "0" etc, 2159 * Anything that looks like "No", "False", "Off", "0" etc,
2155 * is FALSE, otherwise TRUE. 2160 * is FALSE, otherwise TRUE.
2156 */ 2161 */
2157Boolean 2162Boolean
2158s2Boolean(const char *s, Boolean bf) 2163s2Boolean(const char *s, Boolean bf)
2159{ 2164{
2160 if (s) { 2165 if (s) {
2161 switch(*s) { 2166 switch(*s) {
2162 case '\0': /* not set - the default wins */ 2167 case '\0': /* not set - the default wins */
2163 break; 2168 break;
2164 case '0': 2169 case '0':
2165 case 'F': 2170 case 'F':
2166 case 'f': 2171 case 'f':
2167 case 'N': 2172 case 'N':
2168 case 'n': 2173 case 'n':
2169 bf = FALSE; 2174 bf = FALSE;
2170 break; 2175 break;
2171 case 'O': 2176 case 'O':
2172 case 'o': 2177 case 'o':
2173 switch (s[1]) { 2178 switch (s[1]) {
2174 case 'F': 2179 case 'F':
2175 case 'f': 2180 case 'f':
2176 bf = FALSE; 2181 bf = FALSE;
2177 break; 2182 break;
2178 default: 2183 default:
2179 bf = TRUE; 2184 bf = TRUE;
2180 break; 2185 break;
2181 } 2186 }
2182 break; 2187 break;
2183 default: 2188 default:
2184 bf = TRUE; 2189 bf = TRUE;
2185 break; 2190 break;
2186 } 2191 }
2187 } 2192 }
2188 return bf; 2193 return bf;
2189} 2194}
2190 2195
2191/* 2196/*
2192 * Return a Boolean based on setting of a knob. 2197 * Return a Boolean based on setting of a knob.
2193 * 2198 *
2194 * If the knob is not set, the supplied default is the return value. 2199 * If the knob is not set, the supplied default is the return value.
2195 * If set, anything that looks or smells like "No", "False", "Off", "0" etc, 2200 * If set, anything that looks or smells like "No", "False", "Off", "0" etc,
2196 * is FALSE, otherwise TRUE. 2201 * is FALSE, otherwise TRUE.
2197 */ 2202 */
2198Boolean 2203Boolean
2199getBoolean(const char *name, Boolean fallback) 2204getBoolean(const char *name, Boolean fallback)
2200{ 2205{
2201 char *expr = str_concat3("${", name, ":U:tl}"); 2206 char *expr = str_concat3("${", name, ":U:tl}");
2202 char *value; 2207 char *value;
2203 Boolean res; 2208 Boolean res;
2204 2209
2205 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &value); 2210 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &value);
2206 /* TODO: handle errors */ 2211 /* TODO: handle errors */
2207 res = s2Boolean(value, fallback); 2212 res = s2Boolean(value, fallback);
2208 free(value); 2213 free(value);
2209 free(expr); 2214 free(expr);
2210 return res; 2215 return res;
2211} 2216}