Wed Oct 28 03:21:25 2020 UTC ()
make(1): rename defIncPath to defSysIncPath

There are two variables, parseIncPath and sysIncPath, which made the
name defIncPath ambiguous.


(rillig)
diff -r1.408 -r1.409 src/usr.bin/make/main.c
diff -r1.408 -r1.409 src/usr.bin/make/parse.c
diff -r1.174 -r1.175 src/usr.bin/make/make.h

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

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

cvs diff -r1.408 -r1.409 src/usr.bin/make/parse.c (switch to unified diff)

--- src/usr.bin/make/parse.c 2020/10/28 03:12:54 1.408
+++ src/usr.bin/make/parse.c 2020/10/28 03:21:25 1.409
@@ -1,3201 +1,3201 @@ @@ -1,3201 +1,3201 @@
1/* $NetBSD: parse.c,v 1.408 2020/10/28 03:12:54 rillig Exp $ */ 1/* $NetBSD: parse.c,v 1.409 2020/10/28 03:21:25 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 * Parsing of makefiles. 72 * Parsing of makefiles.
73 * 73 *
74 * Parse_File is the main entry point and controls most of the other 74 * Parse_File is the main entry point and controls most of the other
75 * functions in this module. 75 * functions in this module.
76 * 76 *
77 * The directories for the .include "..." directive are kept in 77 * The directories for the .include "..." directive are kept in
78 * 'parseIncPath', while those for .include <...> are kept in 'sysIncPath'. 78 * 'parseIncPath', while those for .include <...> are kept in 'sysIncPath'.
79 * The targets currently being defined are kept in 'targets'. 79 * The targets currently being defined are kept in 'targets'.
80 * 80 *
81 * Interface: 81 * Interface:
82 * Parse_Init Initialize the module 82 * Parse_Init Initialize the module
83 * 83 *
84 * Parse_End Clean up the module 84 * Parse_End Clean up the module
85 * 85 *
86 * Parse_File Parse a top-level makefile. Included files are 86 * Parse_File Parse a top-level makefile. Included files are
87 * handled by Parse_include_file though. 87 * handled by Parse_include_file though.
88 * 88 *
89 * Parse_IsVar Return TRUE if the given line is a variable 89 * Parse_IsVar Return TRUE if the given line is a variable
90 * assignment. Used by MainParseArgs to determine if 90 * assignment. Used by MainParseArgs to determine if
91 * an argument is a target or a variable assignment. 91 * an argument is a target or a variable assignment.
92 * Used internally for pretty much the same thing. 92 * Used internally for pretty much the same thing.
93 * 93 *
94 * Parse_Error Report a parse error, a warning or an informational 94 * Parse_Error Report a parse error, a warning or an informational
95 * message. 95 * message.
96 * 96 *
97 * Parse_MainName Returns a list of the main target to create. 97 * Parse_MainName Returns a list of the main target to create.
98 */ 98 */
99 99
100#include <sys/types.h> 100#include <sys/types.h>
101#include <sys/mman.h> 101#include <sys/mman.h>
102#include <sys/stat.h> 102#include <sys/stat.h>
103#include <errno.h> 103#include <errno.h>
104#include <stdarg.h> 104#include <stdarg.h>
105#include <stdint.h> 105#include <stdint.h>
106 106
107#ifndef MAP_FILE 107#ifndef MAP_FILE
108#define MAP_FILE 0 108#define MAP_FILE 0
109#endif 109#endif
110#ifndef MAP_COPY 110#ifndef MAP_COPY
111#define MAP_COPY MAP_PRIVATE 111#define MAP_COPY MAP_PRIVATE
112#endif 112#endif
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 118
119/* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ 119/* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */
120MAKE_RCSID("$NetBSD: parse.c,v 1.408 2020/10/28 03:12:54 rillig Exp $"); 120MAKE_RCSID("$NetBSD: parse.c,v 1.409 2020/10/28 03:21:25 rillig Exp $");
121 121
122/* types and constants */ 122/* types and constants */
123 123
124/* 124/*
125 * Structure for a file being read ("included file") 125 * Structure for a file being read ("included file")
126 */ 126 */
127typedef struct IFile { 127typedef struct IFile {
128 char *fname; /* name of file */ 128 char *fname; /* name of file */
129 Boolean fromForLoop; /* simulated .include by the .for loop */ 129 Boolean fromForLoop; /* simulated .include by the .for loop */
130 int lineno; /* current line number in file */ 130 int lineno; /* current line number in file */
131 int first_lineno; /* line number of start of text */ 131 int first_lineno; /* line number of start of text */
132 unsigned int cond_depth; /* 'if' nesting when file opened */ 132 unsigned int cond_depth; /* 'if' nesting when file opened */
133 Boolean depending; /* state of doing_depend on EOF */ 133 Boolean depending; /* state of doing_depend on EOF */
134 134
135 /* The buffer from which the file's content is read. */ 135 /* The buffer from which the file's content is read. */
136 char *buf_freeIt; 136 char *buf_freeIt;
137 char *buf_ptr; /* next char to be read */ 137 char *buf_ptr; /* next char to be read */
138 char *buf_end; 138 char *buf_end;
139 139
140 char *(*nextbuf)(void *, size_t *); /* Function to get more data */ 140 char *(*nextbuf)(void *, size_t *); /* Function to get more data */
141 void *nextbuf_arg; /* Opaque arg for nextbuf() */ 141 void *nextbuf_arg; /* Opaque arg for nextbuf() */
142 struct loadedfile *lf; /* loadedfile object, if any */ 142 struct loadedfile *lf; /* loadedfile object, if any */
143} IFile; 143} IFile;
144 144
145/* 145/*
146 * Tokens for target attributes 146 * Tokens for target attributes
147 */ 147 */
148typedef enum ParseSpecial { 148typedef enum ParseSpecial {
149 SP_ATTRIBUTE, /* Generic attribute */ 149 SP_ATTRIBUTE, /* Generic attribute */
150 SP_BEGIN, /* .BEGIN */ 150 SP_BEGIN, /* .BEGIN */
151 SP_DEFAULT, /* .DEFAULT */ 151 SP_DEFAULT, /* .DEFAULT */
152 SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */ 152 SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */
153 SP_END, /* .END */ 153 SP_END, /* .END */
154 SP_ERROR, /* .ERROR */ 154 SP_ERROR, /* .ERROR */
155 SP_IGNORE, /* .IGNORE */ 155 SP_IGNORE, /* .IGNORE */
156 SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */ 156 SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */
157 SP_INTERRUPT, /* .INTERRUPT */ 157 SP_INTERRUPT, /* .INTERRUPT */
158 SP_LIBS, /* .LIBS; not mentioned in the manual page */ 158 SP_LIBS, /* .LIBS; not mentioned in the manual page */
159 SP_MAIN, /* .MAIN and we don't have anything user-specified to 159 SP_MAIN, /* .MAIN and we don't have anything user-specified to
160 * make */ 160 * make */
161 SP_META, /* .META */ 161 SP_META, /* .META */
162 SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */ 162 SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */
163 SP_NOMETA, /* .NOMETA */ 163 SP_NOMETA, /* .NOMETA */
164 SP_NOMETA_CMP, /* .NOMETA_CMP */ 164 SP_NOMETA_CMP, /* .NOMETA_CMP */
165 SP_NOPATH, /* .NOPATH */ 165 SP_NOPATH, /* .NOPATH */
166 SP_NOT, /* Not special */ 166 SP_NOT, /* Not special */
167 SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */ 167 SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */
168 SP_NULL, /* .NULL; not mentioned in the manual page */ 168 SP_NULL, /* .NULL; not mentioned in the manual page */
169 SP_OBJDIR, /* .OBJDIR */ 169 SP_OBJDIR, /* .OBJDIR */
170 SP_ORDER, /* .ORDER */ 170 SP_ORDER, /* .ORDER */
171 SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */ 171 SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */
172 SP_PATH, /* .PATH or .PATH.suffix */ 172 SP_PATH, /* .PATH or .PATH.suffix */
173 SP_PHONY, /* .PHONY */ 173 SP_PHONY, /* .PHONY */
174#ifdef POSIX 174#ifdef POSIX
175 SP_POSIX, /* .POSIX; not mentioned in the manual page */ 175 SP_POSIX, /* .POSIX; not mentioned in the manual page */
176#endif 176#endif
177 SP_PRECIOUS, /* .PRECIOUS */ 177 SP_PRECIOUS, /* .PRECIOUS */
178 SP_SHELL, /* .SHELL */ 178 SP_SHELL, /* .SHELL */
179 SP_SILENT, /* .SILENT */ 179 SP_SILENT, /* .SILENT */
180 SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */ 180 SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */
181 SP_STALE, /* .STALE */ 181 SP_STALE, /* .STALE */
182 SP_SUFFIXES, /* .SUFFIXES */ 182 SP_SUFFIXES, /* .SUFFIXES */
183 SP_WAIT /* .WAIT */ 183 SP_WAIT /* .WAIT */
184} ParseSpecial; 184} ParseSpecial;
185 185
186typedef List SearchPathList; 186typedef List SearchPathList;
187typedef ListNode SearchPathListNode; 187typedef ListNode SearchPathListNode;
188 188
189/* result data */ 189/* result data */
190 190
191/* 191/*
192 * The main target to create. This is the first target on the first 192 * The main target to create. This is the first target on the first
193 * dependency line in the first makefile. 193 * dependency line in the first makefile.
194 */ 194 */
195static GNode *mainNode; 195static GNode *mainNode;
196 196
197/* eval state */ 197/* eval state */
198 198
199/* During parsing, the targets from the currently active dependency line, 199/* During parsing, the targets from the currently active dependency line,
200 * or NULL if the current line does not belong to a dependency line, for 200 * or NULL if the current line does not belong to a dependency line, for
201 * example because it is a variable assignment. 201 * example because it is a variable assignment.
202 * 202 *
203 * See unit-tests/deptgt.mk, keyword "parse.c:targets". */ 203 * See unit-tests/deptgt.mk, keyword "parse.c:targets". */
204static GNodeList *targets; 204static GNodeList *targets;
205 205
206#ifdef CLEANUP 206#ifdef CLEANUP
207/* All shell commands for all targets, in no particular order and possibly 207/* All shell commands for all targets, in no particular order and possibly
208 * with duplicates. Kept in a separate list since the commands from .USE or 208 * with duplicates. Kept in a separate list since the commands from .USE or
209 * .USEBEFORE nodes are shared with other GNodes, thereby giving up the 209 * .USEBEFORE nodes are shared with other GNodes, thereby giving up the
210 * easily understandable ownership over the allocated strings. */ 210 * easily understandable ownership over the allocated strings. */
211static StringList *targCmds; 211static StringList *targCmds;
212#endif 212#endif
213 213
214/* 214/*
215 * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER 215 * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER
216 * seen, then set to each successive source on the line. 216 * seen, then set to each successive source on the line.
217 */ 217 */
218static GNode *order_pred; 218static GNode *order_pred;
219 219
220/* parser state */ 220/* parser state */
221 221
222/* number of fatal errors */ 222/* number of fatal errors */
223static int fatals = 0; 223static int fatals = 0;
224 224
225/* 225/*
226 * Variables for doing includes 226 * Variables for doing includes
227 */ 227 */
228 228
229/* The include chain of makefiles. At the bottom is the top-level makefile 229/* The include chain of makefiles. At the bottom is the top-level makefile
230 * from the command line, and on top of that, there are the included files or 230 * from the command line, and on top of that, there are the included files or
231 * .for loops, up to and including the current file. 231 * .for loops, up to and including the current file.
232 * 232 *
233 * This data could be used to print stack traces on parse errors. As of 233 * This data could be used to print stack traces on parse errors. As of
234 * 2020-09-14, this is not done though. It seems quite simple to print the 234 * 2020-09-14, this is not done though. It seems quite simple to print the
235 * tuples (fname:lineno:fromForLoop), from top to bottom. This simple idea is 235 * tuples (fname:lineno:fromForLoop), from top to bottom. This simple idea is
236 * made complicated by the fact that the .for loops also use this stack for 236 * made complicated by the fact that the .for loops also use this stack for
237 * storing information. 237 * storing information.
238 * 238 *
239 * The lineno fields of the IFiles with fromForLoop == TRUE look confusing, 239 * The lineno fields of the IFiles with fromForLoop == TRUE look confusing,
240 * which is demonstrated by the test 'include-main.mk'. They seem sorted 240 * which is demonstrated by the test 'include-main.mk'. They seem sorted
241 * backwards since they tell the number of completely parsed lines, which for 241 * backwards since they tell the number of completely parsed lines, which for
242 * a .for loop is right after the terminating .endfor. To compensate for this 242 * a .for loop is right after the terminating .endfor. To compensate for this
243 * confusion, there is another field first_lineno pointing at the start of the 243 * confusion, there is another field first_lineno pointing at the start of the
244 * .for loop, 1-based for human consumption. 244 * .for loop, 1-based for human consumption.
245 * 245 *
246 * To make the stack trace intuitive, the entry below the first .for loop must 246 * To make the stack trace intuitive, the entry below the first .for loop must
247 * be ignored completely since neither its lineno nor its first_lineno is 247 * be ignored completely since neither its lineno nor its first_lineno is
248 * useful. Instead, the topmost of each chain of .for loop needs to be 248 * useful. Instead, the topmost of each chain of .for loop needs to be
249 * printed twice, once with its first_lineno and once with its lineno. 249 * printed twice, once with its first_lineno and once with its lineno.
250 * 250 *
251 * As of 2020-10-28, using the above rules, the stack trace for the .info line 251 * As of 2020-10-28, using the above rules, the stack trace for the .info line
252 * in include-subsub.mk would be: 252 * in include-subsub.mk would be:
253 * 253 *
254 * includes[5]: include-subsub.mk:4 254 * includes[5]: include-subsub.mk:4
255 * (lineno, from an .include) 255 * (lineno, from an .include)
256 * includes[4]: include-sub.mk:32 256 * includes[4]: include-sub.mk:32
257 * (lineno, from a .for loop below an .include) 257 * (lineno, from a .for loop below an .include)
258 * includes[4]: include-sub.mk:31 258 * includes[4]: include-sub.mk:31
259 * (first_lineno, from a .for loop, lineno == 32) 259 * (first_lineno, from a .for loop, lineno == 32)
260 * includes[3]: include-sub.mk:30 260 * includes[3]: include-sub.mk:30
261 * (first_lineno, from a .for loop, lineno == 33) 261 * (first_lineno, from a .for loop, lineno == 33)
262 * includes[2]: include-sub.mk:29 262 * includes[2]: include-sub.mk:29
263 * (first_lineno, from a .for loop, lineno == 34) 263 * (first_lineno, from a .for loop, lineno == 34)
264 * includes[1]: include-sub.mk:35 264 * includes[1]: include-sub.mk:35
265 * (not printed since it is below a .for loop) 265 * (not printed since it is below a .for loop)
266 * includes[0]: include-main.mk:27 266 * includes[0]: include-main.mk:27
267 */ 267 */
268static Vector /* of IFile */ includes; 268static Vector /* of IFile */ includes;
269 269
270static IFile * 270static IFile *
271GetInclude(size_t i) 271GetInclude(size_t i)
272{ 272{
273 return Vector_Get(&includes, i); 273 return Vector_Get(&includes, i);
274} 274}
275 275
276/* The file that is currently being read. */ 276/* The file that is currently being read. */
277static IFile * 277static IFile *
278CurFile(void) 278CurFile(void)
279{ 279{
280 return GetInclude(includes.len - 1); 280 return GetInclude(includes.len - 1);
281} 281}
282 282
283/* include paths (lists of directories) */ 283/* include paths */
284SearchPath *parseIncPath; /* dirs for "..." includes */ 284SearchPath *parseIncPath; /* dirs for "..." includes */
285SearchPath *sysIncPath; /* dirs for <...> includes */ 285SearchPath *sysIncPath; /* dirs for <...> includes */
286SearchPath *defIncPath; /* default for sysIncPath */ 286SearchPath *defSysIncPath; /* default for sysIncPath */
287 287
288/* parser tables */ 288/* parser tables */
289 289
290/* 290/*
291 * The parseKeywords table is searched using binary search when deciding 291 * The parseKeywords table is searched using binary search when deciding
292 * if a target or source is special. The 'spec' field is the ParseSpecial 292 * if a target or source is special. The 'spec' field is the ParseSpecial
293 * type of the keyword (SP_NOT if the keyword isn't special as a target) while 293 * type of the keyword (SP_NOT if the keyword isn't special as a target) while
294 * the 'op' field is the operator to apply to the list of targets if the 294 * the 'op' field is the operator to apply to the list of targets if the
295 * keyword is used as a source ("0" if the keyword isn't special as a source) 295 * keyword is used as a source ("0" if the keyword isn't special as a source)
296 */ 296 */
297static const struct { 297static const struct {
298 const char *name; /* Name of keyword */ 298 const char *name; /* Name of keyword */
299 ParseSpecial spec; /* Type when used as a target */ 299 ParseSpecial spec; /* Type when used as a target */
300 GNodeType op; /* Operator when used as a source */ 300 GNodeType op; /* Operator when used as a source */
301} parseKeywords[] = { 301} parseKeywords[] = {
302 { ".BEGIN", SP_BEGIN, 0 }, 302 { ".BEGIN", SP_BEGIN, 0 },
303 { ".DEFAULT", SP_DEFAULT, 0 }, 303 { ".DEFAULT", SP_DEFAULT, 0 },
304 { ".DELETE_ON_ERROR", SP_DELETE_ON_ERROR, 0 }, 304 { ".DELETE_ON_ERROR", SP_DELETE_ON_ERROR, 0 },
305 { ".END", SP_END, 0 }, 305 { ".END", SP_END, 0 },
306 { ".ERROR", SP_ERROR, 0 }, 306 { ".ERROR", SP_ERROR, 0 },
307 { ".EXEC", SP_ATTRIBUTE, OP_EXEC }, 307 { ".EXEC", SP_ATTRIBUTE, OP_EXEC },
308 { ".IGNORE", SP_IGNORE, OP_IGNORE }, 308 { ".IGNORE", SP_IGNORE, OP_IGNORE },
309 { ".INCLUDES", SP_INCLUDES, 0 }, 309 { ".INCLUDES", SP_INCLUDES, 0 },
310 { ".INTERRUPT", SP_INTERRUPT, 0 }, 310 { ".INTERRUPT", SP_INTERRUPT, 0 },
311 { ".INVISIBLE", SP_ATTRIBUTE, OP_INVISIBLE }, 311 { ".INVISIBLE", SP_ATTRIBUTE, OP_INVISIBLE },
312 { ".JOIN", SP_ATTRIBUTE, OP_JOIN }, 312 { ".JOIN", SP_ATTRIBUTE, OP_JOIN },
313 { ".LIBS", SP_LIBS, 0 }, 313 { ".LIBS", SP_LIBS, 0 },
314 { ".MADE", SP_ATTRIBUTE, OP_MADE }, 314 { ".MADE", SP_ATTRIBUTE, OP_MADE },
315 { ".MAIN", SP_MAIN, 0 }, 315 { ".MAIN", SP_MAIN, 0 },
316 { ".MAKE", SP_ATTRIBUTE, OP_MAKE }, 316 { ".MAKE", SP_ATTRIBUTE, OP_MAKE },
317 { ".MAKEFLAGS", SP_MFLAGS, 0 }, 317 { ".MAKEFLAGS", SP_MFLAGS, 0 },
318 { ".META", SP_META, OP_META }, 318 { ".META", SP_META, OP_META },
319 { ".MFLAGS", SP_MFLAGS, 0 }, 319 { ".MFLAGS", SP_MFLAGS, 0 },
320 { ".NOMETA", SP_NOMETA, OP_NOMETA }, 320 { ".NOMETA", SP_NOMETA, OP_NOMETA },
321 { ".NOMETA_CMP", SP_NOMETA_CMP, OP_NOMETA_CMP }, 321 { ".NOMETA_CMP", SP_NOMETA_CMP, OP_NOMETA_CMP },
322 { ".NOPATH", SP_NOPATH, OP_NOPATH }, 322 { ".NOPATH", SP_NOPATH, OP_NOPATH },
323 { ".NOTMAIN", SP_ATTRIBUTE, OP_NOTMAIN }, 323 { ".NOTMAIN", SP_ATTRIBUTE, OP_NOTMAIN },
324 { ".NOTPARALLEL", SP_NOTPARALLEL, 0 }, 324 { ".NOTPARALLEL", SP_NOTPARALLEL, 0 },
325 { ".NO_PARALLEL", SP_NOTPARALLEL, 0 }, 325 { ".NO_PARALLEL", SP_NOTPARALLEL, 0 },
326 { ".NULL", SP_NULL, 0 }, 326 { ".NULL", SP_NULL, 0 },
327 { ".OBJDIR", SP_OBJDIR, 0 }, 327 { ".OBJDIR", SP_OBJDIR, 0 },
328 { ".OPTIONAL", SP_ATTRIBUTE, OP_OPTIONAL }, 328 { ".OPTIONAL", SP_ATTRIBUTE, OP_OPTIONAL },
329 { ".ORDER", SP_ORDER, 0 }, 329 { ".ORDER", SP_ORDER, 0 },
330 { ".PARALLEL", SP_PARALLEL, 0 }, 330 { ".PARALLEL", SP_PARALLEL, 0 },
331 { ".PATH", SP_PATH, 0 }, 331 { ".PATH", SP_PATH, 0 },
332 { ".PHONY", SP_PHONY, OP_PHONY }, 332 { ".PHONY", SP_PHONY, OP_PHONY },
333#ifdef POSIX 333#ifdef POSIX
334 { ".POSIX", SP_POSIX, 0 }, 334 { ".POSIX", SP_POSIX, 0 },
335#endif 335#endif
336 { ".PRECIOUS", SP_PRECIOUS, OP_PRECIOUS }, 336 { ".PRECIOUS", SP_PRECIOUS, OP_PRECIOUS },
337 { ".RECURSIVE", SP_ATTRIBUTE, OP_MAKE }, 337 { ".RECURSIVE", SP_ATTRIBUTE, OP_MAKE },
338 { ".SHELL", SP_SHELL, 0 }, 338 { ".SHELL", SP_SHELL, 0 },
339 { ".SILENT", SP_SILENT, OP_SILENT }, 339 { ".SILENT", SP_SILENT, OP_SILENT },
340 { ".SINGLESHELL", SP_SINGLESHELL, 0 }, 340 { ".SINGLESHELL", SP_SINGLESHELL, 0 },
341 { ".STALE", SP_STALE, 0 }, 341 { ".STALE", SP_STALE, 0 },
342 { ".SUFFIXES", SP_SUFFIXES, 0 }, 342 { ".SUFFIXES", SP_SUFFIXES, 0 },
343 { ".USE", SP_ATTRIBUTE, OP_USE }, 343 { ".USE", SP_ATTRIBUTE, OP_USE },
344 { ".USEBEFORE", SP_ATTRIBUTE, OP_USEBEFORE }, 344 { ".USEBEFORE", SP_ATTRIBUTE, OP_USEBEFORE },
345 { ".WAIT", SP_WAIT, 0 }, 345 { ".WAIT", SP_WAIT, 0 },
346}; 346};
347 347
348/* file loader */ 348/* file loader */
349 349
350struct loadedfile { 350struct loadedfile {
351 const char *path; /* name, for error reports */ 351 const char *path; /* name, for error reports */
352 char *buf; /* contents buffer */ 352 char *buf; /* contents buffer */
353 size_t len; /* length of contents */ 353 size_t len; /* length of contents */
354 size_t maplen; /* length of mmap area, or 0 */ 354 size_t maplen; /* length of mmap area, or 0 */
355 Boolean used; /* XXX: have we used the data yet */ 355 Boolean used; /* XXX: have we used the data yet */
356}; 356};
357 357
358static struct loadedfile * 358static struct loadedfile *
359loadedfile_create(const char *path) 359loadedfile_create(const char *path)
360{ 360{
361 struct loadedfile *lf; 361 struct loadedfile *lf;
362 362
363 lf = bmake_malloc(sizeof(*lf)); 363 lf = bmake_malloc(sizeof(*lf));
364 lf->path = path == NULL ? "(stdin)" : path; 364 lf->path = path == NULL ? "(stdin)" : path;
365 lf->buf = NULL; 365 lf->buf = NULL;
366 lf->len = 0; 366 lf->len = 0;
367 lf->maplen = 0; 367 lf->maplen = 0;
368 lf->used = FALSE; 368 lf->used = FALSE;
369 return lf; 369 return lf;
370} 370}
371 371
372static void 372static void
373loadedfile_destroy(struct loadedfile *lf) 373loadedfile_destroy(struct loadedfile *lf)
374{ 374{
375 if (lf->buf != NULL) { 375 if (lf->buf != NULL) {
376 if (lf->maplen > 0) { 376 if (lf->maplen > 0) {
377 munmap(lf->buf, lf->maplen); 377 munmap(lf->buf, lf->maplen);
378 } else { 378 } else {
379 free(lf->buf); 379 free(lf->buf);
380 } 380 }
381 } 381 }
382 free(lf); 382 free(lf);
383} 383}
384 384
385/* 385/*
386 * nextbuf() operation for loadedfile, as needed by the weird and twisted 386 * nextbuf() operation for loadedfile, as needed by the weird and twisted
387 * logic below. Once that's cleaned up, we can get rid of lf->used... 387 * logic below. Once that's cleaned up, we can get rid of lf->used...
388 */ 388 */
389static char * 389static char *
390loadedfile_nextbuf(void *x, size_t *len) 390loadedfile_nextbuf(void *x, size_t *len)
391{ 391{
392 struct loadedfile *lf = x; 392 struct loadedfile *lf = x;
393 393
394 if (lf->used) { 394 if (lf->used) {
395 return NULL; 395 return NULL;
396 } 396 }
397 lf->used = TRUE; 397 lf->used = TRUE;
398 *len = lf->len; 398 *len = lf->len;
399 return lf->buf; 399 return lf->buf;
400} 400}
401 401
402/* 402/*
403 * Try to get the size of a file. 403 * Try to get the size of a file.
404 */ 404 */
405static Boolean 405static Boolean
406load_getsize(int fd, size_t *ret) 406load_getsize(int fd, size_t *ret)
407{ 407{
408 struct stat st; 408 struct stat st;
409 409
410 if (fstat(fd, &st) < 0) { 410 if (fstat(fd, &st) < 0) {
411 return FALSE; 411 return FALSE;
412 } 412 }
413 413
414 if (!S_ISREG(st.st_mode)) { 414 if (!S_ISREG(st.st_mode)) {
415 return FALSE; 415 return FALSE;
416 } 416 }
417 417
418 /* 418 /*
419 * st_size is an off_t, which is 64 bits signed; *ret is 419 * st_size is an off_t, which is 64 bits signed; *ret is
420 * size_t, which might be 32 bits unsigned or 64 bits 420 * size_t, which might be 32 bits unsigned or 64 bits
421 * unsigned. Rather than being elaborate, just punt on 421 * unsigned. Rather than being elaborate, just punt on
422 * files that are more than 2^31 bytes. We should never 422 * files that are more than 2^31 bytes. We should never
423 * see a makefile that size in practice... 423 * see a makefile that size in practice...
424 * 424 *
425 * While we're at it reject negative sizes too, just in case. 425 * While we're at it reject negative sizes too, just in case.
426 */ 426 */
427 if (st.st_size < 0 || st.st_size > 0x7fffffff) { 427 if (st.st_size < 0 || st.st_size > 0x7fffffff) {
428 return FALSE; 428 return FALSE;
429 } 429 }
430 430
431 *ret = (size_t)st.st_size; 431 *ret = (size_t)st.st_size;
432 return TRUE; 432 return TRUE;
433} 433}
434 434
435/* 435/*
436 * Read in a file. 436 * Read in a file.
437 * 437 *
438 * Until the path search logic can be moved under here instead of 438 * Until the path search logic can be moved under here instead of
439 * being in the caller in another source file, we need to have the fd 439 * being in the caller in another source file, we need to have the fd
440 * passed in already open. Bleh. 440 * passed in already open. Bleh.
441 * 441 *
442 * If the path is NULL use stdin and (to insure against fd leaks) 442 * If the path is NULL use stdin and (to insure against fd leaks)
443 * assert that the caller passed in -1. 443 * assert that the caller passed in -1.
444 */ 444 */
445static struct loadedfile * 445static struct loadedfile *
446loadfile(const char *path, int fd) 446loadfile(const char *path, int fd)
447{ 447{
448 struct loadedfile *lf; 448 struct loadedfile *lf;
449 static unsigned long pagesize = 0; 449 static unsigned long pagesize = 0;
450 ssize_t result; 450 ssize_t result;
451 size_t bufpos; 451 size_t bufpos;
452 452
453 lf = loadedfile_create(path); 453 lf = loadedfile_create(path);
454 454
455 if (path == NULL) { 455 if (path == NULL) {
456 assert(fd == -1); 456 assert(fd == -1);
457 fd = STDIN_FILENO; 457 fd = STDIN_FILENO;
458 } else { 458 } else {
459#if 0 /* notyet */ 459#if 0 /* notyet */
460 fd = open(path, O_RDONLY); 460 fd = open(path, O_RDONLY);
461 if (fd < 0) { 461 if (fd < 0) {
462 ... 462 ...
463 Error("%s: %s", path, strerror(errno)); 463 Error("%s: %s", path, strerror(errno));
464 exit(1); 464 exit(1);
465 } 465 }
466#endif 466#endif
467 } 467 }
468 468
469 if (load_getsize(fd, &lf->len)) { 469 if (load_getsize(fd, &lf->len)) {
470 /* found a size, try mmap */ 470 /* found a size, try mmap */
471 if (pagesize == 0) 471 if (pagesize == 0)
472 pagesize = (unsigned long)sysconf(_SC_PAGESIZE); 472 pagesize = (unsigned long)sysconf(_SC_PAGESIZE);
473 if (pagesize == 0 || pagesize == (unsigned long)-1) { 473 if (pagesize == 0 || pagesize == (unsigned long)-1) {
474 pagesize = 0x1000; 474 pagesize = 0x1000;
475 } 475 }
476 /* round size up to a page */ 476 /* round size up to a page */
477 lf->maplen = pagesize * ((lf->len + pagesize - 1)/pagesize); 477 lf->maplen = pagesize * ((lf->len + pagesize - 1)/pagesize);
478 478
479 /* 479 /*
480 * XXX hack for dealing with empty files; remove when 480 * XXX hack for dealing with empty files; remove when
481 * we're no longer limited by interfacing to the old 481 * we're no longer limited by interfacing to the old
482 * logic elsewhere in this file. 482 * logic elsewhere in this file.
483 */ 483 */
484 if (lf->maplen == 0) { 484 if (lf->maplen == 0) {
485 lf->maplen = pagesize; 485 lf->maplen = pagesize;
486 } 486 }
487 487
488 /* 488 /*
489 * FUTURE: remove PROT_WRITE when the parser no longer 489 * FUTURE: remove PROT_WRITE when the parser no longer
490 * needs to scribble on the input. 490 * needs to scribble on the input.
491 */ 491 */
492 lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE, 492 lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE,
493 MAP_FILE|MAP_COPY, fd, 0); 493 MAP_FILE|MAP_COPY, fd, 0);
494 if (lf->buf != MAP_FAILED) { 494 if (lf->buf != MAP_FAILED) {
495 /* succeeded */ 495 /* succeeded */
496 if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') { 496 if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') {
497 char *b = bmake_malloc(lf->len + 1); 497 char *b = bmake_malloc(lf->len + 1);
498 b[lf->len] = '\n'; 498 b[lf->len] = '\n';
499 memcpy(b, lf->buf, lf->len++); 499 memcpy(b, lf->buf, lf->len++);
500 munmap(lf->buf, lf->maplen); 500 munmap(lf->buf, lf->maplen);
501 lf->maplen = 0; 501 lf->maplen = 0;
502 lf->buf = b; 502 lf->buf = b;
503 } 503 }
504 goto done; 504 goto done;
505 } 505 }
506 } 506 }
507 507
508 /* cannot mmap; load the traditional way */ 508 /* cannot mmap; load the traditional way */
509 509
510 lf->maplen = 0; 510 lf->maplen = 0;
511 lf->len = 1024; 511 lf->len = 1024;
512 lf->buf = bmake_malloc(lf->len); 512 lf->buf = bmake_malloc(lf->len);
513 513
514 bufpos = 0; 514 bufpos = 0;
515 while (1) { 515 while (1) {
516 assert(bufpos <= lf->len); 516 assert(bufpos <= lf->len);
517 if (bufpos == lf->len) { 517 if (bufpos == lf->len) {
518 if (lf->len > SIZE_MAX/2) { 518 if (lf->len > SIZE_MAX/2) {
519 errno = EFBIG; 519 errno = EFBIG;
520 Error("%s: file too large", path); 520 Error("%s: file too large", path);
521 exit(1); 521 exit(1);
522 } 522 }
523 lf->len *= 2; 523 lf->len *= 2;
524 lf->buf = bmake_realloc(lf->buf, lf->len); 524 lf->buf = bmake_realloc(lf->buf, lf->len);
525 } 525 }
526 assert(bufpos < lf->len); 526 assert(bufpos < lf->len);
527 result = read(fd, lf->buf + bufpos, lf->len - bufpos); 527 result = read(fd, lf->buf + bufpos, lf->len - bufpos);
528 if (result < 0) { 528 if (result < 0) {
529 Error("%s: read error: %s", path, strerror(errno)); 529 Error("%s: read error: %s", path, strerror(errno));
530 exit(1); 530 exit(1);
531 } 531 }
532 if (result == 0) { 532 if (result == 0) {
533 break; 533 break;
534 } 534 }
535 bufpos += (size_t)result; 535 bufpos += (size_t)result;
536 } 536 }
537 assert(bufpos <= lf->len); 537 assert(bufpos <= lf->len);
538 lf->len = bufpos; 538 lf->len = bufpos;
539 539
540 /* truncate malloc region to actual length (maybe not useful) */ 540 /* truncate malloc region to actual length (maybe not useful) */
541 if (lf->len > 0) { 541 if (lf->len > 0) {
542 /* as for mmap case, ensure trailing \n */ 542 /* as for mmap case, ensure trailing \n */
543 if (lf->buf[lf->len - 1] != '\n') 543 if (lf->buf[lf->len - 1] != '\n')
544 lf->len++; 544 lf->len++;
545 lf->buf = bmake_realloc(lf->buf, lf->len); 545 lf->buf = bmake_realloc(lf->buf, lf->len);
546 lf->buf[lf->len - 1] = '\n'; 546 lf->buf[lf->len - 1] = '\n';
547 } 547 }
548 548
549done: 549done:
550 if (path != NULL) { 550 if (path != NULL) {
551 close(fd); 551 close(fd);
552 } 552 }
553 return lf; 553 return lf;
554} 554}
555 555
556/* old code */ 556/* old code */
557 557
558/* Check if the current character is escaped on the current line. */ 558/* Check if the current character is escaped on the current line. */
559static Boolean 559static Boolean
560ParseIsEscaped(const char *line, const char *c) 560ParseIsEscaped(const char *line, const char *c)
561{ 561{
562 Boolean active = FALSE; 562 Boolean active = FALSE;
563 for (;;) { 563 for (;;) {
564 if (line == c) 564 if (line == c)
565 return active; 565 return active;
566 if (*--c != '\\') 566 if (*--c != '\\')
567 return active; 567 return active;
568 active = !active; 568 active = !active;
569 } 569 }
570} 570}
571 571
572/* Add the filename and lineno to the GNode so that we remember where it 572/* Add the filename and lineno to the GNode so that we remember where it
573 * was first defined. */ 573 * was first defined. */
574static void 574static void
575ParseMark(GNode *gn) 575ParseMark(GNode *gn)
576{ 576{
577 IFile *curFile = CurFile(); 577 IFile *curFile = CurFile();
578 gn->fname = curFile->fname; 578 gn->fname = curFile->fname;
579 gn->lineno = curFile->lineno; 579 gn->lineno = curFile->lineno;
580} 580}
581 581
582/* Look in the table of keywords for one matching the given string. 582/* Look in the table of keywords for one matching the given string.
583 * Return the index of the keyword, or -1 if it isn't there. */ 583 * Return the index of the keyword, or -1 if it isn't there. */
584static int 584static int
585ParseFindKeyword(const char *str) 585ParseFindKeyword(const char *str)
586{ 586{
587 int start, end, cur; 587 int start, end, cur;
588 int diff; 588 int diff;
589 589
590 start = 0; 590 start = 0;
591 end = sizeof parseKeywords / sizeof parseKeywords[0] - 1; 591 end = sizeof parseKeywords / sizeof parseKeywords[0] - 1;
592 592
593 do { 593 do {
594 cur = start + (end - start) / 2; 594 cur = start + (end - start) / 2;
595 diff = strcmp(str, parseKeywords[cur].name); 595 diff = strcmp(str, parseKeywords[cur].name);
596 596
597 if (diff == 0) { 597 if (diff == 0) {
598 return cur; 598 return cur;
599 } else if (diff < 0) { 599 } else if (diff < 0) {
600 end = cur - 1; 600 end = cur - 1;
601 } else { 601 } else {
602 start = cur + 1; 602 start = cur + 1;
603 } 603 }
604 } while (start <= end); 604 } while (start <= end);
605 return -1; 605 return -1;
606} 606}
607 607
608static void 608static void
609PrintLocation(FILE *f, const char *filename, size_t lineno) 609PrintLocation(FILE *f, const char *filename, size_t lineno)
610{ 610{
611 char dirbuf[MAXPATHLEN+1]; 611 char dirbuf[MAXPATHLEN+1];
612 const char *dir, *base; 612 const char *dir, *base;
613 char *dir_freeIt, *base_freeIt; 613 char *dir_freeIt, *base_freeIt;
614 614
615 if (*filename == '/' || strcmp(filename, "(stdin)") == 0) { 615 if (*filename == '/' || strcmp(filename, "(stdin)") == 0) {
616 (void)fprintf(f, "\"%s\" line %zu: ", filename, lineno); 616 (void)fprintf(f, "\"%s\" line %zu: ", filename, lineno);
617 return; 617 return;
618 } 618 }
619 619
620 /* Find out which makefile is the culprit. 620 /* Find out which makefile is the culprit.
621 * We try ${.PARSEDIR} and apply realpath(3) if not absolute. */ 621 * We try ${.PARSEDIR} and apply realpath(3) if not absolute. */
622 622
623 dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &dir_freeIt); 623 dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &dir_freeIt);
624 if (dir == NULL) 624 if (dir == NULL)
625 dir = "."; 625 dir = ".";
626 if (*dir != '/') 626 if (*dir != '/')
627 dir = realpath(dir, dirbuf); 627 dir = realpath(dir, dirbuf);
628 628
629 base = Var_Value(".PARSEFILE", VAR_GLOBAL, &base_freeIt); 629 base = Var_Value(".PARSEFILE", VAR_GLOBAL, &base_freeIt);
630 if (base == NULL) { 630 if (base == NULL) {
631 const char *slash = strrchr(filename, '/'); 631 const char *slash = strrchr(filename, '/');
632 base = slash != NULL ? slash + 1 : filename; 632 base = slash != NULL ? slash + 1 : filename;
633 } 633 }
634 634
635 (void)fprintf(f, "\"%s/%s\" line %zu: ", dir, base, lineno); 635 (void)fprintf(f, "\"%s/%s\" line %zu: ", dir, base, lineno);
636 bmake_free(base_freeIt); 636 bmake_free(base_freeIt);
637 bmake_free(dir_freeIt); 637 bmake_free(dir_freeIt);
638} 638}
639 639
640/* Print a parse error message, including location information. 640/* Print a parse error message, including location information.
641 * 641 *
642 * Increment "fatals" if the level is PARSE_FATAL, and continue parsing 642 * Increment "fatals" if the level is PARSE_FATAL, and continue parsing
643 * until the end of the current top-level makefile, then exit (see 643 * until the end of the current top-level makefile, then exit (see
644 * Parse_File). */ 644 * Parse_File). */
645static void 645static void
646ParseVErrorInternal(FILE *f, const char *cfname, size_t clineno, 646ParseVErrorInternal(FILE *f, const char *cfname, size_t clineno,
647 ParseErrorLevel type, const char *fmt, va_list ap) 647 ParseErrorLevel type, const char *fmt, va_list ap)
648{ 648{
649 static Boolean fatal_warning_error_printed = FALSE; 649 static Boolean fatal_warning_error_printed = FALSE;
650 650
651 (void)fprintf(f, "%s: ", progname); 651 (void)fprintf(f, "%s: ", progname);
652 652
653 if (cfname != NULL) 653 if (cfname != NULL)
654 PrintLocation(f, cfname, clineno); 654 PrintLocation(f, cfname, clineno);
655 if (type == PARSE_WARNING) 655 if (type == PARSE_WARNING)
656 (void)fprintf(f, "warning: "); 656 (void)fprintf(f, "warning: ");
657 (void)vfprintf(f, fmt, ap); 657 (void)vfprintf(f, fmt, ap);
658 (void)fprintf(f, "\n"); 658 (void)fprintf(f, "\n");
659 (void)fflush(f); 659 (void)fflush(f);
660 660
661 if (type == PARSE_INFO) 661 if (type == PARSE_INFO)
662 return; 662 return;
663 if (type == PARSE_FATAL || opts.parseWarnFatal) 663 if (type == PARSE_FATAL || opts.parseWarnFatal)
664 fatals++; 664 fatals++;
665 if (opts.parseWarnFatal && !fatal_warning_error_printed) { 665 if (opts.parseWarnFatal && !fatal_warning_error_printed) {
666 Error("parsing warnings being treated as errors"); 666 Error("parsing warnings being treated as errors");
667 fatal_warning_error_printed = TRUE; 667 fatal_warning_error_printed = TRUE;
668 } 668 }
669} 669}
670 670
671static void 671static void
672ParseErrorInternal(const char *cfname, size_t clineno, ParseErrorLevel type, 672ParseErrorInternal(const char *cfname, size_t clineno, ParseErrorLevel type,
673 const char *fmt, ...) 673 const char *fmt, ...)
674{ 674{
675 va_list ap; 675 va_list ap;
676 676
677 va_start(ap, fmt); 677 va_start(ap, fmt);
678 (void)fflush(stdout); 678 (void)fflush(stdout);
679 ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap); 679 ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap);
680 va_end(ap); 680 va_end(ap);
681 681
682 if (opts.debug_file != stderr && opts.debug_file != stdout) { 682 if (opts.debug_file != stderr && opts.debug_file != stdout) {
683 va_start(ap, fmt); 683 va_start(ap, fmt);
684 ParseVErrorInternal(opts.debug_file, cfname, clineno, type, 684 ParseVErrorInternal(opts.debug_file, cfname, clineno, type,
685 fmt, ap); 685 fmt, ap);
686 va_end(ap); 686 va_end(ap);
687 } 687 }
688} 688}
689 689
690/* External interface to ParseErrorInternal; uses the default filename and 690/* External interface to ParseErrorInternal; uses the default filename and
691 * line number. 691 * line number.
692 * 692 *
693 * Fmt is given without a trailing newline. */ 693 * Fmt is given without a trailing newline. */
694void 694void
695Parse_Error(ParseErrorLevel type, const char *fmt, ...) 695Parse_Error(ParseErrorLevel type, const char *fmt, ...)
696{ 696{
697 va_list ap; 697 va_list ap;
698 const char *fname; 698 const char *fname;
699 size_t lineno; 699 size_t lineno;
700 700
701 if (includes.len == 0) { 701 if (includes.len == 0) {
702 fname = NULL; 702 fname = NULL;
703 lineno = 0; 703 lineno = 0;
704 } else { 704 } else {
705 IFile *curFile = CurFile(); 705 IFile *curFile = CurFile();
706 fname = curFile->fname; 706 fname = curFile->fname;
707 lineno = (size_t)curFile->lineno; 707 lineno = (size_t)curFile->lineno;
708 } 708 }
709 709
710 va_start(ap, fmt); 710 va_start(ap, fmt);
711 (void)fflush(stdout); 711 (void)fflush(stdout);
712 ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); 712 ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap);
713 va_end(ap); 713 va_end(ap);
714 714
715 if (opts.debug_file != stderr && opts.debug_file != stdout) { 715 if (opts.debug_file != stderr && opts.debug_file != stdout) {
716 va_start(ap, fmt); 716 va_start(ap, fmt);
717 ParseVErrorInternal(opts.debug_file, fname, lineno, type, 717 ParseVErrorInternal(opts.debug_file, fname, lineno, type,
718 fmt, ap); 718 fmt, ap);
719 va_end(ap); 719 va_end(ap);
720 } 720 }
721} 721}
722 722
723 723
724/* Parse a .info .warning or .error directive. 724/* Parse a .info .warning or .error directive.
725 * 725 *
726 * The input is the line minus the ".". We substitute variables, print the 726 * The input is the line minus the ".". We substitute variables, print the
727 * message and exit(1) (for .error) or just print a warning if the directive 727 * message and exit(1) (for .error) or just print a warning if the directive
728 * is malformed. 728 * is malformed.
729 */ 729 */
730static Boolean 730static Boolean
731ParseMessage(const char *directive) 731ParseMessage(const char *directive)
732{ 732{
733 const char *p = directive; 733 const char *p = directive;
734 int mtype = *p == 'i' ? PARSE_INFO : 734 int mtype = *p == 'i' ? PARSE_INFO :
735 *p == 'w' ? PARSE_WARNING : PARSE_FATAL; 735 *p == 'w' ? PARSE_WARNING : PARSE_FATAL;
736 char *arg; 736 char *arg;
737 737
738 while (ch_isalpha(*p)) 738 while (ch_isalpha(*p))
739 p++; 739 p++;
740 if (!ch_isspace(*p)) 740 if (!ch_isspace(*p))
741 return FALSE; /* missing argument */ 741 return FALSE; /* missing argument */
742 742
743 cpp_skip_whitespace(&p); 743 cpp_skip_whitespace(&p);
744 (void)Var_Subst(p, VAR_CMD, VARE_WANTRES, &arg); 744 (void)Var_Subst(p, VAR_CMD, VARE_WANTRES, &arg);
745 /* TODO: handle errors */ 745 /* TODO: handle errors */
746 746
747 Parse_Error(mtype, "%s", arg); 747 Parse_Error(mtype, "%s", arg);
748 free(arg); 748 free(arg);
749 749
750 if (mtype == PARSE_FATAL) { 750 if (mtype == PARSE_FATAL) {
751 PrintOnError(NULL, NULL); 751 PrintOnError(NULL, NULL);
752 exit(1); 752 exit(1);
753 } 753 }
754 return TRUE; 754 return TRUE;
755} 755}
756 756
757/* Add the child to the parent's children. 757/* Add the child to the parent's children.
758 * 758 *
759 * Additionally, add the parent to the child's parents, but only if the 759 * Additionally, add the parent to the child's parents, but only if the
760 * target is not special. An example for such a special target is .END, 760 * target is not special. An example for such a special target is .END,
761 * which does not need to be informed once the child target has been made. */ 761 * which does not need to be informed once the child target has been made. */
762static void 762static void
763LinkSource(GNode *pgn, GNode *cgn, Boolean isSpecial) 763LinkSource(GNode *pgn, GNode *cgn, Boolean isSpecial)
764{ 764{
765 if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(pgn->cohorts)) 765 if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(pgn->cohorts))
766 pgn = pgn->cohorts->last->datum; 766 pgn = pgn->cohorts->last->datum;
767 767
768 Lst_Append(pgn->children, cgn); 768 Lst_Append(pgn->children, cgn);
769 pgn->unmade++; 769 pgn->unmade++;
770 770
771 /* Special targets like .END don't need any children. */ 771 /* Special targets like .END don't need any children. */
772 if (!isSpecial) 772 if (!isSpecial)
773 Lst_Append(cgn->parents, pgn); 773 Lst_Append(cgn->parents, pgn);
774 774
775 if (DEBUG(PARSE)) { 775 if (DEBUG(PARSE)) {
776 debug_printf("# %s: added child %s - %s\n", 776 debug_printf("# %s: added child %s - %s\n",
777 __func__, pgn->name, cgn->name); 777 __func__, pgn->name, cgn->name);
778 Targ_PrintNode(pgn, 0); 778 Targ_PrintNode(pgn, 0);
779 Targ_PrintNode(cgn, 0); 779 Targ_PrintNode(cgn, 0);
780 } 780 }
781} 781}
782 782
783/* Add the node to each target from the current dependency group. */ 783/* Add the node to each target from the current dependency group. */
784static void 784static void
785LinkToTargets(GNode *gn, Boolean isSpecial) 785LinkToTargets(GNode *gn, Boolean isSpecial)
786{ 786{
787 GNodeListNode *ln; 787 GNodeListNode *ln;
788 for (ln = targets->first; ln != NULL; ln = ln->next) 788 for (ln = targets->first; ln != NULL; ln = ln->next)
789 LinkSource(ln->datum, gn, isSpecial); 789 LinkSource(ln->datum, gn, isSpecial);
790} 790}
791 791
792static Boolean 792static Boolean
793TryApplyDependencyOperator(GNode *gn, GNodeType op) 793TryApplyDependencyOperator(GNode *gn, GNodeType op)
794{ 794{
795 /* 795 /*
796 * If the node occurred on the left-hand side of a dependency and the 796 * If the node occurred on the left-hand side of a dependency and the
797 * operator also defines a dependency, they must match. 797 * operator also defines a dependency, they must match.
798 */ 798 */
799 if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) && 799 if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) &&
800 ((op & OP_OPMASK) != (gn->type & OP_OPMASK))) 800 ((op & OP_OPMASK) != (gn->type & OP_OPMASK)))
801 { 801 {
802 Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name); 802 Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name);
803 return FALSE; 803 return FALSE;
804 } 804 }
805 805
806 if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) { 806 if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) {
807 /* 807 /*
808 * If the node was the object of a :: operator, we need to create a 808 * If the node was the object of a :: operator, we need to create a
809 * new instance of it for the children and commands on this dependency 809 * new instance of it for the children and commands on this dependency
810 * line. The new instance is placed on the 'cohorts' list of the 810 * line. The new instance is placed on the 'cohorts' list of the
811 * initial one (note the initial one is not on its own cohorts list) 811 * initial one (note the initial one is not on its own cohorts list)
812 * and the new instance is linked to all parents of the initial 812 * and the new instance is linked to all parents of the initial
813 * instance. 813 * instance.
814 */ 814 */
815 GNode *cohort; 815 GNode *cohort;
816 816
817 /* 817 /*
818 * Propagate copied bits to the initial node. They'll be propagated 818 * Propagate copied bits to the initial node. They'll be propagated
819 * back to the rest of the cohorts later. 819 * back to the rest of the cohorts later.
820 */ 820 */
821 gn->type |= op & ~OP_OPMASK; 821 gn->type |= op & ~OP_OPMASK;
822 822
823 cohort = Targ_NewInternalNode(gn->name); 823 cohort = Targ_NewInternalNode(gn->name);
824 if (doing_depend) 824 if (doing_depend)
825 ParseMark(cohort); 825 ParseMark(cohort);
826 /* 826 /*
827 * Make the cohort invisible as well to avoid duplicating it into 827 * Make the cohort invisible as well to avoid duplicating it into
828 * other variables. True, parents of this target won't tend to do 828 * other variables. True, parents of this target won't tend to do
829 * anything with their local variables, but better safe than 829 * anything with their local variables, but better safe than
830 * sorry. (I think this is pointless now, since the relevant list 830 * sorry. (I think this is pointless now, since the relevant list
831 * traversals will no longer see this node anyway. -mycroft) 831 * traversals will no longer see this node anyway. -mycroft)
832 */ 832 */
833 cohort->type = op | OP_INVISIBLE; 833 cohort->type = op | OP_INVISIBLE;
834 Lst_Append(gn->cohorts, cohort); 834 Lst_Append(gn->cohorts, cohort);
835 cohort->centurion = gn; 835 cohort->centurion = gn;
836 gn->unmade_cohorts++; 836 gn->unmade_cohorts++;
837 snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", 837 snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d",
838 (unsigned int)gn->unmade_cohorts % 1000000); 838 (unsigned int)gn->unmade_cohorts % 1000000);
839 } else { 839 } else {
840 /* 840 /*
841 * We don't want to nuke any previous flags (whatever they were) so we 841 * We don't want to nuke any previous flags (whatever they were) so we
842 * just OR the new operator into the old 842 * just OR the new operator into the old
843 */ 843 */
844 gn->type |= op; 844 gn->type |= op;
845 } 845 }
846 846
847 return TRUE; 847 return TRUE;
848} 848}
849 849
850static void 850static void
851ApplyDependencyOperator(GNodeType op) 851ApplyDependencyOperator(GNodeType op)
852{ 852{
853 GNodeListNode *ln; 853 GNodeListNode *ln;
854 for (ln = targets->first; ln != NULL; ln = ln->next) 854 for (ln = targets->first; ln != NULL; ln = ln->next)
855 if (!TryApplyDependencyOperator(ln->datum, op)) 855 if (!TryApplyDependencyOperator(ln->datum, op))
856 break; 856 break;
857} 857}
858 858
859static Boolean 859static Boolean
860ParseDoSrcKeyword(const char *src, ParseSpecial specType) 860ParseDoSrcKeyword(const char *src, ParseSpecial specType)
861{ 861{
862 static int wait_number = 0; 862 static int wait_number = 0;
863 char wait_src[16]; 863 char wait_src[16];
864 GNode *gn; 864 GNode *gn;
865 865
866 if (*src == '.' && ch_isupper(src[1])) { 866 if (*src == '.' && ch_isupper(src[1])) {
867 int keywd = ParseFindKeyword(src); 867 int keywd = ParseFindKeyword(src);
868 if (keywd != -1) { 868 if (keywd != -1) {
869 int op = parseKeywords[keywd].op; 869 int op = parseKeywords[keywd].op;
870 if (op != 0) { 870 if (op != 0) {
871 ApplyDependencyOperator(op); 871 ApplyDependencyOperator(op);
872 return TRUE; 872 return TRUE;
873 } 873 }
874 if (parseKeywords[keywd].spec == SP_WAIT) { 874 if (parseKeywords[keywd].spec == SP_WAIT) {
875 /* 875 /*
876 * We add a .WAIT node in the dependency list. 876 * We add a .WAIT node in the dependency list.
877 * After any dynamic dependencies (and filename globbing) 877 * After any dynamic dependencies (and filename globbing)
878 * have happened, it is given a dependency on the each 878 * have happened, it is given a dependency on the each
879 * previous child back to and previous .WAIT node. 879 * previous child back to and previous .WAIT node.
880 * The next child won't be scheduled until the .WAIT node 880 * The next child won't be scheduled until the .WAIT node
881 * is built. 881 * is built.
882 * We give each .WAIT node a unique name (mainly for diag). 882 * We give each .WAIT node a unique name (mainly for diag).
883 */ 883 */
884 snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number); 884 snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number);
885 gn = Targ_NewInternalNode(wait_src); 885 gn = Targ_NewInternalNode(wait_src);
886 if (doing_depend) 886 if (doing_depend)
887 ParseMark(gn); 887 ParseMark(gn);
888 gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN; 888 gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN;
889 LinkToTargets(gn, specType != SP_NOT); 889 LinkToTargets(gn, specType != SP_NOT);
890 return TRUE; 890 return TRUE;
891 } 891 }
892 } 892 }
893 } 893 }
894 return FALSE; 894 return FALSE;
895} 895}
896 896
897static void 897static void
898ParseDoSrcMain(const char *src) 898ParseDoSrcMain(const char *src)
899{ 899{
900 /* 900 /*
901 * If we have noted the existence of a .MAIN, it means we need 901 * If we have noted the existence of a .MAIN, it means we need
902 * to add the sources of said target to the list of things 902 * to add the sources of said target to the list of things
903 * to create. The string 'src' is likely to be free, so we 903 * to create. The string 'src' is likely to be free, so we
904 * must make a new copy of it. Note that this will only be 904 * must make a new copy of it. Note that this will only be
905 * invoked if the user didn't specify a target on the command 905 * invoked if the user didn't specify a target on the command
906 * line. This is to allow #ifmake's to succeed, or something... 906 * line. This is to allow #ifmake's to succeed, or something...
907 */ 907 */
908 Lst_Append(opts.create, bmake_strdup(src)); 908 Lst_Append(opts.create, bmake_strdup(src));
909 /* 909 /*
910 * Add the name to the .TARGETS variable as well, so the user can 910 * Add the name to the .TARGETS variable as well, so the user can
911 * employ that, if desired. 911 * employ that, if desired.
912 */ 912 */
913 Var_Append(".TARGETS", src, VAR_GLOBAL); 913 Var_Append(".TARGETS", src, VAR_GLOBAL);
914} 914}
915 915
916static void 916static void
917ParseDoSrcOrder(const char *src) 917ParseDoSrcOrder(const char *src)
918{ 918{
919 GNode *gn; 919 GNode *gn;
920 /* 920 /*
921 * Create proper predecessor/successor links between the previous 921 * Create proper predecessor/successor links between the previous
922 * source and the current one. 922 * source and the current one.
923 */ 923 */
924 gn = Targ_GetNode(src); 924 gn = Targ_GetNode(src);
925 if (doing_depend) 925 if (doing_depend)
926 ParseMark(gn); 926 ParseMark(gn);
927 if (order_pred != NULL) { 927 if (order_pred != NULL) {
928 Lst_Append(order_pred->order_succ, gn); 928 Lst_Append(order_pred->order_succ, gn);
929 Lst_Append(gn->order_pred, order_pred); 929 Lst_Append(gn->order_pred, order_pred);
930 if (DEBUG(PARSE)) { 930 if (DEBUG(PARSE)) {
931 debug_printf("# %s: added Order dependency %s - %s\n", 931 debug_printf("# %s: added Order dependency %s - %s\n",
932 __func__, order_pred->name, gn->name); 932 __func__, order_pred->name, gn->name);
933 Targ_PrintNode(order_pred, 0); 933 Targ_PrintNode(order_pred, 0);
934 Targ_PrintNode(gn, 0); 934 Targ_PrintNode(gn, 0);
935 } 935 }
936 } 936 }
937 /* 937 /*
938 * The current source now becomes the predecessor for the next one. 938 * The current source now becomes the predecessor for the next one.
939 */ 939 */
940 order_pred = gn; 940 order_pred = gn;
941} 941}
942 942
943static void 943static void
944ParseDoSrcOther(const char *src, GNodeType tOp, ParseSpecial specType) 944ParseDoSrcOther(const char *src, GNodeType tOp, ParseSpecial specType)
945{ 945{
946 GNode *gn; 946 GNode *gn;
947 947
948 /* 948 /*
949 * If the source is not an attribute, we need to find/create 949 * If the source is not an attribute, we need to find/create
950 * a node for it. After that we can apply any operator to it 950 * a node for it. After that we can apply any operator to it
951 * from a special target or link it to its parents, as 951 * from a special target or link it to its parents, as
952 * appropriate. 952 * appropriate.
953 * 953 *
954 * In the case of a source that was the object of a :: operator, 954 * In the case of a source that was the object of a :: operator,
955 * the attribute is applied to all of its instances (as kept in 955 * the attribute is applied to all of its instances (as kept in
956 * the 'cohorts' list of the node) or all the cohorts are linked 956 * the 'cohorts' list of the node) or all the cohorts are linked
957 * to all the targets. 957 * to all the targets.
958 */ 958 */
959 959
960 /* Find/create the 'src' node and attach to all targets */ 960 /* Find/create the 'src' node and attach to all targets */
961 gn = Targ_GetNode(src); 961 gn = Targ_GetNode(src);
962 if (doing_depend) 962 if (doing_depend)
963 ParseMark(gn); 963 ParseMark(gn);
964 if (tOp) { 964 if (tOp) {
965 gn->type |= tOp; 965 gn->type |= tOp;
966 } else { 966 } else {
967 LinkToTargets(gn, specType != SP_NOT); 967 LinkToTargets(gn, specType != SP_NOT);
968 } 968 }
969} 969}
970 970
971/* Given the name of a source in a dependency line, figure out if it is an 971/* Given the name of a source in a dependency line, figure out if it is an
972 * attribute (such as .SILENT) and apply it to the targets if it is. Else 972 * attribute (such as .SILENT) and apply it to the targets if it is. Else
973 * decide if there is some attribute which should be applied *to* the source 973 * decide if there is some attribute which should be applied *to* the source
974 * because of some special target (such as .PHONY) and apply it if so. 974 * because of some special target (such as .PHONY) and apply it if so.
975 * Otherwise, make the source a child of the targets in the list 'targets'. 975 * Otherwise, make the source a child of the targets in the list 'targets'.
976 * 976 *
977 * Input: 977 * Input:
978 * tOp operator (if any) from special targets 978 * tOp operator (if any) from special targets
979 * src name of the source to handle 979 * src name of the source to handle
980 */ 980 */
981static void 981static void
982ParseDoSrc(GNodeType tOp, const char *src, ParseSpecial specType) 982ParseDoSrc(GNodeType tOp, const char *src, ParseSpecial specType)
983{ 983{
984 if (ParseDoSrcKeyword(src, specType)) 984 if (ParseDoSrcKeyword(src, specType))
985 return; 985 return;
986 986
987 if (specType == SP_MAIN) 987 if (specType == SP_MAIN)
988 ParseDoSrcMain(src); 988 ParseDoSrcMain(src);
989 else if (specType == SP_ORDER) 989 else if (specType == SP_ORDER)
990 ParseDoSrcOrder(src); 990 ParseDoSrcOrder(src);
991 else 991 else
992 ParseDoSrcOther(src, tOp, specType); 992 ParseDoSrcOther(src, tOp, specType);
993} 993}
994 994
995/* If we have yet to decide on a main target to make, in the absence of any 995/* If we have yet to decide on a main target to make, in the absence of any
996 * user input, we want the first target on the first dependency line that is 996 * user input, we want the first target on the first dependency line that is
997 * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made. */ 997 * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made. */
998static void 998static void
999FindMainTarget(void) 999FindMainTarget(void)
1000{ 1000{
1001 GNodeListNode *ln; 1001 GNodeListNode *ln;
1002 1002
1003 if (mainNode != NULL) 1003 if (mainNode != NULL)
1004 return; 1004 return;
1005 1005
1006 for (ln = targets->first; ln != NULL; ln = ln->next) { 1006 for (ln = targets->first; ln != NULL; ln = ln->next) {
1007 GNode *gn = ln->datum; 1007 GNode *gn = ln->datum;
1008 if (!(gn->type & OP_NOTARGET)) { 1008 if (!(gn->type & OP_NOTARGET)) {
1009 mainNode = gn; 1009 mainNode = gn;
1010 Targ_SetMain(gn); 1010 Targ_SetMain(gn);
1011 return; 1011 return;
1012 } 1012 }
1013 } 1013 }
1014} 1014}
1015 1015
1016/* 1016/*
1017 * We got to the end of the line while we were still looking at targets. 1017 * We got to the end of the line while we were still looking at targets.
1018 * 1018 *
1019 * Ending a dependency line without an operator is a Bozo no-no. As a 1019 * Ending a dependency line without an operator is a Bozo no-no. As a
1020 * heuristic, this is also often triggered by undetected conflicts from 1020 * heuristic, this is also often triggered by undetected conflicts from
1021 * cvs/rcs merges. 1021 * cvs/rcs merges.
1022 */ 1022 */
1023static void 1023static void
1024ParseErrorNoDependency(const char *lstart) 1024ParseErrorNoDependency(const char *lstart)
1025{ 1025{
1026 if ((strncmp(lstart, "<<<<<<", 6) == 0) || 1026 if ((strncmp(lstart, "<<<<<<", 6) == 0) ||
1027 (strncmp(lstart, "======", 6) == 0) || 1027 (strncmp(lstart, "======", 6) == 0) ||
1028 (strncmp(lstart, ">>>>>>", 6) == 0)) 1028 (strncmp(lstart, ">>>>>>", 6) == 0))
1029 Parse_Error(PARSE_FATAL, 1029 Parse_Error(PARSE_FATAL,
1030 "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts"); 1030 "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts");
1031 else if (lstart[0] == '.') { 1031 else if (lstart[0] == '.') {
1032 const char *dirstart = lstart + 1; 1032 const char *dirstart = lstart + 1;
1033 const char *dirend; 1033 const char *dirend;
1034 cpp_skip_whitespace(&dirstart); 1034 cpp_skip_whitespace(&dirstart);
1035 dirend = dirstart; 1035 dirend = dirstart;
1036 while (ch_isalnum(*dirend) || *dirend == '-') 1036 while (ch_isalnum(*dirend) || *dirend == '-')
1037 dirend++; 1037 dirend++;
1038 Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"", 1038 Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"",
1039 (int)(dirend - dirstart), dirstart); 1039 (int)(dirend - dirstart), dirstart);
1040 } else 1040 } else
1041 Parse_Error(PARSE_FATAL, "Need an operator"); 1041 Parse_Error(PARSE_FATAL, "Need an operator");
1042} 1042}
1043 1043
1044static void 1044static void
1045ParseDependencyTargetWord(/*const*/ char **pp, const char *lstart) 1045ParseDependencyTargetWord(/*const*/ char **pp, const char *lstart)
1046{ 1046{
1047 /*const*/ char *cp = *pp; 1047 /*const*/ char *cp = *pp;
1048 1048
1049 while (*cp != '\0') { 1049 while (*cp != '\0') {
1050 if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' || *cp == '(') && 1050 if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' || *cp == '(') &&
1051 !ParseIsEscaped(lstart, cp)) 1051 !ParseIsEscaped(lstart, cp))
1052 break; 1052 break;
1053 1053
1054 if (*cp == '$') { 1054 if (*cp == '$') {
1055 /* 1055 /*
1056 * Must be a dynamic source (would have been expanded 1056 * Must be a dynamic source (would have been expanded
1057 * otherwise), so call the Var module to parse the puppy 1057 * otherwise), so call the Var module to parse the puppy
1058 * so we can safely advance beyond it...There should be 1058 * so we can safely advance beyond it...There should be
1059 * no errors in this, as they would have been discovered 1059 * no errors in this, as they would have been discovered
1060 * in the initial Var_Subst and we wouldn't be here. 1060 * in the initial Var_Subst and we wouldn't be here.
1061 */ 1061 */
1062 const char *nested_p = cp; 1062 const char *nested_p = cp;
1063 const char *nested_val; 1063 const char *nested_val;
1064 void *freeIt; 1064 void *freeIt;
1065 1065
1066 (void)Var_Parse(&nested_p, VAR_CMD, VARE_UNDEFERR|VARE_WANTRES, 1066 (void)Var_Parse(&nested_p, VAR_CMD, VARE_UNDEFERR|VARE_WANTRES,
1067 &nested_val, &freeIt); 1067 &nested_val, &freeIt);
1068 /* TODO: handle errors */ 1068 /* TODO: handle errors */
1069 free(freeIt); 1069 free(freeIt);
1070 cp += nested_p - cp; 1070 cp += nested_p - cp;
1071 } else 1071 } else
1072 cp++; 1072 cp++;
1073 } 1073 }
1074 1074
1075 *pp = cp; 1075 *pp = cp;
1076} 1076}
1077 1077
1078/* 1078/*
1079 * Certain special targets have special semantics: 1079 * Certain special targets have special semantics:
1080 * .PATH Have to set the dirSearchPath 1080 * .PATH Have to set the dirSearchPath
1081 * variable too 1081 * variable too
1082 * .MAIN Its sources are only used if 1082 * .MAIN Its sources are only used if
1083 * nothing has been specified to 1083 * nothing has been specified to
1084 * create. 1084 * create.
1085 * .DEFAULT Need to create a node to hang 1085 * .DEFAULT Need to create a node to hang
1086 * commands on, but we don't want 1086 * commands on, but we don't want
1087 * it in the graph, nor do we want 1087 * it in the graph, nor do we want
1088 * it to be the Main Target, so we 1088 * it to be the Main Target, so we
1089 * create it, set OP_NOTMAIN and 1089 * create it, set OP_NOTMAIN and
1090 * add it to the list, setting 1090 * add it to the list, setting
1091 * DEFAULT to the new node for 1091 * DEFAULT to the new node for
1092 * later use. We claim the node is 1092 * later use. We claim the node is
1093 * A transformation rule to make 1093 * A transformation rule to make
1094 * life easier later, when we'll 1094 * life easier later, when we'll
1095 * use Make_HandleUse to actually 1095 * use Make_HandleUse to actually
1096 * apply the .DEFAULT commands. 1096 * apply the .DEFAULT commands.
1097 * .PHONY The list of targets 1097 * .PHONY The list of targets
1098 * .NOPATH Don't search for file in the path 1098 * .NOPATH Don't search for file in the path
1099 * .STALE 1099 * .STALE
1100 * .BEGIN 1100 * .BEGIN
1101 * .END 1101 * .END
1102 * .ERROR 1102 * .ERROR
1103 * .DELETE_ON_ERROR 1103 * .DELETE_ON_ERROR
1104 * .INTERRUPT Are not to be considered the 1104 * .INTERRUPT Are not to be considered the
1105 * main target. 1105 * main target.
1106 * .NOTPARALLEL Make only one target at a time. 1106 * .NOTPARALLEL Make only one target at a time.
1107 * .SINGLESHELL Create a shell for each command. 1107 * .SINGLESHELL Create a shell for each command.
1108 * .ORDER Must set initial predecessor to NULL 1108 * .ORDER Must set initial predecessor to NULL
1109 */ 1109 */
1110static void 1110static void
1111ParseDoDependencyTargetSpecial(ParseSpecial *inout_specType, 1111ParseDoDependencyTargetSpecial(ParseSpecial *inout_specType,
1112 const char *line, 1112 const char *line,
1113 SearchPathList **inout_paths) 1113 SearchPathList **inout_paths)
1114{ 1114{
1115 switch (*inout_specType) { 1115 switch (*inout_specType) {
1116 case SP_PATH: 1116 case SP_PATH:
1117 if (*inout_paths == NULL) { 1117 if (*inout_paths == NULL) {
1118 *inout_paths = Lst_New(); 1118 *inout_paths = Lst_New();
1119 } 1119 }
1120 Lst_Append(*inout_paths, dirSearchPath); 1120 Lst_Append(*inout_paths, dirSearchPath);
1121 break; 1121 break;
1122 case SP_MAIN: 1122 case SP_MAIN:
1123 if (!Lst_IsEmpty(opts.create)) { 1123 if (!Lst_IsEmpty(opts.create)) {
1124 *inout_specType = SP_NOT; 1124 *inout_specType = SP_NOT;
1125 } 1125 }
1126 break; 1126 break;
1127 case SP_BEGIN: 1127 case SP_BEGIN:
1128 case SP_END: 1128 case SP_END:
1129 case SP_STALE: 1129 case SP_STALE:
1130 case SP_ERROR: 1130 case SP_ERROR:
1131 case SP_INTERRUPT: { 1131 case SP_INTERRUPT: {
1132 GNode *gn = Targ_GetNode(line); 1132 GNode *gn = Targ_GetNode(line);
1133 if (doing_depend) 1133 if (doing_depend)
1134 ParseMark(gn); 1134 ParseMark(gn);
1135 gn->type |= OP_NOTMAIN|OP_SPECIAL; 1135 gn->type |= OP_NOTMAIN|OP_SPECIAL;
1136 Lst_Append(targets, gn); 1136 Lst_Append(targets, gn);
1137 break; 1137 break;
1138 } 1138 }
1139 case SP_DEFAULT: { 1139 case SP_DEFAULT: {
1140 GNode *gn = Targ_NewGN(".DEFAULT"); 1140 GNode *gn = Targ_NewGN(".DEFAULT");
1141 gn->type |= OP_NOTMAIN|OP_TRANSFORM; 1141 gn->type |= OP_NOTMAIN|OP_TRANSFORM;
1142 Lst_Append(targets, gn); 1142 Lst_Append(targets, gn);
1143 DEFAULT = gn; 1143 DEFAULT = gn;
1144 break; 1144 break;
1145 } 1145 }
1146 case SP_DELETE_ON_ERROR: 1146 case SP_DELETE_ON_ERROR:
1147 deleteOnError = TRUE; 1147 deleteOnError = TRUE;
1148 break; 1148 break;
1149 case SP_NOTPARALLEL: 1149 case SP_NOTPARALLEL:
1150 opts.maxJobs = 1; 1150 opts.maxJobs = 1;
1151 break; 1151 break;
1152 case SP_SINGLESHELL: 1152 case SP_SINGLESHELL:
1153 opts.compatMake = TRUE; 1153 opts.compatMake = TRUE;
1154 break; 1154 break;
1155 case SP_ORDER: 1155 case SP_ORDER:
1156 order_pred = NULL; 1156 order_pred = NULL;
1157 break; 1157 break;
1158 default: 1158 default:
1159 break; 1159 break;
1160 } 1160 }
1161} 1161}
1162 1162
1163/* 1163/*
1164 * .PATH<suffix> has to be handled specially. 1164 * .PATH<suffix> has to be handled specially.
1165 * Call on the suffix module to give us a path to modify. 1165 * Call on the suffix module to give us a path to modify.
1166 */ 1166 */
1167static Boolean 1167static Boolean
1168ParseDoDependencyTargetPath(const char *line, SearchPathList **inout_paths) 1168ParseDoDependencyTargetPath(const char *line, SearchPathList **inout_paths)
1169{ 1169{
1170 SearchPath *path; 1170 SearchPath *path;
1171 1171
1172 path = Suff_GetPath(&line[5]); 1172 path = Suff_GetPath(&line[5]);
1173 if (path == NULL) { 1173 if (path == NULL) {
1174 Parse_Error(PARSE_FATAL, 1174 Parse_Error(PARSE_FATAL,
1175 "Suffix '%s' not defined (yet)", 1175 "Suffix '%s' not defined (yet)",
1176 &line[5]); 1176 &line[5]);
1177 return FALSE; 1177 return FALSE;
1178 } else { 1178 } else {
1179 if (*inout_paths == NULL) { 1179 if (*inout_paths == NULL) {
1180 *inout_paths = Lst_New(); 1180 *inout_paths = Lst_New();
1181 } 1181 }
1182 Lst_Append(*inout_paths, path); 1182 Lst_Append(*inout_paths, path);
1183 } 1183 }
1184 return TRUE; 1184 return TRUE;
1185} 1185}
1186 1186
1187/* 1187/*
1188 * See if it's a special target and if so set specType to match it. 1188 * See if it's a special target and if so set specType to match it.
1189 */ 1189 */
1190static Boolean 1190static Boolean
1191ParseDoDependencyTarget(const char *line, ParseSpecial *inout_specType, 1191ParseDoDependencyTarget(const char *line, ParseSpecial *inout_specType,
1192 GNodeType *out_tOp, SearchPathList **inout_paths) 1192 GNodeType *out_tOp, SearchPathList **inout_paths)
1193{ 1193{
1194 int keywd; 1194 int keywd;
1195 1195
1196 if (!(*line == '.' && ch_isupper(line[1]))) 1196 if (!(*line == '.' && ch_isupper(line[1])))
1197 return TRUE; 1197 return TRUE;
1198 1198
1199 /* 1199 /*
1200 * See if the target is a special target that must have it 1200 * See if the target is a special target that must have it
1201 * or its sources handled specially. 1201 * or its sources handled specially.
1202 */ 1202 */
1203 keywd = ParseFindKeyword(line); 1203 keywd = ParseFindKeyword(line);
1204 if (keywd != -1) { 1204 if (keywd != -1) {
1205 if (*inout_specType == SP_PATH && parseKeywords[keywd].spec != SP_PATH) { 1205 if (*inout_specType == SP_PATH && parseKeywords[keywd].spec != SP_PATH) {
1206 Parse_Error(PARSE_FATAL, "Mismatched special targets"); 1206 Parse_Error(PARSE_FATAL, "Mismatched special targets");
1207 return FALSE; 1207 return FALSE;
1208 } 1208 }
1209 1209
1210 *inout_specType = parseKeywords[keywd].spec; 1210 *inout_specType = parseKeywords[keywd].spec;
1211 *out_tOp = parseKeywords[keywd].op; 1211 *out_tOp = parseKeywords[keywd].op;
1212 1212
1213 ParseDoDependencyTargetSpecial(inout_specType, line, inout_paths); 1213 ParseDoDependencyTargetSpecial(inout_specType, line, inout_paths);
1214 1214
1215 } else if (strncmp(line, ".PATH", 5) == 0) { 1215 } else if (strncmp(line, ".PATH", 5) == 0) {
1216 *inout_specType = SP_PATH; 1216 *inout_specType = SP_PATH;
1217 if (!ParseDoDependencyTargetPath(line, inout_paths)) 1217 if (!ParseDoDependencyTargetPath(line, inout_paths))
1218 return FALSE; 1218 return FALSE;
1219 } 1219 }
1220 return TRUE; 1220 return TRUE;
1221} 1221}
1222 1222
1223static void 1223static void
1224ParseDoDependencyTargetMundane(char *line, StringList *curTargs) 1224ParseDoDependencyTargetMundane(char *line, StringList *curTargs)
1225{ 1225{
1226 if (Dir_HasWildcards(line)) { 1226 if (Dir_HasWildcards(line)) {
1227 /* 1227 /*
1228 * Targets are to be sought only in the current directory, 1228 * Targets are to be sought only in the current directory,
1229 * so create an empty path for the thing. Note we need to 1229 * so create an empty path for the thing. Note we need to
1230 * use Dir_Destroy in the destruction of the path as the 1230 * use Dir_Destroy in the destruction of the path as the
1231 * Dir module could have added a directory to the path... 1231 * Dir module could have added a directory to the path...
1232 */ 1232 */
1233 SearchPath *emptyPath = Lst_New(); 1233 SearchPath *emptyPath = Lst_New();
1234 1234
1235 Dir_Expand(line, emptyPath, curTargs); 1235 Dir_Expand(line, emptyPath, curTargs);
1236 1236
1237 Lst_Destroy(emptyPath, Dir_Destroy); 1237 Lst_Destroy(emptyPath, Dir_Destroy);
1238 } else { 1238 } else {
1239 /* 1239 /*
1240 * No wildcards, but we want to avoid code duplication, 1240 * No wildcards, but we want to avoid code duplication,
1241 * so create a list with the word on it. 1241 * so create a list with the word on it.
1242 */ 1242 */
1243 Lst_Append(curTargs, line); 1243 Lst_Append(curTargs, line);
1244 } 1244 }
1245 1245
1246 /* Apply the targets. */ 1246 /* Apply the targets. */
1247 1247
1248 while (!Lst_IsEmpty(curTargs)) { 1248 while (!Lst_IsEmpty(curTargs)) {
1249 char *targName = Lst_Dequeue(curTargs); 1249 char *targName = Lst_Dequeue(curTargs);
1250 GNode *gn = Suff_IsTransform(targName) 1250 GNode *gn = Suff_IsTransform(targName)
1251 ? Suff_AddTransform(targName) 1251 ? Suff_AddTransform(targName)
1252 : Targ_GetNode(targName); 1252 : Targ_GetNode(targName);
1253 if (doing_depend) 1253 if (doing_depend)
1254 ParseMark(gn); 1254 ParseMark(gn);
1255 1255
1256 Lst_Append(targets, gn); 1256 Lst_Append(targets, gn);
1257 } 1257 }
1258} 1258}
1259 1259
1260static void 1260static void
1261ParseDoDependencyTargetExtraWarn(char **pp, const char *lstart) 1261ParseDoDependencyTargetExtraWarn(char **pp, const char *lstart)
1262{ 1262{
1263 Boolean warning = FALSE; 1263 Boolean warning = FALSE;
1264 char *cp = *pp; 1264 char *cp = *pp;
1265 1265
1266 while (*cp && (ParseIsEscaped(lstart, cp) || 1266 while (*cp && (ParseIsEscaped(lstart, cp) ||
1267 (*cp != '!' && *cp != ':'))) { 1267 (*cp != '!' && *cp != ':'))) {
1268 if (ParseIsEscaped(lstart, cp) || 1268 if (ParseIsEscaped(lstart, cp) ||
1269 (*cp != ' ' && *cp != '\t')) { 1269 (*cp != ' ' && *cp != '\t')) {
1270 warning = TRUE; 1270 warning = TRUE;
1271 } 1271 }
1272 cp++; 1272 cp++;
1273 } 1273 }
1274 if (warning) { 1274 if (warning) {
1275 Parse_Error(PARSE_WARNING, "Extra target ignored"); 1275 Parse_Error(PARSE_WARNING, "Extra target ignored");
1276 } 1276 }
1277 *pp = cp; 1277 *pp = cp;
1278} 1278}
1279 1279
1280static void 1280static void
1281ParseDoDependencyCheckSpec(ParseSpecial specType) 1281ParseDoDependencyCheckSpec(ParseSpecial specType)
1282{ 1282{
1283 switch (specType) { 1283 switch (specType) {
1284 default: 1284 default:
1285 Parse_Error(PARSE_WARNING, 1285 Parse_Error(PARSE_WARNING,
1286 "Special and mundane targets don't mix. Mundane ones ignored"); 1286 "Special and mundane targets don't mix. Mundane ones ignored");
1287 break; 1287 break;
1288 case SP_DEFAULT: 1288 case SP_DEFAULT:
1289 case SP_STALE: 1289 case SP_STALE:
1290 case SP_BEGIN: 1290 case SP_BEGIN:
1291 case SP_END: 1291 case SP_END:
1292 case SP_ERROR: 1292 case SP_ERROR:
1293 case SP_INTERRUPT: 1293 case SP_INTERRUPT:
1294 /* 1294 /*
1295 * These four create nodes on which to hang commands, so 1295 * These four create nodes on which to hang commands, so
1296 * targets shouldn't be empty... 1296 * targets shouldn't be empty...
1297 */ 1297 */
1298 case SP_NOT: 1298 case SP_NOT:
1299 /* 1299 /*
1300 * Nothing special here -- targets can be empty if it wants. 1300 * Nothing special here -- targets can be empty if it wants.
1301 */ 1301 */
1302 break; 1302 break;
1303 } 1303 }
1304} 1304}
1305 1305
1306static Boolean 1306static Boolean
1307ParseDoDependencyParseOp(char **pp, const char *lstart, GNodeType *out_op) 1307ParseDoDependencyParseOp(char **pp, const char *lstart, GNodeType *out_op)
1308{ 1308{
1309 const char *cp = *pp; 1309 const char *cp = *pp;
1310 1310
1311 if (*cp == '!') { 1311 if (*cp == '!') {
1312 *out_op = OP_FORCE; 1312 *out_op = OP_FORCE;
1313 (*pp)++; 1313 (*pp)++;
1314 return TRUE; 1314 return TRUE;
1315 } 1315 }
1316 1316
1317 if (*cp == ':') { 1317 if (*cp == ':') {
1318 if (cp[1] == ':') { 1318 if (cp[1] == ':') {
1319 *out_op = OP_DOUBLEDEP; 1319 *out_op = OP_DOUBLEDEP;
1320 (*pp) += 2; 1320 (*pp) += 2;
1321 } else { 1321 } else {
1322 *out_op = OP_DEPENDS; 1322 *out_op = OP_DEPENDS;
1323 (*pp)++; 1323 (*pp)++;
1324 } 1324 }
1325 return TRUE; 1325 return TRUE;
1326 } 1326 }
1327 1327
1328 { 1328 {
1329 const char *msg = lstart[0] == '.' ? "Unknown directive" 1329 const char *msg = lstart[0] == '.' ? "Unknown directive"
1330 : "Missing dependency operator"; 1330 : "Missing dependency operator";
1331 Parse_Error(PARSE_FATAL, "%s", msg); 1331 Parse_Error(PARSE_FATAL, "%s", msg);
1332 return FALSE; 1332 return FALSE;
1333 } 1333 }
1334} 1334}
1335 1335
1336static void 1336static void
1337ClearPaths(SearchPathList *paths) 1337ClearPaths(SearchPathList *paths)
1338{ 1338{
1339 if (paths != NULL) { 1339 if (paths != NULL) {
1340 SearchPathListNode *ln; 1340 SearchPathListNode *ln;
1341 for (ln = paths->first; ln != NULL; ln = ln->next) 1341 for (ln = paths->first; ln != NULL; ln = ln->next)
1342 Dir_ClearPath(ln->datum); 1342 Dir_ClearPath(ln->datum);
1343 } 1343 }
1344 1344
1345 Dir_SetPATH(); 1345 Dir_SetPATH();
1346} 1346}
1347 1347
1348static void 1348static void
1349ParseDoDependencySourcesEmpty(ParseSpecial specType, SearchPathList *paths) 1349ParseDoDependencySourcesEmpty(ParseSpecial specType, SearchPathList *paths)
1350{ 1350{
1351 switch (specType) { 1351 switch (specType) {
1352 case SP_SUFFIXES: 1352 case SP_SUFFIXES:
1353 Suff_ClearSuffixes(); 1353 Suff_ClearSuffixes();
1354 break; 1354 break;
1355 case SP_PRECIOUS: 1355 case SP_PRECIOUS:
1356 allPrecious = TRUE; 1356 allPrecious = TRUE;
1357 break; 1357 break;
1358 case SP_IGNORE: 1358 case SP_IGNORE:
1359 opts.ignoreErrors = TRUE; 1359 opts.ignoreErrors = TRUE;
1360 break; 1360 break;
1361 case SP_SILENT: 1361 case SP_SILENT:
1362 opts.beSilent = TRUE; 1362 opts.beSilent = TRUE;
1363 break; 1363 break;
1364 case SP_PATH: 1364 case SP_PATH:
1365 ClearPaths(paths); 1365 ClearPaths(paths);
1366 break; 1366 break;
1367#ifdef POSIX 1367#ifdef POSIX
1368 case SP_POSIX: 1368 case SP_POSIX:
1369 Var_Set("%POSIX", "1003.2", VAR_GLOBAL); 1369 Var_Set("%POSIX", "1003.2", VAR_GLOBAL);
1370 break; 1370 break;
1371#endif 1371#endif
1372 default: 1372 default:
1373 break; 1373 break;
1374 } 1374 }
1375} 1375}
1376 1376
1377static void 1377static void
1378AddToPaths(const char *dir, SearchPathList *paths) 1378AddToPaths(const char *dir, SearchPathList *paths)
1379{ 1379{
1380 if (paths != NULL) { 1380 if (paths != NULL) {
1381 SearchPathListNode *ln; 1381 SearchPathListNode *ln;
1382 for (ln = paths->first; ln != NULL; ln = ln->next) 1382 for (ln = paths->first; ln != NULL; ln = ln->next)
1383 (void)Dir_AddDir(ln->datum, dir); 1383 (void)Dir_AddDir(ln->datum, dir);
1384 } 1384 }
1385} 1385}
1386 1386
1387/* 1387/*
1388 * If the target was one that doesn't take files as its sources 1388 * If the target was one that doesn't take files as its sources
1389 * but takes something like suffixes, we take each 1389 * but takes something like suffixes, we take each
1390 * space-separated word on the line as a something and deal 1390 * space-separated word on the line as a something and deal
1391 * with it accordingly. 1391 * with it accordingly.
1392 * 1392 *
1393 * If the target was .SUFFIXES, we take each source as a 1393 * If the target was .SUFFIXES, we take each source as a
1394 * suffix and add it to the list of suffixes maintained by the 1394 * suffix and add it to the list of suffixes maintained by the
1395 * Suff module. 1395 * Suff module.
1396 * 1396 *
1397 * If the target was a .PATH, we add the source as a directory 1397 * If the target was a .PATH, we add the source as a directory
1398 * to search on the search path. 1398 * to search on the search path.
1399 * 1399 *
1400 * If it was .INCLUDES, the source is taken to be the suffix of 1400 * If it was .INCLUDES, the source is taken to be the suffix of
1401 * files which will be #included and whose search path should 1401 * files which will be #included and whose search path should
1402 * be present in the .INCLUDES variable. 1402 * be present in the .INCLUDES variable.
1403 * 1403 *
1404 * If it was .LIBS, the source is taken to be the suffix of 1404 * If it was .LIBS, the source is taken to be the suffix of
1405 * files which are considered libraries and whose search path 1405 * files which are considered libraries and whose search path
1406 * should be present in the .LIBS variable. 1406 * should be present in the .LIBS variable.
1407 * 1407 *
1408 * If it was .NULL, the source is the suffix to use when a file 1408 * If it was .NULL, the source is the suffix to use when a file
1409 * has no valid suffix. 1409 * has no valid suffix.
1410 * 1410 *
1411 * If it was .OBJDIR, the source is a new definition for .OBJDIR, 1411 * If it was .OBJDIR, the source is a new definition for .OBJDIR,
1412 * and will cause make to do a new chdir to that path. 1412 * and will cause make to do a new chdir to that path.
1413 */ 1413 */
1414static void 1414static void
1415ParseDoDependencySourceSpecial(ParseSpecial specType, char *word, 1415ParseDoDependencySourceSpecial(ParseSpecial specType, char *word,
1416 SearchPathList *paths) 1416 SearchPathList *paths)
1417{ 1417{
1418 switch (specType) { 1418 switch (specType) {
1419 case SP_SUFFIXES: 1419 case SP_SUFFIXES:
1420 Suff_AddSuffix(word, &mainNode); 1420 Suff_AddSuffix(word, &mainNode);
1421 break; 1421 break;
1422 case SP_PATH: 1422 case SP_PATH:
1423 AddToPaths(word, paths); 1423 AddToPaths(word, paths);
1424 break; 1424 break;
1425 case SP_INCLUDES: 1425 case SP_INCLUDES:
1426 Suff_AddInclude(word); 1426 Suff_AddInclude(word);
1427 break; 1427 break;
1428 case SP_LIBS: 1428 case SP_LIBS:
1429 Suff_AddLib(word); 1429 Suff_AddLib(word);
1430 break; 1430 break;
1431 case SP_NULL: 1431 case SP_NULL:
1432 Suff_SetNull(word); 1432 Suff_SetNull(word);
1433 break; 1433 break;
1434 case SP_OBJDIR: 1434 case SP_OBJDIR:
1435 Main_SetObjdir("%s", word); 1435 Main_SetObjdir("%s", word);
1436 break; 1436 break;
1437 default: 1437 default:
1438 break; 1438 break;
1439 } 1439 }
1440} 1440}
1441 1441
1442static Boolean 1442static Boolean
1443ParseDoDependencyTargets(char **inout_cp, 1443ParseDoDependencyTargets(char **inout_cp,
1444 char **inout_line, 1444 char **inout_line,
1445 const char *lstart, 1445 const char *lstart,
1446 ParseSpecial *inout_specType, 1446 ParseSpecial *inout_specType,
1447 GNodeType *inout_tOp, 1447 GNodeType *inout_tOp,
1448 SearchPathList **inout_paths, 1448 SearchPathList **inout_paths,
1449 StringList *curTargs) 1449 StringList *curTargs)
1450{ 1450{
1451 char *cp = *inout_cp; 1451 char *cp = *inout_cp;
1452 char *line = *inout_line; 1452 char *line = *inout_line;
1453 char savec; 1453 char savec;
1454 1454
1455 for (;;) { 1455 for (;;) {
1456 /* 1456 /*
1457 * Here LINE points to the beginning of the next word, and 1457 * Here LINE points to the beginning of the next word, and
1458 * LSTART points to the actual beginning of the line. 1458 * LSTART points to the actual beginning of the line.
1459 */ 1459 */
1460 1460
1461 /* Find the end of the next word. */ 1461 /* Find the end of the next word. */
1462 cp = line; 1462 cp = line;
1463 ParseDependencyTargetWord(&cp, lstart); 1463 ParseDependencyTargetWord(&cp, lstart);
1464 1464
1465 /* 1465 /*
1466 * If the word is followed by a left parenthesis, it's the 1466 * If the word is followed by a left parenthesis, it's the
1467 * name of an object file inside an archive (ar file). 1467 * name of an object file inside an archive (ar file).
1468 */ 1468 */
1469 if (!ParseIsEscaped(lstart, cp) && *cp == '(') { 1469 if (!ParseIsEscaped(lstart, cp) && *cp == '(') {
1470 /* 1470 /*
1471 * Archives must be handled specially to make sure the OP_ARCHV 1471 * Archives must be handled specially to make sure the OP_ARCHV
1472 * flag is set in their 'type' field, for one thing, and because 1472 * flag is set in their 'type' field, for one thing, and because
1473 * things like "archive(file1.o file2.o file3.o)" are permissible. 1473 * things like "archive(file1.o file2.o file3.o)" are permissible.
1474 * Arch_ParseArchive will set 'line' to be the first non-blank 1474 * Arch_ParseArchive will set 'line' to be the first non-blank
1475 * after the archive-spec. It creates/finds nodes for the members 1475 * after the archive-spec. It creates/finds nodes for the members
1476 * and places them on the given list, returning TRUE if all 1476 * and places them on the given list, returning TRUE if all
1477 * went well and FALSE if there was an error in the 1477 * went well and FALSE if there was an error in the
1478 * specification. On error, line should remain untouched. 1478 * specification. On error, line should remain untouched.
1479 */ 1479 */
1480 if (!Arch_ParseArchive(&line, targets, VAR_CMD)) { 1480 if (!Arch_ParseArchive(&line, targets, VAR_CMD)) {
1481 Parse_Error(PARSE_FATAL, 1481 Parse_Error(PARSE_FATAL,
1482 "Error in archive specification: \"%s\"", line); 1482 "Error in archive specification: \"%s\"", line);
1483 return FALSE; 1483 return FALSE;
1484 } else { 1484 } else {
1485 /* Done with this word; on to the next. */ 1485 /* Done with this word; on to the next. */
1486 cp = line; 1486 cp = line;
1487 continue; 1487 continue;
1488 } 1488 }
1489 } 1489 }
1490 1490
1491 if (!*cp) { 1491 if (!*cp) {
1492 ParseErrorNoDependency(lstart); 1492 ParseErrorNoDependency(lstart);
1493 return FALSE; 1493 return FALSE;
1494 } 1494 }
1495 1495
1496 /* Insert a null terminator. */ 1496 /* Insert a null terminator. */
1497 savec = *cp; 1497 savec = *cp;
1498 *cp = '\0'; 1498 *cp = '\0';
1499 1499
1500 if (!ParseDoDependencyTarget(line, inout_specType, inout_tOp, 1500 if (!ParseDoDependencyTarget(line, inout_specType, inout_tOp,
1501 inout_paths)) 1501 inout_paths))
1502 return FALSE; 1502 return FALSE;
1503 1503
1504 /* 1504 /*
1505 * Have word in line. Get or create its node and stick it at 1505 * Have word in line. Get or create its node and stick it at
1506 * the end of the targets list 1506 * the end of the targets list
1507 */ 1507 */
1508 if (*inout_specType == SP_NOT && *line != '\0') { 1508 if (*inout_specType == SP_NOT && *line != '\0') {
1509 ParseDoDependencyTargetMundane(line, curTargs); 1509 ParseDoDependencyTargetMundane(line, curTargs);
1510 } else if (*inout_specType == SP_PATH && *line != '.' && *line != '\0') { 1510 } else if (*inout_specType == SP_PATH && *line != '.' && *line != '\0') {
1511 Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); 1511 Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);
1512 } 1512 }
1513 1513
1514 /* Don't need the inserted null terminator any more. */ 1514 /* Don't need the inserted null terminator any more. */
1515 *cp = savec; 1515 *cp = savec;
1516 1516
1517 /* 1517 /*
1518 * If it is a special type and not .PATH, it's the only target we 1518 * If it is a special type and not .PATH, it's the only target we
1519 * allow on this line... 1519 * allow on this line...
1520 */ 1520 */
1521 if (*inout_specType != SP_NOT && *inout_specType != SP_PATH) { 1521 if (*inout_specType != SP_NOT && *inout_specType != SP_PATH) {
1522 ParseDoDependencyTargetExtraWarn(&cp, lstart); 1522 ParseDoDependencyTargetExtraWarn(&cp, lstart);
1523 } else { 1523 } else {
1524 pp_skip_whitespace(&cp); 1524 pp_skip_whitespace(&cp);
1525 } 1525 }
1526 line = cp; 1526 line = cp;
1527 if (*line == '\0') 1527 if (*line == '\0')
1528 break; 1528 break;
1529 if ((*line == '!' || *line == ':') && !ParseIsEscaped(lstart, line)) 1529 if ((*line == '!' || *line == ':') && !ParseIsEscaped(lstart, line))
1530 break; 1530 break;
1531 } 1531 }
1532 1532
1533 *inout_cp = cp; 1533 *inout_cp = cp;
1534 *inout_line = line; 1534 *inout_line = line;
1535 return TRUE; 1535 return TRUE;
1536} 1536}
1537 1537
1538static void 1538static void
1539ParseDoDependencySourcesSpecial(char *start, char *end, 1539ParseDoDependencySourcesSpecial(char *start, char *end,
1540 ParseSpecial specType, SearchPathList *paths) 1540 ParseSpecial specType, SearchPathList *paths)
1541{ 1541{
1542 char savec; 1542 char savec;
1543 1543
1544 while (*start) { 1544 while (*start) {
1545 while (*end && !ch_isspace(*end)) 1545 while (*end && !ch_isspace(*end))
1546 end++; 1546 end++;
1547 savec = *end; 1547 savec = *end;
1548 *end = '\0'; 1548 *end = '\0';
1549 ParseDoDependencySourceSpecial(specType, start, paths); 1549 ParseDoDependencySourceSpecial(specType, start, paths);
1550 *end = savec; 1550 *end = savec;
1551 if (savec != '\0') 1551 if (savec != '\0')
1552 end++; 1552 end++;
1553 pp_skip_whitespace(&end); 1553 pp_skip_whitespace(&end);
1554 start = end; 1554 start = end;
1555 } 1555 }
1556} 1556}
1557 1557
1558static Boolean 1558static Boolean
1559ParseDoDependencySourcesMundane(char *start, char *end, 1559ParseDoDependencySourcesMundane(char *start, char *end,
1560 ParseSpecial specType, GNodeType tOp) 1560 ParseSpecial specType, GNodeType tOp)
1561{ 1561{
1562 while (*start) { 1562 while (*start) {
1563 /* 1563 /*
1564 * The targets take real sources, so we must beware of archive 1564 * The targets take real sources, so we must beware of archive
1565 * specifications (i.e. things with left parentheses in them) 1565 * specifications (i.e. things with left parentheses in them)
1566 * and handle them accordingly. 1566 * and handle them accordingly.
1567 */ 1567 */
1568 for (; *end && !ch_isspace(*end); end++) { 1568 for (; *end && !ch_isspace(*end); end++) {
1569 if (*end == '(' && end > start && end[-1] != '$') { 1569 if (*end == '(' && end > start && end[-1] != '$') {
1570 /* 1570 /*
1571 * Only stop for a left parenthesis if it isn't at the 1571 * Only stop for a left parenthesis if it isn't at the
1572 * start of a word (that'll be for variable changes 1572 * start of a word (that'll be for variable changes
1573 * later) and isn't preceded by a dollar sign (a dynamic 1573 * later) and isn't preceded by a dollar sign (a dynamic
1574 * source). 1574 * source).
1575 */ 1575 */
1576 break; 1576 break;
1577 } 1577 }
1578 } 1578 }
1579 1579
1580 if (*end == '(') { 1580 if (*end == '(') {
1581 GNodeList *sources = Lst_New(); 1581 GNodeList *sources = Lst_New();
1582 if (!Arch_ParseArchive(&start, sources, VAR_CMD)) { 1582 if (!Arch_ParseArchive(&start, sources, VAR_CMD)) {
1583 Parse_Error(PARSE_FATAL, 1583 Parse_Error(PARSE_FATAL,
1584 "Error in source archive spec \"%s\"", start); 1584 "Error in source archive spec \"%s\"", start);
1585 return FALSE; 1585 return FALSE;
1586 } 1586 }
1587 1587
1588 while (!Lst_IsEmpty(sources)) { 1588 while (!Lst_IsEmpty(sources)) {
1589 GNode *gn = Lst_Dequeue(sources); 1589 GNode *gn = Lst_Dequeue(sources);
1590 ParseDoSrc(tOp, gn->name, specType); 1590 ParseDoSrc(tOp, gn->name, specType);
1591 } 1591 }
1592 Lst_Free(sources); 1592 Lst_Free(sources);
1593 end = start; 1593 end = start;
1594 } else { 1594 } else {
1595 if (*end) { 1595 if (*end) {
1596 *end = '\0'; 1596 *end = '\0';
1597 end++; 1597 end++;
1598 } 1598 }
1599 1599
1600 ParseDoSrc(tOp, start, specType); 1600 ParseDoSrc(tOp, start, specType);
1601 } 1601 }
1602 pp_skip_whitespace(&end); 1602 pp_skip_whitespace(&end);
1603 start = end; 1603 start = end;
1604 } 1604 }
1605 return TRUE; 1605 return TRUE;
1606} 1606}
1607 1607
1608/* Parse a dependency line consisting of targets, followed by a dependency 1608/* Parse a dependency line consisting of targets, followed by a dependency
1609 * operator, optionally followed by sources. 1609 * operator, optionally followed by sources.
1610 * 1610 *
1611 * The nodes of the sources are linked as children to the nodes of the 1611 * The nodes of the sources are linked as children to the nodes of the
1612 * targets. Nodes are created as necessary. 1612 * targets. Nodes are created as necessary.
1613 * 1613 *
1614 * The operator is applied to each node in the global 'targets' list, 1614 * The operator is applied to each node in the global 'targets' list,
1615 * which is where the nodes found for the targets are kept, by means of 1615 * which is where the nodes found for the targets are kept, by means of
1616 * the ParseDoOp function. 1616 * the ParseDoOp function.
1617 * 1617 *
1618 * The sources are parsed in much the same way as the targets, except 1618 * The sources are parsed in much the same way as the targets, except
1619 * that they are expanded using the wildcarding scheme of the C-Shell, 1619 * that they are expanded using the wildcarding scheme of the C-Shell,
1620 * and all instances of the resulting words in the list of all targets 1620 * and all instances of the resulting words in the list of all targets
1621 * are found. Each of the resulting nodes is then linked to each of the 1621 * are found. Each of the resulting nodes is then linked to each of the
1622 * targets as one of its children. 1622 * targets as one of its children.
1623 * 1623 *
1624 * Certain targets and sources such as .PHONY or .PRECIOUS are handled 1624 * Certain targets and sources such as .PHONY or .PRECIOUS are handled
1625 * specially. These are the ones detailed by the specType variable. 1625 * specially. These are the ones detailed by the specType variable.
1626 * 1626 *
1627 * The storing of transformation rules such as '.c.o' is also taken care of 1627 * The storing of transformation rules such as '.c.o' is also taken care of
1628 * here. A target is recognized as a transformation rule by calling 1628 * here. A target is recognized as a transformation rule by calling
1629 * Suff_IsTransform. If it is a transformation rule, its node is gotten 1629 * Suff_IsTransform. If it is a transformation rule, its node is gotten
1630 * from the suffix module via Suff_AddTransform rather than the standard 1630 * from the suffix module via Suff_AddTransform rather than the standard
1631 * Targ_FindNode in the target module. 1631 * Targ_FindNode in the target module.
1632 */ 1632 */
1633static void 1633static void
1634ParseDoDependency(char *line) 1634ParseDoDependency(char *line)
1635{ 1635{
1636 char *cp; /* our current position */ 1636 char *cp; /* our current position */
1637 GNodeType op; /* the operator on the line */ 1637 GNodeType op; /* the operator on the line */
1638 SearchPathList *paths; /* search paths to alter when parsing 1638 SearchPathList *paths; /* search paths to alter when parsing
1639 * a list of .PATH targets */ 1639 * a list of .PATH targets */
1640 int tOp; /* operator from special target */ 1640 int tOp; /* operator from special target */
1641 StringList *curTargs; /* target names to be found and added 1641 StringList *curTargs; /* target names to be found and added
1642 * to the targets list */ 1642 * to the targets list */
1643 char *lstart = line; 1643 char *lstart = line;
1644 1644
1645 /* 1645 /*
1646 * specType contains the SPECial TYPE of the current target. It is SP_NOT 1646 * specType contains the SPECial TYPE of the current target. It is SP_NOT
1647 * if the target is unspecial. If it *is* special, however, the children 1647 * if the target is unspecial. If it *is* special, however, the children
1648 * are linked as children of the parent but not vice versa. 1648 * are linked as children of the parent but not vice versa.
1649 */ 1649 */
1650 ParseSpecial specType = SP_NOT; 1650 ParseSpecial specType = SP_NOT;
1651 1651
1652 DEBUG1(PARSE, "ParseDoDependency(%s)\n", line); 1652 DEBUG1(PARSE, "ParseDoDependency(%s)\n", line);
1653 tOp = 0; 1653 tOp = 0;
1654 1654
1655 paths = NULL; 1655 paths = NULL;
1656 1656
1657 curTargs = Lst_New(); 1657 curTargs = Lst_New();
1658 1658
1659 /* 1659 /*
1660 * First, grind through the targets. 1660 * First, grind through the targets.
1661 */ 1661 */
1662 if (!ParseDoDependencyTargets(&cp, &line, lstart, &specType, &tOp, &paths, 1662 if (!ParseDoDependencyTargets(&cp, &line, lstart, &specType, &tOp, &paths,
1663 curTargs)) 1663 curTargs))
1664 goto out; 1664 goto out;
1665 1665
1666 /* 1666 /*
1667 * Don't need the list of target names anymore... 1667 * Don't need the list of target names anymore...
1668 */ 1668 */
1669 Lst_Free(curTargs); 1669 Lst_Free(curTargs);
1670 curTargs = NULL; 1670 curTargs = NULL;
1671 1671
1672 if (!Lst_IsEmpty(targets)) 1672 if (!Lst_IsEmpty(targets))
1673 ParseDoDependencyCheckSpec(specType); 1673 ParseDoDependencyCheckSpec(specType);
1674 1674
1675 /* 1675 /*
1676 * Have now parsed all the target names. Must parse the operator next. 1676 * Have now parsed all the target names. Must parse the operator next.
1677 */ 1677 */
1678 if (!ParseDoDependencyParseOp(&cp, lstart, &op)) 1678 if (!ParseDoDependencyParseOp(&cp, lstart, &op))
1679 goto out; 1679 goto out;
1680 1680
1681 /* 1681 /*
1682 * Apply the operator to the target. This is how we remember which 1682 * Apply the operator to the target. This is how we remember which
1683 * operator a target was defined with. It fails if the operator 1683 * operator a target was defined with. It fails if the operator
1684 * used isn't consistent across all references. 1684 * used isn't consistent across all references.
1685 */ 1685 */
1686 ApplyDependencyOperator(op); 1686 ApplyDependencyOperator(op);
1687 1687
1688 /* 1688 /*
1689 * Onward to the sources. 1689 * Onward to the sources.
1690 * 1690 *
1691 * LINE will now point to the first source word, if any, or the 1691 * LINE will now point to the first source word, if any, or the
1692 * end of the string if not. 1692 * end of the string if not.
1693 */ 1693 */
1694 pp_skip_whitespace(&cp); 1694 pp_skip_whitespace(&cp);
1695 line = cp; 1695 line = cp;
1696 1696
1697 /* 1697 /*
1698 * Several special targets take different actions if present with no 1698 * Several special targets take different actions if present with no
1699 * sources: 1699 * sources:
1700 * a .SUFFIXES line with no sources clears out all old suffixes 1700 * a .SUFFIXES line with no sources clears out all old suffixes
1701 * a .PRECIOUS line makes all targets precious 1701 * a .PRECIOUS line makes all targets precious
1702 * a .IGNORE line ignores errors for all targets 1702 * a .IGNORE line ignores errors for all targets
1703 * a .SILENT line creates silence when making all targets 1703 * a .SILENT line creates silence when making all targets
1704 * a .PATH removes all directories from the search path(s). 1704 * a .PATH removes all directories from the search path(s).
1705 */ 1705 */
1706 if (!*line) { 1706 if (!*line) {
1707 ParseDoDependencySourcesEmpty(specType, paths); 1707 ParseDoDependencySourcesEmpty(specType, paths);
1708 } else if (specType == SP_MFLAGS) { 1708 } else if (specType == SP_MFLAGS) {
1709 /* 1709 /*
1710 * Call on functions in main.c to deal with these arguments and 1710 * Call on functions in main.c to deal with these arguments and
1711 * set the initial character to a null-character so the loop to 1711 * set the initial character to a null-character so the loop to
1712 * get sources won't get anything 1712 * get sources won't get anything
1713 */ 1713 */
1714 Main_ParseArgLine(line); 1714 Main_ParseArgLine(line);
1715 *line = '\0'; 1715 *line = '\0';
1716 } else if (specType == SP_SHELL) { 1716 } else if (specType == SP_SHELL) {
1717 if (!Job_ParseShell(line)) { 1717 if (!Job_ParseShell(line)) {
1718 Parse_Error(PARSE_FATAL, "improper shell specification"); 1718 Parse_Error(PARSE_FATAL, "improper shell specification");
1719 goto out; 1719 goto out;
1720 } 1720 }
1721 *line = '\0'; 1721 *line = '\0';
1722 } else if (specType == SP_NOTPARALLEL || specType == SP_SINGLESHELL || 1722 } else if (specType == SP_NOTPARALLEL || specType == SP_SINGLESHELL ||
1723 specType == SP_DELETE_ON_ERROR) { 1723 specType == SP_DELETE_ON_ERROR) {
1724 *line = '\0'; 1724 *line = '\0';
1725 } 1725 }
1726 1726
1727 /* 1727 /*
1728 * NOW GO FOR THE SOURCES 1728 * NOW GO FOR THE SOURCES
1729 */ 1729 */
1730 if (specType == SP_SUFFIXES || specType == SP_PATH || 1730 if (specType == SP_SUFFIXES || specType == SP_PATH ||
1731 specType == SP_INCLUDES || specType == SP_LIBS || 1731 specType == SP_INCLUDES || specType == SP_LIBS ||
1732 specType == SP_NULL || specType == SP_OBJDIR) 1732 specType == SP_NULL || specType == SP_OBJDIR)
1733 { 1733 {
1734 ParseDoDependencySourcesSpecial(line, cp, specType, paths); 1734 ParseDoDependencySourcesSpecial(line, cp, specType, paths);
1735 if (paths) { 1735 if (paths) {
1736 Lst_Free(paths); 1736 Lst_Free(paths);
1737 paths = NULL; 1737 paths = NULL;
1738 } 1738 }
1739 if (specType == SP_PATH) 1739 if (specType == SP_PATH)
1740 Dir_SetPATH(); 1740 Dir_SetPATH();
1741 } else { 1741 } else {
1742 assert(paths == NULL); 1742 assert(paths == NULL);
1743 if (!ParseDoDependencySourcesMundane(line, cp, specType, tOp)) 1743 if (!ParseDoDependencySourcesMundane(line, cp, specType, tOp))
1744 goto out; 1744 goto out;
1745 } 1745 }
1746 1746
1747 FindMainTarget(); 1747 FindMainTarget();
1748 1748
1749out: 1749out:
1750 if (paths != NULL) 1750 if (paths != NULL)
1751 Lst_Free(paths); 1751 Lst_Free(paths);
1752 if (curTargs != NULL) 1752 if (curTargs != NULL)
1753 Lst_Free(curTargs); 1753 Lst_Free(curTargs);
1754} 1754}
1755 1755
1756typedef struct VarAssignParsed { 1756typedef struct VarAssignParsed {
1757 const char *nameStart; /* unexpanded */ 1757 const char *nameStart; /* unexpanded */
1758 const char *nameEnd; /* before operator adjustment */ 1758 const char *nameEnd; /* before operator adjustment */
1759 const char *eq; /* the '=' of the assignment operator */ 1759 const char *eq; /* the '=' of the assignment operator */
1760} VarAssignParsed; 1760} VarAssignParsed;
1761 1761
1762/* Determine the assignment operator and adjust the end of the variable 1762/* Determine the assignment operator and adjust the end of the variable
1763 * name accordingly. */ 1763 * name accordingly. */
1764static void 1764static void
1765AdjustVarassignOp(const VarAssignParsed *pvar, const char *value, 1765AdjustVarassignOp(const VarAssignParsed *pvar, const char *value,
1766 VarAssign *out_var) 1766 VarAssign *out_var)
1767{ 1767{
1768 const char *op = pvar->eq; 1768 const char *op = pvar->eq;
1769 const char * const name = pvar->nameStart; 1769 const char * const name = pvar->nameStart;
1770 VarAssignOp type; 1770 VarAssignOp type;
1771 1771
1772 if (op > name && op[-1] == '+') { 1772 if (op > name && op[-1] == '+') {
1773 type = VAR_APPEND; 1773 type = VAR_APPEND;
1774 op--; 1774 op--;
1775 1775
1776 } else if (op > name && op[-1] == '?') { 1776 } else if (op > name && op[-1] == '?') {
1777 op--; 1777 op--;
1778 type = VAR_DEFAULT; 1778 type = VAR_DEFAULT;
1779 1779
1780 } else if (op > name && op[-1] == ':') { 1780 } else if (op > name && op[-1] == ':') {
1781 op--; 1781 op--;
1782 type = VAR_SUBST; 1782 type = VAR_SUBST;
1783 1783
1784 } else if (op > name && op[-1] == '!') { 1784 } else if (op > name && op[-1] == '!') {
1785 op--; 1785 op--;
1786 type = VAR_SHELL; 1786 type = VAR_SHELL;
1787 1787
1788 } else { 1788 } else {
1789 type = VAR_NORMAL; 1789 type = VAR_NORMAL;
1790#ifdef SUNSHCMD 1790#ifdef SUNSHCMD
1791 while (op > name && ch_isspace(op[-1])) 1791 while (op > name && ch_isspace(op[-1]))
1792 op--; 1792 op--;
1793 1793
1794 if (op >= name + 3 && op[-3] == ':' && op[-2] == 's' && op[-1] == 'h') { 1794 if (op >= name + 3 && op[-3] == ':' && op[-2] == 's' && op[-1] == 'h') {
1795 type = VAR_SHELL; 1795 type = VAR_SHELL;
1796 op -= 3; 1796 op -= 3;
1797 } 1797 }
1798#endif 1798#endif
1799 } 1799 }
1800 1800
1801 { 1801 {
1802 const char *nameEnd = pvar->nameEnd < op ? pvar->nameEnd : op; 1802 const char *nameEnd = pvar->nameEnd < op ? pvar->nameEnd : op;
1803 out_var->varname = bmake_strsedup(pvar->nameStart, nameEnd); 1803 out_var->varname = bmake_strsedup(pvar->nameStart, nameEnd);
1804 out_var->op = type; 1804 out_var->op = type;
1805 out_var->value = value; 1805 out_var->value = value;
1806 } 1806 }
1807} 1807}
1808 1808
1809/* Parse a variable assignment, consisting of a single-word variable name, 1809/* Parse a variable assignment, consisting of a single-word variable name,
1810 * optional whitespace, an assignment operator, optional whitespace and the 1810 * optional whitespace, an assignment operator, optional whitespace and the
1811 * variable value. 1811 * variable value.
1812 * 1812 *
1813 * Used for both lines in a file and command line arguments. */ 1813 * Used for both lines in a file and command line arguments. */
1814Boolean 1814Boolean
1815Parse_IsVar(const char *p, VarAssign *out_var) 1815Parse_IsVar(const char *p, VarAssign *out_var)
1816{ 1816{
1817 VarAssignParsed pvar; 1817 VarAssignParsed pvar;
1818 const char *firstSpace = NULL; 1818 const char *firstSpace = NULL;
1819 char ch; 1819 char ch;
1820 int level = 0; 1820 int level = 0;
1821 1821
1822 /* Skip to variable name */ 1822 /* Skip to variable name */
1823 while (*p == ' ' || *p == '\t') 1823 while (*p == ' ' || *p == '\t')
1824 p++; 1824 p++;
1825 1825
1826 /* During parsing, the '+' of the '+=' operator is initially parsed 1826 /* During parsing, the '+' of the '+=' operator is initially parsed
1827 * as part of the variable name. It is later corrected, as is the ':sh' 1827 * as part of the variable name. It is later corrected, as is the ':sh'
1828 * modifier. Of these two (nameEnd and op), the earlier one determines the 1828 * modifier. Of these two (nameEnd and op), the earlier one determines the
1829 * actual end of the variable name. */ 1829 * actual end of the variable name. */
1830 pvar.nameStart = p; 1830 pvar.nameStart = p;
1831#ifdef CLEANUP 1831#ifdef CLEANUP
1832 pvar.nameEnd = NULL; 1832 pvar.nameEnd = NULL;
1833 pvar.eq = NULL; 1833 pvar.eq = NULL;
1834#endif 1834#endif
1835 1835
1836 /* Scan for one of the assignment operators outside a variable expansion */ 1836 /* Scan for one of the assignment operators outside a variable expansion */
1837 while ((ch = *p++) != 0) { 1837 while ((ch = *p++) != 0) {
1838 if (ch == '(' || ch == '{') { 1838 if (ch == '(' || ch == '{') {
1839 level++; 1839 level++;
1840 continue; 1840 continue;
1841 } 1841 }
1842 if (ch == ')' || ch == '}') { 1842 if (ch == ')' || ch == '}') {
1843 level--; 1843 level--;
1844 continue; 1844 continue;
1845 } 1845 }
1846 1846
1847 if (level != 0) 1847 if (level != 0)
1848 continue; 1848 continue;
1849 1849
1850 if (ch == ' ' || ch == '\t') 1850 if (ch == ' ' || ch == '\t')
1851 if (firstSpace == NULL) 1851 if (firstSpace == NULL)
1852 firstSpace = p - 1; 1852 firstSpace = p - 1;
1853 while (ch == ' ' || ch == '\t') 1853 while (ch == ' ' || ch == '\t')
1854 ch = *p++; 1854 ch = *p++;
1855 1855
1856#ifdef SUNSHCMD 1856#ifdef SUNSHCMD
1857 if (ch == ':' && strncmp(p, "sh", 2) == 0) { 1857 if (ch == ':' && strncmp(p, "sh", 2) == 0) {
1858 p += 2; 1858 p += 2;
1859 continue; 1859 continue;
1860 } 1860 }
1861#endif 1861#endif
1862 if (ch == '=') { 1862 if (ch == '=') {
1863 pvar.eq = p - 1; 1863 pvar.eq = p - 1;
1864 pvar.nameEnd = firstSpace != NULL ? firstSpace : p - 1; 1864 pvar.nameEnd = firstSpace != NULL ? firstSpace : p - 1;
1865 cpp_skip_whitespace(&p); 1865 cpp_skip_whitespace(&p);
1866 AdjustVarassignOp(&pvar, p, out_var); 1866 AdjustVarassignOp(&pvar, p, out_var);
1867 return TRUE; 1867 return TRUE;
1868 } 1868 }
1869 if (*p == '=' && (ch == '+' || ch == ':' || ch == '?' || ch == '!')) { 1869 if (*p == '=' && (ch == '+' || ch == ':' || ch == '?' || ch == '!')) {
1870 pvar.eq = p; 1870 pvar.eq = p;
1871 pvar.nameEnd = firstSpace != NULL ? firstSpace : p; 1871 pvar.nameEnd = firstSpace != NULL ? firstSpace : p;
1872 p++; 1872 p++;
1873 cpp_skip_whitespace(&p); 1873 cpp_skip_whitespace(&p);
1874 AdjustVarassignOp(&pvar, p, out_var); 1874 AdjustVarassignOp(&pvar, p, out_var);
1875 return TRUE; 1875 return TRUE;
1876 } 1876 }
1877 if (firstSpace != NULL) 1877 if (firstSpace != NULL)
1878 return FALSE; 1878 return FALSE;
1879 } 1879 }
1880 1880
1881 return FALSE; 1881 return FALSE;
1882} 1882}
1883 1883
1884static void 1884static void
1885VarCheckSyntax(VarAssignOp type, const char *uvalue, GNode *ctxt) 1885VarCheckSyntax(VarAssignOp type, const char *uvalue, GNode *ctxt)
1886{ 1886{
1887 if (DEBUG(LINT)) { 1887 if (DEBUG(LINT)) {
1888 if (type != VAR_SUBST && strchr(uvalue, '$') != NULL) { 1888 if (type != VAR_SUBST && strchr(uvalue, '$') != NULL) {
1889 /* Check for syntax errors such as unclosed expressions or 1889 /* Check for syntax errors such as unclosed expressions or
1890 * unknown modifiers. */ 1890 * unknown modifiers. */
1891 char *expandedValue; 1891 char *expandedValue;
1892 1892
1893 (void)Var_Subst(uvalue, ctxt, VARE_NONE, &expandedValue); 1893 (void)Var_Subst(uvalue, ctxt, VARE_NONE, &expandedValue);
1894 /* TODO: handle errors */ 1894 /* TODO: handle errors */
1895 free(expandedValue); 1895 free(expandedValue);
1896 } 1896 }
1897 } 1897 }
1898} 1898}
1899 1899
1900static void 1900static void
1901VarAssign_EvalSubst(const char *name, const char *uvalue, GNode *ctxt, 1901VarAssign_EvalSubst(const char *name, const char *uvalue, GNode *ctxt,
1902 const char **out_avalue, void **out_avalue_freeIt) 1902 const char **out_avalue, void **out_avalue_freeIt)
1903{ 1903{
1904 const char *avalue = uvalue; 1904 const char *avalue = uvalue;
1905 char *evalue; 1905 char *evalue;
1906 /* 1906 /*
1907 * Allow variables in the old value to be undefined, but leave their 1907 * Allow variables in the old value to be undefined, but leave their
1908 * expressions alone -- this is done by forcing oldVars to be false. 1908 * expressions alone -- this is done by forcing oldVars to be false.
1909 * XXX: This can cause recursive variables, but that's not hard to do, 1909 * XXX: This can cause recursive variables, but that's not hard to do,
1910 * and this allows someone to do something like 1910 * and this allows someone to do something like
1911 * 1911 *
1912 * CFLAGS = $(.INCLUDES) 1912 * CFLAGS = $(.INCLUDES)
1913 * CFLAGS := -I.. $(CFLAGS) 1913 * CFLAGS := -I.. $(CFLAGS)
1914 * 1914 *
1915 * And not get an error. 1915 * And not get an error.
1916 */ 1916 */
1917 Boolean oldOldVars = oldVars; 1917 Boolean oldOldVars = oldVars;
1918 1918
1919 oldVars = FALSE; 1919 oldVars = FALSE;
1920 1920
1921 /* 1921 /*
1922 * make sure that we set the variable the first time to nothing 1922 * make sure that we set the variable the first time to nothing
1923 * so that it gets substituted! 1923 * so that it gets substituted!
1924 */ 1924 */
1925 if (!Var_Exists(name, ctxt)) 1925 if (!Var_Exists(name, ctxt))
1926 Var_Set(name, "", ctxt); 1926 Var_Set(name, "", ctxt);
1927 1927
1928 (void)Var_Subst(uvalue, ctxt, VARE_WANTRES|VARE_ASSIGN, &evalue); 1928 (void)Var_Subst(uvalue, ctxt, VARE_WANTRES|VARE_ASSIGN, &evalue);
1929 /* TODO: handle errors */ 1929 /* TODO: handle errors */
1930 oldVars = oldOldVars; 1930 oldVars = oldOldVars;
1931 avalue = evalue; 1931 avalue = evalue;
1932 Var_Set(name, avalue, ctxt); 1932 Var_Set(name, avalue, ctxt);
1933 1933
1934 *out_avalue = avalue; 1934 *out_avalue = avalue;
1935 *out_avalue_freeIt = evalue; 1935 *out_avalue_freeIt = evalue;
1936} 1936}
1937 1937
1938static void 1938static void
1939VarAssign_EvalShell(const char *name, const char *uvalue, GNode *ctxt, 1939VarAssign_EvalShell(const char *name, const char *uvalue, GNode *ctxt,
1940 const char **out_avalue, void **out_avalue_freeIt) 1940 const char **out_avalue, void **out_avalue_freeIt)
1941{ 1941{
1942 const char *cmd, *errfmt; 1942 const char *cmd, *errfmt;
1943 char *cmdOut; 1943 char *cmdOut;
1944 void *cmd_freeIt = NULL; 1944 void *cmd_freeIt = NULL;
1945 1945
1946 cmd = uvalue; 1946 cmd = uvalue;
1947 if (strchr(cmd, '$') != NULL) { 1947 if (strchr(cmd, '$') != NULL) {
1948 char *ecmd; 1948 char *ecmd;
1949 (void)Var_Subst(cmd, VAR_CMD, VARE_UNDEFERR|VARE_WANTRES, &ecmd); 1949 (void)Var_Subst(cmd, VAR_CMD, VARE_UNDEFERR|VARE_WANTRES, &ecmd);
1950 /* TODO: handle errors */ 1950 /* TODO: handle errors */
1951 cmd = cmd_freeIt = ecmd; 1951 cmd = cmd_freeIt = ecmd;
1952 } 1952 }
1953 1953
1954 cmdOut = Cmd_Exec(cmd, &errfmt); 1954 cmdOut = Cmd_Exec(cmd, &errfmt);
1955 Var_Set(name, cmdOut, ctxt); 1955 Var_Set(name, cmdOut, ctxt);
1956 *out_avalue = *out_avalue_freeIt = cmdOut; 1956 *out_avalue = *out_avalue_freeIt = cmdOut;
1957 1957
1958 if (errfmt) 1958 if (errfmt)
1959 Parse_Error(PARSE_WARNING, errfmt, cmd); 1959 Parse_Error(PARSE_WARNING, errfmt, cmd);
1960 1960
1961 free(cmd_freeIt); 1961 free(cmd_freeIt);
1962} 1962}
1963 1963
1964/* Perform a variable assignment. 1964/* Perform a variable assignment.
1965 * 1965 *
1966 * The actual value of the variable is returned in *out_avalue and 1966 * The actual value of the variable is returned in *out_avalue and
1967 * *out_avalue_freeIt. Especially for VAR_SUBST and VAR_SHELL this can differ 1967 * *out_avalue_freeIt. Especially for VAR_SUBST and VAR_SHELL this can differ
1968 * from the literal value. 1968 * from the literal value.
1969 * 1969 *
1970 * Return whether the assignment was actually done. The assignment is only 1970 * Return whether the assignment was actually done. The assignment is only
1971 * skipped if the operator is '?=' and the variable already exists. */ 1971 * skipped if the operator is '?=' and the variable already exists. */
1972static Boolean 1972static Boolean
1973VarAssign_Eval(const char *name, VarAssignOp op, const char *uvalue, 1973VarAssign_Eval(const char *name, VarAssignOp op, const char *uvalue,
1974 GNode *ctxt, const char **out_avalue, void **out_avalue_freeIt) 1974 GNode *ctxt, const char **out_avalue, void **out_avalue_freeIt)
1975{ 1975{
1976 const char *avalue = uvalue; 1976 const char *avalue = uvalue;
1977 void *avalue_freeIt = NULL; 1977 void *avalue_freeIt = NULL;
1978 1978
1979 if (op == VAR_APPEND) { 1979 if (op == VAR_APPEND) {
1980 Var_Append(name, uvalue, ctxt); 1980 Var_Append(name, uvalue, ctxt);
1981 } else if (op == VAR_SUBST) { 1981 } else if (op == VAR_SUBST) {
1982 VarAssign_EvalSubst(name, uvalue, ctxt, &avalue, &avalue_freeIt); 1982 VarAssign_EvalSubst(name, uvalue, ctxt, &avalue, &avalue_freeIt);
1983 } else if (op == VAR_SHELL) { 1983 } else if (op == VAR_SHELL) {
1984 VarAssign_EvalShell(name, uvalue, ctxt, &avalue, &avalue_freeIt); 1984 VarAssign_EvalShell(name, uvalue, ctxt, &avalue, &avalue_freeIt);
1985 } else { 1985 } else {
1986 if (op == VAR_DEFAULT && Var_Exists(name, ctxt)) { 1986 if (op == VAR_DEFAULT && Var_Exists(name, ctxt)) {
1987 *out_avalue_freeIt = NULL; 1987 *out_avalue_freeIt = NULL;
1988 return FALSE; 1988 return FALSE;
1989 } 1989 }
1990 1990
1991 /* Normal assignment -- just do it. */ 1991 /* Normal assignment -- just do it. */
1992 Var_Set(name, uvalue, ctxt); 1992 Var_Set(name, uvalue, ctxt);
1993 } 1993 }
1994 1994
1995 *out_avalue = avalue; 1995 *out_avalue = avalue;
1996 *out_avalue_freeIt = avalue_freeIt; 1996 *out_avalue_freeIt = avalue_freeIt;
1997 return TRUE; 1997 return TRUE;
1998} 1998}
1999 1999
2000static void 2000static void
2001VarAssignSpecial(const char *name, const char *avalue) 2001VarAssignSpecial(const char *name, const char *avalue)
2002{ 2002{
2003 if (strcmp(name, MAKEOVERRIDES) == 0) 2003 if (strcmp(name, MAKEOVERRIDES) == 0)
2004 Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */ 2004 Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */
2005 else if (strcmp(name, ".CURDIR") == 0) { 2005 else if (strcmp(name, ".CURDIR") == 0) {
2006 /* 2006 /*
2007 * Someone is being (too?) clever... 2007 * Someone is being (too?) clever...
2008 * Let's pretend they know what they are doing and 2008 * Let's pretend they know what they are doing and
2009 * re-initialize the 'cur' CachedDir. 2009 * re-initialize the 'cur' CachedDir.
2010 */ 2010 */
2011 Dir_InitCur(avalue); 2011 Dir_InitCur(avalue);
2012 Dir_SetPATH(); 2012 Dir_SetPATH();
2013 } else if (strcmp(name, MAKE_JOB_PREFIX) == 0) { 2013 } else if (strcmp(name, MAKE_JOB_PREFIX) == 0) {
2014 Job_SetPrefix(); 2014 Job_SetPrefix();
2015 } else if (strcmp(name, MAKE_EXPORTED) == 0) { 2015 } else if (strcmp(name, MAKE_EXPORTED) == 0) {
2016 Var_Export(avalue, FALSE); 2016 Var_Export(avalue, FALSE);
2017 } 2017 }
2018} 2018}
2019 2019
2020/* Take the variable assignment in the passed line and execute it. 2020/* Take the variable assignment in the passed line and execute it.
2021 * 2021 *
2022 * Note: There is a lexical ambiguity with assignment modifier characters 2022 * Note: There is a lexical ambiguity with assignment modifier characters
2023 * in variable names. This routine interprets the character before the = 2023 * in variable names. This routine interprets the character before the =
2024 * as a modifier. Therefore, an assignment like 2024 * as a modifier. Therefore, an assignment like
2025 * C++=/usr/bin/CC 2025 * C++=/usr/bin/CC
2026 * is interpreted as "C+ +=" instead of "C++ =". 2026 * is interpreted as "C+ +=" instead of "C++ =".
2027 * 2027 *
2028 * Input: 2028 * Input:
2029 * p A line guaranteed to be a variable assignment 2029 * p A line guaranteed to be a variable assignment
2030 * (see Parse_IsVar). 2030 * (see Parse_IsVar).
2031 * ctxt Context in which to do the assignment 2031 * ctxt Context in which to do the assignment
2032 */ 2032 */
2033void 2033void
2034Parse_DoVar(VarAssign *var, GNode *ctxt) 2034Parse_DoVar(VarAssign *var, GNode *ctxt)
2035{ 2035{
2036 const char *avalue; /* actual value (maybe expanded) */ 2036 const char *avalue; /* actual value (maybe expanded) */
2037 void *avalue_freeIt; 2037 void *avalue_freeIt;
2038 2038
2039 VarCheckSyntax(var->op, var->value, ctxt); 2039 VarCheckSyntax(var->op, var->value, ctxt);
2040 if (VarAssign_Eval(var->varname, var->op, var->value, ctxt, 2040 if (VarAssign_Eval(var->varname, var->op, var->value, ctxt,
2041 &avalue, &avalue_freeIt)) 2041 &avalue, &avalue_freeIt))
2042 VarAssignSpecial(var->varname, avalue); 2042 VarAssignSpecial(var->varname, avalue);
2043 2043
2044 free(avalue_freeIt); 2044 free(avalue_freeIt);
2045 free(var->varname); 2045 free(var->varname);
2046} 2046}
2047 2047
2048 2048
2049/* 2049/*
2050 * ParseMaybeSubMake -- 2050 * ParseMaybeSubMake --
2051 * Scan the command string to see if it a possible submake node 2051 * Scan the command string to see if it a possible submake node
2052 * Input: 2052 * Input:
2053 * cmd the command to scan 2053 * cmd the command to scan
2054 * Results: 2054 * Results:
2055 * TRUE if the command is possibly a submake, FALSE if not. 2055 * TRUE if the command is possibly a submake, FALSE if not.
2056 */ 2056 */
2057static Boolean 2057static Boolean
2058ParseMaybeSubMake(const char *cmd) 2058ParseMaybeSubMake(const char *cmd)
2059{ 2059{
2060 size_t i; 2060 size_t i;
2061 static struct { 2061 static struct {
2062 const char *name; 2062 const char *name;
2063 size_t len; 2063 size_t len;
2064 } vals[] = { 2064 } vals[] = {
2065#define MKV(A) { A, sizeof(A) - 1 } 2065#define MKV(A) { A, sizeof(A) - 1 }
2066 MKV("${MAKE}"), 2066 MKV("${MAKE}"),
2067 MKV("${.MAKE}"), 2067 MKV("${.MAKE}"),
2068 MKV("$(MAKE)"), 2068 MKV("$(MAKE)"),
2069 MKV("$(.MAKE)"), 2069 MKV("$(.MAKE)"),
2070 MKV("make"), 2070 MKV("make"),
2071 }; 2071 };
2072 for (i = 0; i < sizeof vals / sizeof vals[0]; i++) { 2072 for (i = 0; i < sizeof vals / sizeof vals[0]; i++) {
2073 char *ptr; 2073 char *ptr;
2074 if ((ptr = strstr(cmd, vals[i].name)) == NULL) 2074 if ((ptr = strstr(cmd, vals[i].name)) == NULL)
2075 continue; 2075 continue;
2076 if ((ptr == cmd || !ch_isalnum(ptr[-1])) 2076 if ((ptr == cmd || !ch_isalnum(ptr[-1]))
2077 && !ch_isalnum(ptr[vals[i].len])) 2077 && !ch_isalnum(ptr[vals[i].len]))
2078 return TRUE; 2078 return TRUE;
2079 } 2079 }
2080 return FALSE; 2080 return FALSE;
2081} 2081}
2082 2082
2083/* Append the command to the target node. 2083/* Append the command to the target node.
2084 * 2084 *
2085 * The node may be marked as a submake node if the command is determined to 2085 * The node may be marked as a submake node if the command is determined to
2086 * be that. */ 2086 * be that. */
2087static void 2087static void
2088ParseAddCmd(GNode *gn, char *cmd) 2088ParseAddCmd(GNode *gn, char *cmd)
2089{ 2089{
2090 /* Add to last (ie current) cohort for :: targets */ 2090 /* Add to last (ie current) cohort for :: targets */
2091 if ((gn->type & OP_DOUBLEDEP) && gn->cohorts->last != NULL) 2091 if ((gn->type & OP_DOUBLEDEP) && gn->cohorts->last != NULL)
2092 gn = gn->cohorts->last->datum; 2092 gn = gn->cohorts->last->datum;
2093 2093
2094 /* if target already supplied, ignore commands */ 2094 /* if target already supplied, ignore commands */
2095 if (!(gn->type & OP_HAS_COMMANDS)) { 2095 if (!(gn->type & OP_HAS_COMMANDS)) {
2096 Lst_Append(gn->commands, cmd); 2096 Lst_Append(gn->commands, cmd);
2097 if (ParseMaybeSubMake(cmd)) 2097 if (ParseMaybeSubMake(cmd))
2098 gn->type |= OP_SUBMAKE; 2098 gn->type |= OP_SUBMAKE;
2099 ParseMark(gn); 2099 ParseMark(gn);
2100 } else { 2100 } else {
2101#if 0 2101#if 0
2102 /* XXX: We cannot do this until we fix the tree */ 2102 /* XXX: We cannot do this until we fix the tree */
2103 Lst_Append(gn->commands, cmd); 2103 Lst_Append(gn->commands, cmd);
2104 Parse_Error(PARSE_WARNING, 2104 Parse_Error(PARSE_WARNING,
2105 "overriding commands for target \"%s\"; " 2105 "overriding commands for target \"%s\"; "
2106 "previous commands defined at %s: %d ignored", 2106 "previous commands defined at %s: %d ignored",
2107 gn->name, gn->fname, gn->lineno); 2107 gn->name, gn->fname, gn->lineno);
2108#else 2108#else
2109 Parse_Error(PARSE_WARNING, 2109 Parse_Error(PARSE_WARNING,
2110 "duplicate script for target \"%s\" ignored", 2110 "duplicate script for target \"%s\" ignored",
2111 gn->name); 2111 gn->name);
2112 ParseErrorInternal(gn->fname, (size_t)gn->lineno, PARSE_WARNING, 2112 ParseErrorInternal(gn->fname, (size_t)gn->lineno, PARSE_WARNING,
2113 "using previous script for \"%s\" defined here", 2113 "using previous script for \"%s\" defined here",
2114 gn->name); 2114 gn->name);
2115#endif 2115#endif
2116 } 2116 }
2117} 2117}
2118 2118
2119/* Add a directory to the path searched for included makefiles bracketed 2119/* Add a directory to the path searched for included makefiles bracketed
2120 * by double-quotes. */ 2120 * by double-quotes. */
2121void 2121void
2122Parse_AddIncludeDir(const char *dir) 2122Parse_AddIncludeDir(const char *dir)
2123{ 2123{
2124 (void)Dir_AddDir(parseIncPath, dir); 2124 (void)Dir_AddDir(parseIncPath, dir);
2125} 2125}
2126 2126
2127/* Push to another file. 2127/* Push to another file.
2128 * 2128 *
2129 * The input is the line minus the '.'. A file spec is a string enclosed in 2129 * The input is the line minus the '.'. A file spec is a string enclosed in
2130 * <> or "". The <> file is looked for only in sysIncPath. The "" file is 2130 * <> or "". The <> file is looked for only in sysIncPath. The "" file is
2131 * first searched in the parsedir and then in the directories specified by 2131 * first searched in the parsedir and then in the directories specified by
2132 * the -I command line options. 2132 * the -I command line options.
2133 */ 2133 */
2134static void 2134static void
2135Parse_include_file(char *file, Boolean isSystem, Boolean depinc, int silent) 2135Parse_include_file(char *file, Boolean isSystem, Boolean depinc, int silent)
2136{ 2136{
2137 struct loadedfile *lf; 2137 struct loadedfile *lf;
2138 char *fullname; /* full pathname of file */ 2138 char *fullname; /* full pathname of file */
2139 char *newName; 2139 char *newName;
2140 char *prefEnd, *incdir; 2140 char *prefEnd, *incdir;
2141 int fd; 2141 int fd;
2142 int i; 2142 int i;
2143 2143
2144 /* 2144 /*
2145 * Now we know the file's name and its search path, we attempt to 2145 * Now we know the file's name and its search path, we attempt to
2146 * find the durn thing. A return of NULL indicates the file don't 2146 * find the durn thing. A return of NULL indicates the file don't
2147 * exist. 2147 * exist.
2148 */ 2148 */
2149 fullname = file[0] == '/' ? bmake_strdup(file) : NULL; 2149 fullname = file[0] == '/' ? bmake_strdup(file) : NULL;
2150 2150
2151 if (fullname == NULL && !isSystem) { 2151 if (fullname == NULL && !isSystem) {
2152 /* 2152 /*
2153 * Include files contained in double-quotes are first searched for 2153 * Include files contained in double-quotes are first searched for
2154 * relative to the including file's location. We don't want to 2154 * relative to the including file's location. We don't want to
2155 * cd there, of course, so we just tack on the old file's 2155 * cd there, of course, so we just tack on the old file's
2156 * leading path components and call Dir_FindFile to see if 2156 * leading path components and call Dir_FindFile to see if
2157 * we can locate the beast. 2157 * we can locate the beast.
2158 */ 2158 */
2159 2159
2160 incdir = bmake_strdup(CurFile()->fname); 2160 incdir = bmake_strdup(CurFile()->fname);
2161 prefEnd = strrchr(incdir, '/'); 2161 prefEnd = strrchr(incdir, '/');
2162 if (prefEnd != NULL) { 2162 if (prefEnd != NULL) {
2163 *prefEnd = '\0'; 2163 *prefEnd = '\0';
2164 /* Now do lexical processing of leading "../" on the filename */ 2164 /* Now do lexical processing of leading "../" on the filename */
2165 for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) { 2165 for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) {
2166 prefEnd = strrchr(incdir + 1, '/'); 2166 prefEnd = strrchr(incdir + 1, '/');
2167 if (prefEnd == NULL || strcmp(prefEnd, "/..") == 0) 2167 if (prefEnd == NULL || strcmp(prefEnd, "/..") == 0)
2168 break; 2168 break;
2169 *prefEnd = '\0'; 2169 *prefEnd = '\0';
2170 } 2170 }
2171 newName = str_concat3(incdir, "/", file + i); 2171 newName = str_concat3(incdir, "/", file + i);
2172 fullname = Dir_FindFile(newName, parseIncPath); 2172 fullname = Dir_FindFile(newName, parseIncPath);
2173 if (fullname == NULL) 2173 if (fullname == NULL)
2174 fullname = Dir_FindFile(newName, dirSearchPath); 2174 fullname = Dir_FindFile(newName, dirSearchPath);
2175 free(newName); 2175 free(newName);
2176 } 2176 }
2177 free(incdir); 2177 free(incdir);
2178 2178
2179 if (fullname == NULL) { 2179 if (fullname == NULL) {
2180 /* 2180 /*
2181 * Makefile wasn't found in same directory as included makefile. 2181 * Makefile wasn't found in same directory as included makefile.
2182 * Search for it first on the -I search path, 2182 * Search for it first on the -I search path,
2183 * then on the .PATH search path, if not found in a -I directory. 2183 * then on the .PATH search path, if not found in a -I directory.
2184 * If we have a suffix specific path we should use that. 2184 * If we have a suffix specific path we should use that.
2185 */ 2185 */
2186 char *suff; 2186 char *suff;
2187 SearchPath *suffPath = NULL; 2187 SearchPath *suffPath = NULL;
2188 2188
2189 if ((suff = strrchr(file, '.'))) { 2189 if ((suff = strrchr(file, '.'))) {
2190 suffPath = Suff_GetPath(suff); 2190 suffPath = Suff_GetPath(suff);
2191 if (suffPath != NULL) { 2191 if (suffPath != NULL) {
2192 fullname = Dir_FindFile(file, suffPath); 2192 fullname = Dir_FindFile(file, suffPath);
2193 } 2193 }
2194 } 2194 }
2195 if (fullname == NULL) { 2195 if (fullname == NULL) {
2196 fullname = Dir_FindFile(file, parseIncPath); 2196 fullname = Dir_FindFile(file, parseIncPath);
2197 if (fullname == NULL) { 2197 if (fullname == NULL) {
2198 fullname = Dir_FindFile(file, dirSearchPath); 2198 fullname = Dir_FindFile(file, dirSearchPath);
2199 } 2199 }
2200 } 2200 }
2201 } 2201 }
2202 } 2202 }
2203 2203
2204 /* Looking for a system file or file still not found */ 2204 /* Looking for a system file or file still not found */
2205 if (fullname == NULL) { 2205 if (fullname == NULL) {
2206 /* 2206 /*
2207 * Look for it on the system path 2207 * Look for it on the system path
2208 */ 2208 */
2209 SearchPath *path = Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath; 2209 SearchPath *path = Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath;
2210 fullname = Dir_FindFile(file, path); 2210 fullname = Dir_FindFile(file, path);
2211 } 2211 }
2212 2212
2213 if (fullname == NULL) { 2213 if (fullname == NULL) {
2214 if (!silent) 2214 if (!silent)
2215 Parse_Error(PARSE_FATAL, "Could not find %s", file); 2215 Parse_Error(PARSE_FATAL, "Could not find %s", file);
2216 return; 2216 return;
2217 } 2217 }
2218 2218
2219 /* Actually open the file... */ 2219 /* Actually open the file... */
2220 fd = open(fullname, O_RDONLY); 2220 fd = open(fullname, O_RDONLY);
2221 if (fd == -1) { 2221 if (fd == -1) {
2222 if (!silent) 2222 if (!silent)
2223 Parse_Error(PARSE_FATAL, "Cannot open %s", fullname); 2223 Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
2224 free(fullname); 2224 free(fullname);
2225 return; 2225 return;
2226 } 2226 }
2227 2227
2228 /* load it */ 2228 /* load it */
2229 lf = loadfile(fullname, fd); 2229 lf = loadfile(fullname, fd);
2230 2230
2231 /* Start reading from this file next */ 2231 /* Start reading from this file next */
2232 Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf); 2232 Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf);
2233 CurFile()->lf = lf; 2233 CurFile()->lf = lf;
2234 if (depinc) 2234 if (depinc)
2235 doing_depend = depinc; /* only turn it on */ 2235 doing_depend = depinc; /* only turn it on */
2236} 2236}
2237 2237
2238static void 2238static void
2239ParseDoInclude(char *line) 2239ParseDoInclude(char *line)
2240{ 2240{
2241 char endc; /* the character which ends the file spec */ 2241 char endc; /* the character which ends the file spec */
2242 char *cp; /* current position in file spec */ 2242 char *cp; /* current position in file spec */
2243 int silent = *line != 'i'; 2243 int silent = *line != 'i';
2244 char *file = line + (silent ? 8 : 7); 2244 char *file = line + (silent ? 8 : 7);
2245 2245
2246 /* Skip to delimiter character so we know where to look */ 2246 /* Skip to delimiter character so we know where to look */
2247 while (*file == ' ' || *file == '\t') 2247 while (*file == ' ' || *file == '\t')
2248 file++; 2248 file++;
2249 2249
2250 if (*file != '"' && *file != '<') { 2250 if (*file != '"' && *file != '<') {
2251 Parse_Error(PARSE_FATAL, 2251 Parse_Error(PARSE_FATAL,
2252 ".include filename must be delimited by '\"' or '<'"); 2252 ".include filename must be delimited by '\"' or '<'");
2253 return; 2253 return;
2254 } 2254 }
2255 2255
2256 /* 2256 /*
2257 * Set the search path on which to find the include file based on the 2257 * Set the search path on which to find the include file based on the
2258 * characters which bracket its name. Angle-brackets imply it's 2258 * characters which bracket its name. Angle-brackets imply it's
2259 * a system Makefile while double-quotes imply it's a user makefile 2259 * a system Makefile while double-quotes imply it's a user makefile
2260 */ 2260 */
2261 if (*file == '<') { 2261 if (*file == '<') {
2262 endc = '>'; 2262 endc = '>';
2263 } else { 2263 } else {
2264 endc = '"'; 2264 endc = '"';
2265 } 2265 }
2266 2266
2267 /* Skip to matching delimiter */ 2267 /* Skip to matching delimiter */
2268 for (cp = ++file; *cp && *cp != endc; cp++) 2268 for (cp = ++file; *cp && *cp != endc; cp++)
2269 continue; 2269 continue;
2270 2270
2271 if (*cp != endc) { 2271 if (*cp != endc) {
2272 Parse_Error(PARSE_FATAL, 2272 Parse_Error(PARSE_FATAL,
2273 "Unclosed %cinclude filename. '%c' expected", 2273 "Unclosed %cinclude filename. '%c' expected",
2274 '.', endc); 2274 '.', endc);
2275 return; 2275 return;
2276 } 2276 }
2277 *cp = '\0'; 2277 *cp = '\0';
2278 2278
2279 /* 2279 /*
2280 * Substitute for any variables in the file name before trying to 2280 * Substitute for any variables in the file name before trying to
2281 * find the thing. 2281 * find the thing.
2282 */ 2282 */
2283 (void)Var_Subst(file, VAR_CMD, VARE_WANTRES, &file); 2283 (void)Var_Subst(file, VAR_CMD, VARE_WANTRES, &file);
2284 /* TODO: handle errors */ 2284 /* TODO: handle errors */
2285 2285
2286 Parse_include_file(file, endc == '>', *line == 'd', silent); 2286 Parse_include_file(file, endc == '>', *line == 'd', silent);
2287 free(file); 2287 free(file);
2288} 2288}
2289 2289
2290/* Split filename into dirname + basename, then assign these to the 2290/* Split filename into dirname + basename, then assign these to the
2291 * given variables. */ 2291 * given variables. */
2292static void 2292static void
2293SetFilenameVars(const char *filename, const char *dirvar, const char *filevar) 2293SetFilenameVars(const char *filename, const char *dirvar, const char *filevar)
2294{ 2294{
2295 const char *slash, *dirname, *basename; 2295 const char *slash, *dirname, *basename;
2296 void *freeIt; 2296 void *freeIt;
2297 2297
2298 slash = strrchr(filename, '/'); 2298 slash = strrchr(filename, '/');
2299 if (slash == NULL) { 2299 if (slash == NULL) {
2300 dirname = curdir; 2300 dirname = curdir;
2301 basename = filename; 2301 basename = filename;
2302 freeIt = NULL; 2302 freeIt = NULL;
2303 } else { 2303 } else {
2304 dirname = freeIt = bmake_strsedup(filename, slash); 2304 dirname = freeIt = bmake_strsedup(filename, slash);
2305 basename = slash + 1; 2305 basename = slash + 1;
2306 } 2306 }
2307 2307
2308 Var_Set(dirvar, dirname, VAR_GLOBAL); 2308 Var_Set(dirvar, dirname, VAR_GLOBAL);
2309 Var_Set(filevar, basename, VAR_GLOBAL); 2309 Var_Set(filevar, basename, VAR_GLOBAL);
2310 2310
2311 DEBUG5(PARSE, "%s: ${%s} = `%s' ${%s} = `%s'\n", 2311 DEBUG5(PARSE, "%s: ${%s} = `%s' ${%s} = `%s'\n",
2312 __func__, dirvar, dirname, filevar, basename); 2312 __func__, dirvar, dirname, filevar, basename);
2313 free(freeIt); 2313 free(freeIt);
2314} 2314}
2315 2315
2316/* Return the immediately including file. 2316/* Return the immediately including file.
2317 * 2317 *
2318 * This is made complicated since the .for loop is implemented as a special 2318 * This is made complicated since the .for loop is implemented as a special
2319 * kind of .include; see For_Run. */ 2319 * kind of .include; see For_Run. */
2320static const char * 2320static const char *
2321GetActuallyIncludingFile(void) 2321GetActuallyIncludingFile(void)
2322{ 2322{
2323 size_t i; 2323 size_t i;
2324 const IFile *incs = GetInclude(0); 2324 const IFile *incs = GetInclude(0);
2325 2325
2326 for (i = includes.len; i >= 2; i--) 2326 for (i = includes.len; i >= 2; i--)
2327 if (!incs[i - 1].fromForLoop) 2327 if (!incs[i - 1].fromForLoop)
2328 return incs[i - 2].fname; 2328 return incs[i - 2].fname;
2329 return NULL; 2329 return NULL;
2330} 2330}
2331 2331
2332/* Set .PARSEDIR, .PARSEFILE, .INCLUDEDFROMDIR and .INCLUDEDFROMFILE. */ 2332/* Set .PARSEDIR, .PARSEFILE, .INCLUDEDFROMDIR and .INCLUDEDFROMFILE. */
2333static void 2333static void
2334ParseSetParseFile(const char *filename) 2334ParseSetParseFile(const char *filename)
2335{ 2335{
2336 const char *including; 2336 const char *including;
2337 2337
2338 SetFilenameVars(filename, ".PARSEDIR", ".PARSEFILE"); 2338 SetFilenameVars(filename, ".PARSEDIR", ".PARSEFILE");
2339 2339
2340 including = GetActuallyIncludingFile(); 2340 including = GetActuallyIncludingFile();
2341 if (including != NULL) { 2341 if (including != NULL) {
2342 SetFilenameVars(including, 2342 SetFilenameVars(including,
2343 ".INCLUDEDFROMDIR", ".INCLUDEDFROMFILE"); 2343 ".INCLUDEDFROMDIR", ".INCLUDEDFROMFILE");
2344 } else { 2344 } else {
2345 Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL); 2345 Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL);
2346 Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL); 2346 Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL);
2347 } 2347 }
2348} 2348}
2349 2349
2350/* Track the makefiles we read - so makefiles can set dependencies on them. 2350/* Track the makefiles we read - so makefiles can set dependencies on them.
2351 * Avoid adding anything more than once. */ 2351 * Avoid adding anything more than once. */
2352static void 2352static void
2353ParseTrackInput(const char *name) 2353ParseTrackInput(const char *name)
2354{ 2354{
2355 char *fp = NULL; 2355 char *fp = NULL;
2356 2356
2357 const char *old = Var_Value(MAKE_MAKEFILES, VAR_GLOBAL, &fp); 2357 const char *old = Var_Value(MAKE_MAKEFILES, VAR_GLOBAL, &fp);
2358 if (old) { 2358 if (old) {
2359 size_t name_len = strlen(name); 2359 size_t name_len = strlen(name);
2360 const char *ep = old + strlen(old) - name_len; 2360 const char *ep = old + strlen(old) - name_len;
2361 /* does it contain name? */ 2361 /* does it contain name? */
2362 for (; old != NULL; old = strchr(old, ' ')) { 2362 for (; old != NULL; old = strchr(old, ' ')) {
2363 if (*old == ' ') 2363 if (*old == ' ')
2364 old++; 2364 old++;
2365 if (old >= ep) 2365 if (old >= ep)
2366 break; /* cannot contain name */ 2366 break; /* cannot contain name */
2367 if (memcmp(old, name, name_len) == 0 && 2367 if (memcmp(old, name, name_len) == 0 &&
2368 (old[name_len] == '\0' || old[name_len] == ' ')) 2368 (old[name_len] == '\0' || old[name_len] == ' '))
2369 goto cleanup; 2369 goto cleanup;
2370 } 2370 }
2371 } 2371 }
2372 Var_Append(MAKE_MAKEFILES, name, VAR_GLOBAL); 2372 Var_Append(MAKE_MAKEFILES, name, VAR_GLOBAL);
2373cleanup: 2373cleanup:
2374 bmake_free(fp); 2374 bmake_free(fp);
2375} 2375}
2376 2376
2377 2377
2378/* Start Parsing from the given source. 2378/* Start Parsing from the given source.
2379 * 2379 *
2380 * The given file is added to the includes stack. */ 2380 * The given file is added to the includes stack. */
2381void 2381void
2382Parse_SetInput(const char *name, int line, int fd, 2382Parse_SetInput(const char *name, int line, int fd,
2383 char *(*nextbuf)(void *, size_t *), void *arg) 2383 char *(*nextbuf)(void *, size_t *), void *arg)
2384{ 2384{
2385 IFile *curFile; 2385 IFile *curFile;
2386 char *buf; 2386 char *buf;
2387 size_t len; 2387 size_t len;
2388 Boolean fromForLoop = name == NULL; 2388 Boolean fromForLoop = name == NULL;
2389 2389
2390 if (fromForLoop) 2390 if (fromForLoop)
2391 name = CurFile()->fname; 2391 name = CurFile()->fname;
2392 else 2392 else
2393 ParseTrackInput(name); 2393 ParseTrackInput(name);
2394 2394
2395 if (DEBUG(PARSE)) 2395 if (DEBUG(PARSE))
2396 debug_printf("%s: file %s, line %d, fd %d, nextbuf %s, arg %p\n", 2396 debug_printf("%s: file %s, line %d, fd %d, nextbuf %s, arg %p\n",
2397 __func__, name, line, fd, 2397 __func__, name, line, fd,
2398 nextbuf == loadedfile_nextbuf ? "loadedfile" : "other", 2398 nextbuf == loadedfile_nextbuf ? "loadedfile" : "other",
2399 arg); 2399 arg);
2400 2400
2401 if (fd == -1 && nextbuf == NULL) 2401 if (fd == -1 && nextbuf == NULL)
2402 /* sanity */ 2402 /* sanity */
2403 return; 2403 return;
2404 2404
2405 curFile = Vector_Push(&includes); 2405 curFile = Vector_Push(&includes);
2406 2406
2407 /* 2407 /*
2408 * Once the previous state has been saved, we can get down to reading 2408 * Once the previous state has been saved, we can get down to reading
2409 * the new file. We set up the name of the file to be the absolute 2409 * the new file. We set up the name of the file to be the absolute
2410 * name of the include file so error messages refer to the right 2410 * name of the include file so error messages refer to the right
2411 * place. 2411 * place.
2412 */ 2412 */
2413 curFile->fname = bmake_strdup(name); 2413 curFile->fname = bmake_strdup(name);
2414 curFile->fromForLoop = fromForLoop; 2414 curFile->fromForLoop = fromForLoop;
2415 curFile->lineno = line; 2415 curFile->lineno = line;
2416 curFile->first_lineno = line; 2416 curFile->first_lineno = line;
2417 curFile->nextbuf = nextbuf; 2417 curFile->nextbuf = nextbuf;
2418 curFile->nextbuf_arg = arg; 2418 curFile->nextbuf_arg = arg;
2419 curFile->lf = NULL; 2419 curFile->lf = NULL;
2420 curFile->depending = doing_depend; /* restore this on EOF */ 2420 curFile->depending = doing_depend; /* restore this on EOF */
2421 2421
2422 assert(nextbuf != NULL); 2422 assert(nextbuf != NULL);
2423 2423
2424 /* Get first block of input data */ 2424 /* Get first block of input data */
2425 buf = curFile->nextbuf(curFile->nextbuf_arg, &len); 2425 buf = curFile->nextbuf(curFile->nextbuf_arg, &len);
2426 if (buf == NULL) { 2426 if (buf == NULL) {
2427 /* Was all a waste of time ... */ 2427 /* Was all a waste of time ... */
2428 if (curFile->fname) 2428 if (curFile->fname)
2429 free(curFile->fname); 2429 free(curFile->fname);
2430 free(curFile); 2430 free(curFile);
2431 return; 2431 return;
2432 } 2432 }
2433 curFile->buf_freeIt = buf; 2433 curFile->buf_freeIt = buf;
2434 curFile->buf_ptr = buf; 2434 curFile->buf_ptr = buf;
2435 curFile->buf_end = buf + len; 2435 curFile->buf_end = buf + len;
2436 2436
2437 curFile->cond_depth = Cond_save_depth(); 2437 curFile->cond_depth = Cond_save_depth();
2438 ParseSetParseFile(name); 2438 ParseSetParseFile(name);
2439} 2439}
2440 2440
2441/* Check if the directive is an include directive. */ 2441/* Check if the directive is an include directive. */
2442static Boolean 2442static Boolean
2443IsInclude(const char *dir, Boolean sysv) 2443IsInclude(const char *dir, Boolean sysv)
2444{ 2444{
2445 if (dir[0] == 's' || dir[0] == '-' || (dir[0] == 'd' && !sysv)) 2445 if (dir[0] == 's' || dir[0] == '-' || (dir[0] == 'd' && !sysv))
2446 dir++; 2446 dir++;
2447 2447
2448 if (strncmp(dir, "include", 7) != 0) 2448 if (strncmp(dir, "include", 7) != 0)
2449 return FALSE; 2449 return FALSE;
2450 2450
2451 /* Space is not mandatory for BSD .include */ 2451 /* Space is not mandatory for BSD .include */
2452 return !sysv || ch_isspace(dir[7]); 2452 return !sysv || ch_isspace(dir[7]);
2453} 2453}
2454 2454
2455 2455
2456#ifdef SYSVINCLUDE 2456#ifdef SYSVINCLUDE
2457/* Check if the line is a SYSV include directive. */ 2457/* Check if the line is a SYSV include directive. */
2458static Boolean 2458static Boolean
2459IsSysVInclude(const char *line) 2459IsSysVInclude(const char *line)
2460{ 2460{
2461 const char *p; 2461 const char *p;
2462 2462
2463 if (!IsInclude(line, TRUE)) 2463 if (!IsInclude(line, TRUE))
2464 return FALSE; 2464 return FALSE;
2465 2465
2466 /* Avoid interpreting a dependency line as an include */ 2466 /* Avoid interpreting a dependency line as an include */
2467 for (p = line; (p = strchr(p, ':')) != NULL;) { 2467 for (p = line; (p = strchr(p, ':')) != NULL;) {
2468 if (*++p == '\0') { 2468 if (*++p == '\0') {
2469 /* end of line -> dependency */ 2469 /* end of line -> dependency */
2470 return FALSE; 2470 return FALSE;
2471 } 2471 }
2472 if (*p == ':' || ch_isspace(*p)) { 2472 if (*p == ':' || ch_isspace(*p)) {
2473 /* :: operator or ': ' -> dependency */ 2473 /* :: operator or ': ' -> dependency */
2474 return FALSE; 2474 return FALSE;
2475 } 2475 }
2476 } 2476 }
2477 return TRUE; 2477 return TRUE;
2478} 2478}
2479 2479
2480/* Push to another file. The line points to the word "include". */ 2480/* Push to another file. The line points to the word "include". */
2481static void 2481static void
2482ParseTraditionalInclude(char *line) 2482ParseTraditionalInclude(char *line)
2483{ 2483{
2484 char *cp; /* current position in file spec */ 2484 char *cp; /* current position in file spec */
2485 int done = 0; 2485 int done = 0;
2486 int silent = line[0] != 'i'; 2486 int silent = line[0] != 'i';
2487 char *file = line + (silent ? 8 : 7); 2487 char *file = line + (silent ? 8 : 7);
2488 char *all_files; 2488 char *all_files;
2489 2489
2490 DEBUG2(PARSE, "%s: %s\n", __func__, file); 2490 DEBUG2(PARSE, "%s: %s\n", __func__, file);
2491 2491
2492 pp_skip_whitespace(&file); 2492 pp_skip_whitespace(&file);
2493 2493
2494 /* 2494 /*
2495 * Substitute for any variables in the file name before trying to 2495 * Substitute for any variables in the file name before trying to
2496 * find the thing. 2496 * find the thing.
2497 */ 2497 */
2498 (void)Var_Subst(file, VAR_CMD, VARE_WANTRES, &all_files); 2498 (void)Var_Subst(file, VAR_CMD, VARE_WANTRES, &all_files);
2499 /* TODO: handle errors */ 2499 /* TODO: handle errors */
2500 2500
2501 if (*file == '\0') { 2501 if (*file == '\0') {
2502 Parse_Error(PARSE_FATAL, "Filename missing from \"include\""); 2502 Parse_Error(PARSE_FATAL, "Filename missing from \"include\"");
2503 goto out; 2503 goto out;
2504 } 2504 }
2505 2505
2506 for (file = all_files; !done; file = cp + 1) { 2506 for (file = all_files; !done; file = cp + 1) {
2507 /* Skip to end of line or next whitespace */ 2507 /* Skip to end of line or next whitespace */
2508 for (cp = file; *cp && !ch_isspace(*cp); cp++) 2508 for (cp = file; *cp && !ch_isspace(*cp); cp++)
2509 continue; 2509 continue;
2510 2510
2511 if (*cp) 2511 if (*cp)
2512 *cp = '\0'; 2512 *cp = '\0';
2513 else 2513 else
2514 done = 1; 2514 done = 1;
2515 2515
2516 Parse_include_file(file, FALSE, FALSE, silent); 2516 Parse_include_file(file, FALSE, FALSE, silent);
2517 } 2517 }
2518out: 2518out:
2519 free(all_files); 2519 free(all_files);
2520} 2520}
2521#endif 2521#endif
2522 2522
2523#ifdef GMAKEEXPORT 2523#ifdef GMAKEEXPORT
2524/* Parse "export <variable>=<value>", and actually export it. */ 2524/* Parse "export <variable>=<value>", and actually export it. */
2525static void 2525static void
2526ParseGmakeExport(char *line) 2526ParseGmakeExport(char *line)
2527{ 2527{
2528 char *variable = line + 6; 2528 char *variable = line + 6;
2529 char *value; 2529 char *value;
2530 2530
2531 DEBUG2(PARSE, "%s: %s\n", __func__, variable); 2531 DEBUG2(PARSE, "%s: %s\n", __func__, variable);
2532 2532
2533 pp_skip_whitespace(&variable); 2533 pp_skip_whitespace(&variable);
2534 2534
2535 for (value = variable; *value && *value != '='; value++) 2535 for (value = variable; *value && *value != '='; value++)
2536 continue; 2536 continue;
2537 2537
2538 if (*value != '=') { 2538 if (*value != '=') {
2539 Parse_Error(PARSE_FATAL, 2539 Parse_Error(PARSE_FATAL,
2540 "Variable/Value missing from \"export\""); 2540 "Variable/Value missing from \"export\"");
2541 return; 2541 return;
2542 } 2542 }
2543 *value++ = '\0'; /* terminate variable */ 2543 *value++ = '\0'; /* terminate variable */
2544 2544
2545 /* 2545 /*
2546 * Expand the value before putting it in the environment. 2546 * Expand the value before putting it in the environment.
2547 */ 2547 */
2548 (void)Var_Subst(value, VAR_CMD, VARE_WANTRES, &value); 2548 (void)Var_Subst(value, VAR_CMD, VARE_WANTRES, &value);
2549 /* TODO: handle errors */ 2549 /* TODO: handle errors */
2550 2550
2551 setenv(variable, value, 1); 2551 setenv(variable, value, 1);
2552 free(value); 2552 free(value);
2553} 2553}
2554#endif 2554#endif
2555 2555
2556/* Called when EOF is reached in the current file. If we were reading an 2556/* Called when EOF is reached in the current file. If we were reading an
2557 * include file, the includes stack is popped and things set up to go back 2557 * include file, the includes stack is popped and things set up to go back
2558 * to reading the previous file at the previous location. 2558 * to reading the previous file at the previous location.
2559 * 2559 *
2560 * Results: 2560 * Results:
2561 * TRUE to continue parsing, i.e. it had only reached the end of an 2561 * TRUE to continue parsing, i.e. it had only reached the end of an
2562 * included file, FALSE if the main file has been parsed completely. 2562 * included file, FALSE if the main file has been parsed completely.
2563 */ 2563 */
2564static Boolean 2564static Boolean
2565ParseEOF(void) 2565ParseEOF(void)
2566{ 2566{
2567 char *ptr; 2567 char *ptr;
2568 size_t len; 2568 size_t len;
2569 IFile *curFile = CurFile(); 2569 IFile *curFile = CurFile();
2570 2570
2571 assert(curFile->nextbuf != NULL); 2571 assert(curFile->nextbuf != NULL);
2572 2572
2573 doing_depend = curFile->depending; /* restore this */ 2573 doing_depend = curFile->depending; /* restore this */
2574 /* get next input buffer, if any */ 2574 /* get next input buffer, if any */
2575 ptr = curFile->nextbuf(curFile->nextbuf_arg, &len); 2575 ptr = curFile->nextbuf(curFile->nextbuf_arg, &len);
2576 curFile->buf_ptr = ptr; 2576 curFile->buf_ptr = ptr;
2577 curFile->buf_freeIt = ptr; 2577 curFile->buf_freeIt = ptr;
2578 curFile->buf_end = ptr + len; 2578 curFile->buf_end = ptr + len;
2579 curFile->lineno = curFile->first_lineno; 2579 curFile->lineno = curFile->first_lineno;
2580 if (ptr != NULL) { 2580 if (ptr != NULL) {
2581 /* Iterate again */ 2581 /* Iterate again */
2582 return TRUE; 2582 return TRUE;
2583 } 2583 }
2584 2584
2585 /* Ensure the makefile (or loop) didn't have mismatched conditionals */ 2585 /* Ensure the makefile (or loop) didn't have mismatched conditionals */
2586 Cond_restore_depth(curFile->cond_depth); 2586 Cond_restore_depth(curFile->cond_depth);
2587 2587
2588 if (curFile->lf != NULL) { 2588 if (curFile->lf != NULL) {
2589 loadedfile_destroy(curFile->lf); 2589 loadedfile_destroy(curFile->lf);
2590 curFile->lf = NULL; 2590 curFile->lf = NULL;
2591 } 2591 }
2592 2592
2593 /* Dispose of curFile info */ 2593 /* Dispose of curFile info */
2594 /* Leak curFile->fname because all the gnodes have pointers to it */ 2594 /* Leak curFile->fname because all the gnodes have pointers to it */
2595 free(curFile->buf_freeIt); 2595 free(curFile->buf_freeIt);
2596 Vector_Pop(&includes); 2596 Vector_Pop(&includes);
2597 2597
2598 if (includes.len == 0) { 2598 if (includes.len == 0) {
2599 /* We've run out of input */ 2599 /* We've run out of input */
2600 Var_Delete(".PARSEDIR", VAR_GLOBAL); 2600 Var_Delete(".PARSEDIR", VAR_GLOBAL);
2601 Var_Delete(".PARSEFILE", VAR_GLOBAL); 2601 Var_Delete(".PARSEFILE", VAR_GLOBAL);
2602 Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL); 2602 Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL);
2603 Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL); 2603 Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL);
2604 return FALSE; 2604 return FALSE;
2605 } 2605 }
2606 2606
2607 curFile = CurFile(); 2607 curFile = CurFile();
2608 DEBUG2(PARSE, "ParseEOF: returning to file %s, line %d\n", 2608 DEBUG2(PARSE, "ParseEOF: returning to file %s, line %d\n",
2609 curFile->fname, curFile->lineno); 2609 curFile->fname, curFile->lineno);
2610 2610
2611 ParseSetParseFile(curFile->fname); 2611 ParseSetParseFile(curFile->fname);
2612 return TRUE; 2612 return TRUE;
2613} 2613}
2614 2614
2615#define PARSE_RAW 1 2615#define PARSE_RAW 1
2616#define PARSE_SKIP 2 2616#define PARSE_SKIP 2
2617 2617
2618static char * 2618static char *
2619ParseGetLine(int flags) 2619ParseGetLine(int flags)
2620{ 2620{
2621 IFile *cf = CurFile(); 2621 IFile *cf = CurFile();
2622 char *ptr; 2622 char *ptr;
2623 char ch; 2623 char ch;
2624 char *line; 2624 char *line;
2625 char *line_end; 2625 char *line_end;
2626 char *escaped; 2626 char *escaped;
2627 char *comment; 2627 char *comment;
2628 char *tp; 2628 char *tp;
2629 2629
2630 /* Loop through blank lines and comment lines */ 2630 /* Loop through blank lines and comment lines */
2631 for (;;) { 2631 for (;;) {
2632 cf->lineno++; 2632 cf->lineno++;
2633 line = cf->buf_ptr; 2633 line = cf->buf_ptr;
2634 ptr = line; 2634 ptr = line;
2635 line_end = line; 2635 line_end = line;
2636 escaped = NULL; 2636 escaped = NULL;
2637 comment = NULL; 2637 comment = NULL;
2638 for (;;) { 2638 for (;;) {
2639 /* XXX: can buf_end ever be null? */ 2639 /* XXX: can buf_end ever be null? */
2640 if (cf->buf_end != NULL && ptr == cf->buf_end) { 2640 if (cf->buf_end != NULL && ptr == cf->buf_end) {
2641 /* end of buffer */ 2641 /* end of buffer */
2642 ch = 0; 2642 ch = 0;
2643 break; 2643 break;
2644 } 2644 }
2645 ch = *ptr; 2645 ch = *ptr;
2646 if (ch == 0 || (ch == '\\' && ptr[1] == 0)) { 2646 if (ch == 0 || (ch == '\\' && ptr[1] == 0)) {
2647 /* XXX: can buf_end ever be null? */ 2647 /* XXX: can buf_end ever be null? */
2648 if (cf->buf_end == NULL) 2648 if (cf->buf_end == NULL)
2649 /* End of string (aka for loop) data */ 2649 /* End of string (aka for loop) data */
2650 break; 2650 break;
2651 /* see if there is more we can parse */ 2651 /* see if there is more we can parse */
2652 while (ptr++ < cf->buf_end) { 2652 while (ptr++ < cf->buf_end) {
2653 if ((ch = *ptr) == '\n') { 2653 if ((ch = *ptr) == '\n') {
2654 if (ptr > line && ptr[-1] == '\\') 2654 if (ptr > line && ptr[-1] == '\\')
2655 continue; 2655 continue;
2656 Parse_Error(PARSE_WARNING, 2656 Parse_Error(PARSE_WARNING,
2657 "Zero byte read from file, " 2657 "Zero byte read from file, "
2658 "skipping rest of line."); 2658 "skipping rest of line.");
2659 break; 2659 break;
2660 } 2660 }
2661 } 2661 }
2662 if (cf->nextbuf != NULL) { 2662 if (cf->nextbuf != NULL) {
2663 /* 2663 /*
2664 * End of this buffer; return EOF and outer logic 2664 * End of this buffer; return EOF and outer logic
2665 * will get the next one. (eww) 2665 * will get the next one. (eww)
2666 */ 2666 */
2667 break; 2667 break;
2668 } 2668 }
2669 Parse_Error(PARSE_FATAL, "Zero byte read from file"); 2669 Parse_Error(PARSE_FATAL, "Zero byte read from file");
2670 return NULL; 2670 return NULL;
2671 } 2671 }
2672 2672
2673 if (ch == '\\') { 2673 if (ch == '\\') {
2674 /* Don't treat next character as special, remember first one */ 2674 /* Don't treat next character as special, remember first one */
2675 if (escaped == NULL) 2675 if (escaped == NULL)
2676 escaped = ptr; 2676 escaped = ptr;
2677 if (ptr[1] == '\n') 2677 if (ptr[1] == '\n')
2678 cf->lineno++; 2678 cf->lineno++;
2679 ptr += 2; 2679 ptr += 2;
2680 line_end = ptr; 2680 line_end = ptr;
2681 continue; 2681 continue;
2682 } 2682 }
2683 if (ch == '#' && comment == NULL) { 2683 if (ch == '#' && comment == NULL) {
2684 /* Remember first '#' for comment stripping */ 2684 /* Remember first '#' for comment stripping */
2685 /* Unless previous char was '[', as in modifier :[#] */ 2685 /* Unless previous char was '[', as in modifier :[#] */
2686 if (!(ptr > line && ptr[-1] == '[')) 2686 if (!(ptr > line && ptr[-1] == '['))
2687 comment = line_end; 2687 comment = line_end;
2688 } 2688 }
2689 ptr++; 2689 ptr++;
2690 if (ch == '\n') 2690 if (ch == '\n')
2691 break; 2691 break;
2692 if (!ch_isspace(ch)) 2692 if (!ch_isspace(ch))
2693 /* We are not interested in trailing whitespace */ 2693 /* We are not interested in trailing whitespace */
2694 line_end = ptr; 2694 line_end = ptr;
2695 } 2695 }
2696 2696
2697 /* Save next 'to be processed' location */ 2697 /* Save next 'to be processed' location */
2698 cf->buf_ptr = ptr; 2698 cf->buf_ptr = ptr;
2699 2699
2700 /* Check we have a non-comment, non-blank line */ 2700 /* Check we have a non-comment, non-blank line */
2701 if (line_end == line || comment == line) { 2701 if (line_end == line || comment == line) {
2702 if (ch == 0) 2702 if (ch == 0)
2703 /* At end of file */ 2703 /* At end of file */
2704 return NULL; 2704 return NULL;
2705 /* Parse another line */ 2705 /* Parse another line */
2706 continue; 2706 continue;
2707 } 2707 }
2708 2708
2709 /* We now have a line of data */ 2709 /* We now have a line of data */
2710 *line_end = 0; 2710 *line_end = 0;
2711 2711
2712 if (flags & PARSE_RAW) { 2712 if (flags & PARSE_RAW) {
2713 /* Leave '\' (etc) in line buffer (eg 'for' lines) */ 2713 /* Leave '\' (etc) in line buffer (eg 'for' lines) */
2714 return line; 2714 return line;
2715 } 2715 }
2716 2716
2717 if (flags & PARSE_SKIP) { 2717 if (flags & PARSE_SKIP) {
2718 /* Completely ignore non-directives */ 2718 /* Completely ignore non-directives */
2719 if (line[0] != '.') 2719 if (line[0] != '.')
2720 continue; 2720 continue;
2721 /* We could do more of the .else/.elif/.endif checks here */ 2721 /* We could do more of the .else/.elif/.endif checks here */
2722 } 2722 }
2723 break; 2723 break;
2724 } 2724 }
2725 2725
2726 /* Brutally ignore anything after a non-escaped '#' in non-commands */ 2726 /* Brutally ignore anything after a non-escaped '#' in non-commands */
2727 if (comment != NULL && line[0] != '\t') { 2727 if (comment != NULL && line[0] != '\t') {
2728 line_end = comment; 2728 line_end = comment;
2729 *line_end = 0; 2729 *line_end = 0;
2730 } 2730 }
2731 2731
2732 /* If we didn't see a '\\' then the in-situ data is fine */ 2732 /* If we didn't see a '\\' then the in-situ data is fine */
2733 if (escaped == NULL) 2733 if (escaped == NULL)
2734 return line; 2734 return line;
2735 2735
2736 /* Remove escapes from '\n' and '#' */ 2736 /* Remove escapes from '\n' and '#' */
2737 tp = ptr = escaped; 2737 tp = ptr = escaped;
2738 escaped = line; 2738 escaped = line;
2739 for (; ; *tp++ = ch) { 2739 for (; ; *tp++ = ch) {
2740 ch = *ptr++; 2740 ch = *ptr++;
2741 if (ch != '\\') { 2741 if (ch != '\\') {
2742 if (ch == 0) 2742 if (ch == 0)
2743 break; 2743 break;
2744 continue; 2744 continue;
2745 } 2745 }
2746 2746
2747 ch = *ptr++; 2747 ch = *ptr++;
2748 if (ch == 0) { 2748 if (ch == 0) {
2749 /* Delete '\\' at end of buffer */ 2749 /* Delete '\\' at end of buffer */
2750 tp--; 2750 tp--;
2751 break; 2751 break;
2752 } 2752 }
2753 2753
2754 if (ch == '#' && line[0] != '\t') 2754 if (ch == '#' && line[0] != '\t')
2755 /* Delete '\\' from before '#' on non-command lines */ 2755 /* Delete '\\' from before '#' on non-command lines */
2756 continue; 2756 continue;
2757 2757
2758 if (ch != '\n') { 2758 if (ch != '\n') {
2759 /* Leave '\\' in buffer for later */ 2759 /* Leave '\\' in buffer for later */
2760 *tp++ = '\\'; 2760 *tp++ = '\\';
2761 /* Make sure we don't delete an escaped ' ' from the line end */ 2761 /* Make sure we don't delete an escaped ' ' from the line end */
2762 escaped = tp + 1; 2762 escaped = tp + 1;
2763 continue; 2763 continue;
2764 } 2764 }
2765 2765
2766 /* Escaped '\n' replace following whitespace with a single ' ' */ 2766 /* Escaped '\n' replace following whitespace with a single ' ' */
2767 while (ptr[0] == ' ' || ptr[0] == '\t') 2767 while (ptr[0] == ' ' || ptr[0] == '\t')
2768 ptr++; 2768 ptr++;
2769 ch = ' '; 2769 ch = ' ';
2770 } 2770 }
2771 2771
2772 /* Delete any trailing spaces - eg from empty continuations */ 2772 /* Delete any trailing spaces - eg from empty continuations */
2773 while (tp > escaped && ch_isspace(tp[-1])) 2773 while (tp > escaped && ch_isspace(tp[-1]))
2774 tp--; 2774 tp--;
2775 2775
2776 *tp = 0; 2776 *tp = 0;
2777 return line; 2777 return line;
2778} 2778}
2779 2779
2780/* Read an entire line from the input file. Called only by Parse_File. 2780/* Read an entire line from the input file. Called only by Parse_File.
2781 * 2781 *
2782 * Results: 2782 * Results:
2783 * A line without its newline. 2783 * A line without its newline.
2784 * 2784 *
2785 * Side Effects: 2785 * Side Effects:
2786 * Only those associated with reading a character 2786 * Only those associated with reading a character
2787 */ 2787 */
2788static char * 2788static char *
2789ParseReadLine(void) 2789ParseReadLine(void)
2790{ 2790{
2791 char *line; /* Result */ 2791 char *line; /* Result */
2792 int lineno; /* Saved line # */ 2792 int lineno; /* Saved line # */
2793 int rval; 2793 int rval;
2794 2794
2795 for (;;) { 2795 for (;;) {
2796 line = ParseGetLine(0); 2796 line = ParseGetLine(0);
2797 if (line == NULL) 2797 if (line == NULL)
2798 return NULL; 2798 return NULL;
2799 2799
2800 if (line[0] != '.') 2800 if (line[0] != '.')
2801 return line; 2801 return line;
2802 2802
2803 /* 2803 /*
2804 * The line might be a conditional. Ask the conditional module 2804 * The line might be a conditional. Ask the conditional module
2805 * about it and act accordingly 2805 * about it and act accordingly
2806 */ 2806 */
2807 switch (Cond_EvalLine(line)) { 2807 switch (Cond_EvalLine(line)) {
2808 case COND_SKIP: 2808 case COND_SKIP:
2809 /* Skip to next conditional that evaluates to COND_PARSE. */ 2809 /* Skip to next conditional that evaluates to COND_PARSE. */
2810 do { 2810 do {
2811 line = ParseGetLine(PARSE_SKIP); 2811 line = ParseGetLine(PARSE_SKIP);
2812 } while (line && Cond_EvalLine(line) != COND_PARSE); 2812 } while (line && Cond_EvalLine(line) != COND_PARSE);
2813 if (line == NULL) 2813 if (line == NULL)
2814 break; 2814 break;
2815 continue; 2815 continue;
2816 case COND_PARSE: 2816 case COND_PARSE:
2817 continue; 2817 continue;
2818 case COND_INVALID: /* Not a conditional line */ 2818 case COND_INVALID: /* Not a conditional line */
2819 /* Check for .for loops */ 2819 /* Check for .for loops */
2820 rval = For_Eval(line); 2820 rval = For_Eval(line);
2821 if (rval == 0) 2821 if (rval == 0)
2822 /* Not a .for line */ 2822 /* Not a .for line */
2823 break; 2823 break;
2824 if (rval < 0) 2824 if (rval < 0)
2825 /* Syntax error - error printed, ignore line */ 2825 /* Syntax error - error printed, ignore line */
2826 continue; 2826 continue;
2827 /* Start of a .for loop */ 2827 /* Start of a .for loop */
2828 lineno = CurFile()->lineno; 2828 lineno = CurFile()->lineno;
2829 /* Accumulate loop lines until matching .endfor */ 2829 /* Accumulate loop lines until matching .endfor */
2830 do { 2830 do {
2831 line = ParseGetLine(PARSE_RAW); 2831 line = ParseGetLine(PARSE_RAW);
2832 if (line == NULL) { 2832 if (line == NULL) {
2833 Parse_Error(PARSE_FATAL, 2833 Parse_Error(PARSE_FATAL,
2834 "Unexpected end of file in for loop."); 2834 "Unexpected end of file in for loop.");
2835 break; 2835 break;
2836 } 2836 }
2837 } while (For_Accum(line)); 2837 } while (For_Accum(line));
2838 /* Stash each iteration as a new 'input file' */ 2838 /* Stash each iteration as a new 'input file' */
2839 For_Run(lineno); 2839 For_Run(lineno);
2840 /* Read next line from for-loop buffer */ 2840 /* Read next line from for-loop buffer */
2841 continue; 2841 continue;
2842 } 2842 }
2843 return line; 2843 return line;
2844 } 2844 }
2845} 2845}
2846 2846
2847static void 2847static void
2848FinishDependencyGroup(void) 2848FinishDependencyGroup(void)
2849{ 2849{
2850 if (targets != NULL) { 2850 if (targets != NULL) {
2851 GNodeListNode *ln; 2851 GNodeListNode *ln;
2852 for (ln = targets->first; ln != NULL; ln = ln->next) { 2852 for (ln = targets->first; ln != NULL; ln = ln->next) {
2853 GNode *gn = ln->datum; 2853 GNode *gn = ln->datum;
2854 2854
2855 Suff_EndTransform(gn); 2855 Suff_EndTransform(gn);
2856 2856
2857 /* Mark the target as already having commands if it does, to 2857 /* Mark the target as already having commands if it does, to
2858 * keep from having shell commands on multiple dependency lines. */ 2858 * keep from having shell commands on multiple dependency lines. */
2859 if (!Lst_IsEmpty(gn->commands)) 2859 if (!Lst_IsEmpty(gn->commands))
2860 gn->type |= OP_HAS_COMMANDS; 2860 gn->type |= OP_HAS_COMMANDS;
2861 } 2861 }
2862 2862
2863 Lst_Free(targets); 2863 Lst_Free(targets);
2864 targets = NULL; 2864 targets = NULL;
2865 } 2865 }
2866} 2866}
2867 2867
2868/* Add the command to each target from the current dependency spec. */ 2868/* Add the command to each target from the current dependency spec. */
2869static void 2869static void
2870ParseLine_ShellCommand(const char *p) 2870ParseLine_ShellCommand(const char *p)
2871{ 2871{
2872 cpp_skip_whitespace(&p); 2872 cpp_skip_whitespace(&p);
2873 if (*p == '\0') 2873 if (*p == '\0')
2874 return; /* skip empty commands */ 2874 return; /* skip empty commands */
2875 2875
2876 if (targets == NULL) { 2876 if (targets == NULL) {
2877 Parse_Error(PARSE_FATAL, "Unassociated shell command \"%s\"", p); 2877 Parse_Error(PARSE_FATAL, "Unassociated shell command \"%s\"", p);
2878 return; 2878 return;
2879 } 2879 }
2880 2880
2881 { 2881 {
2882 char *cmd = bmake_strdup(p); 2882 char *cmd = bmake_strdup(p);
2883 GNodeListNode *ln; 2883 GNodeListNode *ln;
2884 2884
2885 for (ln = targets->first; ln != NULL; ln = ln->next) { 2885 for (ln = targets->first; ln != NULL; ln = ln->next) {
2886 GNode *gn = ln->datum; 2886 GNode *gn = ln->datum;
2887 ParseAddCmd(gn, cmd); 2887 ParseAddCmd(gn, cmd);
2888 } 2888 }
2889#ifdef CLEANUP 2889#ifdef CLEANUP
2890 Lst_Append(targCmds, cmd); 2890 Lst_Append(targCmds, cmd);
2891#endif 2891#endif
2892 } 2892 }
2893} 2893}
2894 2894
2895static Boolean 2895static Boolean
2896ParseDirective(char *line) 2896ParseDirective(char *line)
2897{ 2897{
2898 char *cp; 2898 char *cp;
2899 2899
2900 if (*line == '.') { 2900 if (*line == '.') {
2901 /* 2901 /*
2902 * Lines that begin with the special character may be 2902 * Lines that begin with the special character may be
2903 * include or undef directives. 2903 * include or undef directives.
2904 * On the other hand they can be suffix rules (.c.o: ...) 2904 * On the other hand they can be suffix rules (.c.o: ...)
2905 * or just dependencies for filenames that start '.'. 2905 * or just dependencies for filenames that start '.'.
2906 */ 2906 */
2907 cp = line + 1; 2907 cp = line + 1;
2908 pp_skip_whitespace(&cp); 2908 pp_skip_whitespace(&cp);
2909 if (IsInclude(cp, FALSE)) { 2909 if (IsInclude(cp, FALSE)) {
2910 ParseDoInclude(cp); 2910 ParseDoInclude(cp);
2911 return TRUE; 2911 return TRUE;
2912 } 2912 }
2913 if (strncmp(cp, "undef", 5) == 0) { 2913 if (strncmp(cp, "undef", 5) == 0) {
2914 const char *varname; 2914 const char *varname;
2915 cp += 5; 2915 cp += 5;
2916 pp_skip_whitespace(&cp); 2916 pp_skip_whitespace(&cp);
2917 varname = cp; 2917 varname = cp;
2918 for (; !ch_isspace(*cp) && *cp != '\0'; cp++) 2918 for (; !ch_isspace(*cp) && *cp != '\0'; cp++)
2919 continue; 2919 continue;
2920 *cp = '\0'; 2920 *cp = '\0';
2921 Var_Delete(varname, VAR_GLOBAL); 2921 Var_Delete(varname, VAR_GLOBAL);
2922 /* TODO: undefine all variables, not only the first */ 2922 /* TODO: undefine all variables, not only the first */
2923 /* TODO: use Str_Words, like everywhere else */ 2923 /* TODO: use Str_Words, like everywhere else */
2924 return TRUE; 2924 return TRUE;
2925 } else if (strncmp(cp, "export", 6) == 0) { 2925 } else if (strncmp(cp, "export", 6) == 0) {
2926 cp += 6; 2926 cp += 6;
2927 pp_skip_whitespace(&cp); 2927 pp_skip_whitespace(&cp);
2928 Var_Export(cp, TRUE); 2928 Var_Export(cp, TRUE);
2929 return TRUE; 2929 return TRUE;
2930 } else if (strncmp(cp, "unexport", 8) == 0) { 2930 } else if (strncmp(cp, "unexport", 8) == 0) {
2931 Var_UnExport(cp); 2931 Var_UnExport(cp);
2932 return TRUE; 2932 return TRUE;
2933 } else if (strncmp(cp, "info", 4) == 0 || 2933 } else if (strncmp(cp, "info", 4) == 0 ||
2934 strncmp(cp, "error", 5) == 0 || 2934 strncmp(cp, "error", 5) == 0 ||
2935 strncmp(cp, "warning", 7) == 0) { 2935 strncmp(cp, "warning", 7) == 0) {
2936 if (ParseMessage(cp)) 2936 if (ParseMessage(cp))
2937 return TRUE; 2937 return TRUE;
2938 } 2938 }
2939 } 2939 }
2940 return FALSE; 2940 return FALSE;
2941} 2941}
2942 2942
2943static Boolean 2943static Boolean
2944ParseVarassign(const char *line) 2944ParseVarassign(const char *line)
2945{ 2945{
2946 VarAssign var; 2946 VarAssign var;
2947 if (Parse_IsVar(line, &var)) { 2947 if (Parse_IsVar(line, &var)) {
2948 FinishDependencyGroup(); 2948 FinishDependencyGroup();
2949 Parse_DoVar(&var, VAR_GLOBAL); 2949 Parse_DoVar(&var, VAR_GLOBAL);
2950 return TRUE; 2950 return TRUE;
2951 } 2951 }
2952 return FALSE; 2952 return FALSE;
2953} 2953}
2954 2954
2955static char * 2955static char *
2956FindSemicolon(char *p) 2956FindSemicolon(char *p)
2957{ 2957{
2958 int level = 0; 2958 int level = 0;
2959 2959
2960 for (; *p != '\0'; p++) { 2960 for (; *p != '\0'; p++) {
2961 if (*p == '\\' && p[1] != '\0') { 2961 if (*p == '\\' && p[1] != '\0') {
2962 p++; 2962 p++;
2963 continue; 2963 continue;
2964 } 2964 }
2965 2965
2966 if (*p == '$' && (p[1] == '(' || p[1] == '{')) { 2966 if (*p == '$' && (p[1] == '(' || p[1] == '{')) {
2967 level++; 2967 level++;
2968 continue; 2968 continue;
2969 } 2969 }
2970 2970
2971 if (level > 0 && (*p == ')' || *p == '}')) { 2971 if (level > 0 && (*p == ')' || *p == '}')) {
2972 level--; 2972 level--;
2973 continue; 2973 continue;
2974 } 2974 }
2975 2975
2976 if (level == 0 && *p == ';') { 2976 if (level == 0 && *p == ';') {
2977 break; 2977 break;
2978 } 2978 }
2979 } 2979 }
2980 return p; 2980 return p;
2981} 2981}
2982 2982
2983/* dependency -> target... op [source...] 2983/* dependency -> target... op [source...]
2984 * op -> ':' | '::' | '!' */ 2984 * op -> ':' | '::' | '!' */
2985static void 2985static void
2986ParseDependency(char *line) 2986ParseDependency(char *line)
2987{ 2987{
2988 VarEvalFlags eflags; 2988 VarEvalFlags eflags;
2989 char *expanded_line; 2989 char *expanded_line;
2990 const char *shellcmd = NULL; 2990 const char *shellcmd = NULL;
2991 2991
2992 /* 2992 /*
2993 * For some reason - probably to make the parser impossible - 2993 * For some reason - probably to make the parser impossible -
2994 * a ';' can be used to separate commands from dependencies. 2994 * a ';' can be used to separate commands from dependencies.
2995 * Attempt to avoid ';' inside substitution patterns. 2995 * Attempt to avoid ';' inside substitution patterns.
2996 */ 2996 */
2997 { 2997 {
2998 char *semicolon = FindSemicolon(line); 2998 char *semicolon = FindSemicolon(line);
2999 if (*semicolon != '\0') { 2999 if (*semicolon != '\0') {
3000 /* Terminate the dependency list at the ';' */ 3000 /* Terminate the dependency list at the ';' */
3001 *semicolon = '\0'; 3001 *semicolon = '\0';
3002 shellcmd = semicolon + 1; 3002 shellcmd = semicolon + 1;
3003 } 3003 }
3004 } 3004 }
3005 3005
3006 /* 3006 /*
3007 * We now know it's a dependency line so it needs to have all 3007 * We now know it's a dependency line so it needs to have all
3008 * variables expanded before being parsed. 3008 * variables expanded before being parsed.
3009 * 3009 *
3010 * XXX: Ideally the dependency line would first be split into 3010 * XXX: Ideally the dependency line would first be split into
3011 * its left-hand side, dependency operator and right-hand side, 3011 * its left-hand side, dependency operator and right-hand side,
3012 * and then each side would be expanded on its own. This would 3012 * and then each side would be expanded on its own. This would
3013 * allow for the left-hand side to allow only defined variables 3013 * allow for the left-hand side to allow only defined variables
3014 * and to allow variables on the right-hand side to be undefined 3014 * and to allow variables on the right-hand side to be undefined
3015 * as well. 3015 * as well.
3016 * 3016 *
3017 * Parsing the line first would also prevent that targets 3017 * Parsing the line first would also prevent that targets
3018 * generated from variable expressions are interpreted as the 3018 * generated from variable expressions are interpreted as the
3019 * dependency operator, such as in "target${:U:} middle: source", 3019 * dependency operator, such as in "target${:U:} middle: source",
3020 * in which the middle is interpreted as a source, not a target. 3020 * in which the middle is interpreted as a source, not a target.
3021 */ 3021 */
3022 3022
3023 /* In lint mode, allow undefined variables to appear in 3023 /* In lint mode, allow undefined variables to appear in
3024 * dependency lines. 3024 * dependency lines.
3025 * 3025 *
3026 * Ideally, only the right-hand side would allow undefined 3026 * Ideally, only the right-hand side would allow undefined
3027 * variables since it is common to have no dependencies. 3027 * variables since it is common to have no dependencies.
3028 * Having undefined variables on the left-hand side is more 3028 * Having undefined variables on the left-hand side is more
3029 * unusual though. Since both sides are expanded in a single 3029 * unusual though. Since both sides are expanded in a single
3030 * pass, there is not much choice what to do here. 3030 * pass, there is not much choice what to do here.
3031 * 3031 *
3032 * In normal mode, it does not matter whether undefined 3032 * In normal mode, it does not matter whether undefined
3033 * variables are allowed or not since as of 2020-09-14, 3033 * variables are allowed or not since as of 2020-09-14,
3034 * Var_Parse does not print any parse errors in such a case. 3034 * Var_Parse does not print any parse errors in such a case.
3035 * It simply returns the special empty string var_Error, 3035 * It simply returns the special empty string var_Error,
3036 * which cannot be detected in the result of Var_Subst. */ 3036 * which cannot be detected in the result of Var_Subst. */
3037 eflags = DEBUG(LINT) ? VARE_WANTRES : VARE_UNDEFERR | VARE_WANTRES; 3037 eflags = DEBUG(LINT) ? VARE_WANTRES : VARE_UNDEFERR | VARE_WANTRES;
3038 (void)Var_Subst(line, VAR_CMD, eflags, &expanded_line); 3038 (void)Var_Subst(line, VAR_CMD, eflags, &expanded_line);
3039 /* TODO: handle errors */ 3039 /* TODO: handle errors */
3040 3040
3041 /* Need a fresh list for the target nodes */ 3041 /* Need a fresh list for the target nodes */
3042 if (targets != NULL) 3042 if (targets != NULL)
3043 Lst_Free(targets); 3043 Lst_Free(targets);
3044 targets = Lst_New(); 3044 targets = Lst_New();
3045 3045
3046 ParseDoDependency(expanded_line); 3046 ParseDoDependency(expanded_line);
3047 free(expanded_line); 3047 free(expanded_line);
3048 3048
3049 if (shellcmd != NULL) 3049 if (shellcmd != NULL)
3050 ParseLine_ShellCommand(shellcmd); 3050 ParseLine_ShellCommand(shellcmd);
3051} 3051}
3052 3052
3053static void 3053static void
3054ParseLine(char *line) 3054ParseLine(char *line)
3055{ 3055{
3056 if (ParseDirective(line)) 3056 if (ParseDirective(line))
3057 return; 3057 return;
3058 3058
3059 if (*line == '\t') { 3059 if (*line == '\t') {
3060 ParseLine_ShellCommand(line + 1); 3060 ParseLine_ShellCommand(line + 1);
3061 return; 3061 return;
3062 } 3062 }
3063 3063
3064#ifdef SYSVINCLUDE 3064#ifdef SYSVINCLUDE
3065 if (IsSysVInclude(line)) { 3065 if (IsSysVInclude(line)) {
3066 /* 3066 /*
3067 * It's an S3/S5-style "include". 3067 * It's an S3/S5-style "include".
3068 */ 3068 */
3069 ParseTraditionalInclude(line); 3069 ParseTraditionalInclude(line);
3070 return; 3070 return;
3071 } 3071 }
3072#endif 3072#endif
3073 3073
3074#ifdef GMAKEEXPORT 3074#ifdef GMAKEEXPORT
3075 if (strncmp(line, "export", 6) == 0 && ch_isspace(line[6]) && 3075 if (strncmp(line, "export", 6) == 0 && ch_isspace(line[6]) &&
3076 strchr(line, ':') == NULL) { 3076 strchr(line, ':') == NULL) {
3077 /* 3077 /*
3078 * It's a Gmake "export". 3078 * It's a Gmake "export".
3079 */ 3079 */
3080 ParseGmakeExport(line); 3080 ParseGmakeExport(line);
3081 return; 3081 return;
3082 } 3082 }
3083#endif 3083#endif
3084 3084
3085 if (ParseVarassign(line)) 3085 if (ParseVarassign(line))
3086 return; 3086 return;
3087 3087
3088 FinishDependencyGroup(); 3088 FinishDependencyGroup();
3089 3089
3090 ParseDependency(line); 3090 ParseDependency(line);
3091} 3091}
3092 3092
3093/* Parse a top-level makefile into its component parts, incorporating them 3093/* Parse a top-level makefile into its component parts, incorporating them
3094 * into the global dependency graph. 3094 * into the global dependency graph.
3095 * 3095 *
3096 * Input: 3096 * Input:
3097 * name The name of the file being read 3097 * name The name of the file being read
3098 * fd The open file to parse; will be closed at the end 3098 * fd The open file to parse; will be closed at the end
3099 */ 3099 */
3100void 3100void
3101Parse_File(const char *name, int fd) 3101Parse_File(const char *name, int fd)
3102{ 3102{
3103 char *line; /* the line we're working on */ 3103 char *line; /* the line we're working on */
3104 struct loadedfile *lf; 3104 struct loadedfile *lf;
3105 3105
3106 lf = loadfile(name, fd); 3106 lf = loadfile(name, fd);
3107 3107
3108 assert(targets == NULL); 3108 assert(targets == NULL);
3109 fatals = 0; 3109 fatals = 0;
3110 3110
3111 if (name == NULL) 3111 if (name == NULL)
3112 name = "(stdin)"; 3112 name = "(stdin)";
3113 3113
3114 Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf); 3114 Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf);
3115 CurFile()->lf = lf; 3115 CurFile()->lf = lf;
3116 3116
3117 do { 3117 do {
3118 while ((line = ParseReadLine()) != NULL) { 3118 while ((line = ParseReadLine()) != NULL) {
3119 DEBUG2(PARSE, "ParseReadLine (%d): '%s'\n", 3119 DEBUG2(PARSE, "ParseReadLine (%d): '%s'\n",
3120 CurFile()->lineno, line); 3120 CurFile()->lineno, line);
3121 ParseLine(line); 3121 ParseLine(line);
3122 } 3122 }
3123 /* 3123 /*
3124 * Reached EOF, but it may be just EOF of an include file... 3124 * Reached EOF, but it may be just EOF of an include file...
3125 */ 3125 */
3126 } while (ParseEOF()); 3126 } while (ParseEOF());
3127 3127
3128 FinishDependencyGroup(); 3128 FinishDependencyGroup();
3129 3129
3130 if (fatals) { 3130 if (fatals) {
3131 (void)fflush(stdout); 3131 (void)fflush(stdout);
3132 (void)fprintf(stderr, 3132 (void)fprintf(stderr,
3133 "%s: Fatal errors encountered -- cannot continue", 3133 "%s: Fatal errors encountered -- cannot continue",
3134 progname); 3134 progname);
3135 PrintOnError(NULL, NULL); 3135 PrintOnError(NULL, NULL);
3136 exit(1); 3136 exit(1);
3137 } 3137 }
3138} 3138}
3139 3139
3140/* Initialize the parsing module. */ 3140/* Initialize the parsing module. */
3141void 3141void
3142Parse_Init(void) 3142Parse_Init(void)
3143{ 3143{
3144 mainNode = NULL; 3144 mainNode = NULL;
3145 parseIncPath = Lst_New(); 3145 parseIncPath = Lst_New();
3146 sysIncPath = Lst_New(); 3146 sysIncPath = Lst_New();
3147 defIncPath = Lst_New(); 3147 defSysIncPath = Lst_New();
3148 Vector_Init(&includes, sizeof(IFile)); 3148 Vector_Init(&includes, sizeof(IFile));
3149#ifdef CLEANUP 3149#ifdef CLEANUP
3150 targCmds = Lst_New(); 3150 targCmds = Lst_New();
3151#endif 3151#endif
3152} 3152}
3153 3153
3154/* Clean up the parsing module. */ 3154/* Clean up the parsing module. */
3155void 3155void
3156Parse_End(void) 3156Parse_End(void)
3157{ 3157{
3158#ifdef CLEANUP 3158#ifdef CLEANUP
3159 Lst_Destroy(targCmds, free); 3159 Lst_Destroy(targCmds, free);
3160 assert(targets == NULL); 3160 assert(targets == NULL);
3161 Lst_Destroy(defIncPath, Dir_Destroy); 3161 Lst_Destroy(defSysIncPath, Dir_Destroy);
3162 Lst_Destroy(sysIncPath, Dir_Destroy); 3162 Lst_Destroy(sysIncPath, Dir_Destroy);
3163 Lst_Destroy(parseIncPath, Dir_Destroy); 3163 Lst_Destroy(parseIncPath, Dir_Destroy);
3164 assert(includes.len == 0); 3164 assert(includes.len == 0);
3165 Vector_Done(&includes); 3165 Vector_Done(&includes);
3166#endif 3166#endif
3167} 3167}
3168 3168
3169 3169
3170/*- 3170/*-
3171 *----------------------------------------------------------------------- 3171 *-----------------------------------------------------------------------
3172 * Parse_MainName -- 3172 * Parse_MainName --
3173 * Return a Lst of the main target to create for main()'s sake. If 3173 * Return a Lst of the main target to create for main()'s sake. If
3174 * no such target exists, we Punt with an obnoxious error message. 3174 * no such target exists, we Punt with an obnoxious error message.
3175 * 3175 *
3176 * Results: 3176 * Results:
3177 * A Lst of the single node to create. 3177 * A Lst of the single node to create.
3178 * 3178 *
3179 * Side Effects: 3179 * Side Effects:
3180 * None. 3180 * None.
3181 * 3181 *
3182 *----------------------------------------------------------------------- 3182 *-----------------------------------------------------------------------
3183 */ 3183 */
3184GNodeList * 3184GNodeList *
3185Parse_MainName(void) 3185Parse_MainName(void)
3186{ 3186{
3187 GNodeList *mainList; 3187 GNodeList *mainList;
3188 3188
3189 mainList = Lst_New(); 3189 mainList = Lst_New();
3190 3190
3191 if (mainNode == NULL) { 3191 if (mainNode == NULL) {
3192 Punt("no target to make."); 3192 Punt("no target to make.");
3193 /*NOTREACHED*/ 3193 /*NOTREACHED*/
3194 } else if (mainNode->type & OP_DOUBLEDEP) { 3194 } else if (mainNode->type & OP_DOUBLEDEP) {
3195 Lst_Append(mainList, mainNode); 3195 Lst_Append(mainList, mainNode);
3196 Lst_AppendAll(mainList, mainNode->cohorts); 3196 Lst_AppendAll(mainList, mainNode->cohorts);
3197 } else 3197 } else
3198 Lst_Append(mainList, mainNode); 3198 Lst_Append(mainList, mainNode);
3199 Var_Append(".TARGETS", mainNode->name, VAR_GLOBAL); 3199 Var_Append(".TARGETS", mainNode->name, VAR_GLOBAL);
3200 return mainList; 3200 return mainList;
3201} 3201}

