Tue Oct 27 17:36:17 2020 UTC ()
make(1): extract InitVarMake from main


(rillig)
diff -r1.404 -r1.405 src/usr.bin/make/main.c

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

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