Tue Oct 27 18:16:20 2020 UTC ()
make(1): extract InitObjdir from main


(rillig)
diff -r1.406 -r1.407 src/usr.bin/make/main.c

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

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