cvs diff -r1.174 -r1.175 src/usr.bin/make/make.h (switch to unified diff)

--- src/usr.bin/make/make.h 2020/10/27 07:03:55 1.174
+++ src/usr.bin/make/make.h 2020/10/28 03:21:25 1.175
@@ -1,711 +1,711 @@ @@ -1,711 +1,711 @@
1/* $NetBSD: make.h,v 1.174 2020/10/27 07:03:55 rillig Exp $ */ 1/* $NetBSD: make.h,v 1.175 2020/10/28 03:21:25 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 * from: @(#)make.h 8.3 (Berkeley) 6/13/95 34 * from: @(#)make.h 8.3 (Berkeley) 6/13/95
35 */ 35 */
36 36
37/* 37/*
38 * Copyright (c) 1989 by Berkeley Softworks 38 * Copyright (c) 1989 by Berkeley Softworks
39 * All rights reserved. 39 * All rights reserved.
40 * 40 *
41 * This code is derived from software contributed to Berkeley by 41 * This code is derived from software contributed to Berkeley by
42 * Adam de Boor. 42 * Adam de Boor.
43 * 43 *
44 * Redistribution and use in source and binary forms, with or without 44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions 45 * modification, are permitted provided that the following conditions
46 * are met: 46 * are met:
47 * 1. Redistributions of source code must retain the above copyright 47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer. 48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright 49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the 50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution. 51 * documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software 52 * 3. All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement: 53 * must display the following acknowledgement:
54 * This product includes software developed by the University of 54 * This product includes software developed by the University of
55 * California, Berkeley and its contributors. 55 * California, Berkeley and its contributors.
56 * 4. Neither the name of the University nor the names of its contributors 56 * 4. Neither the name of the University nor the names of its contributors
57 * may be used to endorse or promote products derived from this software 57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission. 58 * without specific prior written permission.
59 * 59 *
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE. 70 * SUCH DAMAGE.
71 * 71 *
72 * from: @(#)make.h 8.3 (Berkeley) 6/13/95 72 * from: @(#)make.h 8.3 (Berkeley) 6/13/95
73 */ 73 */
74 74
75/*- 75/*-
76 * make.h -- 76 * make.h --
77 * The global definitions for pmake 77 * The global definitions for pmake
78 */ 78 */
79 79
80#ifndef MAKE_MAKE_H 80#ifndef MAKE_MAKE_H
81#define MAKE_MAKE_H 81#define MAKE_MAKE_H
82 82
83#include <sys/types.h> 83#include <sys/types.h>
84#include <sys/param.h> 84#include <sys/param.h>
85#include <sys/stat.h> 85#include <sys/stat.h>
86 86
87#include <assert.h> 87#include <assert.h>
88#include <ctype.h> 88#include <ctype.h>
89#include <fcntl.h> 89#include <fcntl.h>
90#include <stdarg.h> 90#include <stdarg.h>
91#include <stdio.h> 91#include <stdio.h>
92#include <stdlib.h> 92#include <stdlib.h>
93#include <string.h> 93#include <string.h>
94#include <unistd.h> 94#include <unistd.h>
95 95
96#ifdef BSD4_4 96#ifdef BSD4_4
97# include <sys/cdefs.h> 97# include <sys/cdefs.h>
98#endif 98#endif
99 99
100#ifndef FD_CLOEXEC 100#ifndef FD_CLOEXEC
101#define FD_CLOEXEC 1 101#define FD_CLOEXEC 1
102#endif 102#endif
103 103
104#if defined(__GNUC__) 104#if defined(__GNUC__)
105#define MAKE_GNUC_PREREQ(x, y) \ 105#define MAKE_GNUC_PREREQ(x, y) \
106 ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \ 106 ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \
107 (__GNUC__ > (x))) 107 (__GNUC__ > (x)))
108#else /* defined(__GNUC__) */ 108#else /* defined(__GNUC__) */
109#define MAKE_GNUC_PREREQ(x, y) 0 109#define MAKE_GNUC_PREREQ(x, y) 0
110#endif /* defined(__GNUC__) */ 110#endif /* defined(__GNUC__) */
111 111
112#if MAKE_GNUC_PREREQ(2, 7) 112#if MAKE_GNUC_PREREQ(2, 7)
113#define MAKE_ATTR_UNUSED __attribute__((__unused__)) 113#define MAKE_ATTR_UNUSED __attribute__((__unused__))
114#else 114#else
115#define MAKE_ATTR_UNUSED /* delete */ 115#define MAKE_ATTR_UNUSED /* delete */
116#endif 116#endif
117 117
118#if MAKE_GNUC_PREREQ(2, 5) 118#if MAKE_GNUC_PREREQ(2, 5)
119#define MAKE_ATTR_DEAD __attribute__((__noreturn__)) 119#define MAKE_ATTR_DEAD __attribute__((__noreturn__))
120#elif defined(__GNUC__) 120#elif defined(__GNUC__)
121#define MAKE_ATTR_DEAD __volatile 121#define MAKE_ATTR_DEAD __volatile
122#else 122#else
123#define MAKE_ATTR_DEAD /* delete */ 123#define MAKE_ATTR_DEAD /* delete */
124#endif 124#endif
125 125
126#if MAKE_GNUC_PREREQ(2, 7) 126#if MAKE_GNUC_PREREQ(2, 7)
127#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) \ 127#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) \
128 __attribute__((__format__ (__printf__, fmtarg, firstvararg))) 128 __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
129#else 129#else
130#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) /* delete */ 130#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) /* delete */
131#endif 131#endif
132 132
133/* 133/*
134 * A boolean type is defined as an integer, not an enum, for historic reasons. 134 * A boolean type is defined as an integer, not an enum, for historic reasons.
135 * The only allowed values are the constants TRUE and FALSE (1 and 0). 135 * The only allowed values are the constants TRUE and FALSE (1 and 0).
136 */ 136 */
137 137
138#ifdef USE_DOUBLE_BOOLEAN 138#ifdef USE_DOUBLE_BOOLEAN
139/* During development, to find type mismatches in function declarations. */ 139/* During development, to find type mismatches in function declarations. */
140typedef double Boolean; 140typedef double Boolean;
141#define TRUE 1.0 141#define TRUE 1.0
142#define FALSE 0.0 142#define FALSE 0.0
143#elif defined(USE_UCHAR_BOOLEAN) 143#elif defined(USE_UCHAR_BOOLEAN)
144/* During development, to find code that depends on the exact value of TRUE or 144/* During development, to find code that depends on the exact value of TRUE or
145 * that stores other values in Boolean variables. */ 145 * that stores other values in Boolean variables. */
146typedef unsigned char Boolean; 146typedef unsigned char Boolean;
147#define TRUE ((unsigned char)0xFF) 147#define TRUE ((unsigned char)0xFF)
148#define FALSE ((unsigned char)0x00) 148#define FALSE ((unsigned char)0x00)
149#elif defined(USE_CHAR_BOOLEAN) 149#elif defined(USE_CHAR_BOOLEAN)
150/* During development, to find code that uses a boolean as array index, via 150/* During development, to find code that uses a boolean as array index, via
151 * -Wchar-subscripts. */ 151 * -Wchar-subscripts. */
152typedef char Boolean; 152typedef char Boolean;
153#define TRUE ((char)-1) 153#define TRUE ((char)-1)
154#define FALSE ((char)0x00) 154#define FALSE ((char)0x00)
155#elif defined(USE_ENUM_BOOLEAN) 155#elif defined(USE_ENUM_BOOLEAN)
156typedef enum Boolean { FALSE, TRUE } Boolean; 156typedef enum Boolean { FALSE, TRUE } Boolean;
157#else 157#else
158typedef int Boolean; 158typedef int Boolean;
159#ifndef TRUE 159#ifndef TRUE
160#define TRUE 1 160#define TRUE 1
161#endif 161#endif
162#ifndef FALSE 162#ifndef FALSE
163#define FALSE 0 163#define FALSE 0
164#endif 164#endif
165#endif 165#endif
166 166
167#include "lst.h" 167#include "lst.h"
168#include "enum.h" 168#include "enum.h"
169#include "hash.h" 169#include "hash.h"
170#include "config.h" 170#include "config.h"
171#include "buf.h" 171#include "buf.h"
172#include "make_malloc.h" 172#include "make_malloc.h"
173 173
174typedef enum { 174typedef enum {
175 UNMADE, /* Not examined yet */ 175 UNMADE, /* Not examined yet */
176 DEFERRED, /* Examined once (building child) */ 176 DEFERRED, /* Examined once (building child) */
177 REQUESTED, /* on toBeMade list */ 177 REQUESTED, /* on toBeMade list */
178 BEINGMADE, /* Target is already being made. 178 BEINGMADE, /* Target is already being made.
179 * Indicates a cycle in the graph. */ 179 * Indicates a cycle in the graph. */
180 MADE, /* Was out-of-date and has been made */ 180 MADE, /* Was out-of-date and has been made */
181 UPTODATE, /* Was already up-to-date */ 181 UPTODATE, /* Was already up-to-date */
182 ERROR, /* An error occurred while it was being 182 ERROR, /* An error occurred while it was being
183 * made (used only in compat mode) */ 183 * made (used only in compat mode) */
184 ABORTED /* The target was aborted due to an error 184 ABORTED /* The target was aborted due to an error
185 * making an inferior (compat). */ 185 * making an inferior (compat). */
186} GNodeMade; 186} GNodeMade;
187 187
188/* The OP_ constants are used when parsing a dependency line as a way of 188/* The OP_ constants are used when parsing a dependency line as a way of
189 * communicating to other parts of the program the way in which a target 189 * communicating to other parts of the program the way in which a target
190 * should be made. 190 * should be made.
191 * 191 *
192 * Some of the OP_ constants can be combined, others cannot. */ 192 * Some of the OP_ constants can be combined, others cannot. */
193typedef enum GNodeType { 193typedef enum GNodeType {
194 /* The dependency operator ':' is the most common one. The commands of 194 /* The dependency operator ':' is the most common one. The commands of
195 * this node are executed if any child is out-of-date. */ 195 * this node are executed if any child is out-of-date. */
196 OP_DEPENDS = 1 << 0, 196 OP_DEPENDS = 1 << 0,
197 /* The dependency operator '!' always executes its commands, even if 197 /* The dependency operator '!' always executes its commands, even if
198 * its children are up-to-date. */ 198 * its children are up-to-date. */
199 OP_FORCE = 1 << 1, 199 OP_FORCE = 1 << 1,
200 /* The dependency operator '::' behaves like ':', except that it allows 200 /* The dependency operator '::' behaves like ':', except that it allows
201 * multiple dependency groups to be defined. Each of these groups is 201 * multiple dependency groups to be defined. Each of these groups is
202 * executed on its own, independently from the others. */ 202 * executed on its own, independently from the others. */
203 OP_DOUBLEDEP = 1 << 2, 203 OP_DOUBLEDEP = 1 << 2,
204 204
205 /* Matches the dependency operators ':', '!' and '::'. */ 205 /* Matches the dependency operators ':', '!' and '::'. */
206 OP_OPMASK = OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP, 206 OP_OPMASK = OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP,
207 207
208 /* Don't care if the target doesn't exist and can't be created */ 208 /* Don't care if the target doesn't exist and can't be created */
209 OP_OPTIONAL = 1 << 3, 209 OP_OPTIONAL = 1 << 3,
210 /* Use associated commands for parents */ 210 /* Use associated commands for parents */
211 OP_USE = 1 << 4, 211 OP_USE = 1 << 4,
212 /* Target is never out of date, but always execute commands anyway. 212 /* Target is never out of date, but always execute commands anyway.
213 * Its time doesn't matter, so it has none...sort of */ 213 * Its time doesn't matter, so it has none...sort of */
214 OP_EXEC = 1 << 5, 214 OP_EXEC = 1 << 5,
215 /* Ignore non-zero exit status from shell commands when creating the node */ 215 /* Ignore non-zero exit status from shell commands when creating the node */
216 OP_IGNORE = 1 << 6, 216 OP_IGNORE = 1 << 6,
217 /* Don't remove the target when interrupted */ 217 /* Don't remove the target when interrupted */
218 OP_PRECIOUS = 1 << 7, 218 OP_PRECIOUS = 1 << 7,
219 /* Don't echo commands when executed */ 219 /* Don't echo commands when executed */
220 OP_SILENT = 1 << 8, 220 OP_SILENT = 1 << 8,
221 /* Target is a recursive make so its commands should always be executed 221 /* Target is a recursive make so its commands should always be executed
222 * when it is out of date, regardless of the state of the -n or -t flags */ 222 * when it is out of date, regardless of the state of the -n or -t flags */
223 OP_MAKE = 1 << 9, 223 OP_MAKE = 1 << 9,
224 /* Target is out-of-date only if any of its children was out-of-date */ 224 /* Target is out-of-date only if any of its children was out-of-date */
225 OP_JOIN = 1 << 10, 225 OP_JOIN = 1 << 10,
226 /* Assume the children of the node have been already made */ 226 /* Assume the children of the node have been already made */
227 OP_MADE = 1 << 11, 227 OP_MADE = 1 << 11,
228 /* Special .BEGIN, .END, .INTERRUPT */ 228 /* Special .BEGIN, .END, .INTERRUPT */
229 OP_SPECIAL = 1 << 12, 229 OP_SPECIAL = 1 << 12,
230 /* Like .USE, only prepend commands */ 230 /* Like .USE, only prepend commands */
231 OP_USEBEFORE = 1 << 13, 231 OP_USEBEFORE = 1 << 13,
232 /* The node is invisible to its parents. I.e. it doesn't show up in the 232 /* The node is invisible to its parents. I.e. it doesn't show up in the
233 * parents' local variables. */ 233 * parents' local variables. */
234 OP_INVISIBLE = 1 << 14, 234 OP_INVISIBLE = 1 << 14,
235 /* The node is exempt from normal 'main target' processing in parse.c */ 235 /* The node is exempt from normal 'main target' processing in parse.c */
236 OP_NOTMAIN = 1 << 15, 236 OP_NOTMAIN = 1 << 15,
237 /* Not a file target; run always */ 237 /* Not a file target; run always */
238 OP_PHONY = 1 << 16, 238 OP_PHONY = 1 << 16,
239 /* Don't search for file in the path */ 239 /* Don't search for file in the path */
240 OP_NOPATH = 1 << 17, 240 OP_NOPATH = 1 << 17,
241 /* .WAIT phony node */ 241 /* .WAIT phony node */
242 OP_WAIT = 1 << 18, 242 OP_WAIT = 1 << 18,
243 /* .NOMETA do not create a .meta file */ 243 /* .NOMETA do not create a .meta file */
244 OP_NOMETA = 1 << 19, 244 OP_NOMETA = 1 << 19,
245 /* .META we _do_ want a .meta file */ 245 /* .META we _do_ want a .meta file */
246 OP_META = 1 << 20, 246 OP_META = 1 << 20,
247 /* Do not compare commands in .meta file */ 247 /* Do not compare commands in .meta file */
248 OP_NOMETA_CMP = 1 << 21, 248 OP_NOMETA_CMP = 1 << 21,
249 /* Possibly a submake node */ 249 /* Possibly a submake node */
250 OP_SUBMAKE = 1 << 22, 250 OP_SUBMAKE = 1 << 22,
251 251
252 /* Attributes applied by PMake */ 252 /* Attributes applied by PMake */
253 253
254 /* The node is a transformation rule */ 254 /* The node is a transformation rule */
255 OP_TRANSFORM = 1 << 31, 255 OP_TRANSFORM = 1 << 31,
256 /* Target is a member of an archive */ 256 /* Target is a member of an archive */
257 /* XXX: How does this differ from OP_ARCHV? */ 257 /* XXX: How does this differ from OP_ARCHV? */
258 OP_MEMBER = 1 << 30, 258 OP_MEMBER = 1 << 30,
259 /* The node is a library, 259 /* The node is a library,
260 * its name has the form "-l<libname>" */ 260 * its name has the form "-l<libname>" */
261 OP_LIB = 1 << 29, 261 OP_LIB = 1 << 29,
262 /* The node is an archive member, 262 /* The node is an archive member,
263 * its name has the form "archive(member)" */ 263 * its name has the form "archive(member)" */
264 /* XXX: How does this differ from OP_MEMBER? */ 264 /* XXX: How does this differ from OP_MEMBER? */
265 OP_ARCHV = 1 << 28, 265 OP_ARCHV = 1 << 28,
266 /* Target has all the commands it should. Used when parsing to catch 266 /* Target has all the commands it should. Used when parsing to catch
267 * multiple command groups for a target. Only applies to the dependency 267 * multiple command groups for a target. Only applies to the dependency
268 * operators ':' and '!', but not to '::'. */ 268 * operators ':' and '!', but not to '::'. */
269 OP_HAS_COMMANDS = 1 << 27, 269 OP_HAS_COMMANDS = 1 << 27,
270 /* The special command "..." has been seen. All further commands from 270 /* The special command "..." has been seen. All further commands from
271 * this node will be saved on the .END node instead, to be executed at 271 * this node will be saved on the .END node instead, to be executed at
272 * the very end. */ 272 * the very end. */
273 OP_SAVE_CMDS = 1 << 26, 273 OP_SAVE_CMDS = 1 << 26,
274 /* Already processed by Suff_FindDeps */ 274 /* Already processed by Suff_FindDeps */
275 OP_DEPS_FOUND = 1 << 25, 275 OP_DEPS_FOUND = 1 << 25,
276 /* Node found while expanding .ALLSRC */ 276 /* Node found while expanding .ALLSRC */
277 OP_MARK = 1 << 24, 277 OP_MARK = 1 << 24,
278 278
279 OP_NOTARGET = OP_NOTMAIN | OP_USE | OP_EXEC | OP_TRANSFORM 279 OP_NOTARGET = OP_NOTMAIN | OP_USE | OP_EXEC | OP_TRANSFORM
280} GNodeType; 280} GNodeType;
281 281
282typedef enum GNodeFlags { 282typedef enum GNodeFlags {
283 REMAKE = 0x0001, /* this target needs to be (re)made */ 283 REMAKE = 0x0001, /* this target needs to be (re)made */
284 CHILDMADE = 0x0002, /* children of this target were made */ 284 CHILDMADE = 0x0002, /* children of this target were made */
285 FORCE = 0x0004, /* children don't exist, and we pretend made */ 285 FORCE = 0x0004, /* children don't exist, and we pretend made */
286 DONE_WAIT = 0x0008, /* Set by Make_ProcessWait() */ 286 DONE_WAIT = 0x0008, /* Set by Make_ProcessWait() */
287 DONE_ORDER = 0x0010, /* Build requested by .ORDER processing */ 287 DONE_ORDER = 0x0010, /* Build requested by .ORDER processing */
288 FROM_DEPEND = 0x0020, /* Node created from .depend */ 288 FROM_DEPEND = 0x0020, /* Node created from .depend */
289 DONE_ALLSRC = 0x0040, /* We do it once only */ 289 DONE_ALLSRC = 0x0040, /* We do it once only */
290 CYCLE = 0x1000, /* Used by MakePrintStatus */ 290 CYCLE = 0x1000, /* Used by MakePrintStatus */
291 DONECYCLE = 0x2000, /* Used by MakePrintStatus */ 291 DONECYCLE = 0x2000, /* Used by MakePrintStatus */
292 INTERNAL = 0x4000 /* Internal use only */ 292 INTERNAL = 0x4000 /* Internal use only */
293} GNodeFlags; 293} GNodeFlags;
294 294
295typedef struct List StringList; 295typedef struct List StringList;
296typedef struct ListNode StringListNode; 296typedef struct ListNode StringListNode;
297 297
298typedef struct List GNodeList; 298typedef struct List GNodeList;
299typedef struct ListNode GNodeListNode; 299typedef struct ListNode GNodeListNode;
300 300
301typedef struct List /* of CachedDir */ SearchPath; 301typedef struct List /* of CachedDir */ SearchPath;
302 302
303/* A graph node represents a target that can possibly be made, including its 303/* A graph node represents a target that can possibly be made, including its
304 * relation to other targets and a lot of other details. */ 304 * relation to other targets and a lot of other details. */
305typedef struct GNode { 305typedef struct GNode {
306 /* The target's name, such as "clean" or "make.c" */ 306 /* The target's name, such as "clean" or "make.c" */
307 char *name; 307 char *name;
308 /* The unexpanded name of a .USE node */ 308 /* The unexpanded name of a .USE node */
309 char *uname; 309 char *uname;
310 /* The full pathname of the file belonging to the target. 310 /* The full pathname of the file belonging to the target.
311 * XXX: What about .PHONY targets? These don't have an associated path. */ 311 * XXX: What about .PHONY targets? These don't have an associated path. */
312 char *path; 312 char *path;
313 313
314 /* The type of operator used to define the sources (see the OP flags below). 314 /* The type of operator used to define the sources (see the OP flags below).
315 * XXX: This looks like a wild mixture of type and flags. */ 315 * XXX: This looks like a wild mixture of type and flags. */
316 GNodeType type; 316 GNodeType type;
317 GNodeFlags flags; 317 GNodeFlags flags;
318 318
319 /* The state of processing on this node */ 319 /* The state of processing on this node */
320 GNodeMade made; 320 GNodeMade made;
321 int unmade; /* The number of unmade children */ 321 int unmade; /* The number of unmade children */
322 322
323 /* The modification time; 0 means the node does not have a corresponding 323 /* The modification time; 0 means the node does not have a corresponding
324 * file; see Make_OODate. */ 324 * file; see Make_OODate. */
325 time_t mtime; 325 time_t mtime;
326 struct GNode *youngestChild; 326 struct GNode *youngestChild;
327 327
328 /* The GNodes for which this node is an implied source. May be empty. 328 /* The GNodes for which this node is an implied source. May be empty.
329 * For example, when there is an inference rule for .c.o, the node for 329 * For example, when there is an inference rule for .c.o, the node for
330 * file.c has the node for file.o in this list. */ 330 * file.c has the node for file.o in this list. */
331 GNodeList *implicitParents; 331 GNodeList *implicitParents;
332 332
333 /* Other nodes of the same name, for the '::' operator. */ 333 /* Other nodes of the same name, for the '::' operator. */
334 GNodeList *cohorts; 334 GNodeList *cohorts;
335 335
336 /* The nodes that depend on this one, or in other words, the nodes for 336 /* The nodes that depend on this one, or in other words, the nodes for
337 * which this is a source. */ 337 * which this is a source. */
338 GNodeList *parents; 338 GNodeList *parents;
339 /* The nodes on which this one depends. */ 339 /* The nodes on which this one depends. */
340 GNodeList *children; 340 GNodeList *children;
341 341
342 /* .ORDER nodes we need made. The nodes that must be made (if they're 342 /* .ORDER nodes we need made. The nodes that must be made (if they're
343 * made) before this node can be made, but that do not enter into the 343 * made) before this node can be made, but that do not enter into the
344 * datedness of this node. */ 344 * datedness of this node. */
345 GNodeList *order_pred; 345 GNodeList *order_pred;
346 /* .ORDER nodes who need us. The nodes that must be made (if they're made 346 /* .ORDER nodes who need us. The nodes that must be made (if they're made
347 * at all) after this node is made, but that do not depend on this node, 347 * at all) after this node is made, but that do not depend on this node,
348 * in the normal sense. */ 348 * in the normal sense. */
349 GNodeList *order_succ; 349 GNodeList *order_succ;
350 350
351 /* The "#n" suffix for this cohort, or "" for other nodes */ 351 /* The "#n" suffix for this cohort, or "" for other nodes */
352 char cohort_num[8]; 352 char cohort_num[8];
353 /* The number of unmade instances on the cohorts list */ 353 /* The number of unmade instances on the cohorts list */
354 int unmade_cohorts; 354 int unmade_cohorts;
355 /* Pointer to the first instance of a '::' node; only set when on a 355 /* Pointer to the first instance of a '::' node; only set when on a
356 * cohorts list */ 356 * cohorts list */
357 struct GNode *centurion; 357 struct GNode *centurion;
358 358
359 /* Last time (sequence number) we tried to make this node */ 359 /* Last time (sequence number) we tried to make this node */
360 unsigned int checked_seqno; 360 unsigned int checked_seqno;
361 361
362 /* The "local" variables that are specific to this target and this target 362 /* The "local" variables that are specific to this target and this target
363 * only, such as $@, $<, $?. 363 * only, such as $@, $<, $?.
364 * 364 *
365 * Also used for the global variable scopes VAR_GLOBAL, VAR_CMD, 365 * Also used for the global variable scopes VAR_GLOBAL, VAR_CMD,
366 * VAR_INTERNAL, which contain variables with arbitrary names. */ 366 * VAR_INTERNAL, which contain variables with arbitrary names. */
367 HashTable context; 367 HashTable context;
368 368
369 /* The commands to be given to a shell to create this target. */ 369 /* The commands to be given to a shell to create this target. */
370 StringList *commands; 370 StringList *commands;
371 371
372 /* Suffix for the node (determined by Suff_FindDeps and opaque to everyone 372 /* Suffix for the node (determined by Suff_FindDeps and opaque to everyone
373 * but the Suff module) */ 373 * but the Suff module) */
374 struct Suff *suffix; 374 struct Suff *suffix;
375 375
376 /* filename where the GNode got defined */ 376 /* filename where the GNode got defined */
377 const char *fname; 377 const char *fname;
378 /* line number where the GNode got defined */ 378 /* line number where the GNode got defined */
379 int lineno; 379 int lineno;
380} GNode; 380} GNode;
381 381
382/* 382/*
383 * Error levels for parsing. PARSE_FATAL means the process cannot continue 383 * Error levels for parsing. PARSE_FATAL means the process cannot continue
384 * once the top-level makefile has been parsed. PARSE_WARNING and PARSE_INFO 384 * once the top-level makefile has been parsed. PARSE_WARNING and PARSE_INFO
385 * mean it can. 385 * mean it can.
386 */ 386 */
387typedef enum ParseErrorLevel { 387typedef enum ParseErrorLevel {
388 PARSE_FATAL = 1, 388 PARSE_FATAL = 1,
389 PARSE_WARNING, 389 PARSE_WARNING,
390 PARSE_INFO 390 PARSE_INFO
391} ParseErrorLevel; 391} ParseErrorLevel;
392 392
393/* 393/*
394 * Values returned by Cond_EvalLine and Cond_EvalCondition. 394 * Values returned by Cond_EvalLine and Cond_EvalCondition.
395 */ 395 */
396typedef enum CondEvalResult { 396typedef enum CondEvalResult {
397 COND_PARSE, /* Parse the next lines */ 397 COND_PARSE, /* Parse the next lines */
398 COND_SKIP, /* Skip the next lines */ 398 COND_SKIP, /* Skip the next lines */
399 COND_INVALID /* Not a conditional statement */ 399 COND_INVALID /* Not a conditional statement */
400} CondEvalResult; 400} CondEvalResult;
401 401
402/* 402/*
403 * Definitions for the "local" variables. Used only for clarity. 403 * Definitions for the "local" variables. Used only for clarity.
404 */ 404 */
405#define TARGET "@" /* Target of dependency */ 405#define TARGET "@" /* Target of dependency */
406#define OODATE "?" /* All out-of-date sources */ 406#define OODATE "?" /* All out-of-date sources */
407#define ALLSRC ">" /* All sources */ 407#define ALLSRC ">" /* All sources */
408#define IMPSRC "<" /* Source implied by transformation */ 408#define IMPSRC "<" /* Source implied by transformation */
409#define PREFIX "*" /* Common prefix */ 409#define PREFIX "*" /* Common prefix */
410#define ARCHIVE "!" /* Archive in "archive(member)" syntax */ 410#define ARCHIVE "!" /* Archive in "archive(member)" syntax */
411#define MEMBER "%" /* Member in "archive(member)" syntax */ 411#define MEMBER "%" /* Member in "archive(member)" syntax */
412 412
413#define FTARGET "@F" /* file part of TARGET */ 413#define FTARGET "@F" /* file part of TARGET */
414#define DTARGET "@D" /* directory part of TARGET */ 414#define DTARGET "@D" /* directory part of TARGET */
415#define FIMPSRC "<F" /* file part of IMPSRC */ 415#define FIMPSRC "<F" /* file part of IMPSRC */
416#define DIMPSRC "<D" /* directory part of IMPSRC */ 416#define DIMPSRC "<D" /* directory part of IMPSRC */
417#define FPREFIX "*F" /* file part of PREFIX */ 417#define FPREFIX "*F" /* file part of PREFIX */
418#define DPREFIX "*D" /* directory part of PREFIX */ 418#define DPREFIX "*D" /* directory part of PREFIX */
419 419
420/* 420/*
421 * Global Variables 421 * Global Variables
422 */ 422 */
423extern SearchPath *dirSearchPath; 423extern SearchPath *dirSearchPath;
424 /* The list of directories to search when 424 /* The list of directories to search when
425 * looking for targets */ 425 * looking for targets */
426extern Boolean allPrecious; /* True if every target is precious */ 426extern Boolean allPrecious; /* True if every target is precious */
427extern Boolean deleteOnError; /* True if failed targets should be deleted */ 427extern Boolean deleteOnError; /* True if failed targets should be deleted */
428extern Boolean doing_depend; /* TRUE if processing .depend */ 428extern Boolean doing_depend; /* TRUE if processing .depend */
429 429
430extern GNode *DEFAULT; /* .DEFAULT rule */ 430extern GNode *DEFAULT; /* .DEFAULT rule */
431 431
432extern GNode *VAR_INTERNAL; /* Variables defined internally by make 432extern GNode *VAR_INTERNAL; /* Variables defined internally by make
433 * which should not override those set by 433 * which should not override those set by
434 * makefiles. 434 * makefiles.
435 */ 435 */
436extern GNode *VAR_GLOBAL; /* Variables defined in a global context, e.g 436extern GNode *VAR_GLOBAL; /* Variables defined in a global context, e.g
437 * in the Makefile itself */ 437 * in the Makefile itself */
438extern GNode *VAR_CMD; /* Variables defined on the command line */ 438extern GNode *VAR_CMD; /* Variables defined on the command line */
439extern char var_Error[]; /* Value returned by Var_Parse when an error 439extern char var_Error[]; /* Value returned by Var_Parse when an error
440 * is encountered. It actually points to 440 * is encountered. It actually points to
441 * an empty string, so naive callers needn't 441 * an empty string, so naive callers needn't
442 * worry about it. */ 442 * worry about it. */
443 443
444extern time_t now; /* The time at the start of this whole 444extern time_t now; /* The time at the start of this whole
445 * process */ 445 * process */
446 446
447extern Boolean oldVars; /* Do old-style variable substitution */ 447extern Boolean oldVars; /* Do old-style variable substitution */
448 448
449extern SearchPath *sysIncPath; /* The system include path. */ 449extern SearchPath *sysIncPath; /* The system include path. */
450extern SearchPath *defIncPath; /* The default include path. */ 450extern SearchPath *defSysIncPath; /* The default system include path. */
451 451
452extern char curdir[]; /* Startup directory */ 452extern char curdir[]; /* Startup directory */
453extern char *progname; /* The program name */ 453extern char *progname; /* The program name */
454extern char *makeDependfile; /* .depend */ 454extern char *makeDependfile; /* .depend */
455extern char **savedEnv; /* if we replaced environ this will be non-NULL */ 455extern char **savedEnv; /* if we replaced environ this will be non-NULL */
456 456
457extern int makelevel; 457extern int makelevel;
458 458
459/* 459/*
460 * We cannot vfork() in a child of vfork(). 460 * We cannot vfork() in a child of vfork().
461 * Most systems do not enforce this but some do. 461 * Most systems do not enforce this but some do.
462 */ 462 */
463#define vFork() ((getpid() == myPid) ? vfork() : fork()) 463#define vFork() ((getpid() == myPid) ? vfork() : fork())
464extern pid_t myPid; 464extern pid_t myPid;
465 465
466#define MAKEFLAGS ".MAKEFLAGS" 466#define MAKEFLAGS ".MAKEFLAGS"
467#define MAKEOVERRIDES ".MAKEOVERRIDES" 467#define MAKEOVERRIDES ".MAKEOVERRIDES"
468#define MAKE_JOB_PREFIX ".MAKE.JOB.PREFIX" /* prefix for job target output */ 468#define MAKE_JOB_PREFIX ".MAKE.JOB.PREFIX" /* prefix for job target output */
469#define MAKE_EXPORTED ".MAKE.EXPORTED" /* variables we export */ 469#define MAKE_EXPORTED ".MAKE.EXPORTED" /* variables we export */
470#define MAKE_MAKEFILES ".MAKE.MAKEFILES" /* all makefiles already loaded */ 470#define MAKE_MAKEFILES ".MAKE.MAKEFILES" /* all makefiles already loaded */
471#define MAKE_LEVEL ".MAKE.LEVEL" /* recursion level */ 471#define MAKE_LEVEL ".MAKE.LEVEL" /* recursion level */
472#define MAKEFILE_PREFERENCE ".MAKE.MAKEFILE_PREFERENCE" 472#define MAKEFILE_PREFERENCE ".MAKE.MAKEFILE_PREFERENCE"
473#define MAKE_DEPENDFILE ".MAKE.DEPENDFILE" /* .depend */ 473#define MAKE_DEPENDFILE ".MAKE.DEPENDFILE" /* .depend */
474#define MAKE_MODE ".MAKE.MODE" 474#define MAKE_MODE ".MAKE.MODE"
475#ifndef MAKE_LEVEL_ENV 475#ifndef MAKE_LEVEL_ENV
476# define MAKE_LEVEL_ENV "MAKELEVEL" 476# define MAKE_LEVEL_ENV "MAKELEVEL"
477#endif 477#endif
478 478
479typedef enum DebugFlags { 479typedef enum DebugFlags {
480 DEBUG_ARCH = 1 << 0, 480 DEBUG_ARCH = 1 << 0,
481 DEBUG_COND = 1 << 1, 481 DEBUG_COND = 1 << 1,
482 DEBUG_DIR = 1 << 2, 482 DEBUG_DIR = 1 << 2,
483 DEBUG_GRAPH1 = 1 << 3, 483 DEBUG_GRAPH1 = 1 << 3,
484 DEBUG_GRAPH2 = 1 << 4, 484 DEBUG_GRAPH2 = 1 << 4,
485 DEBUG_JOB = 1 << 5, 485 DEBUG_JOB = 1 << 5,
486 DEBUG_MAKE = 1 << 6, 486 DEBUG_MAKE = 1 << 6,
487 DEBUG_SUFF = 1 << 7, 487 DEBUG_SUFF = 1 << 7,
488 DEBUG_TARG = 1 << 8, 488 DEBUG_TARG = 1 << 8,
489 DEBUG_VAR = 1 << 9, 489 DEBUG_VAR = 1 << 9,
490 DEBUG_FOR = 1 << 10, 490 DEBUG_FOR = 1 << 10,
491 DEBUG_SHELL = 1 << 11, 491 DEBUG_SHELL = 1 << 11,
492 DEBUG_ERROR = 1 << 12, 492 DEBUG_ERROR = 1 << 12,
493 DEBUG_LOUD = 1 << 13, 493 DEBUG_LOUD = 1 << 13,
494 DEBUG_META = 1 << 14, 494 DEBUG_META = 1 << 14,
495 DEBUG_HASH = 1 << 15, 495 DEBUG_HASH = 1 << 15,
496 496
497 DEBUG_GRAPH3 = 1 << 16, 497 DEBUG_GRAPH3 = 1 << 16,
498 DEBUG_SCRIPT = 1 << 17, 498 DEBUG_SCRIPT = 1 << 17,
499 DEBUG_PARSE = 1 << 18, 499 DEBUG_PARSE = 1 << 18,
500 DEBUG_CWD = 1 << 19, 500 DEBUG_CWD = 1 << 19,
501 501
502 DEBUG_LINT = 1 << 20 502 DEBUG_LINT = 1 << 20
503} DebugFlags; 503} DebugFlags;
504 504
505#define CONCAT(a,b) a##b 505#define CONCAT(a,b) a##b
506 506
507#define DEBUG(module) (opts.debug & CONCAT(DEBUG_,module)) 507#define DEBUG(module) (opts.debug & CONCAT(DEBUG_,module))
508 508
509void debug_printf(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2); 509void debug_printf(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
510 510
511#define DEBUG0(module, text) \ 511#define DEBUG0(module, text) \
512 if (!DEBUG(module)) (void)0; \ 512 if (!DEBUG(module)) (void)0; \
513 else debug_printf("%s", text) 513 else debug_printf("%s", text)
514 514
515#define DEBUG1(module, fmt, arg1) \ 515#define DEBUG1(module, fmt, arg1) \
516 if (!DEBUG(module)) (void)0; \ 516 if (!DEBUG(module)) (void)0; \
517 else debug_printf(fmt, arg1) 517 else debug_printf(fmt, arg1)
518 518
519#define DEBUG2(module, fmt, arg1, arg2) \ 519#define DEBUG2(module, fmt, arg1, arg2) \
520 if (!DEBUG(module)) (void)0; \ 520 if (!DEBUG(module)) (void)0; \
521 else debug_printf(fmt, arg1, arg2) 521 else debug_printf(fmt, arg1, arg2)
522 522
523#define DEBUG3(module, fmt, arg1, arg2, arg3) \ 523#define DEBUG3(module, fmt, arg1, arg2, arg3) \
524 if (!DEBUG(module)) (void)0; \ 524 if (!DEBUG(module)) (void)0; \
525 else debug_printf(fmt, arg1, arg2, arg3) 525 else debug_printf(fmt, arg1, arg2, arg3)
526 526
527#define DEBUG4(module, fmt, arg1, arg2, arg3, arg4) \ 527#define DEBUG4(module, fmt, arg1, arg2, arg3, arg4) \
528 if (!DEBUG(module)) (void)0; \ 528 if (!DEBUG(module)) (void)0; \
529 else debug_printf(fmt, arg1, arg2, arg3, arg4) 529 else debug_printf(fmt, arg1, arg2, arg3, arg4)
530 530
531#define DEBUG5(module, fmt, arg1, arg2, arg3, arg4, arg5) \ 531#define DEBUG5(module, fmt, arg1, arg2, arg3, arg4, arg5) \
532 if (!DEBUG(module)) (void)0; \ 532 if (!DEBUG(module)) (void)0; \
533 else debug_printf(fmt, arg1, arg2, arg3, arg4, arg5) 533 else debug_printf(fmt, arg1, arg2, arg3, arg4, arg5)
534 534
535typedef enum PrintVarsMode { 535typedef enum PrintVarsMode {
536 COMPAT_VARS = 1, 536 COMPAT_VARS = 1,
537 EXPAND_VARS 537 EXPAND_VARS
538} PrintVarsMode; 538} PrintVarsMode;
539 539
540/* Command line options */ 540/* Command line options */
541typedef struct CmdOpts { 541typedef struct CmdOpts {
542 /* -B: whether we are make compatible */ 542 /* -B: whether we are make compatible */
543 Boolean compatMake; 543 Boolean compatMake;
544 544
545 /* -d: debug control: There is one bit per module. It is up to the 545 /* -d: debug control: There is one bit per module. It is up to the
546 * module what debug information to print. */ 546 * module what debug information to print. */
547 DebugFlags debug; 547 DebugFlags debug;
548 548
549 /* -df: debug output is written here - default stderr */ 549 /* -df: debug output is written here - default stderr */
550 FILE *debug_file; 550 FILE *debug_file;
551 551
552 /* -dV: for the -V option, print unexpanded variable values */ 552 /* -dV: for the -V option, print unexpanded variable values */
553 Boolean debugVflag; 553 Boolean debugVflag;
554 554
555 /* -e: check environment variables before global variables */ 555 /* -e: check environment variables before global variables */
556 Boolean checkEnvFirst; 556 Boolean checkEnvFirst;
557 557
558 /* -f: the makefiles to read */ 558 /* -f: the makefiles to read */
559 StringList *makefiles; 559 StringList *makefiles;
560 560
561 /* -i: if true, ignore all errors from shell commands */ 561 /* -i: if true, ignore all errors from shell commands */
562 Boolean ignoreErrors; 562 Boolean ignoreErrors;
563 563
564 /* -j: the maximum number of jobs that can run in parallel; 564 /* -j: the maximum number of jobs that can run in parallel;
565 * this is coordinated with the submakes */ 565 * this is coordinated with the submakes */
566 int maxJobs; 566 int maxJobs;
567 567
568 /* -k: if true, continue on unaffected portions of the graph when an 568 /* -k: if true, continue on unaffected portions of the graph when an
569 * error occurs in one portion */ 569 * error occurs in one portion */
570 Boolean keepgoing; 570 Boolean keepgoing;
571 571
572 /* -N: execute no commands from the targets */ 572 /* -N: execute no commands from the targets */
573 Boolean noRecursiveExecute; 573 Boolean noRecursiveExecute;
574 574
575 /* -n: execute almost no commands from the targets */ 575 /* -n: execute almost no commands from the targets */
576 Boolean noExecute; 576 Boolean noExecute;
577 577
578 /* -q: if true, we aren't supposed to really make anything, just see if 578 /* -q: if true, we aren't supposed to really make anything, just see if
579 * the targets are out-of-date */ 579 * the targets are out-of-date */
580 Boolean queryFlag; 580 Boolean queryFlag;
581 581
582 /* -r: raw mode, without loading the builtin rules. */ 582 /* -r: raw mode, without loading the builtin rules. */
583 Boolean noBuiltins; 583 Boolean noBuiltins;
584 584
585 /* -s: don't echo the shell commands before executing them */ 585 /* -s: don't echo the shell commands before executing them */
586 Boolean beSilent; 586 Boolean beSilent;
587 587
588 /* -t: touch the targets if they are out-of-date, but don't actually 588 /* -t: touch the targets if they are out-of-date, but don't actually
589 * make them */ 589 * make them */
590 Boolean touchFlag; 590 Boolean touchFlag;
591 591
592 /* -[Vv]: print expanded or unexpanded selected variables */ 592 /* -[Vv]: print expanded or unexpanded selected variables */
593 PrintVarsMode printVars; 593 PrintVarsMode printVars;
594 /* -[Vv]: the variables to print */ 594 /* -[Vv]: the variables to print */
595 StringList *variables; 595 StringList *variables;
596 596
597 /* -W: if true, makefile parsing warnings are treated as errors */ 597 /* -W: if true, makefile parsing warnings are treated as errors */
598 Boolean parseWarnFatal; 598 Boolean parseWarnFatal;
599 599
600 /* -w: print Entering and Leaving for submakes */ 600 /* -w: print Entering and Leaving for submakes */
601 Boolean enterFlag; 601 Boolean enterFlag;
602 602
603 /* -X: if true, do not export variables set on the command line to the 603 /* -X: if true, do not export variables set on the command line to the
604 * environment. */ 604 * environment. */
605 Boolean varNoExportEnv; 605 Boolean varNoExportEnv;
606 606
607 /* The target names specified on the command line. 607 /* The target names specified on the command line.
608 * Used to resolve .if make(...) statements. */ 608 * Used to resolve .if make(...) statements. */
609 StringList *create; 609 StringList *create;
610 610
611} CmdOpts; 611} CmdOpts;
612 612
613extern CmdOpts opts; 613extern CmdOpts opts;
614 614
615#include "nonints.h" 615#include "nonints.h"
616 616
617void Make_TimeStamp(GNode *, GNode *); 617void Make_TimeStamp(GNode *, GNode *);
618Boolean Make_OODate(GNode *); 618Boolean Make_OODate(GNode *);
619void Make_ExpandUse(GNodeList *); 619void Make_ExpandUse(GNodeList *);
620time_t Make_Recheck(GNode *); 620time_t Make_Recheck(GNode *);
621void Make_HandleUse(GNode *, GNode *); 621void Make_HandleUse(GNode *, GNode *);
622void Make_Update(GNode *); 622void Make_Update(GNode *);
623void Make_DoAllVar(GNode *); 623void Make_DoAllVar(GNode *);
624Boolean Make_Run(GNodeList *); 624Boolean Make_Run(GNodeList *);
625int dieQuietly(GNode *, int); 625int dieQuietly(GNode *, int);
626void PrintOnError(GNode *, const char *); 626void PrintOnError(GNode *, const char *);
627void Main_ExportMAKEFLAGS(Boolean); 627void Main_ExportMAKEFLAGS(Boolean);
628Boolean Main_SetObjdir(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2); 628Boolean Main_SetObjdir(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
629int mkTempFile(const char *, char **); 629int mkTempFile(const char *, char **);
630int str2Lst_Append(StringList *, char *, const char *); 630int str2Lst_Append(StringList *, char *, const char *);
631void GNode_FprintDetails(FILE *, const char *, const GNode *, const char *); 631void GNode_FprintDetails(FILE *, const char *, const GNode *, const char *);
632Boolean NoExecute(GNode *gn); 632Boolean NoExecute(GNode *gn);
633 633
634/* See if the node was seen on the left-hand side of a dependency operator. */ 634/* See if the node was seen on the left-hand side of a dependency operator. */
635static MAKE_ATTR_UNUSED Boolean 635static MAKE_ATTR_UNUSED Boolean
636GNode_IsTarget(const GNode *gn) 636GNode_IsTarget(const GNode *gn)
637{ 637{
638 return (gn->type & OP_OPMASK) != 0; 638 return (gn->type & OP_OPMASK) != 0;
639} 639}
640 640
641static MAKE_ATTR_UNUSED const char * 641static MAKE_ATTR_UNUSED const char *
642GNode_Path(const GNode *gn) 642GNode_Path(const GNode *gn)
643{ 643{
644 return gn->path != NULL ? gn->path : gn->name; 644 return gn->path != NULL ? gn->path : gn->name;
645} 645}
646 646
647#ifdef __GNUC__ 647#ifdef __GNUC__
648#define UNCONST(ptr) ({ \ 648#define UNCONST(ptr) ({ \
649 union __unconst { \ 649 union __unconst { \
650 const void *__cp; \ 650 const void *__cp; \
651 void *__p; \ 651 void *__p; \
652 } __d; \ 652 } __d; \
653 __d.__cp = ptr, __d.__p; }) 653 __d.__cp = ptr, __d.__p; })
654#else 654#else
655#define UNCONST(ptr) (void *)(ptr) 655#define UNCONST(ptr) (void *)(ptr)
656#endif 656#endif
657 657
658/* At least GNU/Hurd systems lack hardcoded MAXPATHLEN/PATH_MAX */ 658/* At least GNU/Hurd systems lack hardcoded MAXPATHLEN/PATH_MAX */
659#include <limits.h> 659#include <limits.h>
660#ifndef MAXPATHLEN 660#ifndef MAXPATHLEN
661#define MAXPATHLEN 4096 661#define MAXPATHLEN 4096
662#endif 662#endif
663#ifndef PATH_MAX 663#ifndef PATH_MAX
664#define PATH_MAX MAXPATHLEN 664#define PATH_MAX MAXPATHLEN
665#endif 665#endif
666 666
667#if defined(SYSV) 667#if defined(SYSV)
668#define KILLPG(pid, sig) kill(-(pid), (sig)) 668#define KILLPG(pid, sig) kill(-(pid), (sig))
669#else 669#else
670#define KILLPG(pid, sig) killpg((pid), (sig)) 670#define KILLPG(pid, sig) killpg((pid), (sig))
671#endif 671#endif
672 672
673static inline MAKE_ATTR_UNUSED Boolean ch_isalnum(char ch) 673static inline MAKE_ATTR_UNUSED Boolean ch_isalnum(char ch)
674{ return isalnum((unsigned char)ch) != 0; } 674{ return isalnum((unsigned char)ch) != 0; }
675static inline MAKE_ATTR_UNUSED Boolean ch_isalpha(char ch) 675static inline MAKE_ATTR_UNUSED Boolean ch_isalpha(char ch)
676{ return isalpha((unsigned char)ch) != 0; } 676{ return isalpha((unsigned char)ch) != 0; }
677static inline MAKE_ATTR_UNUSED Boolean ch_isdigit(char ch) 677static inline MAKE_ATTR_UNUSED Boolean ch_isdigit(char ch)
678{ return isdigit((unsigned char)ch) != 0; } 678{ return isdigit((unsigned char)ch) != 0; }
679static inline MAKE_ATTR_UNUSED Boolean ch_isspace(char ch) 679static inline MAKE_ATTR_UNUSED Boolean ch_isspace(char ch)
680{ return isspace((unsigned char)ch) != 0; } 680{ return isspace((unsigned char)ch) != 0; }
681static inline MAKE_ATTR_UNUSED Boolean ch_isupper(char ch) 681static inline MAKE_ATTR_UNUSED Boolean ch_isupper(char ch)
682{ return isupper((unsigned char)ch) != 0; } 682{ return isupper((unsigned char)ch) != 0; }
683static inline MAKE_ATTR_UNUSED char ch_tolower(char ch) 683static inline MAKE_ATTR_UNUSED char ch_tolower(char ch)
684{ return (char)tolower((unsigned char)ch); } 684{ return (char)tolower((unsigned char)ch); }
685static inline MAKE_ATTR_UNUSED char ch_toupper(char ch) 685static inline MAKE_ATTR_UNUSED char ch_toupper(char ch)
686{ return (char)toupper((unsigned char)ch); } 686{ return (char)toupper((unsigned char)ch); }
687 687
688static inline MAKE_ATTR_UNUSED void 688static inline MAKE_ATTR_UNUSED void
689cpp_skip_whitespace(const char **pp) 689cpp_skip_whitespace(const char **pp)
690{ 690{
691 while (ch_isspace(**pp)) 691 while (ch_isspace(**pp))
692 (*pp)++; 692 (*pp)++;
693} 693}
694 694
695static inline MAKE_ATTR_UNUSED void 695static inline MAKE_ATTR_UNUSED void
696pp_skip_whitespace(char **pp) 696pp_skip_whitespace(char **pp)
697{ 697{
698 while (ch_isspace(**pp)) 698 while (ch_isspace(**pp))
699 (*pp)++; 699 (*pp)++;
700} 700}
701 701
702#ifdef MAKE_NATIVE 702#ifdef MAKE_NATIVE
703# include <sys/cdefs.h> 703# include <sys/cdefs.h>
704# ifndef lint 704# ifndef lint
705# define MAKE_RCSID(id) __RCSID(id) 705# define MAKE_RCSID(id) __RCSID(id)
706# endif 706# endif
707#else 707#else
708# define MAKE_RCSID(id) static volatile char rcsid[] = id 708# define MAKE_RCSID(id) static volatile char rcsid[] = id
709#endif 709#endif
710 710
711#endif /* MAKE_MAKE_H */ 711#endif /* MAKE_MAKE_H */