Sat Aug 29 10:41:13 2020 UTC ()
make(1): rename LstNode functions to match their type


(rillig)
diff -r1.122 -r1.123 src/usr.bin/make/dir.c
diff -r1.222 -r1.223 src/usr.bin/make/job.c
diff -r1.55 -r1.56 src/usr.bin/make/lst.c
diff -r1.56 -r1.57 src/usr.bin/make/lst.h
diff -r1.326 -r1.327 src/usr.bin/make/main.c
diff -r1.109 -r1.110 src/usr.bin/make/meta.c
diff -r1.130 -r1.131 src/usr.bin/make/suff.c

cvs diff -r1.122 -r1.123 src/usr.bin/make/dir.c (switch to unified diff)

--- src/usr.bin/make/dir.c 2020/08/29 10:12:06 1.122
+++ src/usr.bin/make/dir.c 2020/08/29 10:41:12 1.123
@@ -1,1798 +1,1798 @@ @@ -1,1798 +1,1798 @@
1/* $NetBSD: dir.c,v 1.122 2020/08/29 10:12:06 rillig Exp $ */ 1/* $NetBSD: dir.c,v 1.123 2020/08/29 10:41:12 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 4 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
5 * All rights reserved. 5 * 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) 1988, 1989 by Adam de Boor 36 * Copyright (c) 1988, 1989 by Adam de Boor
37 * Copyright (c) 1989 by Berkeley Softworks 37 * Copyright (c) 1989 by Berkeley Softworks
38 * All rights reserved. 38 * All rights reserved.
39 * 39 *
40 * This code is derived from software contributed to Berkeley by 40 * This code is derived from software contributed to Berkeley by
41 * Adam de Boor. 41 * Adam de Boor.
42 * 42 *
43 * Redistribution and use in source and binary forms, with or without 43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions 44 * modification, are permitted provided that the following conditions
45 * are met: 45 * are met:
46 * 1. Redistributions of source code must retain the above copyright 46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer. 47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright 48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the 49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution. 50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software 51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement: 52 * must display the following acknowledgement:
53 * This product includes software developed by the University of 53 * This product includes software developed by the University of
54 * California, Berkeley and its contributors. 54 * California, Berkeley and its contributors.
55 * 4. Neither the name of the University nor the names of its contributors 55 * 4. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software 56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission. 57 * without specific prior written permission.
58 * 58 *
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * SUCH DAMAGE. 69 * SUCH DAMAGE.
70 */ 70 */
71 71
72#ifndef MAKE_NATIVE 72#ifndef MAKE_NATIVE
73static char rcsid[] = "$NetBSD: dir.c,v 1.122 2020/08/29 10:12:06 rillig Exp $"; 73static char rcsid[] = "$NetBSD: dir.c,v 1.123 2020/08/29 10:41:12 rillig Exp $";
74#else 74#else
75#include <sys/cdefs.h> 75#include <sys/cdefs.h>
76#ifndef lint 76#ifndef lint
77#if 0 77#if 0
78static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94"; 78static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94";
79#else 79#else
80__RCSID("$NetBSD: dir.c,v 1.122 2020/08/29 10:12:06 rillig Exp $"); 80__RCSID("$NetBSD: dir.c,v 1.123 2020/08/29 10:41:12 rillig Exp $");
81#endif 81#endif
82#endif /* not lint */ 82#endif /* not lint */
83#endif 83#endif
84 84
85/*- 85/*-
86 * dir.c -- 86 * dir.c --
87 * Directory searching using wildcards and/or normal names... 87 * Directory searching using wildcards and/or normal names...
88 * Used both for source wildcarding in the Makefile and for finding 88 * Used both for source wildcarding in the Makefile and for finding
89 * implicit sources. 89 * implicit sources.
90 * 90 *
91 * The interface for this module is: 91 * The interface for this module is:
92 * Dir_Init Initialize the module. 92 * Dir_Init Initialize the module.
93 * 93 *
94 * Dir_InitCur Set the cur Path. 94 * Dir_InitCur Set the cur Path.
95 * 95 *
96 * Dir_InitDot Set the dot Path. 96 * Dir_InitDot Set the dot Path.
97 * 97 *
98 * Dir_End Cleanup the module. 98 * Dir_End Cleanup the module.
99 * 99 *
100 * Dir_SetPATH Set ${.PATH} to reflect state of dirSearchPath. 100 * Dir_SetPATH Set ${.PATH} to reflect state of dirSearchPath.
101 * 101 *
102 * Dir_HasWildcards Returns TRUE if the name given it needs to 102 * Dir_HasWildcards Returns TRUE if the name given it needs to
103 * be wildcard-expanded. 103 * be wildcard-expanded.
104 * 104 *
105 * Dir_Expand Given a pattern and a path, return a Lst of names 105 * Dir_Expand Given a pattern and a path, return a Lst of names
106 * which match the pattern on the search path. 106 * which match the pattern on the search path.
107 * 107 *
108 * Dir_FindFile Searches for a file on a given search path. 108 * Dir_FindFile Searches for a file on a given search path.
109 * If it exists, the entire path is returned. 109 * If it exists, the entire path is returned.
110 * Otherwise NULL is returned. 110 * Otherwise NULL is returned.
111 * 111 *
112 * Dir_FindHereOrAbove Search for a path in the current directory and 112 * Dir_FindHereOrAbove Search for a path in the current directory and
113 * then all the directories above it in turn until 113 * then all the directories above it in turn until
114 * the path is found or we reach the root ("/"). 114 * the path is found or we reach the root ("/").
115 * 115 *
116 * Dir_MTime Return the modification time of a node. The file 116 * Dir_MTime Return the modification time of a node. The file
117 * is searched for along the default search path. 117 * is searched for along the default search path.
118 * The path and mtime fields of the node are filled 118 * The path and mtime fields of the node are filled
119 * in. 119 * in.
120 * 120 *
121 * Dir_AddDir Add a directory to a search path. 121 * Dir_AddDir Add a directory to a search path.
122 * 122 *
123 * Dir_MakeFlags Given a search path and a command flag, create 123 * Dir_MakeFlags Given a search path and a command flag, create
124 * a string with each of the directories in the path 124 * a string with each of the directories in the path
125 * preceded by the command flag and all of them 125 * preceded by the command flag and all of them
126 * separated by a space. 126 * separated by a space.
127 * 127 *
128 * Dir_Destroy Destroy an element of a search path. Frees up all 128 * Dir_Destroy Destroy an element of a search path. Frees up all
129 * things that can be freed for the element as long 129 * things that can be freed for the element as long
130 * as the element is no longer referenced by any other 130 * as the element is no longer referenced by any other
131 * search path. 131 * search path.
132 * Dir_ClearPath Resets a search path to the empty list. 132 * Dir_ClearPath Resets a search path to the empty list.
133 * 133 *
134 * For debugging: 134 * For debugging:
135 * Dir_PrintDirectories Print stats about the directory cache. 135 * Dir_PrintDirectories Print stats about the directory cache.
136 */ 136 */
137 137
138#include <sys/types.h> 138#include <sys/types.h>
139#include <sys/stat.h> 139#include <sys/stat.h>
140 140
141#include <dirent.h> 141#include <dirent.h>
142#include <errno.h> 142#include <errno.h>
143#include <stdio.h> 143#include <stdio.h>
144 144
145#include "make.h" 145#include "make.h"
146#include "dir.h" 146#include "dir.h"
147#include "job.h" 147#include "job.h"
148 148
149 149
150#define DIR_DEBUG0(fmt) \ 150#define DIR_DEBUG0(fmt) \
151 if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt) 151 if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt)
152 152
153#define DIR_DEBUG1(fmt, arg1) \ 153#define DIR_DEBUG1(fmt, arg1) \
154 if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1) 154 if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1)
155 155
156#define DIR_DEBUG2(fmt, arg1, arg2) \ 156#define DIR_DEBUG2(fmt, arg1, arg2) \
157 if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1, arg2) 157 if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1, arg2)
158 158
159 159
160/* 160/*
161 * A search path consists of a Lst of Path structures. A Path structure 161 * A search path consists of a Lst of Path structures. A Path structure
162 * has in it the name of the directory and a hash table of all the files 162 * has in it the name of the directory and a hash table of all the files
163 * in the directory. This is used to cut down on the number of system 163 * in the directory. This is used to cut down on the number of system
164 * calls necessary to find implicit dependents and their like. Since 164 * calls necessary to find implicit dependents and their like. Since
165 * these searches are made before any actions are taken, we need not 165 * these searches are made before any actions are taken, we need not
166 * worry about the directory changing due to creation commands. If this 166 * worry about the directory changing due to creation commands. If this
167 * hampers the style of some makefiles, they must be changed. 167 * hampers the style of some makefiles, they must be changed.
168 * 168 *
169 * A list of all previously-read directories is kept in the 169 * A list of all previously-read directories is kept in the
170 * openDirectories Lst. This list is checked first before a directory 170 * openDirectories Lst. This list is checked first before a directory
171 * is opened. 171 * is opened.
172 * 172 *
173 * The need for the caching of whole directories is brought about by 173 * The need for the caching of whole directories is brought about by
174 * the multi-level transformation code in suff.c, which tends to search 174 * the multi-level transformation code in suff.c, which tends to search
175 * for far more files than regular make does. In the initial 175 * for far more files than regular make does. In the initial
176 * implementation, the amount of time spent performing "stat" calls was 176 * implementation, the amount of time spent performing "stat" calls was
177 * truly astronomical. The problem with hashing at the start is, 177 * truly astronomical. The problem with hashing at the start is,
178 * of course, that pmake doesn't then detect changes to these directories 178 * of course, that pmake doesn't then detect changes to these directories
179 * during the course of the make. Three possibilities suggest themselves: 179 * during the course of the make. Three possibilities suggest themselves:
180 * 180 *
181 * 1) just use stat to test for a file's existence. As mentioned 181 * 1) just use stat to test for a file's existence. As mentioned
182 * above, this is very inefficient due to the number of checks 182 * above, this is very inefficient due to the number of checks
183 * engendered by the multi-level transformation code. 183 * engendered by the multi-level transformation code.
184 * 2) use readdir() and company to search the directories, keeping 184 * 2) use readdir() and company to search the directories, keeping
185 * them open between checks. I have tried this and while it 185 * them open between checks. I have tried this and while it
186 * didn't slow down the process too much, it could severely 186 * didn't slow down the process too much, it could severely
187 * affect the amount of parallelism available as each directory 187 * affect the amount of parallelism available as each directory
188 * open would take another file descriptor out of play for 188 * open would take another file descriptor out of play for
189 * handling I/O for another job. Given that it is only recently 189 * handling I/O for another job. Given that it is only recently
190 * that UNIX OS's have taken to allowing more than 20 or 32 190 * that UNIX OS's have taken to allowing more than 20 or 32
191 * file descriptors for a process, this doesn't seem acceptable 191 * file descriptors for a process, this doesn't seem acceptable
192 * to me. 192 * to me.
193 * 3) record the mtime of the directory in the Path structure and 193 * 3) record the mtime of the directory in the Path structure and
194 * verify the directory hasn't changed since the contents were 194 * verify the directory hasn't changed since the contents were
195 * hashed. This will catch the creation or deletion of files, 195 * hashed. This will catch the creation or deletion of files,
196 * but not the updating of files. However, since it is the 196 * but not the updating of files. However, since it is the
197 * creation and deletion that is the problem, this could be 197 * creation and deletion that is the problem, this could be
198 * a good thing to do. Unfortunately, if the directory (say ".") 198 * a good thing to do. Unfortunately, if the directory (say ".")
199 * were fairly large and changed fairly frequently, the constant 199 * were fairly large and changed fairly frequently, the constant
200 * rehashing could seriously degrade performance. It might be 200 * rehashing could seriously degrade performance. It might be
201 * good in such cases to keep track of the number of rehashes 201 * good in such cases to keep track of the number of rehashes
202 * and if the number goes over a (small) limit, resort to using 202 * and if the number goes over a (small) limit, resort to using
203 * stat in its place. 203 * stat in its place.
204 * 204 *
205 * An additional thing to consider is that pmake is used primarily 205 * An additional thing to consider is that pmake is used primarily
206 * to create C programs and until recently pcc-based compilers refused 206 * to create C programs and until recently pcc-based compilers refused
207 * to allow you to specify where the resulting object file should be 207 * to allow you to specify where the resulting object file should be
208 * placed. This forced all objects to be created in the current 208 * placed. This forced all objects to be created in the current
209 * directory. This isn't meant as a full excuse, just an explanation of 209 * directory. This isn't meant as a full excuse, just an explanation of
210 * some of the reasons for the caching used here. 210 * some of the reasons for the caching used here.
211 * 211 *
212 * One more note: the location of a target's file is only performed 212 * One more note: the location of a target's file is only performed
213 * on the downward traversal of the graph and then only for terminal 213 * on the downward traversal of the graph and then only for terminal
214 * nodes in the graph. This could be construed as wrong in some cases, 214 * nodes in the graph. This could be construed as wrong in some cases,
215 * but prevents inadvertent modification of files when the "installed" 215 * but prevents inadvertent modification of files when the "installed"
216 * directory for a file is provided in the search path. 216 * directory for a file is provided in the search path.
217 * 217 *
218 * Another data structure maintained by this module is an mtime 218 * Another data structure maintained by this module is an mtime
219 * cache used when the searching of cached directories fails to find 219 * cache used when the searching of cached directories fails to find
220 * a file. In the past, Dir_FindFile would simply perform an access() 220 * a file. In the past, Dir_FindFile would simply perform an access()
221 * call in such a case to determine if the file could be found using 221 * call in such a case to determine if the file could be found using
222 * just the name given. When this hit, however, all that was gained 222 * just the name given. When this hit, however, all that was gained
223 * was the knowledge that the file existed. Given that an access() is 223 * was the knowledge that the file existed. Given that an access() is
224 * essentially a stat() without the copyout() call, and that the same 224 * essentially a stat() without the copyout() call, and that the same
225 * filesystem overhead would have to be incurred in Dir_MTime, it made 225 * filesystem overhead would have to be incurred in Dir_MTime, it made
226 * sense to replace the access() with a stat() and record the mtime 226 * sense to replace the access() with a stat() and record the mtime
227 * in a cache for when Dir_MTime was actually called. 227 * in a cache for when Dir_MTime was actually called.
228 */ 228 */
229 229
230Lst dirSearchPath; /* main search path */ 230Lst dirSearchPath; /* main search path */
231 231
232static Lst openDirectories; /* the list of all open directories */ 232static Lst openDirectories; /* the list of all open directories */
233 233
234/* 234/*
235 * Variables for gathering statistics on the efficiency of the hashing 235 * Variables for gathering statistics on the efficiency of the hashing
236 * mechanism. 236 * mechanism.
237 */ 237 */
238static int hits; /* Found in directory cache */ 238static int hits; /* Found in directory cache */
239static int misses; /* Sad, but not evil misses */ 239static int misses; /* Sad, but not evil misses */
240static int nearmisses; /* Found under search path */ 240static int nearmisses; /* Found under search path */
241static int bigmisses; /* Sought by itself */ 241static int bigmisses; /* Sought by itself */
242 242
243static Path *dot; /* contents of current directory */ 243static Path *dot; /* contents of current directory */
244static Path *cur; /* contents of current directory, if not dot */ 244static Path *cur; /* contents of current directory, if not dot */
245static Path *dotLast; /* a fake path entry indicating we need to 245static Path *dotLast; /* a fake path entry indicating we need to
246 * look for . last */ 246 * look for . last */
247 247
248/* Results of doing a last-resort stat in Dir_FindFile -- if we have to go to 248/* Results of doing a last-resort stat in Dir_FindFile -- if we have to go to
249 * the system to find the file, we might as well have its mtime on record. 249 * the system to find the file, we might as well have its mtime on record.
250 * 250 *
251 * XXX: If this is done way early, there's a chance other rules will have 251 * XXX: If this is done way early, there's a chance other rules will have
252 * already updated the file, in which case we'll update it again. Generally, 252 * already updated the file, in which case we'll update it again. Generally,
253 * there won't be two rules to update a single file, so this should be ok, 253 * there won't be two rules to update a single file, so this should be ok,
254 * but... */ 254 * but... */
255static Hash_Table mtimes; 255static Hash_Table mtimes;
256 256
257static Hash_Table lmtimes; /* same as mtimes but for lstat */ 257static Hash_Table lmtimes; /* same as mtimes but for lstat */
258 258
259static void DirExpandCurly(const char *, const char *, Lst, Lst); 259static void DirExpandCurly(const char *, const char *, Lst, Lst);
260static void DirExpandInt(const char *, Lst, Lst); 260static void DirExpandInt(const char *, Lst, Lst);
261static int DirPrintWord(void *, void *); 261static int DirPrintWord(void *, void *);
262static int DirPrintDir(void *, void *); 262static int DirPrintDir(void *, void *);
263static char *DirLookup(Path *, const char *, const char *, Boolean); 263static char *DirLookup(Path *, const char *, const char *, Boolean);
264static char *DirLookupSubdir(Path *, const char *); 264static char *DirLookupSubdir(Path *, const char *);
265static char *DirFindDot(Boolean, const char *, const char *); 265static char *DirFindDot(Boolean, const char *, const char *);
266static char *DirLookupAbs(Path *, const char *, const char *); 266static char *DirLookupAbs(Path *, const char *, const char *);
267 267
268 268
269/* 269/*
270 * We use stat(2) a lot, cache the results. 270 * We use stat(2) a lot, cache the results.
271 * mtime and mode are all we care about. 271 * mtime and mode are all we care about.
272 */ 272 */
273struct cache_st { 273struct cache_st {
274 time_t lmtime; /* lstat */ 274 time_t lmtime; /* lstat */
275 time_t mtime; /* stat */ 275 time_t mtime; /* stat */
276 mode_t mode; 276 mode_t mode;
277}; 277};
278 278
279/* minimize changes below */ 279/* minimize changes below */
280typedef enum { 280typedef enum {
281 CST_LSTAT = 0x01, /* call lstat(2) instead of stat(2) */ 281 CST_LSTAT = 0x01, /* call lstat(2) instead of stat(2) */
282 CST_UPDATE = 0x02 /* ignore existing cached entry */ 282 CST_UPDATE = 0x02 /* ignore existing cached entry */
283} CachedStatsFlags; 283} CachedStatsFlags;
284 284
285/* Returns 0 and the result of stat(2) or lstat(2) in *st, or -1 on error. 285/* Returns 0 and the result of stat(2) or lstat(2) in *st, or -1 on error.
286 * Only st->st_mode and st->st_mtime are filled. */ 286 * Only st->st_mode and st->st_mtime are filled. */
287static int 287static int
288cached_stats(Hash_Table *htp, const char *pathname, struct stat *st, 288cached_stats(Hash_Table *htp, const char *pathname, struct stat *st,
289 CachedStatsFlags flags) 289 CachedStatsFlags flags)
290{ 290{
291 Hash_Entry *entry; 291 Hash_Entry *entry;
292 struct cache_st *cst; 292 struct cache_st *cst;
293 int rc; 293 int rc;
294 294
295 if (!pathname || !pathname[0]) 295 if (!pathname || !pathname[0])
296 return -1; 296 return -1;
297 297
298 entry = Hash_FindEntry(htp, pathname); 298 entry = Hash_FindEntry(htp, pathname);
299 299
300 if (entry && !(flags & CST_UPDATE)) { 300 if (entry && !(flags & CST_UPDATE)) {
301 cst = entry->clientPtr; 301 cst = entry->clientPtr;
302 302
303 memset(st, 0, sizeof(*st)); 303 memset(st, 0, sizeof(*st));
304 st->st_mode = cst->mode; 304 st->st_mode = cst->mode;
305 st->st_mtime = (flags & CST_LSTAT) ? cst->lmtime : cst->mtime; 305 st->st_mtime = (flags & CST_LSTAT) ? cst->lmtime : cst->mtime;
306 if (st->st_mtime) { 306 if (st->st_mtime) {
307 DIR_DEBUG2("Using cached time %s for %s\n", 307 DIR_DEBUG2("Using cached time %s for %s\n",
308 Targ_FmtTime(st->st_mtime), pathname); 308 Targ_FmtTime(st->st_mtime), pathname);
309 return 0; 309 return 0;
310 } 310 }
311 } 311 }
312 312
313 rc = (flags & CST_LSTAT) ? lstat(pathname, st) : stat(pathname, st); 313 rc = (flags & CST_LSTAT) ? lstat(pathname, st) : stat(pathname, st);
314 if (rc == -1) 314 if (rc == -1)
315 return -1; 315 return -1;
316 316
317 if (st->st_mtime == 0) 317 if (st->st_mtime == 0)
318 st->st_mtime = 1; /* avoid confusion with missing file */ 318 st->st_mtime = 1; /* avoid confusion with missing file */
319 319
320 if (!entry) 320 if (!entry)
321 entry = Hash_CreateEntry(htp, pathname, NULL); 321 entry = Hash_CreateEntry(htp, pathname, NULL);
322 if (!entry->clientPtr) { 322 if (!entry->clientPtr) {
323 entry->clientPtr = bmake_malloc(sizeof(*cst)); 323 entry->clientPtr = bmake_malloc(sizeof(*cst));
324 memset(entry->clientPtr, 0, sizeof(*cst)); 324 memset(entry->clientPtr, 0, sizeof(*cst));
325 } 325 }
326 cst = entry->clientPtr; 326 cst = entry->clientPtr;
327 if (flags & CST_LSTAT) { 327 if (flags & CST_LSTAT) {
328 cst->lmtime = st->st_mtime; 328 cst->lmtime = st->st_mtime;
329 } else { 329 } else {
330 cst->mtime = st->st_mtime; 330 cst->mtime = st->st_mtime;
331 } 331 }
332 cst->mode = st->st_mode; 332 cst->mode = st->st_mode;
333 DIR_DEBUG2(" Caching %s for %s\n", 333 DIR_DEBUG2(" Caching %s for %s\n",
334 Targ_FmtTime(st->st_mtime), pathname); 334 Targ_FmtTime(st->st_mtime), pathname);
335 335
336 return 0; 336 return 0;
337} 337}
338 338
339int 339int
340cached_stat(const char *pathname, void *st) 340cached_stat(const char *pathname, void *st)
341{ 341{
342 return cached_stats(&mtimes, pathname, st, 0); 342 return cached_stats(&mtimes, pathname, st, 0);
343} 343}
344 344
345int 345int
346cached_lstat(const char *pathname, void *st) 346cached_lstat(const char *pathname, void *st)
347{ 347{
348 return cached_stats(&lmtimes, pathname, st, CST_LSTAT); 348 return cached_stats(&lmtimes, pathname, st, CST_LSTAT);
349} 349}
350 350
351/* Initialize things for this module. */ 351/* Initialize things for this module. */
352void 352void
353Dir_Init(void) 353Dir_Init(void)
354{ 354{
355 dirSearchPath = Lst_Init(); 355 dirSearchPath = Lst_Init();
356 openDirectories = Lst_Init(); 356 openDirectories = Lst_Init();
357 Hash_InitTable(&mtimes, 0); 357 Hash_InitTable(&mtimes, 0);
358 Hash_InitTable(&lmtimes, 0); 358 Hash_InitTable(&lmtimes, 0);
359} 359}
360 360
361void 361void
362Dir_InitDir(const char *cdname) 362Dir_InitDir(const char *cdname)
363{ 363{
364 Dir_InitCur(cdname); 364 Dir_InitCur(cdname);
365 365
366 dotLast = bmake_malloc(sizeof(Path)); 366 dotLast = bmake_malloc(sizeof(Path));
367 dotLast->refCount = 1; 367 dotLast->refCount = 1;
368 dotLast->hits = 0; 368 dotLast->hits = 0;
369 dotLast->name = bmake_strdup(".DOTLAST"); 369 dotLast->name = bmake_strdup(".DOTLAST");
370 Hash_InitTable(&dotLast->files, -1); 370 Hash_InitTable(&dotLast->files, -1);
371} 371}
372 372
373/* 373/*
374 * Called by Dir_InitDir and whenever .CURDIR is assigned to. 374 * Called by Dir_InitDir and whenever .CURDIR is assigned to.
375 */ 375 */
376void 376void
377Dir_InitCur(const char *cdname) 377Dir_InitCur(const char *cdname)
378{ 378{
379 Path *p; 379 Path *p;
380 380
381 if (cdname != NULL) { 381 if (cdname != NULL) {
382 /* 382 /*
383 * Our build directory is not the same as our source directory. 383 * Our build directory is not the same as our source directory.
384 * Keep this one around too. 384 * Keep this one around too.
385 */ 385 */
386 if ((p = Dir_AddDir(NULL, cdname))) { 386 if ((p = Dir_AddDir(NULL, cdname))) {
387 p->refCount += 1; 387 p->refCount += 1;
388 if (cur && cur != p) { 388 if (cur && cur != p) {
389 /* 389 /*
390 * We've been here before, cleanup. 390 * We've been here before, cleanup.
391 */ 391 */
392 cur->refCount -= 1; 392 cur->refCount -= 1;
393 Dir_Destroy(cur); 393 Dir_Destroy(cur);
394 } 394 }
395 cur = p; 395 cur = p;
396 } 396 }
397 } 397 }
398} 398}
399 399
400/*- 400/*-
401 *----------------------------------------------------------------------- 401 *-----------------------------------------------------------------------
402 * Dir_InitDot -- 402 * Dir_InitDot --
403 * (re)initialize "dot" (current/object directory) path hash 403 * (re)initialize "dot" (current/object directory) path hash
404 * 404 *
405 * Results: 405 * Results:
406 * none 406 * none
407 * 407 *
408 * Side Effects: 408 * Side Effects:
409 * some directories may be opened. 409 * some directories may be opened.
410 *----------------------------------------------------------------------- 410 *-----------------------------------------------------------------------
411 */ 411 */
412void 412void
413Dir_InitDot(void) 413Dir_InitDot(void)
414{ 414{
415 if (dot != NULL) { 415 if (dot != NULL) {
416 LstNode ln; 416 LstNode ln;
417 417
418 /* Remove old entry from openDirectories, but do not destroy. */ 418 /* Remove old entry from openDirectories, but do not destroy. */
419 ln = Lst_Member(openDirectories, dot); 419 ln = Lst_Member(openDirectories, dot);
420 Lst_Remove(openDirectories, ln); 420 Lst_Remove(openDirectories, ln);
421 } 421 }
422 422
423 dot = Dir_AddDir(NULL, "."); 423 dot = Dir_AddDir(NULL, ".");
424 424
425 if (dot == NULL) { 425 if (dot == NULL) {
426 Error("Cannot open `.' (%s)", strerror(errno)); 426 Error("Cannot open `.' (%s)", strerror(errno));
427 exit(1); 427 exit(1);
428 } 428 }
429 429
430 /* 430 /*
431 * We always need to have dot around, so we increment its reference count 431 * We always need to have dot around, so we increment its reference count
432 * to make sure it's not destroyed. 432 * to make sure it's not destroyed.
433 */ 433 */
434 dot->refCount += 1; 434 dot->refCount += 1;
435 Dir_SetPATH(); /* initialize */ 435 Dir_SetPATH(); /* initialize */
436} 436}
437 437
438/*- 438/*-
439 *----------------------------------------------------------------------- 439 *-----------------------------------------------------------------------
440 * Dir_End -- 440 * Dir_End --
441 * cleanup things for this module 441 * cleanup things for this module
442 * 442 *
443 * Results: 443 * Results:
444 * none 444 * none
445 * 445 *
446 * Side Effects: 446 * Side Effects:
447 * none 447 * none
448 *----------------------------------------------------------------------- 448 *-----------------------------------------------------------------------
449 */ 449 */
450void 450void
451Dir_End(void) 451Dir_End(void)
452{ 452{
453#ifdef CLEANUP 453#ifdef CLEANUP
454 if (cur) { 454 if (cur) {
455 cur->refCount -= 1; 455 cur->refCount -= 1;
456 Dir_Destroy(cur); 456 Dir_Destroy(cur);
457 } 457 }
458 dot->refCount -= 1; 458 dot->refCount -= 1;
459 dotLast->refCount -= 1; 459 dotLast->refCount -= 1;
460 Dir_Destroy(dotLast); 460 Dir_Destroy(dotLast);
461 Dir_Destroy(dot); 461 Dir_Destroy(dot);
462 Dir_ClearPath(dirSearchPath); 462 Dir_ClearPath(dirSearchPath);
463 Lst_Free(dirSearchPath); 463 Lst_Free(dirSearchPath);
464 Dir_ClearPath(openDirectories); 464 Dir_ClearPath(openDirectories);
465 Lst_Free(openDirectories); 465 Lst_Free(openDirectories);
466 Hash_DeleteTable(&mtimes); 466 Hash_DeleteTable(&mtimes);
467#endif 467#endif
468} 468}
469 469
470/* 470/*
471 * We want ${.PATH} to indicate the order in which we will actually 471 * We want ${.PATH} to indicate the order in which we will actually
472 * search, so we rebuild it after any .PATH: target. 472 * search, so we rebuild it after any .PATH: target.
473 * This is the simplest way to deal with the effect of .DOTLAST. 473 * This is the simplest way to deal with the effect of .DOTLAST.
474 */ 474 */
475void 475void
476Dir_SetPATH(void) 476Dir_SetPATH(void)
477{ 477{
478 LstNode ln; /* a list element */ 478 LstNode ln; /* a list element */
479 Path *p; 479 Path *p;
480 Boolean hasLastDot = FALSE; /* true if we should search dot last */ 480 Boolean hasLastDot = FALSE; /* true if we should search dot last */
481 481
482 Var_Delete(".PATH", VAR_GLOBAL); 482 Var_Delete(".PATH", VAR_GLOBAL);
483 483
484 Lst_Open(dirSearchPath); 484 Lst_Open(dirSearchPath);
485 if ((ln = Lst_First(dirSearchPath)) != NULL) { 485 if ((ln = Lst_First(dirSearchPath)) != NULL) {
486 p = Lst_Datum(ln); 486 p = Lst_Datum(ln);
487 if (p == dotLast) { 487 if (p == dotLast) {
488 hasLastDot = TRUE; 488 hasLastDot = TRUE;
489 Var_Append(".PATH", dotLast->name, VAR_GLOBAL); 489 Var_Append(".PATH", dotLast->name, VAR_GLOBAL);
490 } 490 }
491 } 491 }
492 492
493 if (!hasLastDot) { 493 if (!hasLastDot) {
494 if (dot) 494 if (dot)
495 Var_Append(".PATH", dot->name, VAR_GLOBAL); 495 Var_Append(".PATH", dot->name, VAR_GLOBAL);
496 if (cur) 496 if (cur)
497 Var_Append(".PATH", cur->name, VAR_GLOBAL); 497 Var_Append(".PATH", cur->name, VAR_GLOBAL);
498 } 498 }
499 499
500 while ((ln = Lst_Next(dirSearchPath)) != NULL) { 500 while ((ln = Lst_Next(dirSearchPath)) != NULL) {
501 p = Lst_Datum(ln); 501 p = Lst_Datum(ln);
502 if (p == dotLast) 502 if (p == dotLast)
503 continue; 503 continue;
504 if (p == dot && hasLastDot) 504 if (p == dot && hasLastDot)
505 continue; 505 continue;
506 Var_Append(".PATH", p->name, VAR_GLOBAL); 506 Var_Append(".PATH", p->name, VAR_GLOBAL);
507 } 507 }
508 508
509 if (hasLastDot) { 509 if (hasLastDot) {
510 if (dot) 510 if (dot)
511 Var_Append(".PATH", dot->name, VAR_GLOBAL); 511 Var_Append(".PATH", dot->name, VAR_GLOBAL);
512 if (cur) 512 if (cur)
513 Var_Append(".PATH", cur->name, VAR_GLOBAL); 513 Var_Append(".PATH", cur->name, VAR_GLOBAL);
514 } 514 }
515 Lst_Close(dirSearchPath); 515 Lst_Close(dirSearchPath);
516} 516}
517 517
518/* See if the Path structure describes the same directory as the 518/* See if the Path structure describes the same directory as the
519 * given one by comparing their names. Called from Dir_AddDir via 519 * given one by comparing their names. Called from Dir_AddDir via
520 * Lst_Find when searching the list of open directories. */ 520 * Lst_Find when searching the list of open directories. */
521static Boolean 521static Boolean
522DirFindName(const void *p, const void *desiredName) 522DirFindName(const void *p, const void *desiredName)
523{ 523{
524 return strcmp(((const Path *)p)->name, desiredName) == 0; 524 return strcmp(((const Path *)p)->name, desiredName) == 0;
525} 525}
526 526
527/*- 527/*-
528 *----------------------------------------------------------------------- 528 *-----------------------------------------------------------------------
529 * Dir_HasWildcards -- 529 * Dir_HasWildcards --
530 * see if the given name has any wildcard characters in it 530 * see if the given name has any wildcard characters in it
531 * be careful not to expand unmatching brackets or braces. 531 * be careful not to expand unmatching brackets or braces.
532 * XXX: This code is not 100% correct. ([^]] fails etc.) 532 * XXX: This code is not 100% correct. ([^]] fails etc.)
533 * I really don't think that make(1) should be expanding 533 * I really don't think that make(1) should be expanding
534 * patterns, because then you have to set a mechanism for 534 * patterns, because then you have to set a mechanism for
535 * escaping the expansion! 535 * escaping the expansion!
536 * 536 *
537 * Input: 537 * Input:
538 * name name to check 538 * name name to check
539 * 539 *
540 * Results: 540 * Results:
541 * returns TRUE if the word should be expanded, FALSE otherwise 541 * returns TRUE if the word should be expanded, FALSE otherwise
542 * 542 *
543 * Side Effects: 543 * Side Effects:
544 * none 544 * none
545 *----------------------------------------------------------------------- 545 *-----------------------------------------------------------------------
546 */ 546 */
547Boolean 547Boolean
548Dir_HasWildcards(char *name) 548Dir_HasWildcards(char *name)
549{ 549{
550 char *cp; 550 char *cp;
551 int wild = 0, brace = 0, bracket = 0; 551 int wild = 0, brace = 0, bracket = 0;
552 552
553 for (cp = name; *cp; cp++) { 553 for (cp = name; *cp; cp++) {
554 switch (*cp) { 554 switch (*cp) {
555 case '{': 555 case '{':
556 brace++; 556 brace++;
557 wild = 1; 557 wild = 1;
558 break; 558 break;
559 case '}': 559 case '}':
560 brace--; 560 brace--;
561 break; 561 break;
562 case '[': 562 case '[':
563 bracket++; 563 bracket++;
564 wild = 1; 564 wild = 1;
565 break; 565 break;
566 case ']': 566 case ']':
567 bracket--; 567 bracket--;
568 break; 568 break;
569 case '?': 569 case '?':
570 case '*': 570 case '*':
571 wild = 1; 571 wild = 1;
572 break; 572 break;
573 default: 573 default:
574 break; 574 break;
575 } 575 }
576 } 576 }
577 return wild && bracket == 0 && brace == 0; 577 return wild && bracket == 0 && brace == 0;
578} 578}
579 579
580/*- 580/*-
581 *----------------------------------------------------------------------- 581 *-----------------------------------------------------------------------
582 * DirMatchFiles -- 582 * DirMatchFiles --
583 * Given a pattern and a Path structure, see if any files 583 * Given a pattern and a Path structure, see if any files
584 * match the pattern and add their names to the 'expansions' list if 584 * match the pattern and add their names to the 'expansions' list if
585 * any do. This is incomplete -- it doesn't take care of patterns like 585 * any do. This is incomplete -- it doesn't take care of patterns like
586 * src / *src / *.c properly (just *.c on any of the directories), but it 586 * src / *src / *.c properly (just *.c on any of the directories), but it
587 * will do for now. 587 * will do for now.
588 * 588 *
589 * Input: 589 * Input:
590 * pattern Pattern to look for 590 * pattern Pattern to look for
591 * p Directory to search 591 * p Directory to search
592 * expansion Place to store the results 592 * expansion Place to store the results
593 * 593 *
594 * Side Effects: 594 * Side Effects:
595 * File names are added to the expansions lst. The directory will be 595 * File names are added to the expansions lst. The directory will be
596 * fully hashed when this is done. 596 * fully hashed when this is done.
597 *----------------------------------------------------------------------- 597 *-----------------------------------------------------------------------
598 */ 598 */
599static void 599static void
600DirMatchFiles(const char *pattern, Path *p, Lst expansions) 600DirMatchFiles(const char *pattern, Path *p, Lst expansions)
601{ 601{
602 Hash_Search search; /* Index into the directory's table */ 602 Hash_Search search; /* Index into the directory's table */
603 Hash_Entry *entry; /* Current entry in the table */ 603 Hash_Entry *entry; /* Current entry in the table */
604 Boolean isDot; /* TRUE if the directory being searched is . */ 604 Boolean isDot; /* TRUE if the directory being searched is . */
605 605
606 isDot = (*p->name == '.' && p->name[1] == '\0'); 606 isDot = (*p->name == '.' && p->name[1] == '\0');
607 607
608 for (entry = Hash_EnumFirst(&p->files, &search); 608 for (entry = Hash_EnumFirst(&p->files, &search);
609 entry != NULL; 609 entry != NULL;
610 entry = Hash_EnumNext(&search)) 610 entry = Hash_EnumNext(&search))
611 { 611 {
612 /* 612 /*
613 * See if the file matches the given pattern. Note we follow the UNIX 613 * See if the file matches the given pattern. Note we follow the UNIX
614 * convention that dot files will only be found if the pattern 614 * convention that dot files will only be found if the pattern
615 * begins with a dot (note also that as a side effect of the hashing 615 * begins with a dot (note also that as a side effect of the hashing
616 * scheme, .* won't match . or .. since they aren't hashed). 616 * scheme, .* won't match . or .. since they aren't hashed).
617 */ 617 */
618 if (Str_Match(entry->name, pattern) && 618 if (Str_Match(entry->name, pattern) &&
619 ((entry->name[0] != '.') || 619 ((entry->name[0] != '.') ||
620 (pattern[0] == '.'))) 620 (pattern[0] == '.')))
621 { 621 {
622 Lst_Append(expansions, 622 Lst_Append(expansions,
623 (isDot ? bmake_strdup(entry->name) : 623 (isDot ? bmake_strdup(entry->name) :
624 str_concat3(p->name, "/", entry->name))); 624 str_concat3(p->name, "/", entry->name)));
625 } 625 }
626 } 626 }
627} 627}
628 628
629/* Find the next closing brace in the string, taking nested braces into 629/* Find the next closing brace in the string, taking nested braces into
630 * account. */ 630 * account. */
631static const char * 631static const char *
632closing_brace(const char *p) 632closing_brace(const char *p)
633{ 633{
634 int nest = 0; 634 int nest = 0;
635 while (*p != '\0') { 635 while (*p != '\0') {
636 if (*p == '}' && nest == 0) 636 if (*p == '}' && nest == 0)
637 break; 637 break;
638 if (*p == '{') 638 if (*p == '{')
639 nest++; 639 nest++;
640 if (*p == '}') 640 if (*p == '}')
641 nest--; 641 nest--;
642 p++; 642 p++;
643 } 643 }
644 return p; 644 return p;
645} 645}
646 646
647/* Find the next closing brace or comma in the string, taking nested braces 647/* Find the next closing brace or comma in the string, taking nested braces
648 * into account. */ 648 * into account. */
649static const char * 649static const char *
650separator_comma(const char *p) 650separator_comma(const char *p)
651{ 651{
652 int nest = 0; 652 int nest = 0;
653 while (*p != '\0') { 653 while (*p != '\0') {
654 if ((*p == '}' || *p == ',') && nest == 0) 654 if ((*p == '}' || *p == ',') && nest == 0)
655 break; 655 break;
656 if (*p == '{') 656 if (*p == '{')
657 nest++; 657 nest++;
658 if (*p == '}') 658 if (*p == '}')
659 nest--; 659 nest--;
660 p++; 660 p++;
661 } 661 }
662 return p; 662 return p;
663} 663}
664 664
665static Boolean 665static Boolean
666contains_wildcard(const char *p) 666contains_wildcard(const char *p)
667{ 667{
668 for (; *p != '\0'; p++) { 668 for (; *p != '\0'; p++) {
669 switch (*p) { 669 switch (*p) {
670 case '*': 670 case '*':
671 case '?': 671 case '?':
672 case '{': 672 case '{':
673 case '[': 673 case '[':
674 return TRUE; 674 return TRUE;
675 } 675 }
676 } 676 }
677 return FALSE; 677 return FALSE;
678} 678}
679 679
680static char * 680static char *
681concat3(const char *a, size_t a_len, const char *b, size_t b_len, 681concat3(const char *a, size_t a_len, const char *b, size_t b_len,
682 const char *c, size_t c_len) 682 const char *c, size_t c_len)
683{ 683{
684 size_t s_len = a_len + b_len + c_len; 684 size_t s_len = a_len + b_len + c_len;
685 char *s = bmake_malloc(s_len + 1); 685 char *s = bmake_malloc(s_len + 1);
686 memcpy(s, a, a_len); 686 memcpy(s, a, a_len);
687 memcpy(s + a_len, b, b_len); 687 memcpy(s + a_len, b, b_len);
688 memcpy(s + a_len + b_len, c, c_len); 688 memcpy(s + a_len + b_len, c, c_len);
689 s[s_len] = '\0'; 689 s[s_len] = '\0';
690 return s; 690 return s;
691} 691}
692 692
693/*- 693/*-
694 *----------------------------------------------------------------------- 694 *-----------------------------------------------------------------------
695 * DirExpandCurly -- 695 * DirExpandCurly --
696 * Expand curly braces like the C shell. Does this recursively. 696 * Expand curly braces like the C shell. Does this recursively.
697 * Note the special case: if after the piece of the curly brace is 697 * Note the special case: if after the piece of the curly brace is
698 * done there are no wildcard characters in the result, the result is 698 * done there are no wildcard characters in the result, the result is
699 * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE. 699 * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE.
700 * 700 *
701 * Input: 701 * Input:
702 * word Entire word to expand 702 * word Entire word to expand
703 * brace First curly brace in it 703 * brace First curly brace in it
704 * path Search path to use 704 * path Search path to use
705 * expansions Place to store the expansions 705 * expansions Place to store the expansions
706 * 706 *
707 * Results: 707 * Results:
708 * None. 708 * None.
709 * 709 *
710 * Side Effects: 710 * Side Effects:
711 * The given list is filled with the expansions... 711 * The given list is filled with the expansions...
712 * 712 *
713 *----------------------------------------------------------------------- 713 *-----------------------------------------------------------------------
714 */ 714 */
715static void 715static void
716DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions) 716DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions)
717{ 717{
718 const char *prefix, *middle, *piece, *middle_end, *suffix; 718 const char *prefix, *middle, *piece, *middle_end, *suffix;
719 size_t prefix_len, suffix_len; 719 size_t prefix_len, suffix_len;
720 720
721 /* Split the word into prefix '{' middle '}' suffix. */ 721 /* Split the word into prefix '{' middle '}' suffix. */
722 722
723 middle = brace + 1; 723 middle = brace + 1;
724 middle_end = closing_brace(middle); 724 middle_end = closing_brace(middle);
725 if (*middle_end == '\0') { 725 if (*middle_end == '\0') {
726 Error("Unterminated {} clause \"%s\"", middle); 726 Error("Unterminated {} clause \"%s\"", middle);
727 return; 727 return;
728 } 728 }
729 729
730 prefix = word; 730 prefix = word;
731 prefix_len = (size_t)(brace - prefix); 731 prefix_len = (size_t)(brace - prefix);
732 suffix = middle_end + 1; 732 suffix = middle_end + 1;
733 suffix_len = strlen(suffix); 733 suffix_len = strlen(suffix);
734 734
735 /* Split the middle into pieces, separated by commas. */ 735 /* Split the middle into pieces, separated by commas. */
736 736
737 piece = middle; 737 piece = middle;
738 while (piece < middle_end + 1) { 738 while (piece < middle_end + 1) {
739 const char *piece_end = separator_comma(piece); 739 const char *piece_end = separator_comma(piece);
740 size_t piece_len = (size_t)(piece_end - piece); 740 size_t piece_len = (size_t)(piece_end - piece);
741 741
742 char *file = concat3(prefix, prefix_len, piece, piece_len, 742 char *file = concat3(prefix, prefix_len, piece, piece_len,
743 suffix, suffix_len); 743 suffix, suffix_len);
744 744
745 if (contains_wildcard(file)) { 745 if (contains_wildcard(file)) {
746 Dir_Expand(file, path, expansions); 746 Dir_Expand(file, path, expansions);
747 free(file); 747 free(file);
748 } else { 748 } else {
749 Lst_Append(expansions, file); 749 Lst_Append(expansions, file);
750 } 750 }
751 751
752 piece = piece_end + 1; /* skip over the comma or closing brace */ 752 piece = piece_end + 1; /* skip over the comma or closing brace */
753 } 753 }
754} 754}
755 755
756 756
757/*- 757/*-
758 *----------------------------------------------------------------------- 758 *-----------------------------------------------------------------------
759 * DirExpandInt -- 759 * DirExpandInt --
760 * Internal expand routine. Passes through the directories in the 760 * Internal expand routine. Passes through the directories in the
761 * path one by one, calling DirMatchFiles for each. NOTE: This still 761 * path one by one, calling DirMatchFiles for each. NOTE: This still
762 * doesn't handle patterns in directories... 762 * doesn't handle patterns in directories...
763 * 763 *
764 * Input: 764 * Input:
765 * word Word to expand 765 * word Word to expand
766 * path Path on which to look 766 * path Path on which to look
767 * expansions Place to store the result 767 * expansions Place to store the result
768 * 768 *
769 * Results: 769 * Results:
770 * None. 770 * None.
771 * 771 *
772 * Side Effects: 772 * Side Effects:
773 * Things are added to the expansions list. 773 * Things are added to the expansions list.
774 * 774 *
775 *----------------------------------------------------------------------- 775 *-----------------------------------------------------------------------
776 */ 776 */
777static void 777static void
778DirExpandInt(const char *word, Lst path, Lst expansions) 778DirExpandInt(const char *word, Lst path, Lst expansions)
779{ 779{
780 LstNode ln; /* Current node */ 780 LstNode ln; /* Current node */
781 781
782 Lst_Open(path); 782 Lst_Open(path);
783 while ((ln = Lst_Next(path)) != NULL) { 783 while ((ln = Lst_Next(path)) != NULL) {
784 Path *p = Lst_Datum(ln); 784 Path *p = Lst_Datum(ln);
785 DirMatchFiles(word, p, expansions); 785 DirMatchFiles(word, p, expansions);
786 } 786 }
787 Lst_Close(path); 787 Lst_Close(path);
788} 788}
789 789
790/* Print a word in the list of expansions. 790/* Print a word in the list of expansions.
791 * Callback for Dir_Expand when DEBUG(DIR), via Lst_ForEach. */ 791 * Callback for Dir_Expand when DEBUG(DIR), via Lst_ForEach. */
792static int 792static int
793DirPrintWord(void *word, void *dummy MAKE_ATTR_UNUSED) 793DirPrintWord(void *word, void *dummy MAKE_ATTR_UNUSED)
794{ 794{
795 fprintf(debug_file, "%s ", (char *)word); 795 fprintf(debug_file, "%s ", (char *)word);
796 796
797 return 0; 797 return 0;
798} 798}
799 799
800/*- 800/*-
801 *----------------------------------------------------------------------- 801 *-----------------------------------------------------------------------
802 * Dir_Expand -- 802 * Dir_Expand --
803 * Expand the given word into a list of words by globbing it looking 803 * Expand the given word into a list of words by globbing it looking
804 * in the directories on the given search path. 804 * in the directories on the given search path.
805 * 805 *
806 * Input: 806 * Input:
807 * word the word to expand 807 * word the word to expand
808 * path the list of directories in which to find the 808 * path the list of directories in which to find the
809 * resulting files 809 * resulting files
810 * expansions the list on which to place the results 810 * expansions the list on which to place the results
811 * 811 *
812 * Results: 812 * Results:
813 * A list of words consisting of the files which exist along the search 813 * A list of words consisting of the files which exist along the search
814 * path matching the given pattern. 814 * path matching the given pattern.
815 * 815 *
816 * Side Effects: 816 * Side Effects:
817 * Directories may be opened. Who knows? 817 * Directories may be opened. Who knows?
818 * Undefined behavior if the word is really in read-only memory. 818 * Undefined behavior if the word is really in read-only memory.
819 *----------------------------------------------------------------------- 819 *-----------------------------------------------------------------------
820 */ 820 */
821void 821void
822Dir_Expand(const char *word, Lst path, Lst expansions) 822Dir_Expand(const char *word, Lst path, Lst expansions)
823{ 823{
824 const char *cp; 824 const char *cp;
825 825
826 assert(path != NULL); 826 assert(path != NULL);
827 assert(expansions != NULL); 827 assert(expansions != NULL);
828 828
829 DIR_DEBUG1("Expanding \"%s\"... ", word); 829 DIR_DEBUG1("Expanding \"%s\"... ", word);
830 830
831 cp = strchr(word, '{'); 831 cp = strchr(word, '{');
832 if (cp) { 832 if (cp) {
833 DirExpandCurly(word, cp, path, expansions); 833 DirExpandCurly(word, cp, path, expansions);
834 } else { 834 } else {
835 cp = strchr(word, '/'); 835 cp = strchr(word, '/');
836 if (cp) { 836 if (cp) {
837 /* 837 /*
838 * The thing has a directory component -- find the first wildcard 838 * The thing has a directory component -- find the first wildcard
839 * in the string. 839 * in the string.
840 */ 840 */
841 for (cp = word; *cp; cp++) { 841 for (cp = word; *cp; cp++) {
842 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') { 842 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') {
843 break; 843 break;
844 } 844 }
845 } 845 }
846 if (*cp == '{') { 846 if (*cp == '{') {
847 /* 847 /*
848 * This one will be fun. 848 * This one will be fun.
849 */ 849 */
850 DirExpandCurly(word, cp, path, expansions); 850 DirExpandCurly(word, cp, path, expansions);
851 return; 851 return;
852 } else if (*cp != '\0') { 852 } else if (*cp != '\0') {
853 /* 853 /*
854 * Back up to the start of the component 854 * Back up to the start of the component
855 */ 855 */
856 while (cp > word && *cp != '/') { 856 while (cp > word && *cp != '/') {
857 cp--; 857 cp--;
858 } 858 }
859 if (cp != word) { 859 if (cp != word) {
860 char sc; 860 char sc;
861 char *dirpath; 861 char *dirpath;
862 /* 862 /*
863 * If the glob isn't in the first component, try and find 863 * If the glob isn't in the first component, try and find
864 * all the components up to the one with a wildcard. 864 * all the components up to the one with a wildcard.
865 */ 865 */
866 sc = cp[1]; 866 sc = cp[1];
867 ((char *)UNCONST(cp))[1] = '\0'; 867 ((char *)UNCONST(cp))[1] = '\0';
868 dirpath = Dir_FindFile(word, path); 868 dirpath = Dir_FindFile(word, path);
869 ((char *)UNCONST(cp))[1] = sc; 869 ((char *)UNCONST(cp))[1] = sc;
870 /* 870 /*
871 * dirpath is null if can't find the leading component 871 * dirpath is null if can't find the leading component
872 * XXX: Dir_FindFile won't find internal components. 872 * XXX: Dir_FindFile won't find internal components.
873 * i.e. if the path contains ../Etc/Object and we're 873 * i.e. if the path contains ../Etc/Object and we're
874 * looking for Etc, it won't be found. Ah well. 874 * looking for Etc, it won't be found. Ah well.
875 * Probably not important. 875 * Probably not important.
876 */ 876 */
877 if (dirpath != NULL) { 877 if (dirpath != NULL) {
878 char *dp = &dirpath[strlen(dirpath) - 1]; 878 char *dp = &dirpath[strlen(dirpath) - 1];
879 if (*dp == '/') 879 if (*dp == '/')
880 *dp = '\0'; 880 *dp = '\0';
881 path = Lst_Init(); 881 path = Lst_Init();
882 (void)Dir_AddDir(path, dirpath); 882 (void)Dir_AddDir(path, dirpath);
883 DirExpandInt(cp + 1, path, expansions); 883 DirExpandInt(cp + 1, path, expansions);
884 Lst_Free(path); 884 Lst_Free(path);
885 } 885 }
886 } else { 886 } else {
887 /* 887 /*
888 * Start the search from the local directory 888 * Start the search from the local directory
889 */ 889 */
890 DirExpandInt(word, path, expansions); 890 DirExpandInt(word, path, expansions);
891 } 891 }
892 } else { 892 } else {
893 /* 893 /*
894 * Return the file -- this should never happen. 894 * Return the file -- this should never happen.
895 */ 895 */
896 DirExpandInt(word, path, expansions); 896 DirExpandInt(word, path, expansions);
897 } 897 }
898 } else { 898 } else {
899 /* 899 /*
900 * First the files in dot 900 * First the files in dot
901 */ 901 */
902 DirMatchFiles(word, dot, expansions); 902 DirMatchFiles(word, dot, expansions);
903 903
904 /* 904 /*
905 * Then the files in every other directory on the path. 905 * Then the files in every other directory on the path.
906 */ 906 */
907 DirExpandInt(word, path, expansions); 907 DirExpandInt(word, path, expansions);
908 } 908 }
909 } 909 }
910 if (DEBUG(DIR)) { 910 if (DEBUG(DIR)) {
911 Lst_ForEach(expansions, DirPrintWord, NULL); 911 Lst_ForEach(expansions, DirPrintWord, NULL);
912 fprintf(debug_file, "\n"); 912 fprintf(debug_file, "\n");
913 } 913 }
914} 914}
915 915
916/*- 916/*-
917 *----------------------------------------------------------------------- 917 *-----------------------------------------------------------------------
918 * DirLookup -- 918 * DirLookup --
919 * Find if the file with the given name exists in the given path. 919 * Find if the file with the given name exists in the given path.
920 * 920 *
921 * Results: 921 * Results:
922 * The path to the file or NULL. This path is guaranteed to be in a 922 * The path to the file or NULL. This path is guaranteed to be in a
923 * different part of memory than name and so may be safely free'd. 923 * different part of memory than name and so may be safely free'd.
924 * 924 *
925 * Side Effects: 925 * Side Effects:
926 * None. 926 * None.
927 *----------------------------------------------------------------------- 927 *-----------------------------------------------------------------------
928 */ 928 */
929static char * 929static char *
930DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp, 930DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp,
931 Boolean hasSlash MAKE_ATTR_UNUSED) 931 Boolean hasSlash MAKE_ATTR_UNUSED)
932{ 932{
933 char *file; /* the current filename to check */ 933 char *file; /* the current filename to check */
934 934
935 DIR_DEBUG1(" %s ...\n", p->name); 935 DIR_DEBUG1(" %s ...\n", p->name);
936 936
937 if (Hash_FindEntry(&p->files, cp) == NULL) 937 if (Hash_FindEntry(&p->files, cp) == NULL)
938 return NULL; 938 return NULL;
939 939
940 file = str_concat3(p->name, "/", cp); 940 file = str_concat3(p->name, "/", cp);
941 DIR_DEBUG1(" returning %s\n", file); 941 DIR_DEBUG1(" returning %s\n", file);
942 p->hits += 1; 942 p->hits += 1;
943 hits += 1; 943 hits += 1;
944 return file; 944 return file;
945} 945}
946 946
947 947
948/*- 948/*-
949 *----------------------------------------------------------------------- 949 *-----------------------------------------------------------------------
950 * DirLookupSubdir -- 950 * DirLookupSubdir --
951 * Find if the file with the given name exists in the given path. 951 * Find if the file with the given name exists in the given path.
952 * 952 *
953 * Results: 953 * Results:
954 * The path to the file or NULL. This path is guaranteed to be in a 954 * The path to the file or NULL. This path is guaranteed to be in a
955 * different part of memory than name and so may be safely free'd. 955 * different part of memory than name and so may be safely free'd.
956 * 956 *
957 * Side Effects: 957 * Side Effects:
958 * If the file is found, it is added in the modification times hash 958 * If the file is found, it is added in the modification times hash
959 * table. 959 * table.
960 *----------------------------------------------------------------------- 960 *-----------------------------------------------------------------------
961 */ 961 */
962static char * 962static char *
963DirLookupSubdir(Path *p, const char *name) 963DirLookupSubdir(Path *p, const char *name)
964{ 964{
965 struct stat stb; /* Buffer for stat, if necessary */ 965 struct stat stb; /* Buffer for stat, if necessary */
966 char *file; /* the current filename to check */ 966 char *file; /* the current filename to check */
967 967
968 if (p != dot) { 968 if (p != dot) {
969 file = str_concat3(p->name, "/", name); 969 file = str_concat3(p->name, "/", name);
970 } else { 970 } else {
971 /* 971 /*
972 * Checking in dot -- DON'T put a leading ./ on the thing. 972 * Checking in dot -- DON'T put a leading ./ on the thing.
973 */ 973 */
974 file = bmake_strdup(name); 974 file = bmake_strdup(name);
975 } 975 }
976 976
977 DIR_DEBUG1("checking %s ...\n", file); 977 DIR_DEBUG1("checking %s ...\n", file);
978 978
979 if (cached_stat(file, &stb) == 0) { 979 if (cached_stat(file, &stb) == 0) {
980 nearmisses += 1; 980 nearmisses += 1;
981 return file; 981 return file;
982 } 982 }
983 free(file); 983 free(file);
984 return NULL; 984 return NULL;
985} 985}
986 986
987/*- 987/*-
988 *----------------------------------------------------------------------- 988 *-----------------------------------------------------------------------
989 * DirLookupAbs -- 989 * DirLookupAbs --
990 * Find if the file with the given name exists in the given path. 990 * Find if the file with the given name exists in the given path.
991 * 991 *
992 * Results: 992 * Results:
993 * The path to the file, the empty string or NULL. If the file is 993 * The path to the file, the empty string or NULL. If the file is
994 * the empty string, the search should be terminated. 994 * the empty string, the search should be terminated.
995 * This path is guaranteed to be in a different part of memory 995 * This path is guaranteed to be in a different part of memory
996 * than name and so may be safely free'd. 996 * than name and so may be safely free'd.
997 * 997 *
998 * Side Effects: 998 * Side Effects:
999 * None. 999 * None.
1000 *----------------------------------------------------------------------- 1000 *-----------------------------------------------------------------------
1001 */ 1001 */
1002static char * 1002static char *
1003DirLookupAbs(Path *p, const char *name, const char *cp) 1003DirLookupAbs(Path *p, const char *name, const char *cp)
1004{ 1004{
1005 char *p1; /* pointer into p->name */ 1005 char *p1; /* pointer into p->name */
1006 const char *p2; /* pointer into name */ 1006 const char *p2; /* pointer into name */
1007 1007
1008 DIR_DEBUG1(" %s ...\n", p->name); 1008 DIR_DEBUG1(" %s ...\n", p->name);
1009 1009
1010 /* 1010 /*
1011 * If the file has a leading path component and that component 1011 * If the file has a leading path component and that component
1012 * exactly matches the entire name of the current search 1012 * exactly matches the entire name of the current search
1013 * directory, we can attempt another cache lookup. And if we don't 1013 * directory, we can attempt another cache lookup. And if we don't
1014 * have a hit, we can safely assume the file does not exist at all. 1014 * have a hit, we can safely assume the file does not exist at all.
1015 */ 1015 */
1016 for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) { 1016 for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
1017 continue; 1017 continue;
1018 } 1018 }
1019 if (*p1 != '\0' || p2 != cp - 1) { 1019 if (*p1 != '\0' || p2 != cp - 1) {
1020 return NULL; 1020 return NULL;
1021 } 1021 }
1022 1022
1023 if (Hash_FindEntry(&p->files, cp) == NULL) { 1023 if (Hash_FindEntry(&p->files, cp) == NULL) {
1024 DIR_DEBUG0(" must be here but isn't -- returning\n"); 1024 DIR_DEBUG0(" must be here but isn't -- returning\n");
1025 /* Return empty string: terminates search */ 1025 /* Return empty string: terminates search */
1026 return bmake_strdup(""); 1026 return bmake_strdup("");
1027 } 1027 }
1028 1028
1029 p->hits += 1; 1029 p->hits += 1;
1030 hits += 1; 1030 hits += 1;
1031 DIR_DEBUG1(" returning %s\n", name); 1031 DIR_DEBUG1(" returning %s\n", name);
1032 return bmake_strdup(name); 1032 return bmake_strdup(name);
1033} 1033}
1034 1034
1035/*- 1035/*-
1036 *----------------------------------------------------------------------- 1036 *-----------------------------------------------------------------------
1037 * DirFindDot -- 1037 * DirFindDot --
1038 * Find the file given on "." or curdir 1038 * Find the file given on "." or curdir
1039 * 1039 *
1040 * Results: 1040 * Results:
1041 * The path to the file or NULL. This path is guaranteed to be in a 1041 * The path to the file or NULL. This path is guaranteed to be in a
1042 * different part of memory than name and so may be safely free'd. 1042 * different part of memory than name and so may be safely free'd.
1043 * 1043 *
1044 * Side Effects: 1044 * Side Effects:
1045 * Hit counts change 1045 * Hit counts change
1046 *----------------------------------------------------------------------- 1046 *-----------------------------------------------------------------------
1047 */ 1047 */
1048static char * 1048static char *
1049DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp) 1049DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp)
1050{ 1050{
1051 1051
1052 if (Hash_FindEntry(&dot->files, cp) != NULL) { 1052 if (Hash_FindEntry(&dot->files, cp) != NULL) {
1053 DIR_DEBUG0(" in '.'\n"); 1053 DIR_DEBUG0(" in '.'\n");
1054 hits += 1; 1054 hits += 1;
1055 dot->hits += 1; 1055 dot->hits += 1;
1056 return bmake_strdup(name); 1056 return bmake_strdup(name);
1057 } 1057 }
1058 if (cur && Hash_FindEntry(&cur->files, cp) != NULL) { 1058 if (cur && Hash_FindEntry(&cur->files, cp) != NULL) {
1059 DIR_DEBUG1(" in ${.CURDIR} = %s\n", cur->name); 1059 DIR_DEBUG1(" in ${.CURDIR} = %s\n", cur->name);
1060 hits += 1; 1060 hits += 1;
1061 cur->hits += 1; 1061 cur->hits += 1;
1062 return str_concat3(cur->name, "/", cp); 1062 return str_concat3(cur->name, "/", cp);
1063 } 1063 }
1064 1064
1065 return NULL; 1065 return NULL;
1066} 1066}
1067 1067
1068/*- 1068/*-
1069 *----------------------------------------------------------------------- 1069 *-----------------------------------------------------------------------
1070 * Dir_FindFile -- 1070 * Dir_FindFile --
1071 * Find the file with the given name along the given search path. 1071 * Find the file with the given name along the given search path.
1072 * 1072 *
1073 * Input: 1073 * Input:
1074 * name the file to find 1074 * name the file to find
1075 * path the Lst of directories to search 1075 * path the Lst of directories to search
1076 * 1076 *
1077 * Results: 1077 * Results:
1078 * The path to the file or NULL. This path is guaranteed to be in a 1078 * The path to the file or NULL. This path is guaranteed to be in a
1079 * different part of memory than name and so may be safely free'd. 1079 * different part of memory than name and so may be safely free'd.
1080 * 1080 *
1081 * Side Effects: 1081 * Side Effects:
1082 * If the file is found in a directory which is not on the path 1082 * If the file is found in a directory which is not on the path
1083 * already (either 'name' is absolute or it is a relative path 1083 * already (either 'name' is absolute or it is a relative path
1084 * [ dir1/.../dirn/file ] which exists below one of the directories 1084 * [ dir1/.../dirn/file ] which exists below one of the directories
1085 * already on the search path), its directory is added to the end 1085 * already on the search path), its directory is added to the end
1086 * of the path on the assumption that there will be more files in 1086 * of the path on the assumption that there will be more files in
1087 * that directory later on. Sometimes this is true. Sometimes not. 1087 * that directory later on. Sometimes this is true. Sometimes not.
1088 *----------------------------------------------------------------------- 1088 *-----------------------------------------------------------------------
1089 */ 1089 */
1090char * 1090char *
1091Dir_FindFile(const char *name, Lst path) 1091Dir_FindFile(const char *name, Lst path)
1092{ 1092{
1093 LstNode ln; /* a list element */ 1093 LstNode ln; /* a list element */
1094 char *file; /* the current filename to check */ 1094 char *file; /* the current filename to check */
1095 Path *p; /* current path member */ 1095 Path *p; /* current path member */
1096 const char *cp; /* Terminal name of file */ 1096 const char *cp; /* Terminal name of file */
1097 Boolean hasLastDot = FALSE; /* true we should search dot last */ 1097 Boolean hasLastDot = FALSE; /* true we should search dot last */
1098 Boolean hasSlash; /* true if 'name' contains a / */ 1098 Boolean hasSlash; /* true if 'name' contains a / */
1099 struct stat stb; /* Buffer for stat, if necessary */ 1099 struct stat stb; /* Buffer for stat, if necessary */
1100 const char *trailing_dot = "."; 1100 const char *trailing_dot = ".";
1101 1101
1102 /* 1102 /*
1103 * Find the final component of the name and note whether it has a 1103 * Find the final component of the name and note whether it has a
1104 * slash in it (the name, I mean) 1104 * slash in it (the name, I mean)
1105 */ 1105 */
1106 cp = strrchr(name, '/'); 1106 cp = strrchr(name, '/');
1107 if (cp) { 1107 if (cp) {
1108 hasSlash = TRUE; 1108 hasSlash = TRUE;
1109 cp += 1; 1109 cp += 1;
1110 } else { 1110 } else {
1111 hasSlash = FALSE; 1111 hasSlash = FALSE;
1112 cp = name; 1112 cp = name;
1113 } 1113 }
1114 1114
1115 DIR_DEBUG1("Searching for %s ...", name); 1115 DIR_DEBUG1("Searching for %s ...", name);
1116 1116
1117 if (path == NULL) { 1117 if (path == NULL) {
1118 DIR_DEBUG0("couldn't open path, file not found\n"); 1118 DIR_DEBUG0("couldn't open path, file not found\n");
1119 misses += 1; 1119 misses += 1;
1120 return NULL; 1120 return NULL;
1121 } 1121 }
1122 1122
1123 Lst_Open(path); 1123 Lst_Open(path);
1124 if ((ln = Lst_First(path)) != NULL) { 1124 if ((ln = Lst_First(path)) != NULL) {
1125 p = Lst_Datum(ln); 1125 p = Lst_Datum(ln);
1126 if (p == dotLast) { 1126 if (p == dotLast) {
1127 hasLastDot = TRUE; 1127 hasLastDot = TRUE;
1128 DIR_DEBUG0("[dot last]..."); 1128 DIR_DEBUG0("[dot last]...");
1129 } 1129 }
1130 } 1130 }
1131 DIR_DEBUG0("\n"); 1131 DIR_DEBUG0("\n");
1132 1132
1133 /* 1133 /*
1134 * If there's no leading directory components or if the leading 1134 * If there's no leading directory components or if the leading
1135 * directory component is exactly `./', consult the cached contents 1135 * directory component is exactly `./', consult the cached contents
1136 * of each of the directories on the search path. 1136 * of each of the directories on the search path.
1137 */ 1137 */
1138 if (!hasSlash || (cp - name == 2 && *name == '.')) { 1138 if (!hasSlash || (cp - name == 2 && *name == '.')) {
1139 /* 1139 /*
1140 * We look through all the directories on the path seeking one which 1140 * We look through all the directories on the path seeking one which
1141 * contains the final component of the given name. If such a beast 1141 * contains the final component of the given name. If such a beast
1142 * is found, we concatenate the directory name and the final 1142 * is found, we concatenate the directory name and the final
1143 * component and return the resulting string. If we don't find any 1143 * component and return the resulting string. If we don't find any
1144 * such thing, we go on to phase two... 1144 * such thing, we go on to phase two...
1145 * 1145 *
1146 * No matter what, we always look for the file in the current 1146 * No matter what, we always look for the file in the current
1147 * directory before anywhere else (unless we found the magic 1147 * directory before anywhere else (unless we found the magic
1148 * DOTLAST path, in which case we search it last) and we *do not* 1148 * DOTLAST path, in which case we search it last) and we *do not*
1149 * add the ./ to it if it exists. 1149 * add the ./ to it if it exists.
1150 * This is so there are no conflicts between what the user 1150 * This is so there are no conflicts between what the user
1151 * specifies (fish.c) and what pmake finds (./fish.c). 1151 * specifies (fish.c) and what pmake finds (./fish.c).
1152 */ 1152 */
1153 if (!hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) { 1153 if (!hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) {
1154 Lst_Close(path); 1154 Lst_Close(path);
1155 return file; 1155 return file;
1156 } 1156 }
1157 1157
1158 while ((ln = Lst_Next(path)) != NULL) { 1158 while ((ln = Lst_Next(path)) != NULL) {
1159 p = Lst_Datum(ln); 1159 p = Lst_Datum(ln);
1160 if (p == dotLast) 1160 if (p == dotLast)
1161 continue; 1161 continue;
1162 if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) { 1162 if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) {
1163 Lst_Close(path); 1163 Lst_Close(path);
1164 return file; 1164 return file;
1165 } 1165 }
1166 } 1166 }
1167 1167
1168 if (hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) { 1168 if (hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) {
1169 Lst_Close(path); 1169 Lst_Close(path);
1170 return file; 1170 return file;
1171 } 1171 }
1172 } 1172 }
1173 Lst_Close(path); 1173 Lst_Close(path);
1174 1174
1175 /* 1175 /*
1176 * We didn't find the file on any directory in the search path. 1176 * We didn't find the file on any directory in the search path.
1177 * If the name doesn't contain a slash, that means it doesn't exist. 1177 * If the name doesn't contain a slash, that means it doesn't exist.
1178 * If it *does* contain a slash, however, there is still hope: it 1178 * If it *does* contain a slash, however, there is still hope: it
1179 * could be in a subdirectory of one of the members of the search 1179 * could be in a subdirectory of one of the members of the search
1180 * path. (eg. /usr/include and sys/types.h. The above search would 1180 * path. (eg. /usr/include and sys/types.h. The above search would
1181 * fail to turn up types.h in /usr/include, but it *is* in 1181 * fail to turn up types.h in /usr/include, but it *is* in
1182 * /usr/include/sys/types.h). 1182 * /usr/include/sys/types.h).
1183 * [ This no longer applies: If we find such a beast, we assume there 1183 * [ This no longer applies: If we find such a beast, we assume there
1184 * will be more (what else can we assume?) and add all but the last 1184 * will be more (what else can we assume?) and add all but the last
1185 * component of the resulting name onto the search path (at the 1185 * component of the resulting name onto the search path (at the
1186 * end).] 1186 * end).]
1187 * This phase is only performed if the file is *not* absolute. 1187 * This phase is only performed if the file is *not* absolute.
1188 */ 1188 */
1189 if (!hasSlash) { 1189 if (!hasSlash) {
1190 DIR_DEBUG0(" failed.\n"); 1190 DIR_DEBUG0(" failed.\n");
1191 misses += 1; 1191 misses += 1;
1192 return NULL; 1192 return NULL;
1193 } 1193 }
1194 1194
1195 if (*cp == '\0') { 1195 if (*cp == '\0') {
1196 /* we were given a trailing "/" */ 1196 /* we were given a trailing "/" */
1197 cp = trailing_dot; 1197 cp = trailing_dot;
1198 } 1198 }
1199 1199
1200 if (name[0] != '/') { 1200 if (name[0] != '/') {
1201 Boolean checkedDot = FALSE; 1201 Boolean checkedDot = FALSE;
1202 1202
1203 DIR_DEBUG0(" Trying subdirectories...\n"); 1203 DIR_DEBUG0(" Trying subdirectories...\n");
1204 1204
1205 if (!hasLastDot) { 1205 if (!hasLastDot) {
1206 if (dot) { 1206 if (dot) {
1207 checkedDot = TRUE; 1207 checkedDot = TRUE;
1208 if ((file = DirLookupSubdir(dot, name)) != NULL) 1208 if ((file = DirLookupSubdir(dot, name)) != NULL)
1209 return file; 1209 return file;
1210 } 1210 }
1211 if (cur && (file = DirLookupSubdir(cur, name)) != NULL) 1211 if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
1212 return file; 1212 return file;
1213 } 1213 }
1214 1214
1215 Lst_Open(path); 1215 Lst_Open(path);
1216 while ((ln = Lst_Next(path)) != NULL) { 1216 while ((ln = Lst_Next(path)) != NULL) {
1217 p = Lst_Datum(ln); 1217 p = Lst_Datum(ln);
1218 if (p == dotLast) 1218 if (p == dotLast)
1219 continue; 1219 continue;
1220 if (p == dot) { 1220 if (p == dot) {
1221 if (checkedDot) 1221 if (checkedDot)
1222 continue; 1222 continue;
1223 checkedDot = TRUE; 1223 checkedDot = TRUE;
1224 } 1224 }
1225 if ((file = DirLookupSubdir(p, name)) != NULL) { 1225 if ((file = DirLookupSubdir(p, name)) != NULL) {
1226 Lst_Close(path); 1226 Lst_Close(path);
1227 return file; 1227 return file;
1228 } 1228 }
1229 } 1229 }
1230 Lst_Close(path); 1230 Lst_Close(path);
1231 1231
1232 if (hasLastDot) { 1232 if (hasLastDot) {
1233 if (dot && !checkedDot) { 1233 if (dot && !checkedDot) {
1234 checkedDot = TRUE; 1234 checkedDot = TRUE;
1235 if ((file = DirLookupSubdir(dot, name)) != NULL) 1235 if ((file = DirLookupSubdir(dot, name)) != NULL)
1236 return file; 1236 return file;
1237 } 1237 }
1238 if (cur && (file = DirLookupSubdir(cur, name)) != NULL) 1238 if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
1239 return file; 1239 return file;
1240 } 1240 }
1241 1241
1242 if (checkedDot) { 1242 if (checkedDot) {
1243 /* 1243 /*
1244 * Already checked by the given name, since . was in the path, 1244 * Already checked by the given name, since . was in the path,
1245 * so no point in proceeding... 1245 * so no point in proceeding...
1246 */ 1246 */
1247 DIR_DEBUG0(" Checked . already, returning NULL\n"); 1247 DIR_DEBUG0(" Checked . already, returning NULL\n");
1248 return NULL; 1248 return NULL;
1249 } 1249 }
1250 1250
1251 } else { /* name[0] == '/' */ 1251 } else { /* name[0] == '/' */
1252 1252
1253 /* 1253 /*
1254 * For absolute names, compare directory path prefix against the 1254 * For absolute names, compare directory path prefix against the
1255 * the directory path of each member on the search path for an exact 1255 * the directory path of each member on the search path for an exact
1256 * match. If we have an exact match on any member of the search path, 1256 * match. If we have an exact match on any member of the search path,
1257 * use the cached contents of that member to lookup the final file 1257 * use the cached contents of that member to lookup the final file
1258 * component. If that lookup fails we can safely assume that the 1258 * component. If that lookup fails we can safely assume that the
1259 * file does not exist at all. This is signified by DirLookupAbs() 1259 * file does not exist at all. This is signified by DirLookupAbs()
1260 * returning an empty string. 1260 * returning an empty string.
1261 */ 1261 */
1262 DIR_DEBUG0(" Trying exact path matches...\n"); 1262 DIR_DEBUG0(" Trying exact path matches...\n");
1263 1263
1264 if (!hasLastDot && cur && 1264 if (!hasLastDot && cur &&
1265 ((file = DirLookupAbs(cur, name, cp)) != NULL)) { 1265 ((file = DirLookupAbs(cur, name, cp)) != NULL)) {
1266 if (file[0] == '\0') { 1266 if (file[0] == '\0') {
1267 free(file); 1267 free(file);
1268 return NULL; 1268 return NULL;
1269 } 1269 }
1270 return file; 1270 return file;
1271 } 1271 }
1272 1272
1273 Lst_Open(path); 1273 Lst_Open(path);
1274 while ((ln = Lst_Next(path)) != NULL) { 1274 while ((ln = Lst_Next(path)) != NULL) {
1275 p = Lst_Datum(ln); 1275 p = Lst_Datum(ln);
1276 if (p == dotLast) 1276 if (p == dotLast)
1277 continue; 1277 continue;
1278 if ((file = DirLookupAbs(p, name, cp)) != NULL) { 1278 if ((file = DirLookupAbs(p, name, cp)) != NULL) {
1279 Lst_Close(path); 1279 Lst_Close(path);
1280 if (file[0] == '\0') { 1280 if (file[0] == '\0') {
1281 free(file); 1281 free(file);
1282 return NULL; 1282 return NULL;
1283 } 1283 }
1284 return file; 1284 return file;
1285 } 1285 }
1286 } 1286 }
1287 Lst_Close(path); 1287 Lst_Close(path);
1288 1288
1289 if (hasLastDot && cur && 1289 if (hasLastDot && cur &&
1290 ((file = DirLookupAbs(cur, name, cp)) != NULL)) { 1290 ((file = DirLookupAbs(cur, name, cp)) != NULL)) {
1291 if (file[0] == '\0') { 1291 if (file[0] == '\0') {
1292 free(file); 1292 free(file);
1293 return NULL; 1293 return NULL;
1294 } 1294 }
1295 return file; 1295 return file;
1296 } 1296 }
1297 } 1297 }
1298 1298
1299 /* 1299 /*
1300 * Didn't find it that way, either. Sigh. Phase 3. Add its directory 1300 * Didn't find it that way, either. Sigh. Phase 3. Add its directory
1301 * onto the search path in any case, just in case, then look for the 1301 * onto the search path in any case, just in case, then look for the
1302 * thing in the hash table. If we find it, grand. We return a new 1302 * thing in the hash table. If we find it, grand. We return a new
1303 * copy of the name. Otherwise we sadly return a NULL pointer. Sigh. 1303 * copy of the name. Otherwise we sadly return a NULL pointer. Sigh.
1304 * Note that if the directory holding the file doesn't exist, this will 1304 * Note that if the directory holding the file doesn't exist, this will
1305 * do an extra search of the final directory on the path. Unless something 1305 * do an extra search of the final directory on the path. Unless something
1306 * weird happens, this search won't succeed and life will be groovy. 1306 * weird happens, this search won't succeed and life will be groovy.
1307 * 1307 *
1308 * Sigh. We cannot add the directory onto the search path because 1308 * Sigh. We cannot add the directory onto the search path because
1309 * of this amusing case: 1309 * of this amusing case:
1310 * $(INSTALLDIR)/$(FILE): $(FILE) 1310 * $(INSTALLDIR)/$(FILE): $(FILE)
1311 * 1311 *
1312 * $(FILE) exists in $(INSTALLDIR) but not in the current one. 1312 * $(FILE) exists in $(INSTALLDIR) but not in the current one.
1313 * When searching for $(FILE), we will find it in $(INSTALLDIR) 1313 * When searching for $(FILE), we will find it in $(INSTALLDIR)
1314 * b/c we added it here. This is not good... 1314 * b/c we added it here. This is not good...
1315 */ 1315 */
1316#ifdef notdef 1316#ifdef notdef
1317 if (cp == traling_dot) { 1317 if (cp == traling_dot) {
1318 cp = strrchr(name, '/'); 1318 cp = strrchr(name, '/');
1319 cp += 1; 1319 cp += 1;
1320 } 1320 }
1321 cp[-1] = '\0'; 1321 cp[-1] = '\0';
1322 (void)Dir_AddDir(path, name); 1322 (void)Dir_AddDir(path, name);
1323 cp[-1] = '/'; 1323 cp[-1] = '/';
1324 1324
1325 bigmisses += 1; 1325 bigmisses += 1;
1326 ln = Lst_Last(path); 1326 ln = Lst_Last(path);
1327 if (ln == NULL) { 1327 if (ln == NULL) {
1328 return NULL; 1328 return NULL;
1329 } else { 1329 } else {
1330 p = Lst_Datum(ln); 1330 p = Lst_Datum(ln);
1331 } 1331 }
1332 1332
1333 if (Hash_FindEntry(&p->files, cp) != NULL) { 1333 if (Hash_FindEntry(&p->files, cp) != NULL) {
1334 return bmake_strdup(name); 1334 return bmake_strdup(name);
1335 } else { 1335 } else {
1336 return NULL; 1336 return NULL;
1337 } 1337 }
1338#else /* !notdef */ 1338#else /* !notdef */
1339 DIR_DEBUG1(" Looking for \"%s\" ...\n", name); 1339 DIR_DEBUG1(" Looking for \"%s\" ...\n", name);
1340 1340
1341 bigmisses += 1; 1341 bigmisses += 1;
1342 if (cached_stat(name, &stb) == 0) { 1342 if (cached_stat(name, &stb) == 0) {
1343 return bmake_strdup(name); 1343 return bmake_strdup(name);
1344 } 1344 }
1345 1345
1346 DIR_DEBUG0(" failed. Returning NULL\n"); 1346 DIR_DEBUG0(" failed. Returning NULL\n");
1347 return NULL; 1347 return NULL;
1348#endif /* notdef */ 1348#endif /* notdef */
1349} 1349}
1350 1350
1351 1351
1352/*- 1352/*-
1353 *----------------------------------------------------------------------- 1353 *-----------------------------------------------------------------------
1354 * Dir_FindHereOrAbove -- 1354 * Dir_FindHereOrAbove --
1355 * search for a path starting at a given directory and then working 1355 * search for a path starting at a given directory and then working
1356 * our way up towards the root. 1356 * our way up towards the root.
1357 * 1357 *
1358 * Input: 1358 * Input:
1359 * here starting directory 1359 * here starting directory
1360 * search_path the path we are looking for 1360 * search_path the path we are looking for
1361 * result the result of a successful search is placed here 1361 * result the result of a successful search is placed here
1362 * rlen the length of the result buffer 1362 * rlen the length of the result buffer
1363 * (typically MAXPATHLEN + 1) 1363 * (typically MAXPATHLEN + 1)
1364 * 1364 *
1365 * Results: 1365 * Results:
1366 * 0 on failure, 1 on success [in which case the found path is put 1366 * 0 on failure, 1 on success [in which case the found path is put
1367 * in the result buffer]. 1367 * in the result buffer].
1368 * 1368 *
1369 * Side Effects: 1369 * Side Effects:
1370 *----------------------------------------------------------------------- 1370 *-----------------------------------------------------------------------
1371 */ 1371 */
1372int 1372int
1373Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen) 1373Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen)
1374{ 1374{
1375 struct stat st; 1375 struct stat st;
1376 char dirbase[MAXPATHLEN + 1], *db_end; 1376 char dirbase[MAXPATHLEN + 1], *db_end;
1377 char try[MAXPATHLEN + 1], *try_end; 1377 char try[MAXPATHLEN + 1], *try_end;
1378 1378
1379 /* copy out our starting point */ 1379 /* copy out our starting point */
1380 snprintf(dirbase, sizeof(dirbase), "%s", here); 1380 snprintf(dirbase, sizeof(dirbase), "%s", here);
1381 db_end = dirbase + strlen(dirbase); 1381 db_end = dirbase + strlen(dirbase);
1382 1382
1383 /* loop until we determine a result */ 1383 /* loop until we determine a result */
1384 while (1) { 1384 while (1) {
1385 1385
1386 /* try and stat(2) it ... */ 1386 /* try and stat(2) it ... */
1387 snprintf(try, sizeof(try), "%s/%s", dirbase, search_path); 1387 snprintf(try, sizeof(try), "%s/%s", dirbase, search_path);
1388 if (cached_stat(try, &st) != -1) { 1388 if (cached_stat(try, &st) != -1) {
1389 /* 1389 /*
1390 * success! if we found a file, chop off 1390 * success! if we found a file, chop off
1391 * the filename so we return a directory. 1391 * the filename so we return a directory.
1392 */ 1392 */
1393 if ((st.st_mode & S_IFMT) != S_IFDIR) { 1393 if ((st.st_mode & S_IFMT) != S_IFDIR) {
1394 try_end = try + strlen(try); 1394 try_end = try + strlen(try);
1395 while (try_end > try && *try_end != '/') 1395 while (try_end > try && *try_end != '/')
1396 try_end--; 1396 try_end--;
1397 if (try_end > try) 1397 if (try_end > try)
1398 *try_end = 0; /* chop! */ 1398 *try_end = 0; /* chop! */
1399 } 1399 }
1400 1400
1401 /* 1401 /*
1402 * done! 1402 * done!
1403 */ 1403 */
1404 snprintf(result, rlen, "%s", try); 1404 snprintf(result, rlen, "%s", try);
1405 return 1; 1405 return 1;
1406 } 1406 }
1407 1407
1408 /* 1408 /*
1409 * nope, we didn't find it. if we used up dirbase we've 1409 * nope, we didn't find it. if we used up dirbase we've
1410 * reached the root and failed. 1410 * reached the root and failed.
1411 */ 1411 */
1412 if (db_end == dirbase) 1412 if (db_end == dirbase)
1413 break; /* failed! */ 1413 break; /* failed! */
1414 1414
1415 /* 1415 /*
1416 * truncate dirbase from the end to move up a dir 1416 * truncate dirbase from the end to move up a dir
1417 */ 1417 */
1418 while (db_end > dirbase && *db_end != '/') 1418 while (db_end > dirbase && *db_end != '/')
1419 db_end--; 1419 db_end--;
1420 *db_end = 0; /* chop! */ 1420 *db_end = 0; /* chop! */
1421 1421
1422 } /* while (1) */ 1422 } /* while (1) */
1423 1423
1424 /* 1424 /*
1425 * we failed... 1425 * we failed...
1426 */ 1426 */
1427 return 0; 1427 return 0;
1428} 1428}
1429 1429
1430/*- 1430/*-
1431 *----------------------------------------------------------------------- 1431 *-----------------------------------------------------------------------
1432 * Dir_MTime -- 1432 * Dir_MTime --
1433 * Find the modification time of the file described by gn along the 1433 * Find the modification time of the file described by gn along the
1434 * search path dirSearchPath. 1434 * search path dirSearchPath.
1435 * 1435 *
1436 * Input: 1436 * Input:
1437 * gn the file whose modification time is desired 1437 * gn the file whose modification time is desired
1438 * 1438 *
1439 * Results: 1439 * Results:
1440 * The modification time or 0 if it doesn't exist 1440 * The modification time or 0 if it doesn't exist
1441 * 1441 *
1442 * Side Effects: 1442 * Side Effects:
1443 * The modification time is placed in the node's mtime slot. 1443 * The modification time is placed in the node's mtime slot.
1444 * If the node didn't have a path entry before, and Dir_FindFile 1444 * If the node didn't have a path entry before, and Dir_FindFile
1445 * found one for it, the full name is placed in the path slot. 1445 * found one for it, the full name is placed in the path slot.
1446 *----------------------------------------------------------------------- 1446 *-----------------------------------------------------------------------
1447 */ 1447 */
1448int 1448int
1449Dir_MTime(GNode *gn, Boolean recheck) 1449Dir_MTime(GNode *gn, Boolean recheck)
1450{ 1450{
1451 char *fullName; /* the full pathname of name */ 1451 char *fullName; /* the full pathname of name */
1452 struct stat stb; /* buffer for finding the mod time */ 1452 struct stat stb; /* buffer for finding the mod time */
1453 1453
1454 if (gn->type & OP_ARCHV) { 1454 if (gn->type & OP_ARCHV) {
1455 return Arch_MTime(gn); 1455 return Arch_MTime(gn);
1456 } else if (gn->type & OP_PHONY) { 1456 } else if (gn->type & OP_PHONY) {
1457 gn->mtime = 0; 1457 gn->mtime = 0;
1458 return 0; 1458 return 0;
1459 } else if (gn->path == NULL) { 1459 } else if (gn->path == NULL) {
1460 if (gn->type & OP_NOPATH) 1460 if (gn->type & OP_NOPATH)
1461 fullName = NULL; 1461 fullName = NULL;
1462 else { 1462 else {
1463 fullName = Dir_FindFile(gn->name, Suff_FindPath(gn)); 1463 fullName = Dir_FindFile(gn->name, Suff_FindPath(gn));
1464 if (fullName == NULL && gn->flags & FROM_DEPEND && 1464 if (fullName == NULL && gn->flags & FROM_DEPEND &&
1465 !Lst_IsEmpty(gn->iParents)) { 1465 !Lst_IsEmpty(gn->iParents)) {
1466 char *cp; 1466 char *cp;
1467 1467
1468 cp = strrchr(gn->name, '/'); 1468 cp = strrchr(gn->name, '/');
1469 if (cp) { 1469 if (cp) {
1470 /* 1470 /*
1471 * This is an implied source, and it may have moved, 1471 * This is an implied source, and it may have moved,
1472 * see if we can find it via the current .PATH 1472 * see if we can find it via the current .PATH
1473 */ 1473 */
1474 cp++; 1474 cp++;
1475 1475
1476 fullName = Dir_FindFile(cp, Suff_FindPath(gn)); 1476 fullName = Dir_FindFile(cp, Suff_FindPath(gn));
1477 if (fullName) { 1477 if (fullName) {
1478 /* 1478 /*
1479 * Put the found file in gn->path 1479 * Put the found file in gn->path
1480 * so that we give that to the compiler. 1480 * so that we give that to the compiler.
1481 */ 1481 */
1482 gn->path = bmake_strdup(fullName); 1482 gn->path = bmake_strdup(fullName);
1483 if (!Job_RunTarget(".STALE", gn->fname)) 1483 if (!Job_RunTarget(".STALE", gn->fname))
1484 fprintf(stdout, 1484 fprintf(stdout,
1485 "%s: %s, %d: ignoring stale %s for %s, " 1485 "%s: %s, %d: ignoring stale %s for %s, "
1486 "found %s\n", progname, gn->fname, 1486 "found %s\n", progname, gn->fname,
1487 gn->lineno, 1487 gn->lineno,
1488 makeDependfile, gn->name, fullName); 1488 makeDependfile, gn->name, fullName);
1489 } 1489 }
1490 } 1490 }
1491 } 1491 }
1492 DIR_DEBUG2("Found '%s' as '%s'\n", 1492 DIR_DEBUG2("Found '%s' as '%s'\n",
1493 gn->name, fullName ? fullName : "(not found)"); 1493 gn->name, fullName ? fullName : "(not found)");
1494 } 1494 }
1495 } else { 1495 } else {
1496 fullName = gn->path; 1496 fullName = gn->path;
1497 } 1497 }
1498 1498
1499 if (fullName == NULL) { 1499 if (fullName == NULL) {
1500 fullName = bmake_strdup(gn->name); 1500 fullName = bmake_strdup(gn->name);
1501 } 1501 }
1502 1502
1503 if (cached_stats(&mtimes, fullName, &stb, recheck ? CST_UPDATE : 0) < 0) { 1503 if (cached_stats(&mtimes, fullName, &stb, recheck ? CST_UPDATE : 0) < 0) {
1504 if (gn->type & OP_MEMBER) { 1504 if (gn->type & OP_MEMBER) {
1505 if (fullName != gn->path) 1505 if (fullName != gn->path)
1506 free(fullName); 1506 free(fullName);
1507 return Arch_MemMTime(gn); 1507 return Arch_MemMTime(gn);
1508 } else { 1508 } else {
1509 stb.st_mtime = 0; 1509 stb.st_mtime = 0;
1510 } 1510 }
1511 } 1511 }
1512 1512
1513 if (fullName && gn->path == NULL) { 1513 if (fullName && gn->path == NULL) {
1514 gn->path = fullName; 1514 gn->path = fullName;
1515 } 1515 }
1516 1516
1517 gn->mtime = stb.st_mtime; 1517 gn->mtime = stb.st_mtime;
1518 return gn->mtime; 1518 return gn->mtime;
1519} 1519}
1520 1520
1521/*- 1521/*-
1522 *----------------------------------------------------------------------- 1522 *-----------------------------------------------------------------------
1523 * Dir_AddDir -- 1523 * Dir_AddDir --
1524 * Add the given name to the end of the given path. The order of 1524 * Add the given name to the end of the given path. The order of
1525 * the arguments is backwards so ParseDoDependency can do a 1525 * the arguments is backwards so ParseDoDependency can do a
1526 * Lst_ForEach of its list of paths... 1526 * Lst_ForEach of its list of paths...
1527 * 1527 *
1528 * Input: 1528 * Input:
1529 * path the path to which the directory should be 1529 * path the path to which the directory should be
1530 * added 1530 * added
1531 * XXX: Why would this ever be NULL, and what does 1531 * XXX: Why would this ever be NULL, and what does
1532 * that mean? 1532 * that mean?
1533 * name the name of the directory to add 1533 * name the name of the directory to add
1534 * 1534 *
1535 * Results: 1535 * Results:
1536 * none 1536 * none
1537 * 1537 *
1538 * Side Effects: 1538 * Side Effects:
1539 * A structure is added to the list and the directory is 1539 * A structure is added to the list and the directory is
1540 * read and hashed. 1540 * read and hashed.
1541 *----------------------------------------------------------------------- 1541 *-----------------------------------------------------------------------
1542 */ 1542 */
1543Path * 1543Path *
1544Dir_AddDir(Lst path, const char *name) 1544Dir_AddDir(Lst path, const char *name)
1545{ 1545{
1546 LstNode ln = NULL; /* node in case Path structure is found */ 1546 LstNode ln = NULL; /* node in case Path structure is found */
1547 Path *p = NULL; /* pointer to new Path structure */ 1547 Path *p = NULL; /* pointer to new Path structure */
1548 DIR *d; /* for reading directory */ 1548 DIR *d; /* for reading directory */
1549 struct dirent *dp; /* entry in directory */ 1549 struct dirent *dp; /* entry in directory */
1550 1550
1551 if (path != NULL && strcmp(name, ".DOTLAST") == 0) { 1551 if (path != NULL && strcmp(name, ".DOTLAST") == 0) {
1552 ln = Lst_Find(path, DirFindName, name); 1552 ln = Lst_Find(path, DirFindName, name);
1553 if (ln != NULL) 1553 if (ln != NULL)
1554 return Lst_Datum(ln); 1554 return Lst_Datum(ln);
1555 1555
1556 dotLast->refCount++; 1556 dotLast->refCount++;
1557 Lst_Prepend(path, dotLast); 1557 Lst_Prepend(path, dotLast);
1558 } 1558 }
1559 1559
1560 if (path != NULL) 1560 if (path != NULL)
1561 ln = Lst_Find(openDirectories, DirFindName, name); 1561 ln = Lst_Find(openDirectories, DirFindName, name);
1562 if (ln != NULL) { 1562 if (ln != NULL) {
1563 p = Lst_Datum(ln); 1563 p = Lst_Datum(ln);
1564 if (Lst_Member(path, p) == NULL) { 1564 if (Lst_Member(path, p) == NULL) {
1565 p->refCount += 1; 1565 p->refCount += 1;
1566 Lst_Append(path, p); 1566 Lst_Append(path, p);
1567 } 1567 }
1568 return p; 1568 return p;
1569 } 1569 }
1570 1570
1571 DIR_DEBUG1("Caching %s ...", name); 1571 DIR_DEBUG1("Caching %s ...", name);
1572 1572
1573 if ((d = opendir(name)) != NULL) { 1573 if ((d = opendir(name)) != NULL) {
1574 p = bmake_malloc(sizeof(Path)); 1574 p = bmake_malloc(sizeof(Path));
1575 p->name = bmake_strdup(name); 1575 p->name = bmake_strdup(name);
1576 p->hits = 0; 1576 p->hits = 0;
1577 p->refCount = 1; 1577 p->refCount = 1;
1578 Hash_InitTable(&p->files, -1); 1578 Hash_InitTable(&p->files, -1);
1579 1579
1580 while ((dp = readdir(d)) != NULL) { 1580 while ((dp = readdir(d)) != NULL) {
1581#if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ 1581#if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */
1582 /* 1582 /*
1583 * The sun directory library doesn't check for a 0 inode 1583 * The sun directory library doesn't check for a 0 inode
1584 * (0-inode slots just take up space), so we have to do 1584 * (0-inode slots just take up space), so we have to do
1585 * it ourselves. 1585 * it ourselves.
1586 */ 1586 */
1587 if (dp->d_fileno == 0) { 1587 if (dp->d_fileno == 0) {
1588 continue; 1588 continue;
1589 } 1589 }
1590#endif /* sun && d_ino */ 1590#endif /* sun && d_ino */
1591 (void)Hash_CreateEntry(&p->files, dp->d_name, NULL); 1591 (void)Hash_CreateEntry(&p->files, dp->d_name, NULL);
1592 } 1592 }
1593 (void)closedir(d); 1593 (void)closedir(d);
1594 Lst_Append(openDirectories, p); 1594 Lst_Append(openDirectories, p);
1595 if (path != NULL) 1595 if (path != NULL)
1596 Lst_Append(path, p); 1596 Lst_Append(path, p);
1597 } 1597 }
1598 DIR_DEBUG0("done\n"); 1598 DIR_DEBUG0("done\n");
1599 return p; 1599 return p;
1600} 1600}
1601 1601
1602/*- 1602/*-
1603 *----------------------------------------------------------------------- 1603 *-----------------------------------------------------------------------
1604 * Dir_CopyDir -- 1604 * Dir_CopyDir --
1605 * Callback function for duplicating a search path via Lst_Copy. 1605 * Callback function for duplicating a search path via Lst_Copy.
1606 * Ups the reference count for the directory. 1606 * Ups the reference count for the directory.
1607 * 1607 *
1608 * Results: 1608 * Results:
1609 * Returns the Path it was given. 1609 * Returns the Path it was given.
1610 *----------------------------------------------------------------------- 1610 *-----------------------------------------------------------------------
1611 */ 1611 */
1612void * 1612void *
1613Dir_CopyDir(void *p) 1613Dir_CopyDir(void *p)
1614{ 1614{
1615 ((Path *)p)->refCount += 1; 1615 ((Path *)p)->refCount += 1;
1616 1616
1617 return p; 1617 return p;
1618} 1618}
1619 1619
1620/*- 1620/*-
1621 *----------------------------------------------------------------------- 1621 *-----------------------------------------------------------------------
1622 * Dir_MakeFlags -- 1622 * Dir_MakeFlags --
1623 * Make a string by taking all the directories in the given search 1623 * Make a string by taking all the directories in the given search
1624 * path and preceding them by the given flag. Used by the suffix 1624 * path and preceding them by the given flag. Used by the suffix
1625 * module to create variables for compilers based on suffix search 1625 * module to create variables for compilers based on suffix search
1626 * paths. 1626 * paths.
1627 * 1627 *
1628 * Input: 1628 * Input:
1629 * flag flag which should precede each directory 1629 * flag flag which should precede each directory
1630 * path list of directories 1630 * path list of directories
1631 * 1631 *
1632 * Results: 1632 * Results:
1633 * The string mentioned above. Note that there is no space between 1633 * The string mentioned above. Note that there is no space between
1634 * the given flag and each directory. The empty string is returned if 1634 * the given flag and each directory. The empty string is returned if
1635 * Things don't go well. 1635 * Things don't go well.
1636 * 1636 *
1637 * Side Effects: 1637 * Side Effects:
1638 * None 1638 * None
1639 *----------------------------------------------------------------------- 1639 *-----------------------------------------------------------------------
1640 */ 1640 */
1641char * 1641char *
1642Dir_MakeFlags(const char *flag, Lst path) 1642Dir_MakeFlags(const char *flag, Lst path)
1643{ 1643{
1644 Buffer buf; 1644 Buffer buf;
1645 LstNode ln; /* the node of the current directory */ 1645 LstNode ln; /* the node of the current directory */
1646 1646
1647 Buf_Init(&buf, 0); 1647 Buf_Init(&buf, 0);
1648 1648
1649 if (path != NULL) { 1649 if (path != NULL) {
1650 Lst_Open(path); 1650 Lst_Open(path);
1651 while ((ln = Lst_Next(path)) != NULL) { 1651 while ((ln = Lst_Next(path)) != NULL) {
1652 Path *p = Lst_Datum(ln); 1652 Path *p = Lst_Datum(ln);
1653 Buf_AddStr(&buf, " "); 1653 Buf_AddStr(&buf, " ");
1654 Buf_AddStr(&buf, flag); 1654 Buf_AddStr(&buf, flag);
1655 Buf_AddStr(&buf, p->name); 1655 Buf_AddStr(&buf, p->name);
1656 } 1656 }
1657 Lst_Close(path); 1657 Lst_Close(path);
1658 } 1658 }
1659 1659
1660 return Buf_Destroy(&buf, FALSE); 1660 return Buf_Destroy(&buf, FALSE);
1661} 1661}
1662 1662
1663/*- 1663/*-
1664 *----------------------------------------------------------------------- 1664 *-----------------------------------------------------------------------
1665 * Dir_Destroy -- 1665 * Dir_Destroy --
1666 * Nuke a directory descriptor, if possible. Callback procedure 1666 * Nuke a directory descriptor, if possible. Callback procedure
1667 * for the suffixes module when destroying a search path. 1667 * for the suffixes module when destroying a search path.
1668 * 1668 *
1669 * Input: 1669 * Input:
1670 * pp The directory descriptor to nuke 1670 * pp The directory descriptor to nuke
1671 * 1671 *
1672 * Results: 1672 * Results:
1673 * None. 1673 * None.
1674 * 1674 *
1675 * Side Effects: 1675 * Side Effects:
1676 * If no other path references this directory (refCount == 0), 1676 * If no other path references this directory (refCount == 0),
1677 * the Path and all its data are freed. 1677 * the Path and all its data are freed.
1678 * 1678 *
1679 *----------------------------------------------------------------------- 1679 *-----------------------------------------------------------------------
1680 */ 1680 */
1681void 1681void
1682Dir_Destroy(void *pp) 1682Dir_Destroy(void *pp)
1683{ 1683{
1684 Path *p = (Path *)pp; 1684 Path *p = (Path *)pp;
1685 p->refCount -= 1; 1685 p->refCount -= 1;
1686 1686
1687 if (p->refCount == 0) { 1687 if (p->refCount == 0) {
1688 LstNode ln; 1688 LstNode ln;
1689 1689
1690 ln = Lst_Member(openDirectories, p); 1690 ln = Lst_Member(openDirectories, p);
1691 Lst_Remove(openDirectories, ln); 1691 Lst_Remove(openDirectories, ln);
1692 1692
1693 Hash_DeleteTable(&p->files); 1693 Hash_DeleteTable(&p->files);
1694 free(p->name); 1694 free(p->name);
1695 free(p); 1695 free(p);
1696 } 1696 }
1697} 1697}
1698 1698
1699/*- 1699/*-
1700 *----------------------------------------------------------------------- 1700 *-----------------------------------------------------------------------
1701 * Dir_ClearPath -- 1701 * Dir_ClearPath --
1702 * Clear out all elements of the given search path. This is different 1702 * Clear out all elements of the given search path. This is different
1703 * from destroying the list, notice. 1703 * from destroying the list, notice.
1704 * 1704 *
1705 * Input: 1705 * Input:
1706 * path Path to clear 1706 * path Path to clear
1707 * 1707 *
1708 * Results: 1708 * Results:
1709 * None. 1709 * None.
1710 * 1710 *
1711 * Side Effects: 1711 * Side Effects:
1712 * The path is set to the empty list. 1712 * The path is set to the empty list.
1713 * 1713 *
1714 *----------------------------------------------------------------------- 1714 *-----------------------------------------------------------------------
1715 */ 1715 */
1716void 1716void
1717Dir_ClearPath(Lst path) 1717Dir_ClearPath(Lst path)
1718{ 1718{
1719 while (!Lst_IsEmpty(path)) { 1719 while (!Lst_IsEmpty(path)) {
1720 Path *p = Lst_Dequeue(path); 1720 Path *p = Lst_Dequeue(path);
1721 Dir_Destroy(p); 1721 Dir_Destroy(p);
1722 } 1722 }
1723} 1723}
1724 1724
1725 1725
1726/*- 1726/*-
1727 *----------------------------------------------------------------------- 1727 *-----------------------------------------------------------------------
1728 * Dir_Concat -- 1728 * Dir_Concat --
1729 * Concatenate two paths, adding the second to the end of the first. 1729 * Concatenate two paths, adding the second to the end of the first.
1730 * Makes sure to avoid duplicates. 1730 * Makes sure to avoid duplicates.
1731 * 1731 *
1732 * Input: 1732 * Input:
1733 * path1 Dest 1733 * path1 Dest
1734 * path2 Source 1734 * path2 Source
1735 * 1735 *
1736 * Results: 1736 * Results:
1737 * None 1737 * None
1738 * 1738 *
1739 * Side Effects: 1739 * Side Effects:
1740 * Reference counts for added dirs are upped. 1740 * Reference counts for added dirs are upped.
1741 * 1741 *
1742 *----------------------------------------------------------------------- 1742 *-----------------------------------------------------------------------
1743 */ 1743 */
1744void 1744void
1745Dir_Concat(Lst path1, Lst path2) 1745Dir_Concat(Lst path1, Lst path2)
1746{ 1746{
1747 LstNode ln; 1747 LstNode ln;
1748 Path *p; 1748 Path *p;
1749 1749
1750 for (ln = Lst_First(path2); ln != NULL; ln = Lst_Succ(ln)) { 1750 for (ln = Lst_First(path2); ln != NULL; ln = LstNode_Next(ln)) {
1751 p = Lst_Datum(ln); 1751 p = Lst_Datum(ln);
1752 if (Lst_Member(path1, p) == NULL) { 1752 if (Lst_Member(path1, p) == NULL) {
1753 p->refCount += 1; 1753 p->refCount += 1;
1754 Lst_Append(path1, p); 1754 Lst_Append(path1, p);
1755 } 1755 }
1756 } 1756 }
1757} 1757}
1758 1758
1759static int 1759static int
1760percentage(int num, int den) 1760percentage(int num, int den)
1761{ 1761{
1762 return den != 0 ? num * 100 / den : 0; 1762 return den != 0 ? num * 100 / den : 0;
1763} 1763}
1764 1764
1765/********** DEBUG INFO **********/ 1765/********** DEBUG INFO **********/
1766void 1766void
1767Dir_PrintDirectories(void) 1767Dir_PrintDirectories(void)
1768{ 1768{
1769 LstNode ln; 1769 LstNode ln;
1770 1770
1771 fprintf(debug_file, "#*** Directory Cache:\n"); 1771 fprintf(debug_file, "#*** Directory Cache:\n");
1772 fprintf(debug_file, 1772 fprintf(debug_file,
1773 "# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n", 1773 "# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n",
1774 hits, misses, nearmisses, bigmisses, 1774 hits, misses, nearmisses, bigmisses,
1775 percentage(hits, hits + bigmisses + nearmisses)); 1775 percentage(hits, hits + bigmisses + nearmisses));
1776 fprintf(debug_file, "# %-20s referenced\thits\n", "directory"); 1776 fprintf(debug_file, "# %-20s referenced\thits\n", "directory");
1777 1777
1778 Lst_Open(openDirectories); 1778 Lst_Open(openDirectories);
1779 while ((ln = Lst_Next(openDirectories)) != NULL) { 1779 while ((ln = Lst_Next(openDirectories)) != NULL) {
1780 Path *p = Lst_Datum(ln); 1780 Path *p = Lst_Datum(ln);
1781 fprintf(debug_file, "# %-20s %10d\t%4d\n", p->name, p->refCount, 1781 fprintf(debug_file, "# %-20s %10d\t%4d\n", p->name, p->refCount,
1782 p->hits); 1782 p->hits);
1783 } 1783 }
1784 Lst_Close(openDirectories); 1784 Lst_Close(openDirectories);
1785} 1785}
1786 1786
1787static int 1787static int
1788DirPrintDir(void *p, void *dummy MAKE_ATTR_UNUSED) 1788DirPrintDir(void *p, void *dummy MAKE_ATTR_UNUSED)
1789{ 1789{
1790 fprintf(debug_file, "%s ", ((Path *)p)->name); 1790 fprintf(debug_file, "%s ", ((Path *)p)->name);
1791 return 0; 1791 return 0;
1792} 1792}
1793 1793
1794void 1794void
1795Dir_PrintPath(Lst path) 1795Dir_PrintPath(Lst path)
1796{ 1796{
1797 Lst_ForEach(path, DirPrintDir, NULL); 1797 Lst_ForEach(path, DirPrintDir, NULL);
1798} 1798}

cvs diff -r1.222 -r1.223 src/usr.bin/make/job.c (switch to unified diff)

--- src/usr.bin/make/job.c 2020/08/29 10:35:03 1.222
+++ src/usr.bin/make/job.c 2020/08/29 10:41:12 1.223
@@ -1,1711 +1,1711 @@ @@ -1,1711 +1,1711 @@
1/* $NetBSD: job.c,v 1.222 2020/08/29 10:35:03 rillig Exp $ */ 1/* $NetBSD: job.c,v 1.223 2020/08/29 10:41:12 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 4 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
5 * All rights reserved. 5 * 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) 1988, 1989 by Adam de Boor 36 * Copyright (c) 1988, 1989 by Adam de Boor
37 * Copyright (c) 1989 by Berkeley Softworks 37 * Copyright (c) 1989 by Berkeley Softworks
38 * All rights reserved. 38 * All rights reserved.
39 * 39 *
40 * This code is derived from software contributed to Berkeley by 40 * This code is derived from software contributed to Berkeley by
41 * Adam de Boor. 41 * Adam de Boor.
42 * 42 *
43 * Redistribution and use in source and binary forms, with or without 43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions 44 * modification, are permitted provided that the following conditions
45 * are met: 45 * are met:
46 * 1. Redistributions of source code must retain the above copyright 46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer. 47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright 48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the 49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution. 50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software 51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement: 52 * must display the following acknowledgement:
53 * This product includes software developed by the University of 53 * This product includes software developed by the University of
54 * California, Berkeley and its contributors. 54 * California, Berkeley and its contributors.
55 * 4. Neither the name of the University nor the names of its contributors 55 * 4. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software 56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission. 57 * without specific prior written permission.
58 * 58 *
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * SUCH DAMAGE. 69 * SUCH DAMAGE.
70 */ 70 */
71 71
72#ifndef MAKE_NATIVE 72#ifndef MAKE_NATIVE
73static char rcsid[] = "$NetBSD: job.c,v 1.222 2020/08/29 10:35:03 rillig Exp $"; 73static char rcsid[] = "$NetBSD: job.c,v 1.223 2020/08/29 10:41:12 rillig Exp $";
74#else 74#else
75#include <sys/cdefs.h> 75#include <sys/cdefs.h>
76#ifndef lint 76#ifndef lint
77#if 0 77#if 0
78static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; 78static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94";
79#else 79#else
80__RCSID("$NetBSD: job.c,v 1.222 2020/08/29 10:35:03 rillig Exp $"); 80__RCSID("$NetBSD: job.c,v 1.223 2020/08/29 10:41:12 rillig Exp $");
81#endif 81#endif
82#endif /* not lint */ 82#endif /* not lint */
83#endif 83#endif
84 84
85/*- 85/*-
86 * job.c -- 86 * job.c --
87 * handle the creation etc. of our child processes. 87 * handle the creation etc. of our child processes.
88 * 88 *
89 * Interface: 89 * Interface:
90 * Job_Make Start the creation of the given target. 90 * Job_Make Start the creation of the given target.
91 * 91 *
92 * Job_CatchChildren Check for and handle the termination of any 92 * Job_CatchChildren Check for and handle the termination of any
93 * children. This must be called reasonably 93 * children. This must be called reasonably
94 * frequently to keep the whole make going at 94 * frequently to keep the whole make going at
95 * a decent clip, since job table entries aren't 95 * a decent clip, since job table entries aren't
96 * removed until their process is caught this way. 96 * removed until their process is caught this way.
97 * 97 *
98 * Job_CatchOutput Print any output our children have produced. 98 * Job_CatchOutput Print any output our children have produced.
99 * Should also be called fairly frequently to 99 * Should also be called fairly frequently to
100 * keep the user informed of what's going on. 100 * keep the user informed of what's going on.
101 * If no output is waiting, it will block for 101 * If no output is waiting, it will block for
102 * a time given by the SEL_* constants, below, 102 * a time given by the SEL_* constants, below,
103 * or until output is ready. 103 * or until output is ready.
104 * 104 *
105 * Job_Init Called to initialize this module. in addition, 105 * Job_Init Called to initialize this module. in addition,
106 * any commands attached to the .BEGIN target 106 * any commands attached to the .BEGIN target
107 * are executed before this function returns. 107 * are executed before this function returns.
108 * Hence, the makefile must have been parsed 108 * Hence, the makefile must have been parsed
109 * before this function is called. 109 * before this function is called.
110 * 110 *
111 * Job_End Cleanup any memory used. 111 * Job_End Cleanup any memory used.
112 * 112 *
113 * Job_ParseShell Given the line following a .SHELL target, parse 113 * Job_ParseShell Given the line following a .SHELL target, parse
114 * the line as a shell specification. Returns 114 * the line as a shell specification. Returns
115 * FAILURE if the spec was incorrect. 115 * FAILURE if the spec was incorrect.
116 * 116 *
117 * Job_Finish Perform any final processing which needs doing. 117 * Job_Finish Perform any final processing which needs doing.
118 * This includes the execution of any commands 118 * This includes the execution of any commands
119 * which have been/were attached to the .END 119 * which have been/were attached to the .END
120 * target. It should only be called when the 120 * target. It should only be called when the
121 * job table is empty. 121 * job table is empty.
122 * 122 *
123 * Job_AbortAll Abort all currently running jobs. It doesn't 123 * Job_AbortAll Abort all currently running jobs. It doesn't
124 * handle output or do anything for the jobs, 124 * handle output or do anything for the jobs,
125 * just kills them. It should only be called in 125 * just kills them. It should only be called in
126 * an emergency, as it were. 126 * an emergency, as it were.
127 * 127 *
128 * Job_CheckCommands Verify that the commands for a target are 128 * Job_CheckCommands Verify that the commands for a target are
129 * ok. Provide them if necessary and possible. 129 * ok. Provide them if necessary and possible.
130 * 130 *
131 * Job_Touch Update a target without really updating it. 131 * Job_Touch Update a target without really updating it.
132 * 132 *
133 * Job_Wait Wait for all currently-running jobs to finish. 133 * Job_Wait Wait for all currently-running jobs to finish.
134 */ 134 */
135 135
136#include <sys/types.h> 136#include <sys/types.h>
137#include <sys/stat.h> 137#include <sys/stat.h>
138#include <sys/file.h> 138#include <sys/file.h>
139#include <sys/time.h> 139#include <sys/time.h>
140#include <sys/wait.h> 140#include <sys/wait.h>
141 141
142#include <errno.h> 142#include <errno.h>
143#ifndef USE_SELECT 143#ifndef USE_SELECT
144#include <poll.h> 144#include <poll.h>
145#endif 145#endif
146#include <signal.h> 146#include <signal.h>
147#include <utime.h> 147#include <utime.h>
148 148
149#include "make.h" 149#include "make.h"
150#include "dir.h" 150#include "dir.h"
151#include "job.h" 151#include "job.h"
152#include "pathnames.h" 152#include "pathnames.h"
153#include "trace.h" 153#include "trace.h"
154# define STATIC static 154# define STATIC static
155 155
156/* 156/*
157 * error handling variables 157 * error handling variables
158 */ 158 */
159static int errors = 0; /* number of errors reported */ 159static int errors = 0; /* number of errors reported */
160static int aborting = 0; /* why is the make aborting? */ 160static int aborting = 0; /* why is the make aborting? */
161#define ABORT_ERROR 1 /* Because of an error */ 161#define ABORT_ERROR 1 /* Because of an error */
162#define ABORT_INTERRUPT 2 /* Because it was interrupted */ 162#define ABORT_INTERRUPT 2 /* Because it was interrupted */
163#define ABORT_WAIT 3 /* Waiting for jobs to finish */ 163#define ABORT_WAIT 3 /* Waiting for jobs to finish */
164#define JOB_TOKENS "+EI+" /* Token to requeue for each abort state */ 164#define JOB_TOKENS "+EI+" /* Token to requeue for each abort state */
165 165
166/* 166/*
167 * this tracks the number of tokens currently "out" to build jobs. 167 * this tracks the number of tokens currently "out" to build jobs.
168 */ 168 */
169int jobTokensRunning = 0; 169int jobTokensRunning = 0;
170 170
171/* 171/*
172 * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file 172 * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file
173 * is a char! So when we go above 127 we turn negative! 173 * is a char! So when we go above 127 we turn negative!
174 */ 174 */
175#define FILENO(a) ((unsigned) fileno(a)) 175#define FILENO(a) ((unsigned) fileno(a))
176 176
177/* 177/*
178 * post-make command processing. The node postCommands is really just the 178 * post-make command processing. The node postCommands is really just the
179 * .END target but we keep it around to avoid having to search for it 179 * .END target but we keep it around to avoid having to search for it
180 * all the time. 180 * all the time.
181 */ 181 */
182static GNode *postCommands = NULL; 182static GNode *postCommands = NULL;
183 /* node containing commands to execute when 183 /* node containing commands to execute when
184 * everything else is done */ 184 * everything else is done */
185static int numCommands; /* The number of commands actually printed 185static int numCommands; /* The number of commands actually printed
186 * for a target. Should this number be 186 * for a target. Should this number be
187 * 0, no shell will be executed. */ 187 * 0, no shell will be executed. */
188 188
189/* 189/*
190 * Return values from JobStart. 190 * Return values from JobStart.
191 */ 191 */
192#define JOB_RUNNING 0 /* Job is running */ 192#define JOB_RUNNING 0 /* Job is running */
193#define JOB_ERROR 1 /* Error in starting the job */ 193#define JOB_ERROR 1 /* Error in starting the job */
194#define JOB_FINISHED 2 /* The job is already finished */ 194#define JOB_FINISHED 2 /* The job is already finished */
195 195
196/* 196/*
197 * Descriptions for various shells. 197 * Descriptions for various shells.
198 * 198 *
199 * The build environment may set DEFSHELL_INDEX to one of 199 * The build environment may set DEFSHELL_INDEX to one of
200 * DEFSHELL_INDEX_SH, DEFSHELL_INDEX_KSH, or DEFSHELL_INDEX_CSH, to 200 * DEFSHELL_INDEX_SH, DEFSHELL_INDEX_KSH, or DEFSHELL_INDEX_CSH, to
201 * select one of the prefedined shells as the default shell. 201 * select one of the prefedined shells as the default shell.
202 * 202 *
203 * Alternatively, the build environment may set DEFSHELL_CUSTOM to the 203 * Alternatively, the build environment may set DEFSHELL_CUSTOM to the
204 * name or the full path of a sh-compatible shell, which will be used as 204 * name or the full path of a sh-compatible shell, which will be used as
205 * the default shell. 205 * the default shell.
206 * 206 *
207 * ".SHELL" lines in Makefiles can choose the default shell from the 207 * ".SHELL" lines in Makefiles can choose the default shell from the
208 # set defined here, or add additional shells. 208 # set defined here, or add additional shells.
209 */ 209 */
210 210
211#ifdef DEFSHELL_CUSTOM 211#ifdef DEFSHELL_CUSTOM
212#define DEFSHELL_INDEX_CUSTOM 0 212#define DEFSHELL_INDEX_CUSTOM 0
213#define DEFSHELL_INDEX_SH 1 213#define DEFSHELL_INDEX_SH 1
214#define DEFSHELL_INDEX_KSH 2 214#define DEFSHELL_INDEX_KSH 2
215#define DEFSHELL_INDEX_CSH 3 215#define DEFSHELL_INDEX_CSH 3
216#else /* !DEFSHELL_CUSTOM */ 216#else /* !DEFSHELL_CUSTOM */
217#define DEFSHELL_INDEX_SH 0 217#define DEFSHELL_INDEX_SH 0
218#define DEFSHELL_INDEX_KSH 1 218#define DEFSHELL_INDEX_KSH 1
219#define DEFSHELL_INDEX_CSH 2 219#define DEFSHELL_INDEX_CSH 2
220#endif /* !DEFSHELL_CUSTOM */ 220#endif /* !DEFSHELL_CUSTOM */
221 221
222#ifndef DEFSHELL_INDEX 222#ifndef DEFSHELL_INDEX
223#define DEFSHELL_INDEX 0 /* DEFSHELL_INDEX_CUSTOM or DEFSHELL_INDEX_SH */ 223#define DEFSHELL_INDEX 0 /* DEFSHELL_INDEX_CUSTOM or DEFSHELL_INDEX_SH */
224#endif /* !DEFSHELL_INDEX */ 224#endif /* !DEFSHELL_INDEX */
225 225
226static Shell shells[] = { 226static Shell shells[] = {
227#ifdef DEFSHELL_CUSTOM 227#ifdef DEFSHELL_CUSTOM
228 /* 228 /*
229 * An sh-compatible shell with a non-standard name. 229 * An sh-compatible shell with a non-standard name.
230 * 230 *
231 * Keep this in sync with the "sh" description below, but avoid 231 * Keep this in sync with the "sh" description below, but avoid
232 * non-portable features that might not be supplied by all 232 * non-portable features that might not be supplied by all
233 * sh-compatible shells. 233 * sh-compatible shells.
234 */ 234 */
235{ 235{
236 DEFSHELL_CUSTOM, 236 DEFSHELL_CUSTOM,
237 FALSE, "", "", "", 0, 237 FALSE, "", "", "", 0,
238 FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#', 238 FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#',
239 "", 239 "",
240 "", 240 "",
241}, 241},
242#endif /* DEFSHELL_CUSTOM */ 242#endif /* DEFSHELL_CUSTOM */
243 /* 243 /*
244 * SH description. Echo control is also possible and, under 244 * SH description. Echo control is also possible and, under
245 * sun UNIX anyway, one can even control error checking. 245 * sun UNIX anyway, one can even control error checking.
246 */ 246 */
247{ 247{
248 "sh", 248 "sh",
249 FALSE, "", "", "", 0, 249 FALSE, "", "", "", 0,
250 FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#', 250 FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#',
251#if defined(MAKE_NATIVE) && defined(__NetBSD__) 251#if defined(MAKE_NATIVE) && defined(__NetBSD__)
252 "q", 252 "q",
253#else 253#else
254 "", 254 "",
255#endif 255#endif
256 "", 256 "",
257}, 257},
258 /* 258 /*
259 * KSH description. 259 * KSH description.
260 */ 260 */
261{ 261{
262 "ksh", 262 "ksh",
263 TRUE, "set +v", "set -v", "set +v", 6, 263 TRUE, "set +v", "set -v", "set +v", 6,
264 FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#', 264 FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#',
265 "v", 265 "v",
266 "", 266 "",
267}, 267},
268 /* 268 /*
269 * CSH description. The csh can do echo control by playing 269 * CSH description. The csh can do echo control by playing
270 * with the setting of the 'echo' shell variable. Sadly, 270 * with the setting of the 'echo' shell variable. Sadly,
271 * however, it is unable to do error control nicely. 271 * however, it is unable to do error control nicely.
272 */ 272 */
273{ 273{
274 "csh", 274 "csh",
275 TRUE, "unset verbose", "set verbose", "unset verbose", 10, 275 TRUE, "unset verbose", "set verbose", "unset verbose", 10,
276 FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"\n", "", "'\\\n'", '#', 276 FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"\n", "", "'\\\n'", '#',
277 "v", "e", 277 "v", "e",
278}, 278},
279 /* 279 /*
280 * UNKNOWN. 280 * UNKNOWN.
281 */ 281 */
282{ 282{
283 NULL, 283 NULL,
284 FALSE, NULL, NULL, NULL, 0, 284 FALSE, NULL, NULL, NULL, 0,
285 FALSE, NULL, NULL, NULL, NULL, 0, 285 FALSE, NULL, NULL, NULL, NULL, 0,
286 NULL, NULL, 286 NULL, NULL,
287} 287}
288}; 288};
289static Shell *commandShell = &shells[DEFSHELL_INDEX]; /* this is the shell to 289static Shell *commandShell = &shells[DEFSHELL_INDEX]; /* this is the shell to
290 * which we pass all 290 * which we pass all
291 * commands in the Makefile. 291 * commands in the Makefile.
292 * It is set by the 292 * It is set by the
293 * Job_ParseShell function */ 293 * Job_ParseShell function */
294const char *shellPath = NULL, /* full pathname of 294const char *shellPath = NULL, /* full pathname of
295 * executable image */ 295 * executable image */
296 *shellName = NULL; /* last component of shell */ 296 *shellName = NULL; /* last component of shell */
297char *shellErrFlag = NULL; 297char *shellErrFlag = NULL;
298static char *shellArgv = NULL; /* Custom shell args */ 298static char *shellArgv = NULL; /* Custom shell args */
299 299
300 300
301STATIC Job *job_table; /* The structures that describe them */ 301STATIC Job *job_table; /* The structures that describe them */
302STATIC Job *job_table_end; /* job_table + maxJobs */ 302STATIC Job *job_table_end; /* job_table + maxJobs */
303static int wantToken; /* we want a token */ 303static int wantToken; /* we want a token */
304static int lurking_children = 0; 304static int lurking_children = 0;
305static int make_suspended = 0; /* non-zero if we've seen a SIGTSTP (etc) */ 305static int make_suspended = 0; /* non-zero if we've seen a SIGTSTP (etc) */
306 306
307/* 307/*
308 * Set of descriptors of pipes connected to 308 * Set of descriptors of pipes connected to
309 * the output channels of children 309 * the output channels of children
310 */ 310 */
311static struct pollfd *fds = NULL; 311static struct pollfd *fds = NULL;
312static Job **jobfds = NULL; 312static Job **jobfds = NULL;
313static int nfds = 0; 313static int nfds = 0;
314static void watchfd(Job *); 314static void watchfd(Job *);
315static void clearfd(Job *); 315static void clearfd(Job *);
316static int readyfd(Job *); 316static int readyfd(Job *);
317 317
318STATIC GNode *lastNode; /* The node for which output was most recently 318STATIC GNode *lastNode; /* The node for which output was most recently
319 * produced. */ 319 * produced. */
320static char *targPrefix = NULL; /* What we print at the start of TARG_FMT */ 320static char *targPrefix = NULL; /* What we print at the start of TARG_FMT */
321static Job tokenWaitJob; /* token wait pseudo-job */ 321static Job tokenWaitJob; /* token wait pseudo-job */
322 322
323static Job childExitJob; /* child exit pseudo-job */ 323static Job childExitJob; /* child exit pseudo-job */
324#define CHILD_EXIT "." 324#define CHILD_EXIT "."
325#define DO_JOB_RESUME "R" 325#define DO_JOB_RESUME "R"
326 326
327static const int npseudojobs = 2; /* number of pseudo-jobs */ 327static const int npseudojobs = 2; /* number of pseudo-jobs */
328 328
329#define TARG_FMT "%s %s ---\n" /* Default format */ 329#define TARG_FMT "%s %s ---\n" /* Default format */
330#define MESSAGE(fp, gn) \ 330#define MESSAGE(fp, gn) \
331 if (maxJobs != 1 && targPrefix && *targPrefix) \ 331 if (maxJobs != 1 && targPrefix && *targPrefix) \
332 (void)fprintf(fp, TARG_FMT, targPrefix, gn->name) 332 (void)fprintf(fp, TARG_FMT, targPrefix, gn->name)
333 333
334static sigset_t caught_signals; /* Set of signals we handle */ 334static sigset_t caught_signals; /* Set of signals we handle */
335 335
336static void JobChildSig(int); 336static void JobChildSig(int);
337static void JobContinueSig(int); 337static void JobContinueSig(int);
338static Job *JobFindPid(int, int, Boolean); 338static Job *JobFindPid(int, int, Boolean);
339static int JobPrintCommand(void *, void *); 339static int JobPrintCommand(void *, void *);
340static int JobSaveCommand(void *, void *); 340static int JobSaveCommand(void *, void *);
341static void JobClose(Job *); 341static void JobClose(Job *);
342static void JobExec(Job *, char **); 342static void JobExec(Job *, char **);
343static void JobMakeArgv(Job *, char **); 343static void JobMakeArgv(Job *, char **);
344static int JobStart(GNode *, int); 344static int JobStart(GNode *, int);
345static char *JobOutput(Job *, char *, char *, int); 345static char *JobOutput(Job *, char *, char *, int);
346static void JobDoOutput(Job *, Boolean); 346static void JobDoOutput(Job *, Boolean);
347static Shell *JobMatchShell(const char *); 347static Shell *JobMatchShell(const char *);
348static void JobInterrupt(int, int) MAKE_ATTR_DEAD; 348static void JobInterrupt(int, int) MAKE_ATTR_DEAD;
349static void JobRestartJobs(void); 349static void JobRestartJobs(void);
350static void JobTokenAdd(void); 350static void JobTokenAdd(void);
351static void JobSigLock(sigset_t *); 351static void JobSigLock(sigset_t *);
352static void JobSigUnlock(sigset_t *); 352static void JobSigUnlock(sigset_t *);
353static void JobSigReset(void); 353static void JobSigReset(void);
354 354
355const char *malloc_options MAKE_ATTR_UNUSED = "A"; /* see jemalloc(3) */ 355const char *malloc_options MAKE_ATTR_UNUSED = "A"; /* see jemalloc(3) */
356 356
357static unsigned 357static unsigned
358nfds_per_job(void) 358nfds_per_job(void)
359{ 359{
360#if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) 360#if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
361 if (useMeta) 361 if (useMeta)
362 return 2; 362 return 2;
363#endif 363#endif
364 return 1; 364 return 1;
365} 365}
366 366
367static void 367static void
368job_table_dump(const char *where) 368job_table_dump(const char *where)
369{ 369{
370 Job *job; 370 Job *job;
371 371
372 fprintf(debug_file, "job table @ %s\n", where); 372 fprintf(debug_file, "job table @ %s\n", where);
373 for (job = job_table; job < job_table_end; job++) { 373 for (job = job_table; job < job_table_end; job++) {
374 fprintf(debug_file, "job %d, status %d, flags %d, pid %d\n", 374 fprintf(debug_file, "job %d, status %d, flags %d, pid %d\n",
375 (int)(job - job_table), job->job_state, job->flags, job->pid); 375 (int)(job - job_table), job->job_state, job->flags, job->pid);
376 } 376 }
377} 377}
378 378
379/* 379/*
380 * Delete the target of a failed, interrupted, or otherwise 380 * Delete the target of a failed, interrupted, or otherwise
381 * unsuccessful job unless inhibited by .PRECIOUS. 381 * unsuccessful job unless inhibited by .PRECIOUS.
382 */ 382 */
383static void 383static void
384JobDeleteTarget(GNode *gn) 384JobDeleteTarget(GNode *gn)
385{ 385{
386 if ((gn->type & (OP_JOIN|OP_PHONY)) == 0 && !Targ_Precious(gn)) { 386 if ((gn->type & (OP_JOIN|OP_PHONY)) == 0 && !Targ_Precious(gn)) {
387 char *file = (gn->path == NULL ? gn->name : gn->path); 387 char *file = (gn->path == NULL ? gn->name : gn->path);
388 if (!noExecute && eunlink(file) != -1) { 388 if (!noExecute && eunlink(file) != -1) {
389 Error("*** %s removed", file); 389 Error("*** %s removed", file);
390 } 390 }
391 } 391 }
392} 392}
393 393
394/* 394/*
395 * JobSigLock/JobSigUnlock 395 * JobSigLock/JobSigUnlock
396 * 396 *
397 * Signal lock routines to get exclusive access. Currently used to 397 * Signal lock routines to get exclusive access. Currently used to
398 * protect `jobs' and `stoppedJobs' list manipulations. 398 * protect `jobs' and `stoppedJobs' list manipulations.
399 */ 399 */
400static void JobSigLock(sigset_t *omaskp) 400static void JobSigLock(sigset_t *omaskp)
401{ 401{
402 if (sigprocmask(SIG_BLOCK, &caught_signals, omaskp) != 0) { 402 if (sigprocmask(SIG_BLOCK, &caught_signals, omaskp) != 0) {
403 Punt("JobSigLock: sigprocmask: %s", strerror(errno)); 403 Punt("JobSigLock: sigprocmask: %s", strerror(errno));
404 sigemptyset(omaskp); 404 sigemptyset(omaskp);
405 } 405 }
406} 406}
407 407
408static void JobSigUnlock(sigset_t *omaskp) 408static void JobSigUnlock(sigset_t *omaskp)
409{ 409{
410 (void)sigprocmask(SIG_SETMASK, omaskp, NULL); 410 (void)sigprocmask(SIG_SETMASK, omaskp, NULL);
411} 411}
412 412
413static void 413static void
414JobCreatePipe(Job *job, int minfd) 414JobCreatePipe(Job *job, int minfd)
415{ 415{
416 int i, fd, flags; 416 int i, fd, flags;
417 417
418 if (pipe(job->jobPipe) == -1) 418 if (pipe(job->jobPipe) == -1)
419 Punt("Cannot create pipe: %s", strerror(errno)); 419 Punt("Cannot create pipe: %s", strerror(errno));
420 420
421 for (i = 0; i < 2; i++) { 421 for (i = 0; i < 2; i++) {
422 /* Avoid using low numbered fds */ 422 /* Avoid using low numbered fds */
423 fd = fcntl(job->jobPipe[i], F_DUPFD, minfd); 423 fd = fcntl(job->jobPipe[i], F_DUPFD, minfd);
424 if (fd != -1) { 424 if (fd != -1) {
425 close(job->jobPipe[i]); 425 close(job->jobPipe[i]);
426 job->jobPipe[i] = fd; 426 job->jobPipe[i] = fd;
427 } 427 }
428 } 428 }
429 429
430 /* Set close-on-exec flag for both */ 430 /* Set close-on-exec flag for both */
431 if (fcntl(job->jobPipe[0], F_SETFD, FD_CLOEXEC) == -1) 431 if (fcntl(job->jobPipe[0], F_SETFD, FD_CLOEXEC) == -1)
432 Punt("Cannot set close-on-exec: %s", strerror(errno)); 432 Punt("Cannot set close-on-exec: %s", strerror(errno));
433 if (fcntl(job->jobPipe[1], F_SETFD, FD_CLOEXEC) == -1) 433 if (fcntl(job->jobPipe[1], F_SETFD, FD_CLOEXEC) == -1)
434 Punt("Cannot set close-on-exec: %s", strerror(errno)); 434 Punt("Cannot set close-on-exec: %s", strerror(errno));
435 435
436 /* 436 /*
437 * We mark the input side of the pipe non-blocking; we poll(2) the 437 * We mark the input side of the pipe non-blocking; we poll(2) the
438 * pipe when we're waiting for a job token, but we might lose the 438 * pipe when we're waiting for a job token, but we might lose the
439 * race for the token when a new one becomes available, so the read 439 * race for the token when a new one becomes available, so the read
440 * from the pipe should not block. 440 * from the pipe should not block.
441 */ 441 */
442 flags = fcntl(job->jobPipe[0], F_GETFL, 0); 442 flags = fcntl(job->jobPipe[0], F_GETFL, 0);
443 if (flags == -1) 443 if (flags == -1)
444 Punt("Cannot get flags: %s", strerror(errno)); 444 Punt("Cannot get flags: %s", strerror(errno));
445 flags |= O_NONBLOCK; 445 flags |= O_NONBLOCK;
446 if (fcntl(job->jobPipe[0], F_SETFL, flags) == -1) 446 if (fcntl(job->jobPipe[0], F_SETFL, flags) == -1)
447 Punt("Cannot set flags: %s", strerror(errno)); 447 Punt("Cannot set flags: %s", strerror(errno));
448} 448}
449 449
450/*- 450/*-
451 *----------------------------------------------------------------------- 451 *-----------------------------------------------------------------------
452 * JobCondPassSig -- 452 * JobCondPassSig --
453 * Pass a signal to a job 453 * Pass a signal to a job
454 * 454 *
455 * Input: 455 * Input:
456 * signop Signal to send it 456 * signop Signal to send it
457 * 457 *
458 * Side Effects: 458 * Side Effects:
459 * None, except the job may bite it. 459 * None, except the job may bite it.
460 * 460 *
461 *----------------------------------------------------------------------- 461 *-----------------------------------------------------------------------
462 */ 462 */
463static void 463static void
464JobCondPassSig(int signo) 464JobCondPassSig(int signo)
465{ 465{
466 Job *job; 466 Job *job;
467 467
468 if (DEBUG(JOB)) { 468 if (DEBUG(JOB)) {
469 (void)fprintf(debug_file, "JobCondPassSig(%d) called.\n", signo); 469 (void)fprintf(debug_file, "JobCondPassSig(%d) called.\n", signo);
470 } 470 }
471 471
472 for (job = job_table; job < job_table_end; job++) { 472 for (job = job_table; job < job_table_end; job++) {
473 if (job->job_state != JOB_ST_RUNNING) 473 if (job->job_state != JOB_ST_RUNNING)
474 continue; 474 continue;
475 if (DEBUG(JOB)) { 475 if (DEBUG(JOB)) {
476 (void)fprintf(debug_file, 476 (void)fprintf(debug_file,
477 "JobCondPassSig passing signal %d to child %d.\n", 477 "JobCondPassSig passing signal %d to child %d.\n",
478 signo, job->pid); 478 signo, job->pid);
479 } 479 }
480 KILLPG(job->pid, signo); 480 KILLPG(job->pid, signo);
481 } 481 }
482} 482}
483 483
484/*- 484/*-
485 *----------------------------------------------------------------------- 485 *-----------------------------------------------------------------------
486 * JobChldSig -- 486 * JobChldSig --
487 * SIGCHLD handler. 487 * SIGCHLD handler.
488 * 488 *
489 * Input: 489 * Input:
490 * signo The signal number we've received 490 * signo The signal number we've received
491 * 491 *
492 * Results: 492 * Results:
493 * None. 493 * None.
494 * 494 *
495 * Side Effects: 495 * Side Effects:
496 * Sends a token on the child exit pipe to wake us up from 496 * Sends a token on the child exit pipe to wake us up from
497 * select()/poll(). 497 * select()/poll().
498 * 498 *
499 *----------------------------------------------------------------------- 499 *-----------------------------------------------------------------------
500 */ 500 */
501static void 501static void
502JobChildSig(int signo MAKE_ATTR_UNUSED) 502JobChildSig(int signo MAKE_ATTR_UNUSED)
503{ 503{
504 while (write(childExitJob.outPipe, CHILD_EXIT, 1) == -1 && errno == EAGAIN) 504 while (write(childExitJob.outPipe, CHILD_EXIT, 1) == -1 && errno == EAGAIN)
505 continue; 505 continue;
506} 506}
507 507
508 508
509/*- 509/*-
510 *----------------------------------------------------------------------- 510 *-----------------------------------------------------------------------
511 * JobContinueSig -- 511 * JobContinueSig --
512 * Resume all stopped jobs. 512 * Resume all stopped jobs.
513 * 513 *
514 * Input: 514 * Input:
515 * signo The signal number we've received 515 * signo The signal number we've received
516 * 516 *
517 * Results: 517 * Results:
518 * None. 518 * None.
519 * 519 *
520 * Side Effects: 520 * Side Effects:
521 * Jobs start running again. 521 * Jobs start running again.
522 * 522 *
523 *----------------------------------------------------------------------- 523 *-----------------------------------------------------------------------
524 */ 524 */
525static void 525static void
526JobContinueSig(int signo MAKE_ATTR_UNUSED) 526JobContinueSig(int signo MAKE_ATTR_UNUSED)
527{ 527{
528 /* 528 /*
529 * Defer sending to SIGCONT to our stopped children until we return 529 * Defer sending to SIGCONT to our stopped children until we return
530 * from the signal handler. 530 * from the signal handler.
531 */ 531 */
532 while (write(childExitJob.outPipe, DO_JOB_RESUME, 1) == -1 && 532 while (write(childExitJob.outPipe, DO_JOB_RESUME, 1) == -1 &&
533 errno == EAGAIN) 533 errno == EAGAIN)
534 continue; 534 continue;
535} 535}
536 536
537/*- 537/*-
538 *----------------------------------------------------------------------- 538 *-----------------------------------------------------------------------
539 * JobPassSig -- 539 * JobPassSig --
540 * Pass a signal on to all jobs, then resend to ourselves. 540 * Pass a signal on to all jobs, then resend to ourselves.
541 * 541 *
542 * Input: 542 * Input:
543 * signo The signal number we've received 543 * signo The signal number we've received
544 * 544 *
545 * Results: 545 * Results:
546 * None. 546 * None.
547 * 547 *
548 * Side Effects: 548 * Side Effects:
549 * We die by the same signal. 549 * We die by the same signal.
550 * 550 *
551 *----------------------------------------------------------------------- 551 *-----------------------------------------------------------------------
552 */ 552 */
553MAKE_ATTR_DEAD static void 553MAKE_ATTR_DEAD static void
554JobPassSig_int(int signo) 554JobPassSig_int(int signo)
555{ 555{
556 /* Run .INTERRUPT target then exit */ 556 /* Run .INTERRUPT target then exit */
557 JobInterrupt(TRUE, signo); 557 JobInterrupt(TRUE, signo);
558} 558}
559 559
560MAKE_ATTR_DEAD static void 560MAKE_ATTR_DEAD static void
561JobPassSig_term(int signo) 561JobPassSig_term(int signo)
562{ 562{
563 /* Dont run .INTERRUPT target then exit */ 563 /* Dont run .INTERRUPT target then exit */
564 JobInterrupt(FALSE, signo); 564 JobInterrupt(FALSE, signo);
565} 565}
566 566
567static void 567static void
568JobPassSig_suspend(int signo) 568JobPassSig_suspend(int signo)
569{ 569{
570 sigset_t nmask, omask; 570 sigset_t nmask, omask;
571 struct sigaction act; 571 struct sigaction act;
572 572
573 /* Suppress job started/continued messages */ 573 /* Suppress job started/continued messages */
574 make_suspended = 1; 574 make_suspended = 1;
575 575
576 /* Pass the signal onto every job */ 576 /* Pass the signal onto every job */
577 JobCondPassSig(signo); 577 JobCondPassSig(signo);
578 578
579 /* 579 /*
580 * Send ourselves the signal now we've given the message to everyone else. 580 * Send ourselves the signal now we've given the message to everyone else.
581 * Note we block everything else possible while we're getting the signal. 581 * Note we block everything else possible while we're getting the signal.
582 * This ensures that all our jobs get continued when we wake up before 582 * This ensures that all our jobs get continued when we wake up before
583 * we take any other signal. 583 * we take any other signal.
584 */ 584 */
585 sigfillset(&nmask); 585 sigfillset(&nmask);
586 sigdelset(&nmask, signo); 586 sigdelset(&nmask, signo);
587 (void)sigprocmask(SIG_SETMASK, &nmask, &omask); 587 (void)sigprocmask(SIG_SETMASK, &nmask, &omask);
588 588
589 act.sa_handler = SIG_DFL; 589 act.sa_handler = SIG_DFL;
590 sigemptyset(&act.sa_mask); 590 sigemptyset(&act.sa_mask);
591 act.sa_flags = 0; 591 act.sa_flags = 0;
592 (void)sigaction(signo, &act, NULL); 592 (void)sigaction(signo, &act, NULL);
593 593
594 if (DEBUG(JOB)) { 594 if (DEBUG(JOB)) {
595 (void)fprintf(debug_file, 595 (void)fprintf(debug_file,
596 "JobPassSig passing signal %d to self.\n", signo); 596 "JobPassSig passing signal %d to self.\n", signo);
597 } 597 }
598 598
599 (void)kill(getpid(), signo); 599 (void)kill(getpid(), signo);
600 600
601 /* 601 /*
602 * We've been continued. 602 * We've been continued.
603 * 603 *
604 * A whole host of signals continue to happen! 604 * A whole host of signals continue to happen!
605 * SIGCHLD for any processes that actually suspended themselves. 605 * SIGCHLD for any processes that actually suspended themselves.
606 * SIGCHLD for any processes that exited while we were alseep. 606 * SIGCHLD for any processes that exited while we were alseep.
607 * The SIGCONT that actually caused us to wakeup. 607 * The SIGCONT that actually caused us to wakeup.
608 * 608 *
609 * Since we defer passing the SIGCONT on to our children until 609 * Since we defer passing the SIGCONT on to our children until
610 * the main processing loop, we can be sure that all the SIGCHLD 610 * the main processing loop, we can be sure that all the SIGCHLD
611 * events will have happened by then - and that the waitpid() will 611 * events will have happened by then - and that the waitpid() will
612 * collect the child 'suspended' events. 612 * collect the child 'suspended' events.
613 * For correct sequencing we just need to ensure we process the 613 * For correct sequencing we just need to ensure we process the
614 * waitpid() before passign on the SIGCONT. 614 * waitpid() before passign on the SIGCONT.
615 * 615 *
616 * In any case nothing else is needed here. 616 * In any case nothing else is needed here.
617 */ 617 */
618 618
619 /* Restore handler and signal mask */ 619 /* Restore handler and signal mask */
620 act.sa_handler = JobPassSig_suspend; 620 act.sa_handler = JobPassSig_suspend;
621 (void)sigaction(signo, &act, NULL); 621 (void)sigaction(signo, &act, NULL);
622 (void)sigprocmask(SIG_SETMASK, &omask, NULL); 622 (void)sigprocmask(SIG_SETMASK, &omask, NULL);
623} 623}
624 624
625/*- 625/*-
626 *----------------------------------------------------------------------- 626 *-----------------------------------------------------------------------
627 * JobFindPid -- 627 * JobFindPid --
628 * Compare the pid of the job with the given pid and return 0 if they 628 * Compare the pid of the job with the given pid and return 0 if they
629 * are equal. This function is called from Job_CatchChildren 629 * are equal. This function is called from Job_CatchChildren
630 * to find the job descriptor of the finished job. 630 * to find the job descriptor of the finished job.
631 * 631 *
632 * Input: 632 * Input:
633 * job job to examine 633 * job job to examine
634 * pid process id desired 634 * pid process id desired
635 * 635 *
636 * Results: 636 * Results:
637 * Job with matching pid 637 * Job with matching pid
638 * 638 *
639 * Side Effects: 639 * Side Effects:
640 * None 640 * None
641 *----------------------------------------------------------------------- 641 *-----------------------------------------------------------------------
642 */ 642 */
643static Job * 643static Job *
644JobFindPid(int pid, int status, Boolean isJobs) 644JobFindPid(int pid, int status, Boolean isJobs)
645{ 645{
646 Job *job; 646 Job *job;
647 647
648 for (job = job_table; job < job_table_end; job++) { 648 for (job = job_table; job < job_table_end; job++) {
649 if ((job->job_state == status) && job->pid == pid) 649 if ((job->job_state == status) && job->pid == pid)
650 return job; 650 return job;
651 } 651 }
652 if (DEBUG(JOB) && isJobs) 652 if (DEBUG(JOB) && isJobs)
653 job_table_dump("no pid"); 653 job_table_dump("no pid");
654 return NULL; 654 return NULL;
655} 655}
656 656
657/*- 657/*-
658 *----------------------------------------------------------------------- 658 *-----------------------------------------------------------------------
659 * JobPrintCommand -- 659 * JobPrintCommand --
660 * Put out another command for the given job. If the command starts 660 * Put out another command for the given job. If the command starts
661 * with an @ or a - we process it specially. In the former case, 661 * with an @ or a - we process it specially. In the former case,
662 * so long as the -s and -n flags weren't given to make, we stick 662 * so long as the -s and -n flags weren't given to make, we stick
663 * a shell-specific echoOff command in the script. In the latter, 663 * a shell-specific echoOff command in the script. In the latter,
664 * we ignore errors for the entire job, unless the shell has error 664 * we ignore errors for the entire job, unless the shell has error
665 * control. 665 * control.
666 * If the command is just "..." we take all future commands for this 666 * If the command is just "..." we take all future commands for this
667 * job to be commands to be executed once the entire graph has been 667 * job to be commands to be executed once the entire graph has been
668 * made and return non-zero to signal that the end of the commands 668 * made and return non-zero to signal that the end of the commands
669 * was reached. These commands are later attached to the postCommands 669 * was reached. These commands are later attached to the postCommands
670 * node and executed by Job_End when all things are done. 670 * node and executed by Job_End when all things are done.
671 * This function is called from JobStart via Lst_ForEach. 671 * This function is called from JobStart via Lst_ForEach.
672 * 672 *
673 * Input: 673 * Input:
674 * cmdp command string to print 674 * cmdp command string to print
675 * jobp job for which to print it 675 * jobp job for which to print it
676 * 676 *
677 * Results: 677 * Results:
678 * Always 0, unless the command was "..." 678 * Always 0, unless the command was "..."
679 * 679 *
680 * Side Effects: 680 * Side Effects:
681 * If the command begins with a '-' and the shell has no error control, 681 * If the command begins with a '-' and the shell has no error control,
682 * the JOB_IGNERR flag is set in the job descriptor. 682 * the JOB_IGNERR flag is set in the job descriptor.
683 * If the command is "..." and we're not ignoring such things, 683 * If the command is "..." and we're not ignoring such things,
684 * tailCmds is set to the successor node of the cmd. 684 * tailCmds is set to the successor node of the cmd.
685 * numCommands is incremented if the command is actually printed. 685 * numCommands is incremented if the command is actually printed.
686 *----------------------------------------------------------------------- 686 *-----------------------------------------------------------------------
687 */ 687 */
688static int 688static int
689JobPrintCommand(void *cmdp, void *jobp) 689JobPrintCommand(void *cmdp, void *jobp)
690{ 690{
691 Boolean noSpecials; /* true if we shouldn't worry about 691 Boolean noSpecials; /* true if we shouldn't worry about
692 * inserting special commands into 692 * inserting special commands into
693 * the input stream. */ 693 * the input stream. */
694 Boolean shutUp = FALSE; /* true if we put a no echo command 694 Boolean shutUp = FALSE; /* true if we put a no echo command
695 * into the command file */ 695 * into the command file */
696 Boolean errOff = FALSE; /* true if we turned error checking 696 Boolean errOff = FALSE; /* true if we turned error checking
697 * off before printing the command 697 * off before printing the command
698 * and need to turn it back on */ 698 * and need to turn it back on */
699 const char *cmdTemplate; /* Template to use when printing the 699 const char *cmdTemplate; /* Template to use when printing the
700 * command */ 700 * command */
701 char *cmdStart; /* Start of expanded command */ 701 char *cmdStart; /* Start of expanded command */
702 char *escCmd = NULL; /* Command with quotes/backticks escaped */ 702 char *escCmd = NULL; /* Command with quotes/backticks escaped */
703 char *cmd = (char *)cmdp; 703 char *cmd = (char *)cmdp;
704 Job *job = (Job *)jobp; 704 Job *job = (Job *)jobp;
705 705
706 noSpecials = NoExecute(job->node); 706 noSpecials = NoExecute(job->node);
707 707
708 if (strcmp(cmd, "...") == 0) { 708 if (strcmp(cmd, "...") == 0) {
709 job->node->type |= OP_SAVE_CMDS; 709 job->node->type |= OP_SAVE_CMDS;
710 if ((job->flags & JOB_IGNDOTS) == 0) { 710 if ((job->flags & JOB_IGNDOTS) == 0) {
711 LstNode dotsNode = Lst_Member(job->node->commands, cmd); 711 LstNode dotsNode = Lst_Member(job->node->commands, cmd);
712 job->tailCmds = dotsNode != NULL ? Lst_Succ(dotsNode) : NULL; 712 job->tailCmds = dotsNode != NULL ? LstNode_Next(dotsNode) : NULL;
713 return 1; 713 return 1;
714 } 714 }
715 return 0; 715 return 0;
716 } 716 }
717 717
718#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \ 718#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \
719 (void)fprintf(debug_file, fmt, arg); \ 719 (void)fprintf(debug_file, fmt, arg); \
720 } \ 720 } \
721 (void)fprintf(job->cmdFILE, fmt, arg); \ 721 (void)fprintf(job->cmdFILE, fmt, arg); \
722 (void)fflush(job->cmdFILE); 722 (void)fflush(job->cmdFILE);
723 723
724 numCommands += 1; 724 numCommands += 1;
725 725
726 cmdStart = cmd = Var_Subst(cmd, job->node, VARE_WANTRES); 726 cmdStart = cmd = Var_Subst(cmd, job->node, VARE_WANTRES);
727 727
728 cmdTemplate = "%s\n"; 728 cmdTemplate = "%s\n";
729 729
730 /* 730 /*
731 * Check for leading @' and -'s to control echoing and error checking. 731 * Check for leading @' and -'s to control echoing and error checking.
732 */ 732 */
733 while (*cmd == '@' || *cmd == '-' || (*cmd == '+')) { 733 while (*cmd == '@' || *cmd == '-' || (*cmd == '+')) {
734 switch (*cmd) { 734 switch (*cmd) {
735 case '@': 735 case '@':
736 shutUp = DEBUG(LOUD) ? FALSE : TRUE; 736 shutUp = DEBUG(LOUD) ? FALSE : TRUE;
737 break; 737 break;
738 case '-': 738 case '-':
739 errOff = TRUE; 739 errOff = TRUE;
740 break; 740 break;
741 case '+': 741 case '+':
742 if (noSpecials) { 742 if (noSpecials) {
743 /* 743 /*
744 * We're not actually executing anything... 744 * We're not actually executing anything...
745 * but this one needs to be - use compat mode just for it. 745 * but this one needs to be - use compat mode just for it.
746 */ 746 */
747 CompatRunCommand(cmdp, job->node); 747 CompatRunCommand(cmdp, job->node);
748 free(cmdStart); 748 free(cmdStart);
749 return 0; 749 return 0;
750 } 750 }
751 break; 751 break;
752 } 752 }
753 cmd++; 753 cmd++;
754 } 754 }
755 755
756 while (isspace((unsigned char) *cmd)) 756 while (isspace((unsigned char) *cmd))
757 cmd++; 757 cmd++;
758 758
759 /* 759 /*
760 * If the shell doesn't have error control the alternate echo'ing will 760 * If the shell doesn't have error control the alternate echo'ing will
761 * be done (to avoid showing additional error checking code) 761 * be done (to avoid showing additional error checking code)
762 * and this will need the characters '$ ` \ "' escaped 762 * and this will need the characters '$ ` \ "' escaped
763 */ 763 */
764 764
765 if (!commandShell->hasErrCtl) { 765 if (!commandShell->hasErrCtl) {
766 int i, j; 766 int i, j;
767 767
768 /* Worst that could happen is every char needs escaping. */ 768 /* Worst that could happen is every char needs escaping. */
769 escCmd = bmake_malloc((strlen(cmd) * 2) + 1); 769 escCmd = bmake_malloc((strlen(cmd) * 2) + 1);
770 for (i = 0, j = 0; cmd[i] != '\0'; i++, j++) { 770 for (i = 0, j = 0; cmd[i] != '\0'; i++, j++) {
771 if (cmd[i] == '$' || cmd[i] == '`' || cmd[i] == '\\' || 771 if (cmd[i] == '$' || cmd[i] == '`' || cmd[i] == '\\' ||
772 cmd[i] == '"') 772 cmd[i] == '"')
773 escCmd[j++] = '\\'; 773 escCmd[j++] = '\\';
774 escCmd[j] = cmd[i]; 774 escCmd[j] = cmd[i];
775 } 775 }
776 escCmd[j] = '\0'; 776 escCmd[j] = '\0';
777 } 777 }
778 778
779 if (shutUp) { 779 if (shutUp) {
780 if (!(job->flags & JOB_SILENT) && !noSpecials && 780 if (!(job->flags & JOB_SILENT) && !noSpecials &&
781 commandShell->hasEchoCtl) { 781 commandShell->hasEchoCtl) {
782 DBPRINTF("%s\n", commandShell->echoOff); 782 DBPRINTF("%s\n", commandShell->echoOff);
783 } else { 783 } else {
784 if (commandShell->hasErrCtl) 784 if (commandShell->hasErrCtl)
785 shutUp = FALSE; 785 shutUp = FALSE;
786 } 786 }
787 } 787 }
788 788
789 if (errOff) { 789 if (errOff) {
790 if (!noSpecials) { 790 if (!noSpecials) {
791 if (commandShell->hasErrCtl) { 791 if (commandShell->hasErrCtl) {
792 /* 792 /*
793 * we don't want the error-control commands showing 793 * we don't want the error-control commands showing
794 * up either, so we turn off echoing while executing 794 * up either, so we turn off echoing while executing
795 * them. We could put another field in the shell 795 * them. We could put another field in the shell
796 * structure to tell JobDoOutput to look for this 796 * structure to tell JobDoOutput to look for this
797 * string too, but why make it any more complex than 797 * string too, but why make it any more complex than
798 * it already is? 798 * it already is?
799 */ 799 */
800 if (!(job->flags & JOB_SILENT) && !shutUp && 800 if (!(job->flags & JOB_SILENT) && !shutUp &&
801 commandShell->hasEchoCtl) { 801 commandShell->hasEchoCtl) {
802 DBPRINTF("%s\n", commandShell->echoOff); 802 DBPRINTF("%s\n", commandShell->echoOff);
803 DBPRINTF("%s\n", commandShell->ignErr); 803 DBPRINTF("%s\n", commandShell->ignErr);
804 DBPRINTF("%s\n", commandShell->echoOn); 804 DBPRINTF("%s\n", commandShell->echoOn);
805 } else { 805 } else {
806 DBPRINTF("%s\n", commandShell->ignErr); 806 DBPRINTF("%s\n", commandShell->ignErr);
807 } 807 }
808 } else if (commandShell->ignErr && 808 } else if (commandShell->ignErr &&
809 (*commandShell->ignErr != '\0')) 809 (*commandShell->ignErr != '\0'))
810 { 810 {
811 /* 811 /*
812 * The shell has no error control, so we need to be 812 * The shell has no error control, so we need to be
813 * weird to get it to ignore any errors from the command. 813 * weird to get it to ignore any errors from the command.
814 * If echoing is turned on, we turn it off and use the 814 * If echoing is turned on, we turn it off and use the
815 * errCheck template to echo the command. Leave echoing 815 * errCheck template to echo the command. Leave echoing
816 * off so the user doesn't see the weirdness we go through 816 * off so the user doesn't see the weirdness we go through
817 * to ignore errors. Set cmdTemplate to use the weirdness 817 * to ignore errors. Set cmdTemplate to use the weirdness
818 * instead of the simple "%s\n" template. 818 * instead of the simple "%s\n" template.
819 */ 819 */
820 job->flags |= JOB_IGNERR; 820 job->flags |= JOB_IGNERR;
821 if (!(job->flags & JOB_SILENT) && !shutUp) { 821 if (!(job->flags & JOB_SILENT) && !shutUp) {
822 if (commandShell->hasEchoCtl) { 822 if (commandShell->hasEchoCtl) {
823 DBPRINTF("%s\n", commandShell->echoOff); 823 DBPRINTF("%s\n", commandShell->echoOff);
824 } 824 }
825 DBPRINTF(commandShell->errCheck, escCmd); 825 DBPRINTF(commandShell->errCheck, escCmd);
826 shutUp = TRUE; 826 shutUp = TRUE;
827 } else { 827 } else {
828 if (!shutUp) { 828 if (!shutUp) {
829 DBPRINTF(commandShell->errCheck, escCmd); 829 DBPRINTF(commandShell->errCheck, escCmd);
830 } 830 }
831 } 831 }
832 cmdTemplate = commandShell->ignErr; 832 cmdTemplate = commandShell->ignErr;
833 /* 833 /*
834 * The error ignoration (hee hee) is already taken care 834 * The error ignoration (hee hee) is already taken care
835 * of by the ignErr template, so pretend error checking 835 * of by the ignErr template, so pretend error checking
836 * is still on. 836 * is still on.
837 */ 837 */
838 errOff = FALSE; 838 errOff = FALSE;
839 } else { 839 } else {
840 errOff = FALSE; 840 errOff = FALSE;
841 } 841 }
842 } else { 842 } else {
843 errOff = FALSE; 843 errOff = FALSE;
844 } 844 }
845 } else { 845 } else {
846 846
847 /* 847 /*
848 * If errors are being checked and the shell doesn't have error control 848 * If errors are being checked and the shell doesn't have error control
849 * but does supply an errOut template, then setup commands to run 849 * but does supply an errOut template, then setup commands to run
850 * through it. 850 * through it.
851 */ 851 */
852 852
853 if (!commandShell->hasErrCtl && commandShell->errOut && 853 if (!commandShell->hasErrCtl && commandShell->errOut &&
854 (*commandShell->errOut != '\0')) { 854 (*commandShell->errOut != '\0')) {
855 if (!(job->flags & JOB_SILENT) && !shutUp) { 855 if (!(job->flags & JOB_SILENT) && !shutUp) {
856 if (commandShell->hasEchoCtl) { 856 if (commandShell->hasEchoCtl) {
857 DBPRINTF("%s\n", commandShell->echoOff); 857 DBPRINTF("%s\n", commandShell->echoOff);
858 } 858 }
859 DBPRINTF(commandShell->errCheck, escCmd); 859 DBPRINTF(commandShell->errCheck, escCmd);
860 shutUp = TRUE; 860 shutUp = TRUE;
861 } 861 }
862 /* If it's a comment line or blank, treat as an ignored error */ 862 /* If it's a comment line or blank, treat as an ignored error */
863 if ((escCmd[0] == commandShell->commentChar) || 863 if ((escCmd[0] == commandShell->commentChar) ||
864 (escCmd[0] == 0)) 864 (escCmd[0] == 0))
865 cmdTemplate = commandShell->ignErr; 865 cmdTemplate = commandShell->ignErr;
866 else 866 else
867 cmdTemplate = commandShell->errOut; 867 cmdTemplate = commandShell->errOut;
868 errOff = FALSE; 868 errOff = FALSE;
869 } 869 }
870 } 870 }
871 871
872 if (DEBUG(SHELL) && strcmp(shellName, "sh") == 0 && 872 if (DEBUG(SHELL) && strcmp(shellName, "sh") == 0 &&
873 (job->flags & JOB_TRACED) == 0) { 873 (job->flags & JOB_TRACED) == 0) {
874 DBPRINTF("set -%s\n", "x"); 874 DBPRINTF("set -%s\n", "x");
875 job->flags |= JOB_TRACED; 875 job->flags |= JOB_TRACED;
876 } 876 }
877 877
878 DBPRINTF(cmdTemplate, cmd); 878 DBPRINTF(cmdTemplate, cmd);
879 free(cmdStart); 879 free(cmdStart);
880 free(escCmd); 880 free(escCmd);
881 if (errOff) { 881 if (errOff) {
882 /* 882 /*
883 * If echoing is already off, there's no point in issuing the 883 * If echoing is already off, there's no point in issuing the
884 * echoOff command. Otherwise we issue it and pretend it was on 884 * echoOff command. Otherwise we issue it and pretend it was on
885 * for the whole command... 885 * for the whole command...
886 */ 886 */
887 if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){ 887 if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){
888 DBPRINTF("%s\n", commandShell->echoOff); 888 DBPRINTF("%s\n", commandShell->echoOff);
889 shutUp = TRUE; 889 shutUp = TRUE;
890 } 890 }
891 DBPRINTF("%s\n", commandShell->errCheck); 891 DBPRINTF("%s\n", commandShell->errCheck);
892 } 892 }
893 if (shutUp && commandShell->hasEchoCtl) { 893 if (shutUp && commandShell->hasEchoCtl) {
894 DBPRINTF("%s\n", commandShell->echoOn); 894 DBPRINTF("%s\n", commandShell->echoOn);
895 } 895 }
896 return 0; 896 return 0;
897} 897}
898 898
899/*- 899/*-
900 *----------------------------------------------------------------------- 900 *-----------------------------------------------------------------------
901 * JobSaveCommand -- 901 * JobSaveCommand --
902 * Save a command to be executed when everything else is done. 902 * Save a command to be executed when everything else is done.
903 * Callback function for JobFinish... 903 * Callback function for JobFinish...
904 * 904 *
905 * Results: 905 * Results:
906 * Always returns 0 906 * Always returns 0
907 * 907 *
908 * Side Effects: 908 * Side Effects:
909 * The command is tacked onto the end of postCommands' commands list. 909 * The command is tacked onto the end of postCommands' commands list.
910 * 910 *
911 *----------------------------------------------------------------------- 911 *-----------------------------------------------------------------------
912 */ 912 */
913static int 913static int
914JobSaveCommand(void *cmd, void *gn) 914JobSaveCommand(void *cmd, void *gn)
915{ 915{
916 cmd = Var_Subst((char *)cmd, (GNode *)gn, VARE_WANTRES); 916 cmd = Var_Subst((char *)cmd, (GNode *)gn, VARE_WANTRES);
917 Lst_Append(postCommands->commands, cmd); 917 Lst_Append(postCommands->commands, cmd);
918 return 0; 918 return 0;
919} 919}
920 920
921 921
922/*- 922/*-
923 *----------------------------------------------------------------------- 923 *-----------------------------------------------------------------------
924 * JobClose -- 924 * JobClose --
925 * Called to close both input and output pipes when a job is finished. 925 * Called to close both input and output pipes when a job is finished.
926 * 926 *
927 * Results: 927 * Results:
928 * Nada 928 * Nada
929 * 929 *
930 * Side Effects: 930 * Side Effects:
931 * The file descriptors associated with the job are closed. 931 * The file descriptors associated with the job are closed.
932 * 932 *
933 *----------------------------------------------------------------------- 933 *-----------------------------------------------------------------------
934 */ 934 */
935static void 935static void
936JobClose(Job *job) 936JobClose(Job *job)
937{ 937{
938 clearfd(job); 938 clearfd(job);
939 (void)close(job->outPipe); 939 (void)close(job->outPipe);
940 job->outPipe = -1; 940 job->outPipe = -1;
941 941
942 JobDoOutput(job, TRUE); 942 JobDoOutput(job, TRUE);
943 (void)close(job->inPipe); 943 (void)close(job->inPipe);
944 job->inPipe = -1; 944 job->inPipe = -1;
945} 945}
946 946
947/*- 947/*-
948 *----------------------------------------------------------------------- 948 *-----------------------------------------------------------------------
949 * JobFinish -- 949 * JobFinish --
950 * Do final processing for the given job including updating 950 * Do final processing for the given job including updating
951 * parents and starting new jobs as available/necessary. Note 951 * parents and starting new jobs as available/necessary. Note
952 * that we pay no attention to the JOB_IGNERR flag here. 952 * that we pay no attention to the JOB_IGNERR flag here.
953 * This is because when we're called because of a noexecute flag 953 * This is because when we're called because of a noexecute flag
954 * or something, jstat.w_status is 0 and when called from 954 * or something, jstat.w_status is 0 and when called from
955 * Job_CatchChildren, the status is zeroed if it s/b ignored. 955 * Job_CatchChildren, the status is zeroed if it s/b ignored.
956 * 956 *
957 * Input: 957 * Input:
958 * job job to finish 958 * job job to finish
959 * status sub-why job went away 959 * status sub-why job went away
960 * 960 *
961 * Results: 961 * Results:
962 * None 962 * None
963 * 963 *
964 * Side Effects: 964 * Side Effects:
965 * Final commands for the job are placed on postCommands. 965 * Final commands for the job are placed on postCommands.
966 * 966 *
967 * If we got an error and are aborting (aborting == ABORT_ERROR) and 967 * If we got an error and are aborting (aborting == ABORT_ERROR) and
968 * the job list is now empty, we are done for the day. 968 * the job list is now empty, we are done for the day.
969 * If we recognized an error (errors !=0), we set the aborting flag 969 * If we recognized an error (errors !=0), we set the aborting flag
970 * to ABORT_ERROR so no more jobs will be started. 970 * to ABORT_ERROR so no more jobs will be started.
971 *----------------------------------------------------------------------- 971 *-----------------------------------------------------------------------
972 */ 972 */
973/*ARGSUSED*/ 973/*ARGSUSED*/
974static void 974static void
975JobFinish(Job *job, int status) 975JobFinish(Job *job, int status)
976{ 976{
977 Boolean done, return_job_token; 977 Boolean done, return_job_token;
978 978
979 if (DEBUG(JOB)) { 979 if (DEBUG(JOB)) {
980 fprintf(debug_file, "Jobfinish: %d [%s], status %d\n", 980 fprintf(debug_file, "Jobfinish: %d [%s], status %d\n",
981 job->pid, job->node->name, status); 981 job->pid, job->node->name, status);
982 } 982 }
983 983
984 if ((WIFEXITED(status) && 984 if ((WIFEXITED(status) &&
985 (((WEXITSTATUS(status) != 0) && !(job->flags & JOB_IGNERR)))) || 985 (((WEXITSTATUS(status) != 0) && !(job->flags & JOB_IGNERR)))) ||
986 WIFSIGNALED(status)) 986 WIFSIGNALED(status))
987 { 987 {
988 /* 988 /*
989 * If it exited non-zero and either we're doing things our 989 * If it exited non-zero and either we're doing things our
990 * way or we're not ignoring errors, the job is finished. 990 * way or we're not ignoring errors, the job is finished.
991 * Similarly, if the shell died because of a signal 991 * Similarly, if the shell died because of a signal
992 * the job is also finished. In these 992 * the job is also finished. In these
993 * cases, finish out the job's output before printing the exit 993 * cases, finish out the job's output before printing the exit
994 * status... 994 * status...
995 */ 995 */
996 JobClose(job); 996 JobClose(job);
997 if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 997 if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
998 (void)fclose(job->cmdFILE); 998 (void)fclose(job->cmdFILE);
999 job->cmdFILE = NULL; 999 job->cmdFILE = NULL;
1000 } 1000 }
1001 done = TRUE; 1001 done = TRUE;
1002 } else if (WIFEXITED(status)) { 1002 } else if (WIFEXITED(status)) {
1003 /* 1003 /*
1004 * Deal with ignored errors in -B mode. We need to print a message 1004 * Deal with ignored errors in -B mode. We need to print a message
1005 * telling of the ignored error as well as setting status.w_status 1005 * telling of the ignored error as well as setting status.w_status
1006 * to 0 so the next command gets run. To do this, we set done to be 1006 * to 0 so the next command gets run. To do this, we set done to be
1007 * TRUE if in -B mode and the job exited non-zero. 1007 * TRUE if in -B mode and the job exited non-zero.
1008 */ 1008 */
1009 done = WEXITSTATUS(status) != 0; 1009 done = WEXITSTATUS(status) != 0;
1010 /* 1010 /*
1011 * Old comment said: "Note we don't 1011 * Old comment said: "Note we don't
1012 * want to close down any of the streams until we know we're at the 1012 * want to close down any of the streams until we know we're at the
1013 * end." 1013 * end."
1014 * But we do. Otherwise when are we going to print the rest of the 1014 * But we do. Otherwise when are we going to print the rest of the
1015 * stuff? 1015 * stuff?
1016 */ 1016 */
1017 JobClose(job); 1017 JobClose(job);
1018 } else { 1018 } else {
1019 /* 1019 /*
1020 * No need to close things down or anything. 1020 * No need to close things down or anything.
1021 */ 1021 */
1022 done = FALSE; 1022 done = FALSE;
1023 } 1023 }
1024 1024
1025 if (done) { 1025 if (done) {
1026 if (WIFEXITED(status)) { 1026 if (WIFEXITED(status)) {
1027 if (DEBUG(JOB)) { 1027 if (DEBUG(JOB)) {
1028 (void)fprintf(debug_file, "Process %d [%s] exited.\n", 1028 (void)fprintf(debug_file, "Process %d [%s] exited.\n",
1029 job->pid, job->node->name); 1029 job->pid, job->node->name);
1030 } 1030 }
1031 if (WEXITSTATUS(status) != 0) { 1031 if (WEXITSTATUS(status) != 0) {
1032 if (job->node != lastNode) { 1032 if (job->node != lastNode) {
1033 MESSAGE(stdout, job->node); 1033 MESSAGE(stdout, job->node);
1034 lastNode = job->node; 1034 lastNode = job->node;
1035 } 1035 }
1036#ifdef USE_META 1036#ifdef USE_META
1037 if (useMeta) { 1037 if (useMeta) {
1038 meta_job_error(job, job->node, job->flags, WEXITSTATUS(status)); 1038 meta_job_error(job, job->node, job->flags, WEXITSTATUS(status));
1039 } 1039 }
1040#endif 1040#endif
1041 if (!dieQuietly(job->node, -1)) 1041 if (!dieQuietly(job->node, -1))
1042 (void)printf("*** [%s] Error code %d%s\n", 1042 (void)printf("*** [%s] Error code %d%s\n",
1043 job->node->name, 1043 job->node->name,
1044 WEXITSTATUS(status), 1044 WEXITSTATUS(status),
1045 (job->flags & JOB_IGNERR) ? " (ignored)" : ""); 1045 (job->flags & JOB_IGNERR) ? " (ignored)" : "");
1046 if (job->flags & JOB_IGNERR) { 1046 if (job->flags & JOB_IGNERR) {
1047 status = 0; 1047 status = 0;
1048 } else { 1048 } else {
1049 if (deleteOnError) { 1049 if (deleteOnError) {
1050 JobDeleteTarget(job->node); 1050 JobDeleteTarget(job->node);
1051 } 1051 }
1052 PrintOnError(job->node, NULL); 1052 PrintOnError(job->node, NULL);
1053 } 1053 }
1054 } else if (DEBUG(JOB)) { 1054 } else if (DEBUG(JOB)) {
1055 if (job->node != lastNode) { 1055 if (job->node != lastNode) {
1056 MESSAGE(stdout, job->node); 1056 MESSAGE(stdout, job->node);
1057 lastNode = job->node; 1057 lastNode = job->node;
1058 } 1058 }
1059 (void)printf("*** [%s] Completed successfully\n", 1059 (void)printf("*** [%s] Completed successfully\n",
1060 job->node->name); 1060 job->node->name);
1061 } 1061 }
1062 } else { 1062 } else {
1063 if (job->node != lastNode) { 1063 if (job->node != lastNode) {
1064 MESSAGE(stdout, job->node); 1064 MESSAGE(stdout, job->node);
1065 lastNode = job->node; 1065 lastNode = job->node;
1066 } 1066 }
1067 (void)printf("*** [%s] Signal %d\n", 1067 (void)printf("*** [%s] Signal %d\n",
1068 job->node->name, WTERMSIG(status)); 1068 job->node->name, WTERMSIG(status));
1069 if (deleteOnError) { 1069 if (deleteOnError) {
1070 JobDeleteTarget(job->node); 1070 JobDeleteTarget(job->node);
1071 } 1071 }
1072 } 1072 }
1073 (void)fflush(stdout); 1073 (void)fflush(stdout);
1074 } 1074 }
1075 1075
1076#ifdef USE_META 1076#ifdef USE_META
1077 if (useMeta) { 1077 if (useMeta) {
1078 int x; 1078 int x;
1079 1079
1080 if ((x = meta_job_finish(job)) != 0 && status == 0) { 1080 if ((x = meta_job_finish(job)) != 0 && status == 0) {
1081 status = x; 1081 status = x;
1082 } 1082 }
1083 } 1083 }
1084#endif 1084#endif
1085 1085
1086 return_job_token = FALSE; 1086 return_job_token = FALSE;
1087 1087
1088 Trace_Log(JOBEND, job); 1088 Trace_Log(JOBEND, job);
1089 if (!(job->flags & JOB_SPECIAL)) { 1089 if (!(job->flags & JOB_SPECIAL)) {
1090 if ((status != 0) || 1090 if ((status != 0) ||
1091 (aborting == ABORT_ERROR) || 1091 (aborting == ABORT_ERROR) ||
1092 (aborting == ABORT_INTERRUPT)) 1092 (aborting == ABORT_INTERRUPT))
1093 return_job_token = TRUE; 1093 return_job_token = TRUE;
1094 } 1094 }
1095 1095
1096 if ((aborting != ABORT_ERROR) && (aborting != ABORT_INTERRUPT) && (status == 0)) { 1096 if ((aborting != ABORT_ERROR) && (aborting != ABORT_INTERRUPT) && (status == 0)) {
1097 /* 1097 /*
1098 * As long as we aren't aborting and the job didn't return a non-zero 1098 * As long as we aren't aborting and the job didn't return a non-zero
1099 * status that we shouldn't ignore, we call Make_Update to update 1099 * status that we shouldn't ignore, we call Make_Update to update
1100 * the parents. In addition, any saved commands for the node are placed 1100 * the parents. In addition, any saved commands for the node are placed
1101 * on the .END target. 1101 * on the .END target.
1102 */ 1102 */
1103 if (job->tailCmds != NULL) { 1103 if (job->tailCmds != NULL) {
1104 Lst_ForEachFrom(job->node->commands, job->tailCmds, 1104 Lst_ForEachFrom(job->node->commands, job->tailCmds,
1105 JobSaveCommand, 1105 JobSaveCommand,
1106 job->node); 1106 job->node);
1107 } 1107 }
1108 job->node->made = MADE; 1108 job->node->made = MADE;
1109 if (!(job->flags & JOB_SPECIAL)) 1109 if (!(job->flags & JOB_SPECIAL))
1110 return_job_token = TRUE; 1110 return_job_token = TRUE;
1111 Make_Update(job->node); 1111 Make_Update(job->node);
1112 job->job_state = JOB_ST_FREE; 1112 job->job_state = JOB_ST_FREE;
1113 } else if (status != 0) { 1113 } else if (status != 0) {
1114 errors += 1; 1114 errors += 1;
1115 job->job_state = JOB_ST_FREE; 1115 job->job_state = JOB_ST_FREE;
1116 } 1116 }
1117 1117
1118 /* 1118 /*
1119 * Set aborting if any error. 1119 * Set aborting if any error.
1120 */ 1120 */
1121 if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) { 1121 if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) {
1122 /* 1122 /*
1123 * If we found any errors in this batch of children and the -k flag 1123 * If we found any errors in this batch of children and the -k flag
1124 * wasn't given, we set the aborting flag so no more jobs get 1124 * wasn't given, we set the aborting flag so no more jobs get
1125 * started. 1125 * started.
1126 */ 1126 */
1127 aborting = ABORT_ERROR; 1127 aborting = ABORT_ERROR;
1128 } 1128 }
1129 1129
1130 if (return_job_token) 1130 if (return_job_token)
1131 Job_TokenReturn(); 1131 Job_TokenReturn();
1132 1132
1133 if (aborting == ABORT_ERROR && jobTokensRunning == 0) { 1133 if (aborting == ABORT_ERROR && jobTokensRunning == 0) {
1134 /* 1134 /*
1135 * If we are aborting and the job table is now empty, we finish. 1135 * If we are aborting and the job table is now empty, we finish.
1136 */ 1136 */
1137 Finish(errors); 1137 Finish(errors);
1138 } 1138 }
1139} 1139}
1140 1140
1141/*- 1141/*-
1142 *----------------------------------------------------------------------- 1142 *-----------------------------------------------------------------------
1143 * Job_Touch -- 1143 * Job_Touch --
1144 * Touch the given target. Called by JobStart when the -t flag was 1144 * Touch the given target. Called by JobStart when the -t flag was
1145 * given 1145 * given
1146 * 1146 *
1147 * Input: 1147 * Input:
1148 * gn the node of the file to touch 1148 * gn the node of the file to touch
1149 * silent TRUE if should not print message 1149 * silent TRUE if should not print message
1150 * 1150 *
1151 * Results: 1151 * Results:
1152 * None 1152 * None
1153 * 1153 *
1154 * Side Effects: 1154 * Side Effects:
1155 * The data modification of the file is changed. In addition, if the 1155 * The data modification of the file is changed. In addition, if the
1156 * file did not exist, it is created. 1156 * file did not exist, it is created.
1157 *----------------------------------------------------------------------- 1157 *-----------------------------------------------------------------------
1158 */ 1158 */
1159void 1159void
1160Job_Touch(GNode *gn, Boolean silent) 1160Job_Touch(GNode *gn, Boolean silent)
1161{ 1161{
1162 int streamID; /* ID of stream opened to do the touch */ 1162 int streamID; /* ID of stream opened to do the touch */
1163 struct utimbuf times; /* Times for utime() call */ 1163 struct utimbuf times; /* Times for utime() call */
1164 1164
1165 if (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC|OP_OPTIONAL| 1165 if (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC|OP_OPTIONAL|
1166 OP_SPECIAL|OP_PHONY)) { 1166 OP_SPECIAL|OP_PHONY)) {
1167 /* 1167 /*
1168 * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets 1168 * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets
1169 * and, as such, shouldn't really be created. 1169 * and, as such, shouldn't really be created.
1170 */ 1170 */
1171 return; 1171 return;
1172 } 1172 }
1173 1173
1174 if (!silent || NoExecute(gn)) { 1174 if (!silent || NoExecute(gn)) {
1175 (void)fprintf(stdout, "touch %s\n", gn->name); 1175 (void)fprintf(stdout, "touch %s\n", gn->name);
1176 (void)fflush(stdout); 1176 (void)fflush(stdout);
1177 } 1177 }
1178 1178
1179 if (NoExecute(gn)) { 1179 if (NoExecute(gn)) {
1180 return; 1180 return;
1181 } 1181 }
1182 1182
1183 if (gn->type & OP_ARCHV) { 1183 if (gn->type & OP_ARCHV) {
1184 Arch_Touch(gn); 1184 Arch_Touch(gn);
1185 } else if (gn->type & OP_LIB) { 1185 } else if (gn->type & OP_LIB) {
1186 Arch_TouchLib(gn); 1186 Arch_TouchLib(gn);
1187 } else { 1187 } else {
1188 char *file = gn->path ? gn->path : gn->name; 1188 char *file = gn->path ? gn->path : gn->name;
1189 1189
1190 times.actime = times.modtime = now; 1190 times.actime = times.modtime = now;
1191 if (utime(file, &times) < 0){ 1191 if (utime(file, &times) < 0){
1192 streamID = open(file, O_RDWR | O_CREAT, 0666); 1192 streamID = open(file, O_RDWR | O_CREAT, 0666);
1193 1193
1194 if (streamID >= 0) { 1194 if (streamID >= 0) {
1195 char c; 1195 char c;
1196 1196
1197 /* 1197 /*
1198 * Read and write a byte to the file to change the 1198 * Read and write a byte to the file to change the
1199 * modification time, then close the file. 1199 * modification time, then close the file.
1200 */ 1200 */
1201 if (read(streamID, &c, 1) == 1) { 1201 if (read(streamID, &c, 1) == 1) {
1202 (void)lseek(streamID, (off_t)0, SEEK_SET); 1202 (void)lseek(streamID, (off_t)0, SEEK_SET);
1203 while (write(streamID, &c, 1) == -1 && errno == EAGAIN) 1203 while (write(streamID, &c, 1) == -1 && errno == EAGAIN)
1204 continue; 1204 continue;
1205 } 1205 }
1206 1206
1207 (void)close(streamID); 1207 (void)close(streamID);
1208 } else { 1208 } else {
1209 (void)fprintf(stdout, "*** couldn't touch %s: %s", 1209 (void)fprintf(stdout, "*** couldn't touch %s: %s",
1210 file, strerror(errno)); 1210 file, strerror(errno));
1211 (void)fflush(stdout); 1211 (void)fflush(stdout);
1212 } 1212 }
1213 } 1213 }
1214 } 1214 }
1215} 1215}
1216 1216
1217/*- 1217/*-
1218 *----------------------------------------------------------------------- 1218 *-----------------------------------------------------------------------
1219 * Job_CheckCommands -- 1219 * Job_CheckCommands --
1220 * Make sure the given node has all the commands it needs. 1220 * Make sure the given node has all the commands it needs.
1221 * 1221 *
1222 * Input: 1222 * Input:
1223 * gn The target whose commands need verifying 1223 * gn The target whose commands need verifying
1224 * abortProc Function to abort with message 1224 * abortProc Function to abort with message
1225 * 1225 *
1226 * Results: 1226 * Results:
1227 * TRUE if the commands list is/was ok. 1227 * TRUE if the commands list is/was ok.
1228 * 1228 *
1229 * Side Effects: 1229 * Side Effects:
1230 * The node will have commands from the .DEFAULT rule added to it 1230 * The node will have commands from the .DEFAULT rule added to it
1231 * if it needs them. 1231 * if it needs them.
1232 *----------------------------------------------------------------------- 1232 *-----------------------------------------------------------------------
1233 */ 1233 */
1234Boolean 1234Boolean
1235Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...)) 1235Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...))
1236{ 1236{
1237 if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) && 1237 if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) &&
1238 ((gn->type & OP_LIB) == 0 || Lst_IsEmpty(gn->children))) { 1238 ((gn->type & OP_LIB) == 0 || Lst_IsEmpty(gn->children))) {
1239 /* 1239 /*
1240 * No commands. Look for .DEFAULT rule from which we might infer 1240 * No commands. Look for .DEFAULT rule from which we might infer
1241 * commands 1241 * commands
1242 */ 1242 */
1243 if ((DEFAULT != NULL) && !Lst_IsEmpty(DEFAULT->commands) && 1243 if ((DEFAULT != NULL) && !Lst_IsEmpty(DEFAULT->commands) &&
1244 (gn->type & OP_SPECIAL) == 0) { 1244 (gn->type & OP_SPECIAL) == 0) {
1245 char *p1; 1245 char *p1;
1246 /* 1246 /*
1247 * Make only looks for a .DEFAULT if the node was never the 1247 * Make only looks for a .DEFAULT if the node was never the
1248 * target of an operator, so that's what we do too. If 1248 * target of an operator, so that's what we do too. If
1249 * a .DEFAULT was given, we substitute its commands for gn's 1249 * a .DEFAULT was given, we substitute its commands for gn's
1250 * commands and set the IMPSRC variable to be the target's name 1250 * commands and set the IMPSRC variable to be the target's name
1251 * The DEFAULT node acts like a transformation rule, in that 1251 * The DEFAULT node acts like a transformation rule, in that
1252 * gn also inherits any attributes or sources attached to 1252 * gn also inherits any attributes or sources attached to
1253 * .DEFAULT itself. 1253 * .DEFAULT itself.
1254 */ 1254 */
1255 Make_HandleUse(DEFAULT, gn); 1255 Make_HandleUse(DEFAULT, gn);
1256 Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn); 1256 Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn);
1257 bmake_free(p1); 1257 bmake_free(p1);
1258 } else if (Dir_MTime(gn, 0) == 0 && (gn->type & OP_SPECIAL) == 0) { 1258 } else if (Dir_MTime(gn, 0) == 0 && (gn->type & OP_SPECIAL) == 0) {
1259 /* 1259 /*
1260 * The node wasn't the target of an operator we have no .DEFAULT 1260 * The node wasn't the target of an operator we have no .DEFAULT
1261 * rule to go on and the target doesn't already exist. There's 1261 * rule to go on and the target doesn't already exist. There's
1262 * nothing more we can do for this branch. If the -k flag wasn't 1262 * nothing more we can do for this branch. If the -k flag wasn't
1263 * given, we stop in our tracks, otherwise we just don't update 1263 * given, we stop in our tracks, otherwise we just don't update
1264 * this node's parents so they never get examined. 1264 * this node's parents so they never get examined.
1265 */ 1265 */
1266 static const char msg[] = ": don't know how to make"; 1266 static const char msg[] = ": don't know how to make";
1267 1267
1268 if (gn->flags & FROM_DEPEND) { 1268 if (gn->flags & FROM_DEPEND) {
1269 if (!Job_RunTarget(".STALE", gn->fname)) 1269 if (!Job_RunTarget(".STALE", gn->fname))
1270 fprintf(stdout, "%s: %s, %d: ignoring stale %s for %s\n", 1270 fprintf(stdout, "%s: %s, %d: ignoring stale %s for %s\n",
1271 progname, gn->fname, gn->lineno, makeDependfile, 1271 progname, gn->fname, gn->lineno, makeDependfile,
1272 gn->name); 1272 gn->name);
1273 return TRUE; 1273 return TRUE;
1274 } 1274 }
1275 1275
1276 if (gn->type & OP_OPTIONAL) { 1276 if (gn->type & OP_OPTIONAL) {
1277 (void)fprintf(stdout, "%s%s %s (ignored)\n", progname, 1277 (void)fprintf(stdout, "%s%s %s (ignored)\n", progname,
1278 msg, gn->name); 1278 msg, gn->name);
1279 (void)fflush(stdout); 1279 (void)fflush(stdout);
1280 } else if (keepgoing) { 1280 } else if (keepgoing) {
1281 (void)fprintf(stdout, "%s%s %s (continuing)\n", progname, 1281 (void)fprintf(stdout, "%s%s %s (continuing)\n", progname,
1282 msg, gn->name); 1282 msg, gn->name);
1283 (void)fflush(stdout); 1283 (void)fflush(stdout);
1284 return FALSE; 1284 return FALSE;
1285 } else { 1285 } else {
1286 (*abortProc)("%s%s %s. Stop", progname, msg, gn->name); 1286 (*abortProc)("%s%s %s. Stop", progname, msg, gn->name);
1287 return FALSE; 1287 return FALSE;
1288 } 1288 }
1289 } 1289 }
1290 } 1290 }
1291 return TRUE; 1291 return TRUE;
1292} 1292}
1293 1293
1294/*- 1294/*-
1295 *----------------------------------------------------------------------- 1295 *-----------------------------------------------------------------------
1296 * JobExec -- 1296 * JobExec --
1297 * Execute the shell for the given job. Called from JobStart 1297 * Execute the shell for the given job. Called from JobStart
1298 * 1298 *
1299 * Input: 1299 * Input:
1300 * job Job to execute 1300 * job Job to execute
1301 * 1301 *
1302 * Results: 1302 * Results:
1303 * None. 1303 * None.
1304 * 1304 *
1305 * Side Effects: 1305 * Side Effects:
1306 * A shell is executed, outputs is altered and the Job structure added 1306 * A shell is executed, outputs is altered and the Job structure added
1307 * to the job table. 1307 * to the job table.
1308 * 1308 *
1309 *----------------------------------------------------------------------- 1309 *-----------------------------------------------------------------------
1310 */ 1310 */
1311static void 1311static void
1312JobExec(Job *job, char **argv) 1312JobExec(Job *job, char **argv)
1313{ 1313{
1314 int cpid; /* ID of new child */ 1314 int cpid; /* ID of new child */
1315 sigset_t mask; 1315 sigset_t mask;
1316 1316
1317 job->flags &= ~JOB_TRACED; 1317 job->flags &= ~JOB_TRACED;
1318 1318
1319 if (DEBUG(JOB)) { 1319 if (DEBUG(JOB)) {
1320 int i; 1320 int i;
1321 1321
1322 (void)fprintf(debug_file, "Running %s %sly\n", job->node->name, "local"); 1322 (void)fprintf(debug_file, "Running %s %sly\n", job->node->name, "local");
1323 (void)fprintf(debug_file, "\tCommand: "); 1323 (void)fprintf(debug_file, "\tCommand: ");
1324 for (i = 0; argv[i] != NULL; i++) { 1324 for (i = 0; argv[i] != NULL; i++) {
1325 (void)fprintf(debug_file, "%s ", argv[i]); 1325 (void)fprintf(debug_file, "%s ", argv[i]);
1326 } 1326 }
1327 (void)fprintf(debug_file, "\n"); 1327 (void)fprintf(debug_file, "\n");
1328 } 1328 }
1329 1329
1330 /* 1330 /*
1331 * Some jobs produce no output and it's disconcerting to have 1331 * Some jobs produce no output and it's disconcerting to have
1332 * no feedback of their running (since they produce no output, the 1332 * no feedback of their running (since they produce no output, the
1333 * banner with their name in it never appears). This is an attempt to 1333 * banner with their name in it never appears). This is an attempt to
1334 * provide that feedback, even if nothing follows it. 1334 * provide that feedback, even if nothing follows it.
1335 */ 1335 */
1336 if ((lastNode != job->node) && !(job->flags & JOB_SILENT)) { 1336 if ((lastNode != job->node) && !(job->flags & JOB_SILENT)) {
1337 MESSAGE(stdout, job->node); 1337 MESSAGE(stdout, job->node);
1338 lastNode = job->node; 1338 lastNode = job->node;
1339 } 1339 }
1340 1340
1341 /* No interruptions until this job is on the `jobs' list */ 1341 /* No interruptions until this job is on the `jobs' list */
1342 JobSigLock(&mask); 1342 JobSigLock(&mask);
1343 1343
1344 /* Pre-emptively mark job running, pid still zero though */ 1344 /* Pre-emptively mark job running, pid still zero though */
1345 job->job_state = JOB_ST_RUNNING; 1345 job->job_state = JOB_ST_RUNNING;
1346 1346
1347 cpid = vFork(); 1347 cpid = vFork();
1348 if (cpid == -1) 1348 if (cpid == -1)
1349 Punt("Cannot vfork: %s", strerror(errno)); 1349 Punt("Cannot vfork: %s", strerror(errno));
1350 1350
1351 if (cpid == 0) { 1351 if (cpid == 0) {
1352 /* Child */ 1352 /* Child */
1353 sigset_t tmask; 1353 sigset_t tmask;
1354 1354
1355#ifdef USE_META 1355#ifdef USE_META
1356 if (useMeta) { 1356 if (useMeta) {
1357 meta_job_child(job); 1357 meta_job_child(job);
1358 } 1358 }
1359#endif 1359#endif
1360 /* 1360 /*
1361 * Reset all signal handlers; this is necessary because we also 1361 * Reset all signal handlers; this is necessary because we also
1362 * need to unblock signals before we exec(2). 1362 * need to unblock signals before we exec(2).
1363 */ 1363 */
1364 JobSigReset(); 1364 JobSigReset();
1365 1365
1366 /* Now unblock signals */ 1366 /* Now unblock signals */
1367 sigemptyset(&tmask); 1367 sigemptyset(&tmask);
1368 JobSigUnlock(&tmask); 1368 JobSigUnlock(&tmask);
1369 1369
1370 /* 1370 /*
1371 * Must duplicate the input stream down to the child's input and 1371 * Must duplicate the input stream down to the child's input and
1372 * reset it to the beginning (again). Since the stream was marked 1372 * reset it to the beginning (again). Since the stream was marked
1373 * close-on-exec, we must clear that bit in the new input. 1373 * close-on-exec, we must clear that bit in the new input.
1374 */ 1374 */
1375 if (dup2(FILENO(job->cmdFILE), 0) == -1) { 1375 if (dup2(FILENO(job->cmdFILE), 0) == -1) {
1376 execError("dup2", "job->cmdFILE"); 1376 execError("dup2", "job->cmdFILE");
1377 _exit(1); 1377 _exit(1);
1378 } 1378 }
1379 if (fcntl(0, F_SETFD, 0) == -1) { 1379 if (fcntl(0, F_SETFD, 0) == -1) {
1380 execError("fcntl clear close-on-exec", "stdin"); 1380 execError("fcntl clear close-on-exec", "stdin");
1381 _exit(1); 1381 _exit(1);
1382 } 1382 }
1383 if (lseek(0, (off_t)0, SEEK_SET) == -1) { 1383 if (lseek(0, (off_t)0, SEEK_SET) == -1) {
1384 execError("lseek to 0", "stdin"); 1384 execError("lseek to 0", "stdin");
1385 _exit(1); 1385 _exit(1);
1386 } 1386 }
1387 1387
1388 if (job->node->type & (OP_MAKE | OP_SUBMAKE)) { 1388 if (job->node->type & (OP_MAKE | OP_SUBMAKE)) {
1389 /* 1389 /*
1390 * Pass job token pipe to submakes. 1390 * Pass job token pipe to submakes.
1391 */ 1391 */
1392 if (fcntl(tokenWaitJob.inPipe, F_SETFD, 0) == -1) { 1392 if (fcntl(tokenWaitJob.inPipe, F_SETFD, 0) == -1) {
1393 execError("clear close-on-exec", "tokenWaitJob.inPipe"); 1393 execError("clear close-on-exec", "tokenWaitJob.inPipe");
1394 _exit(1); 1394 _exit(1);
1395 } 1395 }
1396 if (fcntl(tokenWaitJob.outPipe, F_SETFD, 0) == -1) { 1396 if (fcntl(tokenWaitJob.outPipe, F_SETFD, 0) == -1) {
1397 execError("clear close-on-exec", "tokenWaitJob.outPipe"); 1397 execError("clear close-on-exec", "tokenWaitJob.outPipe");
1398 _exit(1); 1398 _exit(1);
1399 } 1399 }
1400 } 1400 }
1401 1401
1402 /* 1402 /*
1403 * Set up the child's output to be routed through the pipe 1403 * Set up the child's output to be routed through the pipe
1404 * we've created for it. 1404 * we've created for it.
1405 */ 1405 */
1406 if (dup2(job->outPipe, 1) == -1) { 1406 if (dup2(job->outPipe, 1) == -1) {
1407 execError("dup2", "job->outPipe"); 1407 execError("dup2", "job->outPipe");
1408 _exit(1); 1408 _exit(1);
1409 } 1409 }
1410 /* 1410 /*
1411 * The output channels are marked close on exec. This bit was 1411 * The output channels are marked close on exec. This bit was
1412 * duplicated by the dup2(on some systems), so we have to clear 1412 * duplicated by the dup2(on some systems), so we have to clear
1413 * it before routing the shell's error output to the same place as 1413 * it before routing the shell's error output to the same place as
1414 * its standard output. 1414 * its standard output.
1415 */ 1415 */
1416 if (fcntl(1, F_SETFD, 0) == -1) { 1416 if (fcntl(1, F_SETFD, 0) == -1) {
1417 execError("clear close-on-exec", "stdout"); 1417 execError("clear close-on-exec", "stdout");
1418 _exit(1); 1418 _exit(1);
1419 } 1419 }
1420 if (dup2(1, 2) == -1) { 1420 if (dup2(1, 2) == -1) {
1421 execError("dup2", "1, 2"); 1421 execError("dup2", "1, 2");
1422 _exit(1); 1422 _exit(1);
1423 } 1423 }
1424 1424
1425 /* 1425 /*
1426 * We want to switch the child into a different process family so 1426 * We want to switch the child into a different process family so
1427 * we can kill it and all its descendants in one fell swoop, 1427 * we can kill it and all its descendants in one fell swoop,
1428 * by killing its process family, but not commit suicide. 1428 * by killing its process family, but not commit suicide.
1429 */ 1429 */
1430#if defined(MAKE_NATIVE) || defined(HAVE_SETPGID) 1430#if defined(MAKE_NATIVE) || defined(HAVE_SETPGID)
1431#if defined(SYSV) 1431#if defined(SYSV)
1432 /* XXX: dsl - I'm sure this should be setpgrp()... */ 1432 /* XXX: dsl - I'm sure this should be setpgrp()... */
1433 (void)setsid(); 1433 (void)setsid();
1434#else 1434#else
1435 (void)setpgid(0, getpid()); 1435 (void)setpgid(0, getpid());
1436#endif 1436#endif
1437#endif 1437#endif
1438 1438
1439 Var_ExportVars(); 1439 Var_ExportVars();
1440 1440
1441 (void)execv(shellPath, argv); 1441 (void)execv(shellPath, argv);
1442 execError("exec", shellPath); 1442 execError("exec", shellPath);
1443 _exit(1); 1443 _exit(1);
1444 } 1444 }
1445 1445
1446 /* Parent, continuing after the child exec */ 1446 /* Parent, continuing after the child exec */
1447 job->pid = cpid; 1447 job->pid = cpid;
1448 1448
1449 Trace_Log(JOBSTART, job); 1449 Trace_Log(JOBSTART, job);
1450 1450
1451#ifdef USE_META 1451#ifdef USE_META
1452 if (useMeta) { 1452 if (useMeta) {
1453 meta_job_parent(job, cpid); 1453 meta_job_parent(job, cpid);
1454 } 1454 }
1455#endif 1455#endif
1456 1456
1457 /* 1457 /*
1458 * Set the current position in the buffer to the beginning 1458 * Set the current position in the buffer to the beginning
1459 * and mark another stream to watch in the outputs mask 1459 * and mark another stream to watch in the outputs mask
1460 */ 1460 */
1461 job->curPos = 0; 1461 job->curPos = 0;
1462 1462
1463 watchfd(job); 1463 watchfd(job);
1464 1464
1465 if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 1465 if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
1466 (void)fclose(job->cmdFILE); 1466 (void)fclose(job->cmdFILE);
1467 job->cmdFILE = NULL; 1467 job->cmdFILE = NULL;
1468 } 1468 }
1469 1469
1470 /* 1470 /*
1471 * Now the job is actually running, add it to the table. 1471 * Now the job is actually running, add it to the table.
1472 */ 1472 */
1473 if (DEBUG(JOB)) { 1473 if (DEBUG(JOB)) {
1474 fprintf(debug_file, "JobExec(%s): pid %d added to jobs table\n", 1474 fprintf(debug_file, "JobExec(%s): pid %d added to jobs table\n",
1475 job->node->name, job->pid); 1475 job->node->name, job->pid);
1476 job_table_dump("job started"); 1476 job_table_dump("job started");
1477 } 1477 }
1478 JobSigUnlock(&mask); 1478 JobSigUnlock(&mask);
1479} 1479}
1480 1480
1481/*- 1481/*-
1482 *----------------------------------------------------------------------- 1482 *-----------------------------------------------------------------------
1483 * JobMakeArgv -- 1483 * JobMakeArgv --
1484 * Create the argv needed to execute the shell for a given job. 1484 * Create the argv needed to execute the shell for a given job.
1485 * 1485 *
1486 * 1486 *
1487 * Results: 1487 * Results:
1488 * 1488 *
1489 * Side Effects: 1489 * Side Effects:
1490 * 1490 *
1491 *----------------------------------------------------------------------- 1491 *-----------------------------------------------------------------------
1492 */ 1492 */
1493static void 1493static void
1494JobMakeArgv(Job *job, char **argv) 1494JobMakeArgv(Job *job, char **argv)
1495{ 1495{
1496 int argc; 1496 int argc;
1497 static char args[10]; /* For merged arguments */ 1497 static char args[10]; /* For merged arguments */
1498 1498
1499 argv[0] = UNCONST(shellName); 1499 argv[0] = UNCONST(shellName);
1500 argc = 1; 1500 argc = 1;
1501 1501
1502 if ((commandShell->exit && (*commandShell->exit != '-')) || 1502 if ((commandShell->exit && (*commandShell->exit != '-')) ||
1503 (commandShell->echo && (*commandShell->echo != '-'))) 1503 (commandShell->echo && (*commandShell->echo != '-')))
1504 { 1504 {
1505 /* 1505 /*
1506 * At least one of the flags doesn't have a minus before it, so 1506 * At least one of the flags doesn't have a minus before it, so
1507 * merge them together. Have to do this because the *(&(@*#*&#$# 1507 * merge them together. Have to do this because the *(&(@*#*&#$#
1508 * Bourne shell thinks its second argument is a file to source. 1508 * Bourne shell thinks its second argument is a file to source.
1509 * Grrrr. Note the ten-character limitation on the combined arguments. 1509 * Grrrr. Note the ten-character limitation on the combined arguments.
1510 */ 1510 */
1511 (void)snprintf(args, sizeof(args), "-%s%s", 1511 (void)snprintf(args, sizeof(args), "-%s%s",
1512 ((job->flags & JOB_IGNERR) ? "" : 1512 ((job->flags & JOB_IGNERR) ? "" :
1513 (commandShell->exit ? commandShell->exit : "")), 1513 (commandShell->exit ? commandShell->exit : "")),
1514 ((job->flags & JOB_SILENT) ? "" : 1514 ((job->flags & JOB_SILENT) ? "" :
1515 (commandShell->echo ? commandShell->echo : ""))); 1515 (commandShell->echo ? commandShell->echo : "")));
1516 1516
1517 if (args[1]) { 1517 if (args[1]) {
1518 argv[argc] = args; 1518 argv[argc] = args;
1519 argc++; 1519 argc++;
1520 } 1520 }
1521 } else { 1521 } else {
1522 if (!(job->flags & JOB_IGNERR) && commandShell->exit) { 1522 if (!(job->flags & JOB_IGNERR) && commandShell->exit) {
1523 argv[argc] = UNCONST(commandShell->exit); 1523 argv[argc] = UNCONST(commandShell->exit);
1524 argc++; 1524 argc++;
1525 } 1525 }
1526 if (!(job->flags & JOB_SILENT) && commandShell->echo) { 1526 if (!(job->flags & JOB_SILENT) && commandShell->echo) {
1527 argv[argc] = UNCONST(commandShell->echo); 1527 argv[argc] = UNCONST(commandShell->echo);
1528 argc++; 1528 argc++;
1529 } 1529 }
1530 } 1530 }
1531 argv[argc] = NULL; 1531 argv[argc] = NULL;
1532} 1532}
1533 1533
1534/*- 1534/*-
1535 *----------------------------------------------------------------------- 1535 *-----------------------------------------------------------------------
1536 * JobStart -- 1536 * JobStart --
1537 * Start a target-creation process going for the target described 1537 * Start a target-creation process going for the target described
1538 * by the graph node gn. 1538 * by the graph node gn.
1539 * 1539 *
1540 * Input: 1540 * Input:
1541 * gn target to create 1541 * gn target to create
1542 * flags flags for the job to override normal ones. 1542 * flags flags for the job to override normal ones.
1543 * e.g. JOB_SPECIAL or JOB_IGNDOTS 1543 * e.g. JOB_SPECIAL or JOB_IGNDOTS
1544 * previous The previous Job structure for this node, if any. 1544 * previous The previous Job structure for this node, if any.
1545 * 1545 *
1546 * Results: 1546 * Results:
1547 * JOB_ERROR if there was an error in the commands, JOB_FINISHED 1547 * JOB_ERROR if there was an error in the commands, JOB_FINISHED
1548 * if there isn't actually anything left to do for the job and 1548 * if there isn't actually anything left to do for the job and
1549 * JOB_RUNNING if the job has been started. 1549 * JOB_RUNNING if the job has been started.
1550 * 1550 *
1551 * Side Effects: 1551 * Side Effects:
1552 * A new Job node is created and added to the list of running 1552 * A new Job node is created and added to the list of running
1553 * jobs. PMake is forked and a child shell created. 1553 * jobs. PMake is forked and a child shell created.
1554 * 1554 *
1555 * NB: I'm fairly sure that this code is never called with JOB_SPECIAL set 1555 * NB: I'm fairly sure that this code is never called with JOB_SPECIAL set
1556 * JOB_IGNDOTS is never set (dsl) 1556 * JOB_IGNDOTS is never set (dsl)
1557 * Also the return value is ignored by everyone. 1557 * Also the return value is ignored by everyone.
1558 *----------------------------------------------------------------------- 1558 *-----------------------------------------------------------------------
1559 */ 1559 */
1560static int 1560static int
1561JobStart(GNode *gn, int flags) 1561JobStart(GNode *gn, int flags)
1562{ 1562{
1563 Job *job; /* new job descriptor */ 1563 Job *job; /* new job descriptor */
1564 char *argv[10]; /* Argument vector to shell */ 1564 char *argv[10]; /* Argument vector to shell */
1565 Boolean cmdsOK; /* true if the nodes commands were all right */ 1565 Boolean cmdsOK; /* true if the nodes commands were all right */
1566 Boolean noExec; /* Set true if we decide not to run the job */ 1566 Boolean noExec; /* Set true if we decide not to run the job */
1567 int tfd; /* File descriptor to the temp file */ 1567 int tfd; /* File descriptor to the temp file */
1568 1568
1569 for (job = job_table; job < job_table_end; job++) { 1569 for (job = job_table; job < job_table_end; job++) {
1570 if (job->job_state == JOB_ST_FREE) 1570 if (job->job_state == JOB_ST_FREE)
1571 break; 1571 break;
1572 } 1572 }
1573 if (job >= job_table_end) 1573 if (job >= job_table_end)
1574 Punt("JobStart no job slots vacant"); 1574 Punt("JobStart no job slots vacant");
1575 1575
1576 memset(job, 0, sizeof *job); 1576 memset(job, 0, sizeof *job);
1577 job->job_state = JOB_ST_SETUP; 1577 job->job_state = JOB_ST_SETUP;
1578 if (gn->type & OP_SPECIAL) 1578 if (gn->type & OP_SPECIAL)
1579 flags |= JOB_SPECIAL; 1579 flags |= JOB_SPECIAL;
1580 1580
1581 job->node = gn; 1581 job->node = gn;
1582 job->tailCmds = NULL; 1582 job->tailCmds = NULL;
1583 1583
1584 /* 1584 /*
1585 * Set the initial value of the flags for this job based on the global 1585 * Set the initial value of the flags for this job based on the global
1586 * ones and the node's attributes... Any flags supplied by the caller 1586 * ones and the node's attributes... Any flags supplied by the caller
1587 * are also added to the field. 1587 * are also added to the field.
1588 */ 1588 */
1589 job->flags = 0; 1589 job->flags = 0;
1590 if (Targ_Ignore(gn)) { 1590 if (Targ_Ignore(gn)) {
1591 job->flags |= JOB_IGNERR; 1591 job->flags |= JOB_IGNERR;
1592 } 1592 }
1593 if (Targ_Silent(gn)) { 1593 if (Targ_Silent(gn)) {
1594 job->flags |= JOB_SILENT; 1594 job->flags |= JOB_SILENT;
1595 } 1595 }
1596 job->flags |= flags; 1596 job->flags |= flags;
1597 1597
1598 /* 1598 /*
1599 * Check the commands now so any attributes from .DEFAULT have a chance 1599 * Check the commands now so any attributes from .DEFAULT have a chance
1600 * to migrate to the node 1600 * to migrate to the node
1601 */ 1601 */
1602 cmdsOK = Job_CheckCommands(gn, Error); 1602 cmdsOK = Job_CheckCommands(gn, Error);
1603 1603
1604 job->inPollfd = NULL; 1604 job->inPollfd = NULL;
1605 /* 1605 /*
1606 * If the -n flag wasn't given, we open up OUR (not the child's) 1606 * If the -n flag wasn't given, we open up OUR (not the child's)
1607 * temporary file to stuff commands in it. The thing is rd/wr so we don't 1607 * temporary file to stuff commands in it. The thing is rd/wr so we don't
1608 * need to reopen it to feed it to the shell. If the -n flag *was* given, 1608 * need to reopen it to feed it to the shell. If the -n flag *was* given,
1609 * we just set the file to be stdout. Cute, huh? 1609 * we just set the file to be stdout. Cute, huh?
1610 */ 1610 */
1611 if (((gn->type & OP_MAKE) && !(noRecursiveExecute)) || 1611 if (((gn->type & OP_MAKE) && !(noRecursiveExecute)) ||
1612 (!noExecute && !touchFlag)) { 1612 (!noExecute && !touchFlag)) {
1613 /* 1613 /*
1614 * tfile is the name of a file into which all shell commands are 1614 * tfile is the name of a file into which all shell commands are
1615 * put. It is removed before the child shell is executed, unless 1615 * put. It is removed before the child shell is executed, unless
1616 * DEBUG(SCRIPT) is set. 1616 * DEBUG(SCRIPT) is set.
1617 */ 1617 */
1618 char *tfile; 1618 char *tfile;
1619 sigset_t mask; 1619 sigset_t mask;
1620 /* 1620 /*
1621 * We're serious here, but if the commands were bogus, we're 1621 * We're serious here, but if the commands were bogus, we're
1622 * also dead... 1622 * also dead...
1623 */ 1623 */
1624 if (!cmdsOK) { 1624 if (!cmdsOK) {
1625 PrintOnError(gn, NULL); /* provide some clue */ 1625 PrintOnError(gn, NULL); /* provide some clue */
1626 DieHorribly(); 1626 DieHorribly();
1627 } 1627 }
1628 1628
1629 JobSigLock(&mask); 1629 JobSigLock(&mask);
1630 tfd = mkTempFile(TMPPAT, &tfile); 1630 tfd = mkTempFile(TMPPAT, &tfile);
1631 if (!DEBUG(SCRIPT)) 1631 if (!DEBUG(SCRIPT))
1632 (void)eunlink(tfile); 1632 (void)eunlink(tfile);
1633 JobSigUnlock(&mask); 1633 JobSigUnlock(&mask);
1634 1634
1635 job->cmdFILE = fdopen(tfd, "w+"); 1635 job->cmdFILE = fdopen(tfd, "w+");
1636 if (job->cmdFILE == NULL) { 1636 if (job->cmdFILE == NULL) {
1637 Punt("Could not fdopen %s", tfile); 1637 Punt("Could not fdopen %s", tfile);
1638 } 1638 }
1639 (void)fcntl(FILENO(job->cmdFILE), F_SETFD, FD_CLOEXEC); 1639 (void)fcntl(FILENO(job->cmdFILE), F_SETFD, FD_CLOEXEC);
1640 /* 1640 /*
1641 * Send the commands to the command file, flush all its buffers then 1641 * Send the commands to the command file, flush all its buffers then
1642 * rewind and remove the thing. 1642 * rewind and remove the thing.
1643 */ 1643 */
1644 noExec = FALSE; 1644 noExec = FALSE;
1645 1645
1646#ifdef USE_META 1646#ifdef USE_META
1647 if (useMeta) { 1647 if (useMeta) {
1648 meta_job_start(job, gn); 1648 meta_job_start(job, gn);
1649 if (Targ_Silent(gn)) { /* might have changed */ 1649 if (Targ_Silent(gn)) { /* might have changed */
1650 job->flags |= JOB_SILENT; 1650 job->flags |= JOB_SILENT;
1651 } 1651 }
1652 } 1652 }
1653#endif 1653#endif
1654 /* 1654 /*
1655 * We can do all the commands at once. hooray for sanity 1655 * We can do all the commands at once. hooray for sanity
1656 */ 1656 */
1657 numCommands = 0; 1657 numCommands = 0;
1658 Lst_ForEach(gn->commands, JobPrintCommand, job); 1658 Lst_ForEach(gn->commands, JobPrintCommand, job);
1659 1659
1660 /* 1660 /*
1661 * If we didn't print out any commands to the shell script, 1661 * If we didn't print out any commands to the shell script,
1662 * there's not much point in executing the shell, is there? 1662 * there's not much point in executing the shell, is there?
1663 */ 1663 */
1664 if (numCommands == 0) { 1664 if (numCommands == 0) {
1665 noExec = TRUE; 1665 noExec = TRUE;
1666 } 1666 }
1667 1667
1668 free(tfile); 1668 free(tfile);
1669 } else if (NoExecute(gn)) { 1669 } else if (NoExecute(gn)) {
1670 /* 1670 /*
1671 * Not executing anything -- just print all the commands to stdout 1671 * Not executing anything -- just print all the commands to stdout
1672 * in one fell swoop. This will still set up job->tailCmds correctly. 1672 * in one fell swoop. This will still set up job->tailCmds correctly.
1673 */ 1673 */
1674 if (lastNode != gn) { 1674 if (lastNode != gn) {
1675 MESSAGE(stdout, gn); 1675 MESSAGE(stdout, gn);
1676 lastNode = gn; 1676 lastNode = gn;
1677 } 1677 }
1678 job->cmdFILE = stdout; 1678 job->cmdFILE = stdout;
1679 /* 1679 /*
1680 * Only print the commands if they're ok, but don't die if they're 1680 * Only print the commands if they're ok, but don't die if they're
1681 * not -- just let the user know they're bad and keep going. It 1681 * not -- just let the user know they're bad and keep going. It
1682 * doesn't do any harm in this case and may do some good. 1682 * doesn't do any harm in this case and may do some good.
1683 */ 1683 */
1684 if (cmdsOK) { 1684 if (cmdsOK) {
1685 Lst_ForEach(gn->commands, JobPrintCommand, job); 1685 Lst_ForEach(gn->commands, JobPrintCommand, job);
1686 } 1686 }
1687 /* 1687 /*
1688 * Don't execute the shell, thank you. 1688 * Don't execute the shell, thank you.
1689 */ 1689 */
1690 noExec = TRUE; 1690 noExec = TRUE;
1691 } else { 1691 } else {
1692 /* 1692 /*
1693 * Just touch the target and note that no shell should be executed. 1693 * Just touch the target and note that no shell should be executed.
1694 * Set cmdFILE to stdout to make life easier. Check the commands, too, 1694 * Set cmdFILE to stdout to make life easier. Check the commands, too,
1695 * but don't die if they're no good -- it does no harm to keep working 1695 * but don't die if they're no good -- it does no harm to keep working
1696 * up the graph. 1696 * up the graph.
1697 */ 1697 */
1698 job->cmdFILE = stdout; 1698 job->cmdFILE = stdout;
1699 Job_Touch(gn, job->flags&JOB_SILENT); 1699 Job_Touch(gn, job->flags&JOB_SILENT);
1700 noExec = TRUE; 1700 noExec = TRUE;
1701 } 1701 }
1702 /* Just in case it isn't already... */ 1702 /* Just in case it isn't already... */
1703 (void)fflush(job->cmdFILE); 1703 (void)fflush(job->cmdFILE);
1704 1704
1705 /* 1705 /*
1706 * If we're not supposed to execute a shell, don't. 1706 * If we're not supposed to execute a shell, don't.
1707 */ 1707 */
1708 if (noExec) { 1708 if (noExec) {
1709 if (!(job->flags & JOB_SPECIAL)) 1709 if (!(job->flags & JOB_SPECIAL))
1710 Job_TokenReturn(); 1710 Job_TokenReturn();
1711 /* 1711 /*

cvs diff -r1.55 -r1.56 src/usr.bin/make/lst.c (switch to unified diff)

--- src/usr.bin/make/lst.c 2020/08/29 10:12:06 1.55
+++ src/usr.bin/make/lst.c 2020/08/29 10:41:12 1.56
@@ -1,638 +1,638 @@ @@ -1,638 +1,638 @@
1/* $NetBSD: lst.c,v 1.55 2020/08/29 10:12:06 rillig Exp $ */ 1/* $NetBSD: lst.c,v 1.56 2020/08/29 10:41:12 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#include <stdint.h> 35#include <stdint.h>
36 36
37#include "make.h" 37#include "make.h"
38 38
39#ifndef MAKE_NATIVE 39#ifndef MAKE_NATIVE
40static char rcsid[] = "$NetBSD: lst.c,v 1.55 2020/08/29 10:12:06 rillig Exp $"; 40static char rcsid[] = "$NetBSD: lst.c,v 1.56 2020/08/29 10:41:12 rillig Exp $";
41#else 41#else
42#include <sys/cdefs.h> 42#include <sys/cdefs.h>
43#ifndef lint 43#ifndef lint
44__RCSID("$NetBSD: lst.c,v 1.55 2020/08/29 10:12:06 rillig Exp $"); 44__RCSID("$NetBSD: lst.c,v 1.56 2020/08/29 10:41:12 rillig Exp $");
45#endif /* not lint */ 45#endif /* not lint */
46#endif 46#endif
47 47
48struct ListNode { 48struct ListNode {
49 struct ListNode *prev; /* previous element in list */ 49 struct ListNode *prev; /* previous element in list */
50 struct ListNode *next; /* next in list */ 50 struct ListNode *next; /* next in list */
51 uint8_t useCount; /* Count of functions using the node. 51 uint8_t useCount; /* Count of functions using the node.
52 * node may not be deleted until count 52 * node may not be deleted until count
53 * goes to 0 */ 53 * goes to 0 */
54 Boolean deleted; /* List node should be removed when done */ 54 Boolean deleted; /* List node should be removed when done */
55 union { 55 union {
56 void *datum; /* datum associated with this element */ 56 void *datum; /* datum associated with this element */
57 const GNode *gnode; /* alias, just for debugging */ 57 const GNode *gnode; /* alias, just for debugging */
58 const char *str; /* alias, just for debugging */ 58 const char *str; /* alias, just for debugging */
59 }; 59 };
60}; 60};
61 61
62typedef enum { 62typedef enum {
63 Head, Middle, Tail, Unknown 63 Head, Middle, Tail, Unknown
64} Where; 64} Where;
65 65
66struct List { 66struct List {
67 LstNode first; /* first node in list */ 67 LstNode first; /* first node in list */
68 LstNode last; /* last node in list */ 68 LstNode last; /* last node in list */
69 69
70 /* fields for sequential access */ 70 /* fields for sequential access */
71 Boolean isOpen; /* true if list has been Lst_Open'ed */ 71 Boolean isOpen; /* true if list has been Lst_Open'ed */
72 Where lastAccess; /* Where in the list the last access was */ 72 Where lastAccess; /* Where in the list the last access was */
73 LstNode curr; /* current node, if open. NULL if 73 LstNode curr; /* current node, if open. NULL if
74 * *just* opened */ 74 * *just* opened */
75 LstNode prev; /* Previous node, if open. Used by Lst_Remove */ 75 LstNode prev; /* Previous node, if open. Used by Lst_Remove */
76}; 76};
77 77
78/* Allocate and initialize a list node. 78/* Allocate and initialize a list node.
79 * 79 *
80 * The fields 'prev' and 'next' must be initialized by the caller. 80 * The fields 'prev' and 'next' must be initialized by the caller.
81 */ 81 */
82static LstNode 82static LstNode
83LstNodeNew(void *datum) 83LstNodeNew(void *datum)
84{ 84{
85 LstNode node = bmake_malloc(sizeof *node); 85 LstNode node = bmake_malloc(sizeof *node);
86 node->useCount = 0; 86 node->useCount = 0;
87 node->deleted = FALSE; 87 node->deleted = FALSE;
88 node->datum = datum; 88 node->datum = datum;
89 return node; 89 return node;
90} 90}
91 91
92static Boolean 92static Boolean
93LstIsEmpty(Lst list) 93LstIsEmpty(Lst list)
94{ 94{
95 return list->first == NULL; 95 return list->first == NULL;
96} 96}
97 97
98/* Create and initialize a new, empty list. */ 98/* Create and initialize a new, empty list. */
99Lst 99Lst
100Lst_Init(void) 100Lst_Init(void)
101{ 101{
102 Lst list = bmake_malloc(sizeof *list); 102 Lst list = bmake_malloc(sizeof *list);
103 103
104 list->first = NULL; 104 list->first = NULL;
105 list->last = NULL; 105 list->last = NULL;
106 list->isOpen = FALSE; 106 list->isOpen = FALSE;
107 list->lastAccess = Unknown; 107 list->lastAccess = Unknown;
108 108
109 return list; 109 return list;
110} 110}
111 111
112/* Duplicate an entire list, usually by copying the datum pointers. 112/* Duplicate an entire list, usually by copying the datum pointers.
113 * If copyProc is given, that function is used to create the new datum from the 113 * If copyProc is given, that function is used to create the new datum from the
114 * old datum, usually by creating a copy of it. */ 114 * old datum, usually by creating a copy of it. */
115Lst 115Lst
116Lst_Copy(Lst list, LstCopyProc copyProc) 116Lst_Copy(Lst list, LstCopyProc copyProc)
117{ 117{
118 Lst newList; 118 Lst newList;
119 LstNode node; 119 LstNode node;
120 120
121 assert(list != NULL); 121 assert(list != NULL);
122 122
123 newList = Lst_Init(); 123 newList = Lst_Init();
124 124
125 for (node = list->first; node != NULL; node = node->next) { 125 for (node = list->first; node != NULL; node = node->next) {
126 void *datum = copyProc != NULL ? copyProc(node->datum) : node->datum; 126 void *datum = copyProc != NULL ? copyProc(node->datum) : node->datum;
127 Lst_Append(newList, datum); 127 Lst_Append(newList, datum);
128 } 128 }
129 129
130 return newList; 130 return newList;
131} 131}
132 132
133/* Free a list and all its nodes. The list data itself are not freed though. */ 133/* Free a list and all its nodes. The list data itself are not freed though. */
134void 134void
135Lst_Free(Lst list) 135Lst_Free(Lst list)
136{ 136{
137 LstNode node; 137 LstNode node;
138 LstNode next; 138 LstNode next;
139 139
140 assert(list != NULL); 140 assert(list != NULL);
141 141
142 for (node = list->first; node != NULL; node = next) { 142 for (node = list->first; node != NULL; node = next) {
143 next = node->next; 143 next = node->next;
144 free(node); 144 free(node);
145 } 145 }
146 146
147 free(list); 147 free(list);
148} 148}
149 149
150/* Destroy a list and free all its resources. If the freeProc is given, it is 150/* Destroy a list and free all its resources. If the freeProc is given, it is
151 * called with the datum from each node in turn before the node is freed. */ 151 * called with the datum from each node in turn before the node is freed. */
152void 152void
153Lst_Destroy(Lst list, LstFreeProc freeProc) 153Lst_Destroy(Lst list, LstFreeProc freeProc)
154{ 154{
155 LstNode node; 155 LstNode node;
156 LstNode next; 156 LstNode next;
157 157
158 assert(list != NULL); 158 assert(list != NULL);
159 assert(freeProc != NULL); 159 assert(freeProc != NULL);
160 160
161 for (node = list->first; node != NULL; node = next) { 161 for (node = list->first; node != NULL; node = next) {
162 next = node->next; 162 next = node->next;
163 freeProc(node->datum); 163 freeProc(node->datum);
164 free(node); 164 free(node);
165 } 165 }
166 166
167 free(list); 167 free(list);
168} 168}
169 169
170/* 170/*
171 * Functions to modify a list 171 * Functions to modify a list
172 */ 172 */
173 173
174/* Insert a new node with the given piece of data before the given node in the 174/* Insert a new node with the given piece of data before the given node in the
175 * given list. */ 175 * given list. */
176void 176void
177Lst_InsertBefore(Lst list, LstNode node, void *datum) 177Lst_InsertBefore(Lst list, LstNode node, void *datum)
178{ 178{
179 LstNode newNode; 179 LstNode newNode;
180 180
181 assert(list != NULL); 181 assert(list != NULL);
182 assert(!LstIsEmpty(list)); 182 assert(!LstIsEmpty(list));
183 assert(node != NULL); 183 assert(node != NULL);
184 assert(datum != NULL); 184 assert(datum != NULL);
185 185
186 newNode = LstNodeNew(datum); 186 newNode = LstNodeNew(datum);
187 newNode->prev = node->prev; 187 newNode->prev = node->prev;
188 newNode->next = node; 188 newNode->next = node;
189 189
190 if (node->prev != NULL) { 190 if (node->prev != NULL) {
191 node->prev->next = newNode; 191 node->prev->next = newNode;
192 } 192 }
193 node->prev = newNode; 193 node->prev = newNode;
194 194
195 if (node == list->first) { 195 if (node == list->first) {
196 list->first = newNode; 196 list->first = newNode;
197 } 197 }
198} 198}
199 199
200/* Add a piece of data at the start of the given list. */ 200/* Add a piece of data at the start of the given list. */
201void 201void
202Lst_Prepend(Lst list, void *datum) 202Lst_Prepend(Lst list, void *datum)
203{ 203{
204 LstNode node; 204 LstNode node;
205 205
206 assert(list != NULL); 206 assert(list != NULL);
207 assert(datum != NULL); 207 assert(datum != NULL);
208 208
209 node = LstNodeNew(datum); 209 node = LstNodeNew(datum);
210 node->prev = NULL; 210 node->prev = NULL;
211 node->next = list->first; 211 node->next = list->first;
212 212
213 if (list->first == NULL) { 213 if (list->first == NULL) {
214 list->first = node; 214 list->first = node;
215 list->last = node; 215 list->last = node;
216 } else { 216 } else {
217 list->first->prev = node; 217 list->first->prev = node;
218 list->first = node; 218 list->first = node;
219 } 219 }
220} 220}
221 221
222/* Add a piece of data at the end of the given list. */ 222/* Add a piece of data at the end of the given list. */
223void 223void
224Lst_Append(Lst list, void *datum) 224Lst_Append(Lst list, void *datum)
225{ 225{
226 LstNode node; 226 LstNode node;
227 227
228 assert(list != NULL); 228 assert(list != NULL);
229 assert(datum != NULL); 229 assert(datum != NULL);
230 230
231 node = LstNodeNew(datum); 231 node = LstNodeNew(datum);
232 node->prev = list->last; 232 node->prev = list->last;
233 node->next = NULL; 233 node->next = NULL;
234 234
235 if (list->last == NULL) { 235 if (list->last == NULL) {
236 list->first = node; 236 list->first = node;
237 list->last = node; 237 list->last = node;
238 } else { 238 } else {
239 list->last->next = node; 239 list->last->next = node;
240 list->last = node; 240 list->last = node;
241 } 241 }
242} 242}
243 243
244/* Remove the given node from the given list. 244/* Remove the given node from the given list.
245 * The datum stored in the node must be freed by the caller, if necessary. */ 245 * The datum stored in the node must be freed by the caller, if necessary. */
246void 246void
247Lst_Remove(Lst list, LstNode node) 247Lst_Remove(Lst list, LstNode node)
248{ 248{
249 assert(list != NULL); 249 assert(list != NULL);
250 assert(node != NULL); 250 assert(node != NULL);
251 251
252 /* 252 /*
253 * unlink it from the list 253 * unlink it from the list
254 */ 254 */
255 if (node->next != NULL) { 255 if (node->next != NULL) {
256 node->next->prev = node->prev; 256 node->next->prev = node->prev;
257 } 257 }
258 if (node->prev != NULL) { 258 if (node->prev != NULL) {
259 node->prev->next = node->next; 259 node->prev->next = node->next;
260 } 260 }
261 261
262 /* 262 /*
263 * if either the first or last of the list point to this node, 263 * if either the first or last of the list point to this node,
264 * adjust them accordingly 264 * adjust them accordingly
265 */ 265 */
266 if (list->first == node) { 266 if (list->first == node) {
267 list->first = node->next; 267 list->first = node->next;
268 } 268 }
269 if (list->last == node) { 269 if (list->last == node) {
270 list->last = node->prev; 270 list->last = node->prev;
271 } 271 }
272 272
273 /* 273 /*
274 * Sequential access stuff. If the node we're removing is the current 274 * Sequential access stuff. If the node we're removing is the current
275 * node in the list, reset the current node to the previous one. If the 275 * node in the list, reset the current node to the previous one. If the
276 * previous one was non-existent (prev == NULL), we set the 276 * previous one was non-existent (prev == NULL), we set the
277 * end to be Unknown, since it is. 277 * end to be Unknown, since it is.
278 */ 278 */
279 if (list->isOpen && list->curr == node) { 279 if (list->isOpen && list->curr == node) {
280 list->curr = list->prev; 280 list->curr = list->prev;
281 if (list->curr == NULL) { 281 if (list->curr == NULL) {
282 list->lastAccess = Unknown; 282 list->lastAccess = Unknown;
283 } 283 }
284 } 284 }
285 285
286 /* 286 /*
287 * note that the datum is unmolested. The caller must free it as 287 * note that the datum is unmolested. The caller must free it as
288 * necessary and as expected. 288 * necessary and as expected.
289 */ 289 */
290 if (node->useCount == 0) { 290 if (node->useCount == 0) {
291 free(node); 291 free(node);
292 } else { 292 } else {
293 node->deleted = TRUE; 293 node->deleted = TRUE;
294 } 294 }
295} 295}
296 296
297/* Replace the datum in the given node with the new datum. */ 297/* Replace the datum in the given node with the new datum. */
298void 298void
299LstNode_Set(LstNode node, void *datum) 299LstNode_Set(LstNode node, void *datum)
300{ 300{
301 assert(node != NULL); 301 assert(node != NULL);
302 assert(datum != NULL); 302 assert(datum != NULL);
303 303
304 node->datum = datum; 304 node->datum = datum;
305} 305}
306 306
307/* Replace the datum in the given node to NULL. */ 307/* Replace the datum in the given node to NULL. */
308void 308void
309LstNode_SetNull(LstNode node) 309LstNode_SetNull(LstNode node)
310{ 310{
311 assert(node != NULL); 311 assert(node != NULL);
312 312
313 node->datum = NULL; 313 node->datum = NULL;
314} 314}
315 315
316 316
317/* 317/*
318 * Node-specific functions 318 * Node-specific functions
319 */ 319 */
320 320
321/* Return the first node from the given list, or NULL if the list is empty. */ 321/* Return the first node from the given list, or NULL if the list is empty. */
322LstNode 322LstNode
323Lst_First(Lst list) 323Lst_First(Lst list)
324{ 324{
325 assert(list != NULL); 325 assert(list != NULL);
326 326
327 return list->first; 327 return list->first;
328} 328}
329 329
330/* Return the last node from the given list, or NULL if the list is empty. */ 330/* Return the last node from the given list, or NULL if the list is empty. */
331LstNode 331LstNode
332Lst_Last(Lst list) 332Lst_Last(Lst list)
333{ 333{
334 assert(list != NULL); 334 assert(list != NULL);
335 335
336 return list->last; 336 return list->last;
337} 337}
338 338
339/* Return the successor to the given node on its list, or NULL. */ 339/* Return the successor to the given node on its list, or NULL. */
340LstNode 340LstNode
341Lst_Succ(LstNode node) 341LstNode_Next(LstNode node)
342{ 342{
343 assert(node != NULL); 343 assert(node != NULL);
344 344
345 return node->next; 345 return node->next;
346} 346}
347 347
348/* Return the predecessor to the given node on its list, or NULL. */ 348/* Return the predecessor to the given node on its list, or NULL. */
349LstNode 349LstNode
350Lst_Prev(LstNode node) 350LstNode_Prev(LstNode node)
351{ 351{
352 assert(node != NULL); 352 assert(node != NULL);
353 return node->prev; 353 return node->prev;
354} 354}
355 355
356/* Return the datum stored in the given node. */ 356/* Return the datum stored in the given node. */
357void * 357void *
358Lst_Datum(LstNode node) 358Lst_Datum(LstNode node)
359{ 359{
360 assert(node != NULL); 360 assert(node != NULL);
361 return node->datum; 361 return node->datum;
362} 362}
363 363
364 364
365/* 365/*
366 * Functions for entire lists 366 * Functions for entire lists
367 */ 367 */
368 368
369/* Return TRUE if the given list is empty. */ 369/* Return TRUE if the given list is empty. */
370Boolean 370Boolean
371Lst_IsEmpty(Lst list) 371Lst_IsEmpty(Lst list)
372{ 372{
373 assert(list != NULL); 373 assert(list != NULL);
374 374
375 return LstIsEmpty(list); 375 return LstIsEmpty(list);
376} 376}
377 377
378/* Return the first node from the list for which the match function returns 378/* Return the first node from the list for which the match function returns
379 * TRUE, or NULL if none of the nodes matched. */ 379 * TRUE, or NULL if none of the nodes matched. */
380LstNode 380LstNode
381Lst_Find(Lst list, LstFindProc match, const void *matchArgs) 381Lst_Find(Lst list, LstFindProc match, const void *matchArgs)
382{ 382{
383 return Lst_FindFrom(list, Lst_First(list), match, matchArgs); 383 return Lst_FindFrom(list, Lst_First(list), match, matchArgs);
384} 384}
385 385
386/* Return the first node from the list, starting at the given node, for which 386/* Return the first node from the list, starting at the given node, for which
387 * the match function returns TRUE, or NULL if none of the nodes matches. 387 * the match function returns TRUE, or NULL if none of the nodes matches.
388 * 388 *
389 * The start node may be NULL, in which case nothing is found. This allows 389 * The start node may be NULL, in which case nothing is found. This allows
390 * for passing Lst_First or Lst_Succ as the start node. */ 390 * for passing Lst_First or LstNode_Next as the start node. */
391LstNode 391LstNode
392Lst_FindFrom(Lst list, LstNode node, LstFindProc match, const void *matchArgs) 392Lst_FindFrom(Lst list, LstNode node, LstFindProc match, const void *matchArgs)
393{ 393{
394 LstNode tln; 394 LstNode tln;
395 395
396 assert(list != NULL); 396 assert(list != NULL);
397 assert(match != NULL); 397 assert(match != NULL);
398 398
399 for (tln = node; tln != NULL; tln = tln->next) { 399 for (tln = node; tln != NULL; tln = tln->next) {
400 if (match(tln->datum, matchArgs)) 400 if (match(tln->datum, matchArgs))
401 return tln; 401 return tln;
402 } 402 }
403 403
404 return NULL; 404 return NULL;
405} 405}
406 406
407/* Return the first node that contains the given datum, or NULL. */ 407/* Return the first node that contains the given datum, or NULL. */
408LstNode 408LstNode
409Lst_Member(Lst list, void *datum) 409Lst_Member(Lst list, void *datum)
410{ 410{
411 LstNode node; 411 LstNode node;
412 412
413 assert(list != NULL); 413 assert(list != NULL);
414 assert(datum != NULL); 414 assert(datum != NULL);
415 415
416 for (node = list->first; node != NULL; node = node->next) { 416 for (node = list->first; node != NULL; node = node->next) {
417 if (node->datum == datum) { 417 if (node->datum == datum) {
418 return node; 418 return node;
419 } 419 }
420 } 420 }
421 421
422 return NULL; 422 return NULL;
423} 423}
424 424
425/* Apply the given function to each element of the given list. The function 425/* Apply the given function to each element of the given list. The function
426 * should return 0 if traversal should continue and non-zero if it should 426 * should return 0 if traversal should continue and non-zero if it should
427 * abort. */ 427 * abort. */
428int 428int
429Lst_ForEach(Lst list, LstActionProc proc, void *procData) 429Lst_ForEach(Lst list, LstActionProc proc, void *procData)
430{ 430{
431 if (LstIsEmpty(list)) 431 if (LstIsEmpty(list))
432 return 0; /* XXX: Document what this value means. */ 432 return 0; /* XXX: Document what this value means. */
433 return Lst_ForEachFrom(list, Lst_First(list), proc, procData); 433 return Lst_ForEachFrom(list, Lst_First(list), proc, procData);
434} 434}
435 435
436/* Apply the given function to each element of the given list, starting from 436/* Apply the given function to each element of the given list, starting from
437 * the given node. The function should return 0 if traversal should continue, 437 * the given node. The function should return 0 if traversal should continue,
438 * and non-zero if it should abort. */ 438 * and non-zero if it should abort. */
439int 439int
440Lst_ForEachFrom(Lst list, LstNode node, 440Lst_ForEachFrom(Lst list, LstNode node,
441 LstActionProc proc, void *procData) 441 LstActionProc proc, void *procData)
442{ 442{
443 LstNode tln = node; 443 LstNode tln = node;
444 LstNode next; 444 LstNode next;
445 Boolean done; 445 Boolean done;
446 int result; 446 int result;
447 447
448 assert(list != NULL); 448 assert(list != NULL);
449 assert(node != NULL); 449 assert(node != NULL);
450 assert(proc != NULL); 450 assert(proc != NULL);
451 451
452 do { 452 do {
453 /* 453 /*
454 * Take care of having the current element deleted out from under 454 * Take care of having the current element deleted out from under
455 * us. 455 * us.
456 */ 456 */
457 457
458 next = tln->next; 458 next = tln->next;
459 459
460 /* 460 /*
461 * We're done with the traversal if 461 * We're done with the traversal if
462 * - the next node to examine doesn't exist and 462 * - the next node to examine doesn't exist and
463 * - nothing's been added after the current node (check this 463 * - nothing's been added after the current node (check this
464 * after proc() has been called). 464 * after proc() has been called).
465 */ 465 */
466 done = next == NULL; 466 done = next == NULL;
467 467
468 tln->useCount++; 468 tln->useCount++;
469 result = (*proc)(tln->datum, procData); 469 result = (*proc)(tln->datum, procData);
470 tln->useCount--; 470 tln->useCount--;
471 471
472 /* 472 /*
473 * Now check whether a node has been added. 473 * Now check whether a node has been added.
474 * Note: this doesn't work if this node was deleted before 474 * Note: this doesn't work if this node was deleted before
475 * the new node was added. 475 * the new node was added.
476 */ 476 */
477 if (next != tln->next) { 477 if (next != tln->next) {
478 next = tln->next; 478 next = tln->next;
479 done = 0; 479 done = 0;
480 } 480 }
481 481
482 if (tln->deleted) { 482 if (tln->deleted) {
483 free((char *)tln); 483 free((char *)tln);
484 } 484 }
485 tln = next; 485 tln = next;
486 } while (!result && !LstIsEmpty(list) && !done); 486 } while (!result && !LstIsEmpty(list) && !done);
487 487
488 return result; 488 return result;
489} 489}
490 490
491/* Move all nodes from list2 to the end of list1. 491/* Move all nodes from list2 to the end of list1.
492 * List2 is destroyed and freed. */ 492 * List2 is destroyed and freed. */
493void 493void
494Lst_MoveAll(Lst list1, Lst list2) 494Lst_MoveAll(Lst list1, Lst list2)
495{ 495{
496 assert(list1 != NULL); 496 assert(list1 != NULL);
497 assert(list2 != NULL); 497 assert(list2 != NULL);
498 498
499 if (list2->first != NULL) { 499 if (list2->first != NULL) {
500 list2->first->prev = list1->last; 500 list2->first->prev = list1->last;
501 if (list1->last != NULL) { 501 if (list1->last != NULL) {
502 list1->last->next = list2->first; 502 list1->last->next = list2->first;
503 } else { 503 } else {
504 list1->first = list2->first; 504 list1->first = list2->first;
505 } 505 }
506 list1->last = list2->last; 506 list1->last = list2->last;
507 } 507 }
508 free(list2); 508 free(list2);
509} 509}
510 510
511/* Copy the element data from src to the start of dst. */ 511/* Copy the element data from src to the start of dst. */
512void 512void
513Lst_PrependAll(Lst dst, Lst src) 513Lst_PrependAll(Lst dst, Lst src)
514{ 514{
515 LstNode node; 515 LstNode node;
516 for (node = src->last; node != NULL; node = node->prev) 516 for (node = src->last; node != NULL; node = node->prev)
517 Lst_Prepend(dst, node->datum); 517 Lst_Prepend(dst, node->datum);
518} 518}
519 519
520/* Copy the element data from src to the end of dst. */ 520/* Copy the element data from src to the end of dst. */
521void 521void
522Lst_AppendAll(Lst dst, Lst src) 522Lst_AppendAll(Lst dst, Lst src)
523{ 523{
524 LstNode node; 524 LstNode node;
525 for (node = src->first; node != NULL; node = node->next) 525 for (node = src->first; node != NULL; node = node->next)
526 Lst_Append(dst, node->datum); 526 Lst_Append(dst, node->datum);
527} 527}
528 528
529/* 529/*
530 * these functions are for dealing with a list as a table, of sorts. 530 * these functions are for dealing with a list as a table, of sorts.
531 * An idea of the "current element" is kept and used by all the functions 531 * An idea of the "current element" is kept and used by all the functions
532 * between Lst_Open() and Lst_Close(). 532 * between Lst_Open() and Lst_Close().
533 * 533 *
534 * The sequential functions access the list in a slightly different way. 534 * The sequential functions access the list in a slightly different way.
535 * CurPtr points to their idea of the current node in the list and they 535 * CurPtr points to their idea of the current node in the list and they
536 * access the list based on it. 536 * access the list based on it.
537 */ 537 */
538 538
539/* Open a list for sequential access. A list can still be searched, etc., 539/* Open a list for sequential access. A list can still be searched, etc.,
540 * without confusing these functions. */ 540 * without confusing these functions. */
541void 541void
542Lst_Open(Lst list) 542Lst_Open(Lst list)
543{ 543{
544 assert(list != NULL); 544 assert(list != NULL);
545 545
546 /* XXX: This assertion fails for NetBSD's "build.sh -j1 tools", somewhere 546 /* XXX: This assertion fails for NetBSD's "build.sh -j1 tools", somewhere
547 * between "dependall ===> compat" and "dependall ===> binstall". 547 * between "dependall ===> compat" and "dependall ===> binstall".
548 * Building without the "-j1" succeeds though. */ 548 * Building without the "-j1" succeeds though. */
549 if (DEBUG(LINT) && list->isOpen) 549 if (DEBUG(LINT) && list->isOpen)
550 Parse_Error(PARSE_WARNING, "Internal inconsistency: list opened twice"); 550 Parse_Error(PARSE_WARNING, "Internal inconsistency: list opened twice");
551 551
552 list->isOpen = TRUE; 552 list->isOpen = TRUE;
553 list->lastAccess = LstIsEmpty(list) ? Head : Unknown; 553 list->lastAccess = LstIsEmpty(list) ? Head : Unknown;
554 list->curr = NULL; 554 list->curr = NULL;
555} 555}
556 556
557/* Return the next node for the given list, or NULL if the end has been 557/* Return the next node for the given list, or NULL if the end has been
558 * reached. */ 558 * reached. */
559LstNode 559LstNode
560Lst_Next(Lst list) 560Lst_Next(Lst list)
561{ 561{
562 LstNode node; 562 LstNode node;
563 563
564 assert(list != NULL); 564 assert(list != NULL);
565 assert(list->isOpen); 565 assert(list->isOpen);
566 566
567 list->prev = list->curr; 567 list->prev = list->curr;
568 568
569 if (list->curr == NULL) { 569 if (list->curr == NULL) {
570 if (list->lastAccess == Unknown) { 570 if (list->lastAccess == Unknown) {
571 /* 571 /*
572 * If we're just starting out, lastAccess will be Unknown. 572 * If we're just starting out, lastAccess will be Unknown.
573 * Then we want to start this thing off in the right 573 * Then we want to start this thing off in the right
574 * direction -- at the start with lastAccess being Middle. 574 * direction -- at the start with lastAccess being Middle.
575 */ 575 */
576 list->curr = node = list->first; 576 list->curr = node = list->first;
577 list->lastAccess = Middle; 577 list->lastAccess = Middle;
578 } else { 578 } else {
579 node = NULL; 579 node = NULL;
580 list->lastAccess = Tail; 580 list->lastAccess = Tail;
581 } 581 }
582 } else { 582 } else {
583 node = list->curr->next; 583 node = list->curr->next;
584 list->curr = node; 584 list->curr = node;
585 585
586 if (node == list->first || node == NULL) { 586 if (node == list->first || node == NULL) {
587 /* 587 /*
588 * If back at the front, then we've hit the end... 588 * If back at the front, then we've hit the end...
589 */ 589 */
590 list->lastAccess = Tail; 590 list->lastAccess = Tail;
591 } else { 591 } else {
592 /* 592 /*
593 * Reset to Middle if gone past first. 593 * Reset to Middle if gone past first.
594 */ 594 */
595 list->lastAccess = Middle; 595 list->lastAccess = Middle;
596 } 596 }
597 } 597 }
598 598
599 return node; 599 return node;
600} 600}
601 601
602/* Close a list which was opened for sequential access. */ 602/* Close a list which was opened for sequential access. */
603void 603void
604Lst_Close(Lst list) 604Lst_Close(Lst list)
605{ 605{
606 assert(list != NULL); 606 assert(list != NULL);
607 assert(list->isOpen); 607 assert(list->isOpen);
608 608
609 list->isOpen = FALSE; 609 list->isOpen = FALSE;
610 list->lastAccess = Unknown; 610 list->lastAccess = Unknown;
611} 611}
612 612
613 613
614/* 614/*
615 * for using the list as a queue 615 * for using the list as a queue
616 */ 616 */
617 617
618/* Add the datum to the tail of the given list. */ 618/* Add the datum to the tail of the given list. */
619void 619void
620Lst_Enqueue(Lst list, void *datum) 620Lst_Enqueue(Lst list, void *datum)
621{ 621{
622 Lst_Append(list, datum); 622 Lst_Append(list, datum);
623} 623}
624 624
625/* Remove and return the datum at the head of the given list. */ 625/* Remove and return the datum at the head of the given list. */
626void * 626void *
627Lst_Dequeue(Lst list) 627Lst_Dequeue(Lst list)
628{ 628{
629 void *datum; 629 void *datum;
630 630
631 assert(list != NULL); 631 assert(list != NULL);
632 assert(!LstIsEmpty(list)); 632 assert(!LstIsEmpty(list));
633 633
634 datum = list->first->datum; 634 datum = list->first->datum;
635 Lst_Remove(list, list->first); 635 Lst_Remove(list, list->first);
636 assert(datum != NULL); 636 assert(datum != NULL);
637 return datum; 637 return datum;
638} 638}

cvs diff -r1.56 -r1.57 src/usr.bin/make/lst.h (switch to unified diff)

--- src/usr.bin/make/lst.h 2020/08/29 10:12:06 1.56
+++ src/usr.bin/make/lst.h 2020/08/29 10:41:12 1.57
@@ -1,180 +1,180 @@ @@ -1,180 +1,180 @@
1/* $NetBSD: lst.h,v 1.56 2020/08/29 10:12:06 rillig Exp $ */ 1/* $NetBSD: lst.h,v 1.57 2020/08/29 10:41:12 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 4 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
5 * All rights reserved. 5 * 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: @(#)lst.h 8.1 (Berkeley) 6/6/93 34 * from: @(#)lst.h 8.1 (Berkeley) 6/6/93
35 */ 35 */
36 36
37/* 37/*
38 * Copyright (c) 1988, 1989 by Adam de Boor 38 * Copyright (c) 1988, 1989 by Adam de Boor
39 * Copyright (c) 1989 by Berkeley Softworks 39 * Copyright (c) 1989 by Berkeley Softworks
40 * All rights reserved. 40 * All rights reserved.
41 * 41 *
42 * This code is derived from software contributed to Berkeley by 42 * This code is derived from software contributed to Berkeley by
43 * Adam de Boor. 43 * Adam de Boor.
44 * 44 *
45 * Redistribution and use in source and binary forms, with or without 45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions 46 * modification, are permitted provided that the following conditions
47 * are met: 47 * are met:
48 * 1. Redistributions of source code must retain the above copyright 48 * 1. Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer. 49 * notice, this list of conditions and the following disclaimer.
50 * 2. Redistributions in binary form must reproduce the above copyright 50 * 2. Redistributions in binary form must reproduce the above copyright
51 * notice, this list of conditions and the following disclaimer in the 51 * notice, this list of conditions and the following disclaimer in the
52 * documentation and/or other materials provided with the distribution. 52 * documentation and/or other materials provided with the distribution.
53 * 3. All advertising materials mentioning features or use of this software 53 * 3. All advertising materials mentioning features or use of this software
54 * must display the following acknowledgement: 54 * must display the following acknowledgement:
55 * This product includes software developed by the University of 55 * This product includes software developed by the University of
56 * California, Berkeley and its contributors. 56 * California, Berkeley and its contributors.
57 * 4. Neither the name of the University nor the names of its contributors 57 * 4. Neither the name of the University nor the names of its contributors
58 * may be used to endorse or promote products derived from this software 58 * may be used to endorse or promote products derived from this software
59 * without specific prior written permission. 59 * without specific prior written permission.
60 * 60 *
61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 64 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71 * SUCH DAMAGE. 71 * SUCH DAMAGE.
72 * 72 *
73 * from: @(#)lst.h 8.1 (Berkeley) 6/6/93 73 * from: @(#)lst.h 8.1 (Berkeley) 6/6/93
74 */ 74 */
75 75
76/*- 76/*-
77 * lst.h -- 77 * lst.h --
78 * Header for using the list library 78 * Header for using the list library
79 */ 79 */
80#ifndef MAKE_LST_H 80#ifndef MAKE_LST_H
81#define MAKE_LST_H 81#define MAKE_LST_H
82 82
83#include <sys/param.h> 83#include <sys/param.h>
84#include <stdlib.h> 84#include <stdlib.h>
85 85
86/* 86/*
87 * basic typedef. This is what the Lst_ functions handle 87 * basic typedef. This is what the Lst_ functions handle
88 */ 88 */
89 89
90typedef struct List *Lst; 90typedef struct List *Lst;
91typedef struct ListNode *LstNode; 91typedef struct ListNode *LstNode;
92 92
93typedef void *LstCopyProc(void *); 93typedef void *LstCopyProc(void *);
94typedef void LstFreeProc(void *); 94typedef void LstFreeProc(void *);
95typedef Boolean LstFindProc(const void *, const void *); 95typedef Boolean LstFindProc(const void *, const void *);
96typedef int LstActionProc(void *, void *); 96typedef int LstActionProc(void *, void *);
97 97
98/* 98/*
99 * Creation/destruction functions 99 * Creation/destruction functions
100 */ 100 */
101/* Create a new list */ 101/* Create a new list */
102Lst Lst_Init(void); 102Lst Lst_Init(void);
103/* Duplicate an existing list */ 103/* Duplicate an existing list */
104Lst Lst_Copy(Lst, LstCopyProc); 104Lst Lst_Copy(Lst, LstCopyProc);
105/* Destroy an old one */ 105/* Destroy an old one */
106void Lst_Free(Lst); 106void Lst_Free(Lst);
107void Lst_Destroy(Lst, LstFreeProc); 107void Lst_Destroy(Lst, LstFreeProc);
108/* True if list is empty */ 108/* True if list is empty */
109Boolean Lst_IsEmpty(Lst); 109Boolean Lst_IsEmpty(Lst);
110 110
111/* 111/*
112 * Functions to modify a list 112 * Functions to modify a list
113 */ 113 */
114/* Insert an element before another */ 114/* Insert an element before another */
115void Lst_InsertBefore(Lst, LstNode, void *); 115void Lst_InsertBefore(Lst, LstNode, void *);
116/* Place an element at the front of a lst. */ 116/* Place an element at the front of a lst. */
117void Lst_Prepend(Lst, void *); 117void Lst_Prepend(Lst, void *);
118/* Place an element at the end of a lst. */ 118/* Place an element at the end of a lst. */
119void Lst_Append(Lst, void *); 119void Lst_Append(Lst, void *);
120/* Remove an element */ 120/* Remove an element */
121void Lst_Remove(Lst, LstNode); 121void Lst_Remove(Lst, LstNode);
122/* Replace a node with a new value */ 122/* Replace a node with a new value */
123void LstNode_Set(LstNode, void *); 123void LstNode_Set(LstNode, void *);
124void LstNode_SetNull(LstNode); 124void LstNode_SetNull(LstNode);
125 125
126void Lst_PrependAll(Lst, Lst); 126void Lst_PrependAll(Lst, Lst);
127void Lst_AppendAll(Lst, Lst); 127void Lst_AppendAll(Lst, Lst);
128void Lst_MoveAll(Lst, Lst); 128void Lst_MoveAll(Lst, Lst);
129 129
130/* 130/*
131 * Node-specific functions 131 * Node-specific functions
132 */ 132 */
133/* Return first element in list */ 133/* Return first element in list */
134LstNode Lst_First(Lst); 134LstNode Lst_First(Lst);
135/* Return last element in list */ 135/* Return last element in list */
136LstNode Lst_Last(Lst); 136LstNode Lst_Last(Lst);
137/* Return successor to given element */ 137/* Return successor to given element */
138LstNode Lst_Succ(LstNode); 138LstNode LstNode_Next(LstNode);
139/* Return predecessor to given element */ 139/* Return predecessor to given element */
140LstNode Lst_Prev(LstNode); 140LstNode LstNode_Prev(LstNode);
141/* Get datum from LstNode */ 141/* Get datum from LstNode */
142void *Lst_Datum(LstNode); 142void *Lst_Datum(LstNode);
143 143
144/* 144/*
145 * Functions for entire lists 145 * Functions for entire lists
146 */ 146 */
147/* Find an element in a list */ 147/* Find an element in a list */
148LstNode Lst_Find(Lst, LstFindProc, const void *); 148LstNode Lst_Find(Lst, LstFindProc, const void *);
149/* Find an element starting from somewhere */ 149/* Find an element starting from somewhere */
150LstNode Lst_FindFrom(Lst, LstNode, LstFindProc, const void *); 150LstNode Lst_FindFrom(Lst, LstNode, LstFindProc, const void *);
151/* 151/*
152 * See if the given datum is on the list. Returns the LstNode containing 152 * See if the given datum is on the list. Returns the LstNode containing
153 * the datum 153 * the datum
154 */ 154 */
155LstNode Lst_Member(Lst, void *); 155LstNode Lst_Member(Lst, void *);
156/* Apply a function to all elements of a lst */ 156/* Apply a function to all elements of a lst */
157int Lst_ForEach(Lst, LstActionProc, void *); 157int Lst_ForEach(Lst, LstActionProc, void *);
158/* Apply a function to all elements of a lst starting from a certain point. */ 158/* Apply a function to all elements of a lst starting from a certain point. */
159int Lst_ForEachFrom(Lst, LstNode, LstActionProc, void *); 159int Lst_ForEachFrom(Lst, LstNode, LstActionProc, void *);
160/* 160/*
161 * these functions are for dealing with a list as a table, of sorts. 161 * these functions are for dealing with a list as a table, of sorts.
162 * An idea of the "current element" is kept and used by all the functions 162 * An idea of the "current element" is kept and used by all the functions
163 * between Lst_Open() and Lst_Close(). 163 * between Lst_Open() and Lst_Close().
164 */ 164 */
165/* Open the list */ 165/* Open the list */
166void Lst_Open(Lst); 166void Lst_Open(Lst);
167/* Next element please, or NULL */ 167/* Next element please, or NULL */
168LstNode Lst_Next(Lst); 168LstNode Lst_Next(Lst);
169/* Finish table access */ 169/* Finish table access */
170void Lst_Close(Lst); 170void Lst_Close(Lst);
171 171
172/* 172/*
173 * for using the list as a queue 173 * for using the list as a queue
174 */ 174 */
175/* Place an element at tail of queue */ 175/* Place an element at tail of queue */
176void Lst_Enqueue(Lst, void *); 176void Lst_Enqueue(Lst, void *);
177/* Remove an element from head of queue */ 177/* Remove an element from head of queue */
178void *Lst_Dequeue(Lst); 178void *Lst_Dequeue(Lst);
179 179
180#endif /* MAKE_LST_H */ 180#endif /* MAKE_LST_H */

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

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

cvs diff -r1.109 -r1.110 src/usr.bin/make/meta.c (switch to unified diff)

--- src/usr.bin/make/meta.c 2020/08/29 10:12:06 1.109
+++ src/usr.bin/make/meta.c 2020/08/29 10:41:12 1.110
@@ -1,1728 +1,1729 @@ @@ -1,1728 +1,1729 @@
1/* $NetBSD: meta.c,v 1.109 2020/08/29 10:12:06 rillig Exp $ */ 1/* $NetBSD: meta.c,v 1.110 2020/08/29 10:41:12 rillig Exp $ */
2 2
3/* 3/*
4 * Implement 'meta' mode. 4 * Implement 'meta' mode.
5 * Adapted from John Birrell's patches to FreeBSD make. 5 * Adapted from John Birrell's patches to FreeBSD make.
6 * --sjg 6 * --sjg
7 */ 7 */
8/* 8/*
9 * Copyright (c) 2009-2016, Juniper Networks, Inc. 9 * Copyright (c) 2009-2016, Juniper Networks, Inc.
10 * Portions Copyright (c) 2009, John Birrell. 10 * Portions Copyright (c) 2009, John Birrell.
11 * 11 *
12 * Redistribution and use in source and binary forms, with or without 12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions 13 * modification, are permitted provided that the following conditions
14 * are met: 14 * are met:
15 * 1. Redistributions of source code must retain the above copyright 15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer. 16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright 17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the 18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution. 19 * documentation and/or other materials provided with the distribution.
20 * 20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */ 32 */
33#if defined(USE_META) 33#if defined(USE_META)
34 34
35#ifdef HAVE_CONFIG_H 35#ifdef HAVE_CONFIG_H
36# include "config.h" 36# include "config.h"
37#endif 37#endif
38#include <sys/stat.h> 38#include <sys/stat.h>
39#include <libgen.h> 39#include <libgen.h>
40#include <errno.h> 40#include <errno.h>
41#if !defined(HAVE_CONFIG_H) || defined(HAVE_ERR_H) 41#if !defined(HAVE_CONFIG_H) || defined(HAVE_ERR_H)
42#include <err.h> 42#include <err.h>
43#endif 43#endif
44 44
45#include "make.h" 45#include "make.h"
46#include "job.h" 46#include "job.h"
47 47
48#ifdef USE_FILEMON 48#ifdef USE_FILEMON
49#include "filemon/filemon.h" 49#include "filemon/filemon.h"
50#endif 50#endif
51 51
52static BuildMon Mybm; /* for compat */ 52static BuildMon Mybm; /* for compat */
53static Lst metaBailiwick; /* our scope of control */ 53static Lst metaBailiwick; /* our scope of control */
54static char *metaBailiwickStr; /* string storage for the list */ 54static char *metaBailiwickStr; /* string storage for the list */
55static Lst metaIgnorePaths; /* paths we deliberately ignore */ 55static Lst metaIgnorePaths; /* paths we deliberately ignore */
56static char *metaIgnorePathsStr; /* string storage for the list */ 56static char *metaIgnorePathsStr; /* string storage for the list */
57 57
58#ifndef MAKE_META_IGNORE_PATHS 58#ifndef MAKE_META_IGNORE_PATHS
59#define MAKE_META_IGNORE_PATHS ".MAKE.META.IGNORE_PATHS" 59#define MAKE_META_IGNORE_PATHS ".MAKE.META.IGNORE_PATHS"
60#endif 60#endif
61#ifndef MAKE_META_IGNORE_PATTERNS 61#ifndef MAKE_META_IGNORE_PATTERNS
62#define MAKE_META_IGNORE_PATTERNS ".MAKE.META.IGNORE_PATTERNS" 62#define MAKE_META_IGNORE_PATTERNS ".MAKE.META.IGNORE_PATTERNS"
63#endif 63#endif
64#ifndef MAKE_META_IGNORE_FILTER 64#ifndef MAKE_META_IGNORE_FILTER
65#define MAKE_META_IGNORE_FILTER ".MAKE.META.IGNORE_FILTER" 65#define MAKE_META_IGNORE_FILTER ".MAKE.META.IGNORE_FILTER"
66#endif 66#endif
67 67
68Boolean useMeta = FALSE; 68Boolean useMeta = FALSE;
69static Boolean useFilemon = FALSE; 69static Boolean useFilemon = FALSE;
70static Boolean writeMeta = FALSE; 70static Boolean writeMeta = FALSE;
71static Boolean metaMissing = FALSE; /* oodate if missing */ 71static Boolean metaMissing = FALSE; /* oodate if missing */
72static Boolean filemonMissing = FALSE; /* oodate if missing */ 72static Boolean filemonMissing = FALSE; /* oodate if missing */
73static Boolean metaEnv = FALSE; /* don't save env unless asked */ 73static Boolean metaEnv = FALSE; /* don't save env unless asked */
74static Boolean metaVerbose = FALSE; 74static Boolean metaVerbose = FALSE;
75static Boolean metaIgnoreCMDs = FALSE; /* ignore CMDs in .meta files */ 75static Boolean metaIgnoreCMDs = FALSE; /* ignore CMDs in .meta files */
76static Boolean metaIgnorePatterns = FALSE; /* do we need to do pattern matches */ 76static Boolean metaIgnorePatterns = FALSE; /* do we need to do pattern matches */
77static Boolean metaIgnoreFilter = FALSE; /* do we have more complex filtering? */ 77static Boolean metaIgnoreFilter = FALSE; /* do we have more complex filtering? */
78static Boolean metaCurdirOk = FALSE; /* write .meta in .CURDIR Ok? */ 78static Boolean metaCurdirOk = FALSE; /* write .meta in .CURDIR Ok? */
79static Boolean metaSilent = FALSE; /* if we have a .meta be SILENT */ 79static Boolean metaSilent = FALSE; /* if we have a .meta be SILENT */
80 80
81extern Boolean forceJobs; 81extern Boolean forceJobs;
82extern Boolean comatMake; 82extern Boolean comatMake;
83extern char **environ; 83extern char **environ;
84 84
85#define MAKE_META_PREFIX ".MAKE.META.PREFIX" 85#define MAKE_META_PREFIX ".MAKE.META.PREFIX"
86 86
87#ifndef N2U 87#ifndef N2U
88# define N2U(n, u) (((n) + ((u) - 1)) / (u)) 88# define N2U(n, u) (((n) + ((u) - 1)) / (u))
89#endif 89#endif
90#ifndef ROUNDUP 90#ifndef ROUNDUP
91# define ROUNDUP(n, u) (N2U((n), (u)) * (u)) 91# define ROUNDUP(n, u) (N2U((n), (u)) * (u))
92#endif 92#endif
93 93
94#if !defined(HAVE_STRSEP) 94#if !defined(HAVE_STRSEP)
95# define strsep(s, d) stresep((s), (d), 0) 95# define strsep(s, d) stresep((s), (d), 0)
96#endif 96#endif
97 97
98/* 98/*
99 * Filemon is a kernel module which snoops certain syscalls. 99 * Filemon is a kernel module which snoops certain syscalls.
100 * 100 *
101 * C chdir 101 * C chdir
102 * E exec 102 * E exec
103 * F [v]fork 103 * F [v]fork
104 * L [sym]link 104 * L [sym]link
105 * M rename 105 * M rename
106 * R read 106 * R read
107 * W write 107 * W write
108 * S stat 108 * S stat
109 * 109 *
110 * See meta_oodate below - we mainly care about 'E' and 'R'. 110 * See meta_oodate below - we mainly care about 'E' and 'R'.
111 * 111 *
112 * We can still use meta mode without filemon, but 112 * We can still use meta mode without filemon, but
113 * the benefits are more limited. 113 * the benefits are more limited.
114 */ 114 */
115#ifdef USE_FILEMON 115#ifdef USE_FILEMON
116 116
117/* 117/*
118 * Open the filemon device. 118 * Open the filemon device.
119 */ 119 */
120static void 120static void
121meta_open_filemon(BuildMon *pbm) 121meta_open_filemon(BuildMon *pbm)
122{ 122{
123 int dupfd; 123 int dupfd;
124 124
125 pbm->mon_fd = -1; 125 pbm->mon_fd = -1;
126 pbm->filemon = NULL; 126 pbm->filemon = NULL;
127 if (!useFilemon || !pbm->mfp) 127 if (!useFilemon || !pbm->mfp)
128 return; 128 return;
129 129
130 pbm->filemon = filemon_open(); 130 pbm->filemon = filemon_open();
131 if (pbm->filemon == NULL) { 131 if (pbm->filemon == NULL) {
132 useFilemon = FALSE; 132 useFilemon = FALSE;
133 warn("Could not open filemon %s", filemon_path()); 133 warn("Could not open filemon %s", filemon_path());
134 return; 134 return;
135 } 135 }
136 136
137 /* 137 /*
138 * We use a file outside of '.' 138 * We use a file outside of '.'
139 * to avoid a FreeBSD kernel bug where unlink invalidates 139 * to avoid a FreeBSD kernel bug where unlink invalidates
140 * cwd causing getcwd to do a lot more work. 140 * cwd causing getcwd to do a lot more work.
141 * We only care about the descriptor. 141 * We only care about the descriptor.
142 */ 142 */
143 pbm->mon_fd = mkTempFile("filemon.XXXXXX", NULL); 143 pbm->mon_fd = mkTempFile("filemon.XXXXXX", NULL);
144 if ((dupfd = dup(pbm->mon_fd)) == -1) { 144 if ((dupfd = dup(pbm->mon_fd)) == -1) {
145 err(1, "Could not dup filemon output!"); 145 err(1, "Could not dup filemon output!");
146 } 146 }
147 (void)fcntl(dupfd, F_SETFD, FD_CLOEXEC); 147 (void)fcntl(dupfd, F_SETFD, FD_CLOEXEC);
148 if (filemon_setfd(pbm->filemon, dupfd) == -1) { 148 if (filemon_setfd(pbm->filemon, dupfd) == -1) {
149 err(1, "Could not set filemon file descriptor!"); 149 err(1, "Could not set filemon file descriptor!");
150 } 150 }
151 /* we don't need these once we exec */ 151 /* we don't need these once we exec */
152 (void)fcntl(pbm->mon_fd, F_SETFD, FD_CLOEXEC); 152 (void)fcntl(pbm->mon_fd, F_SETFD, FD_CLOEXEC);
153} 153}
154 154
155/* 155/*
156 * Read the build monitor output file and write records to the target's 156 * Read the build monitor output file and write records to the target's
157 * metadata file. 157 * metadata file.
158 */ 158 */
159static int 159static int
160filemon_read(FILE *mfp, int fd) 160filemon_read(FILE *mfp, int fd)
161{ 161{
162 char buf[BUFSIZ]; 162 char buf[BUFSIZ];
163 int n; 163 int n;
164 int error; 164 int error;
165 165
166 /* Check if we're not writing to a meta data file.*/ 166 /* Check if we're not writing to a meta data file.*/
167 if (mfp == NULL) { 167 if (mfp == NULL) {
168 if (fd >= 0) 168 if (fd >= 0)
169 close(fd); /* not interested */ 169 close(fd); /* not interested */
170 return 0; 170 return 0;
171 } 171 }
172 /* rewind */ 172 /* rewind */
173 if (lseek(fd, (off_t)0, SEEK_SET) < 0) { 173 if (lseek(fd, (off_t)0, SEEK_SET) < 0) {
174 error = errno; 174 error = errno;
175 warn("Could not rewind filemon"); 175 warn("Could not rewind filemon");
176 fprintf(mfp, "\n"); 176 fprintf(mfp, "\n");
177 } else { 177 } else {
178 error = 0; 178 error = 0;
179 fprintf(mfp, "\n-- filemon acquired metadata --\n"); 179 fprintf(mfp, "\n-- filemon acquired metadata --\n");
180 180
181 while ((n = read(fd, buf, sizeof(buf))) > 0) { 181 while ((n = read(fd, buf, sizeof(buf))) > 0) {
182 if ((int)fwrite(buf, 1, n, mfp) < n) 182 if ((int)fwrite(buf, 1, n, mfp) < n)
183 error = EIO; 183 error = EIO;
184 } 184 }
185 } 185 }
186 fflush(mfp); 186 fflush(mfp);
187 if (close(fd) < 0) 187 if (close(fd) < 0)
188 error = errno; 188 error = errno;
189 return error; 189 return error;
190} 190}
191#endif 191#endif
192 192
193/* 193/*
194 * when realpath() fails, 194 * when realpath() fails,
195 * we use this, to clean up ./ and ../ 195 * we use this, to clean up ./ and ../
196 */ 196 */
197static void 197static void
198eat_dots(char *buf, size_t bufsz, int dots) 198eat_dots(char *buf, size_t bufsz, int dots)
199{ 199{
200 char *cp; 200 char *cp;
201 char *cp2; 201 char *cp2;
202 const char *eat; 202 const char *eat;
203 size_t eatlen; 203 size_t eatlen;
204 204
205 switch (dots) { 205 switch (dots) {
206 case 1: 206 case 1:
207 eat = "/./"; 207 eat = "/./";
208 eatlen = 2; 208 eatlen = 2;
209 break; 209 break;
210 case 2: 210 case 2:
211 eat = "/../"; 211 eat = "/../";
212 eatlen = 3; 212 eatlen = 3;
213 break; 213 break;
214 default: 214 default:
215 return; 215 return;
216 } 216 }
217 217
218 do { 218 do {
219 cp = strstr(buf, eat); 219 cp = strstr(buf, eat);
220 if (cp) { 220 if (cp) {
221 cp2 = cp + eatlen; 221 cp2 = cp + eatlen;
222 if (dots == 2 && cp > buf) { 222 if (dots == 2 && cp > buf) {
223 do { 223 do {
224 cp--; 224 cp--;
225 } while (cp > buf && *cp != '/'); 225 } while (cp > buf && *cp != '/');
226 } 226 }
227 if (*cp == '/') { 227 if (*cp == '/') {
228 strlcpy(cp, cp2, bufsz - (cp - buf)); 228 strlcpy(cp, cp2, bufsz - (cp - buf));
229 } else { 229 } else {
230 return; /* can't happen? */ 230 return; /* can't happen? */
231 } 231 }
232 } 232 }
233 } while (cp); 233 } while (cp);
234} 234}
235 235
236static char * 236static char *
237meta_name(struct GNode *gn, char *mname, size_t mnamelen, 237meta_name(struct GNode *gn, char *mname, size_t mnamelen,
238 const char *dname, 238 const char *dname,
239 const char *tname, 239 const char *tname,
240 const char *cwd) 240 const char *cwd)
241{ 241{
242 char buf[MAXPATHLEN]; 242 char buf[MAXPATHLEN];
243 char *rp; 243 char *rp;
244 char *cp; 244 char *cp;
245 char *tp; 245 char *tp;
246 char *dtp; 246 char *dtp;
247 size_t ldname; 247 size_t ldname;
248 248
249 /* 249 /*
250 * Weed out relative paths from the target file name. 250 * Weed out relative paths from the target file name.
251 * We have to be careful though since if target is a 251 * We have to be careful though since if target is a
252 * symlink, the result will be unstable. 252 * symlink, the result will be unstable.
253 * So we use realpath() just to get the dirname, and leave the 253 * So we use realpath() just to get the dirname, and leave the
254 * basename as given to us. 254 * basename as given to us.
255 */ 255 */
256 if ((cp = strrchr(tname, '/'))) { 256 if ((cp = strrchr(tname, '/'))) {
257 if (cached_realpath(tname, buf)) { 257 if (cached_realpath(tname, buf)) {
258 if ((rp = strrchr(buf, '/'))) { 258 if ((rp = strrchr(buf, '/'))) {
259 rp++; 259 rp++;
260 cp++; 260 cp++;
261 if (strcmp(cp, rp) != 0) 261 if (strcmp(cp, rp) != 0)
262 strlcpy(rp, cp, sizeof(buf) - (rp - buf)); 262 strlcpy(rp, cp, sizeof(buf) - (rp - buf));
263 } 263 }
264 tname = buf; 264 tname = buf;
265 } else { 265 } else {
266 /* 266 /*
267 * We likely have a directory which is about to be made. 267 * We likely have a directory which is about to be made.
268 * We pretend realpath() succeeded, to have a chance 268 * We pretend realpath() succeeded, to have a chance
269 * of generating the same meta file name that we will 269 * of generating the same meta file name that we will
270 * next time through. 270 * next time through.
271 */ 271 */
272 if (tname[0] == '/') { 272 if (tname[0] == '/') {
273 strlcpy(buf, tname, sizeof(buf)); 273 strlcpy(buf, tname, sizeof(buf));
274 } else { 274 } else {
275 snprintf(buf, sizeof(buf), "%s/%s", cwd, tname); 275 snprintf(buf, sizeof(buf), "%s/%s", cwd, tname);
276 } 276 }
277 eat_dots(buf, sizeof(buf), 1); /* ./ */ 277 eat_dots(buf, sizeof(buf), 1); /* ./ */
278 eat_dots(buf, sizeof(buf), 2); /* ../ */ 278 eat_dots(buf, sizeof(buf), 2); /* ../ */
279 tname = buf; 279 tname = buf;
280 } 280 }
281 } 281 }
282 /* on some systems dirname may modify its arg */ 282 /* on some systems dirname may modify its arg */
283 tp = bmake_strdup(tname); 283 tp = bmake_strdup(tname);
284 dtp = dirname(tp); 284 dtp = dirname(tp);
285 if (strcmp(dname, dtp) == 0) 285 if (strcmp(dname, dtp) == 0)
286 snprintf(mname, mnamelen, "%s.meta", tname); 286 snprintf(mname, mnamelen, "%s.meta", tname);
287 else { 287 else {
288 ldname = strlen(dname); 288 ldname = strlen(dname);
289 if (strncmp(dname, dtp, ldname) == 0 && dtp[ldname] == '/') 289 if (strncmp(dname, dtp, ldname) == 0 && dtp[ldname] == '/')
290 snprintf(mname, mnamelen, "%s/%s.meta", dname, &tname[ldname+1]); 290 snprintf(mname, mnamelen, "%s/%s.meta", dname, &tname[ldname+1]);
291 else 291 else
292 snprintf(mname, mnamelen, "%s/%s.meta", dname, tname); 292 snprintf(mname, mnamelen, "%s/%s.meta", dname, tname);
293 293
294 /* 294 /*
295 * Replace path separators in the file name after the 295 * Replace path separators in the file name after the
296 * current object directory path. 296 * current object directory path.
297 */ 297 */
298 cp = mname + strlen(dname) + 1; 298 cp = mname + strlen(dname) + 1;
299 299
300 while (*cp != '\0') { 300 while (*cp != '\0') {
301 if (*cp == '/') 301 if (*cp == '/')
302 *cp = '_'; 302 *cp = '_';
303 cp++; 303 cp++;
304 } 304 }
305 } 305 }
306 free(tp); 306 free(tp);
307 return mname; 307 return mname;
308} 308}
309 309
310/* 310/*
311 * Return true if running ${.MAKE} 311 * Return true if running ${.MAKE}
312 * Bypassed if target is flagged .MAKE 312 * Bypassed if target is flagged .MAKE
313 */ 313 */
314static int 314static int
315is_submake(void *cmdp, void *gnp) 315is_submake(void *cmdp, void *gnp)
316{ 316{
317 static const char *p_make = NULL; 317 static const char *p_make = NULL;
318 static int p_len; 318 static int p_len;
319 char *cmd = cmdp; 319 char *cmd = cmdp;
320 GNode *gn = gnp; 320 GNode *gn = gnp;
321 char *mp = NULL; 321 char *mp = NULL;
322 char *cp; 322 char *cp;
323 char *cp2; 323 char *cp2;
324 int rc = 0; /* keep looking */ 324 int rc = 0; /* keep looking */
325 325
326 if (!p_make) { 326 if (!p_make) {
327 p_make = Var_Value(".MAKE", gn, &cp); 327 p_make = Var_Value(".MAKE", gn, &cp);
328 p_len = strlen(p_make); 328 p_len = strlen(p_make);
329 } 329 }
330 cp = strchr(cmd, '$'); 330 cp = strchr(cmd, '$');
331 if ((cp)) { 331 if ((cp)) {
332 mp = Var_Subst(cmd, gn, VARE_WANTRES); 332 mp = Var_Subst(cmd, gn, VARE_WANTRES);
333 cmd = mp; 333 cmd = mp;
334 } 334 }
335 cp2 = strstr(cmd, p_make); 335 cp2 = strstr(cmd, p_make);
336 if ((cp2)) { 336 if ((cp2)) {
337 switch (cp2[p_len]) { 337 switch (cp2[p_len]) {
338 case '\0': 338 case '\0':
339 case ' ': 339 case ' ':
340 case '\t': 340 case '\t':
341 case '\n': 341 case '\n':
342 rc = 1; 342 rc = 1;
343 break; 343 break;
344 } 344 }
345 if (cp2 > cmd && rc > 0) { 345 if (cp2 > cmd && rc > 0) {
346 switch (cp2[-1]) { 346 switch (cp2[-1]) {
347 case ' ': 347 case ' ':
348 case '\t': 348 case '\t':
349 case '\n': 349 case '\n':
350 break; 350 break;
351 default: 351 default:
352 rc = 0; /* no match */ 352 rc = 0; /* no match */
353 break; 353 break;
354 } 354 }
355 } 355 }
356 } 356 }
357 free(mp); 357 free(mp);
358 return rc; 358 return rc;
359} 359}
360 360
361typedef struct meta_file_s { 361typedef struct meta_file_s {
362 FILE *fp; 362 FILE *fp;
363 GNode *gn; 363 GNode *gn;
364} meta_file_t; 364} meta_file_t;
365 365
366static int 366static int
367printCMD(void *cmdp, void *mfpp) 367printCMD(void *cmdp, void *mfpp)
368{ 368{
369 meta_file_t *mfp = mfpp; 369 meta_file_t *mfp = mfpp;
370 char *cmd = cmdp; 370 char *cmd = cmdp;
371 char *cp = NULL; 371 char *cp = NULL;
372 372
373 if (strchr(cmd, '$')) { 373 if (strchr(cmd, '$')) {
374 cmd = cp = Var_Subst(cmd, mfp->gn, VARE_WANTRES); 374 cmd = cp = Var_Subst(cmd, mfp->gn, VARE_WANTRES);
375 } 375 }
376 fprintf(mfp->fp, "CMD %s\n", cmd); 376 fprintf(mfp->fp, "CMD %s\n", cmd);
377 free(cp); 377 free(cp);
378 return 0; 378 return 0;
379} 379}
380 380
381/* 381/*
382 * Certain node types never get a .meta file 382 * Certain node types never get a .meta file
383 */ 383 */
384#define SKIP_META_TYPE(_type) do { \ 384#define SKIP_META_TYPE(_type) do { \
385 if ((gn->type & __CONCAT(OP_, _type))) { \ 385 if ((gn->type & __CONCAT(OP_, _type))) { \
386 if (verbose) { \ 386 if (verbose) { \
387 fprintf(debug_file, "Skipping meta for %s: .%s\n", \ 387 fprintf(debug_file, "Skipping meta for %s: .%s\n", \
388 gn->name, __STRING(_type)); \ 388 gn->name, __STRING(_type)); \
389 } \ 389 } \
390 return FALSE; \ 390 return FALSE; \
391 } \ 391 } \
392} while (0) 392} while (0)
393 393
394 394
395/* 395/*
396 * Do we need/want a .meta file ? 396 * Do we need/want a .meta file ?
397 */ 397 */
398static Boolean 398static Boolean
399meta_needed(GNode *gn, const char *dname, const char *tname, 399meta_needed(GNode *gn, const char *dname, const char *tname,
400 char *objdir, int verbose) 400 char *objdir, int verbose)
401{ 401{
402 struct stat fs; 402 struct stat fs;
403 403
404 if (verbose) 404 if (verbose)
405 verbose = DEBUG(META); 405 verbose = DEBUG(META);
406 406
407 /* This may be a phony node which we don't want meta data for... */ 407 /* This may be a phony node which we don't want meta data for... */
408 /* Skip .meta for .BEGIN, .END, .ERROR etc as well. */ 408 /* Skip .meta for .BEGIN, .END, .ERROR etc as well. */
409 /* Or it may be explicitly flagged as .NOMETA */ 409 /* Or it may be explicitly flagged as .NOMETA */
410 SKIP_META_TYPE(NOMETA); 410 SKIP_META_TYPE(NOMETA);
411 /* Unless it is explicitly flagged as .META */ 411 /* Unless it is explicitly flagged as .META */
412 if (!(gn->type & OP_META)) { 412 if (!(gn->type & OP_META)) {
413 SKIP_META_TYPE(PHONY); 413 SKIP_META_TYPE(PHONY);
414 SKIP_META_TYPE(SPECIAL); 414 SKIP_META_TYPE(SPECIAL);
415 SKIP_META_TYPE(MAKE); 415 SKIP_META_TYPE(MAKE);
416 } 416 }
417 417
418 /* Check if there are no commands to execute. */ 418 /* Check if there are no commands to execute. */
419 if (Lst_IsEmpty(gn->commands)) { 419 if (Lst_IsEmpty(gn->commands)) {
420 if (verbose) 420 if (verbose)
421 fprintf(debug_file, "Skipping meta for %s: no commands\n", 421 fprintf(debug_file, "Skipping meta for %s: no commands\n",
422 gn->name); 422 gn->name);
423 return FALSE; 423 return FALSE;
424 } 424 }
425 if ((gn->type & (OP_META|OP_SUBMAKE)) == OP_SUBMAKE) { 425 if ((gn->type & (OP_META|OP_SUBMAKE)) == OP_SUBMAKE) {
426 /* OP_SUBMAKE is a bit too aggressive */ 426 /* OP_SUBMAKE is a bit too aggressive */
427 if (Lst_ForEach(gn->commands, is_submake, gn)) { 427 if (Lst_ForEach(gn->commands, is_submake, gn)) {
428 if (DEBUG(META)) 428 if (DEBUG(META))
429 fprintf(debug_file, "Skipping meta for %s: .SUBMAKE\n", 429 fprintf(debug_file, "Skipping meta for %s: .SUBMAKE\n",
430 gn->name); 430 gn->name);
431 return FALSE; 431 return FALSE;
432 } 432 }
433 } 433 }
434 434
435 /* The object directory may not exist. Check it.. */ 435 /* The object directory may not exist. Check it.. */
436 if (cached_stat(dname, &fs) != 0) { 436 if (cached_stat(dname, &fs) != 0) {
437 if (verbose) 437 if (verbose)
438 fprintf(debug_file, "Skipping meta for %s: no .OBJDIR\n", 438 fprintf(debug_file, "Skipping meta for %s: no .OBJDIR\n",
439 gn->name); 439 gn->name);
440 return FALSE; 440 return FALSE;
441 } 441 }
442 442
443 /* make sure these are canonical */ 443 /* make sure these are canonical */
444 if (cached_realpath(dname, objdir)) 444 if (cached_realpath(dname, objdir))
445 dname = objdir; 445 dname = objdir;
446 446
447 /* If we aren't in the object directory, don't create a meta file. */ 447 /* If we aren't in the object directory, don't create a meta file. */
448 if (!metaCurdirOk && strcmp(curdir, dname) == 0) { 448 if (!metaCurdirOk && strcmp(curdir, dname) == 0) {
449 if (verbose) 449 if (verbose)
450 fprintf(debug_file, "Skipping meta for %s: .OBJDIR == .CURDIR\n", 450 fprintf(debug_file, "Skipping meta for %s: .OBJDIR == .CURDIR\n",
451 gn->name); 451 gn->name);
452 return FALSE; 452 return FALSE;
453 } 453 }
454 return TRUE; 454 return TRUE;
455} 455}
456 456
457 457
458static FILE * 458static FILE *
459meta_create(BuildMon *pbm, GNode *gn) 459meta_create(BuildMon *pbm, GNode *gn)
460{ 460{
461 meta_file_t mf; 461 meta_file_t mf;
462 char buf[MAXPATHLEN]; 462 char buf[MAXPATHLEN];
463 char objdir[MAXPATHLEN]; 463 char objdir[MAXPATHLEN];
464 char **ptr; 464 char **ptr;
465 const char *dname; 465 const char *dname;
466 const char *tname; 466 const char *tname;
467 char *fname; 467 char *fname;
468 const char *cp; 468 const char *cp;
469 char *p[5]; /* >= possible uses */ 469 char *p[5]; /* >= possible uses */
470 int i; 470 int i;
471 471
472 mf.fp = NULL; 472 mf.fp = NULL;
473 i = 0; 473 i = 0;
474 474
475 dname = Var_Value(".OBJDIR", gn, &p[i++]); 475 dname = Var_Value(".OBJDIR", gn, &p[i++]);
476 tname = Var_Value(TARGET, gn, &p[i++]); 476 tname = Var_Value(TARGET, gn, &p[i++]);
477 477
478 /* if this succeeds objdir is realpath of dname */ 478 /* if this succeeds objdir is realpath of dname */
479 if (!meta_needed(gn, dname, tname, objdir, TRUE)) 479 if (!meta_needed(gn, dname, tname, objdir, TRUE))
480 goto out; 480 goto out;
481 dname = objdir; 481 dname = objdir;
482 482
483 if (metaVerbose) { 483 if (metaVerbose) {
484 char *mp; 484 char *mp;
485 485
486 /* Describe the target we are building */ 486 /* Describe the target we are building */
487 mp = Var_Subst("${" MAKE_META_PREFIX "}", gn, VARE_WANTRES); 487 mp = Var_Subst("${" MAKE_META_PREFIX "}", gn, VARE_WANTRES);
488 if (*mp) 488 if (*mp)
489 fprintf(stdout, "%s\n", mp); 489 fprintf(stdout, "%s\n", mp);
490 free(mp); 490 free(mp);
491 } 491 }
492 /* Get the basename of the target */ 492 /* Get the basename of the target */
493 if ((cp = strrchr(tname, '/')) == NULL) { 493 if ((cp = strrchr(tname, '/')) == NULL) {
494 cp = tname; 494 cp = tname;
495 } else { 495 } else {
496 cp++; 496 cp++;
497 } 497 }
498 498
499 fflush(stdout); 499 fflush(stdout);
500 500
501 if (!writeMeta) 501 if (!writeMeta)
502 /* Don't create meta data. */ 502 /* Don't create meta data. */
503 goto out; 503 goto out;
504 504
505 fname = meta_name(gn, pbm->meta_fname, sizeof(pbm->meta_fname), 505 fname = meta_name(gn, pbm->meta_fname, sizeof(pbm->meta_fname),
506 dname, tname, objdir); 506 dname, tname, objdir);
507 507
508#ifdef DEBUG_META_MODE 508#ifdef DEBUG_META_MODE
509 if (DEBUG(META)) 509 if (DEBUG(META))
510 fprintf(debug_file, "meta_create: %s\n", fname); 510 fprintf(debug_file, "meta_create: %s\n", fname);
511#endif 511#endif
512 512
513 if ((mf.fp = fopen(fname, "w")) == NULL) 513 if ((mf.fp = fopen(fname, "w")) == NULL)
514 err(1, "Could not open meta file '%s'", fname); 514 err(1, "Could not open meta file '%s'", fname);
515 515
516 fprintf(mf.fp, "# Meta data file %s\n", fname); 516 fprintf(mf.fp, "# Meta data file %s\n", fname);
517 517
518 mf.gn = gn; 518 mf.gn = gn;
519 519
520 Lst_ForEach(gn->commands, printCMD, &mf); 520 Lst_ForEach(gn->commands, printCMD, &mf);
521 521
522 fprintf(mf.fp, "CWD %s\n", getcwd(buf, sizeof(buf))); 522 fprintf(mf.fp, "CWD %s\n", getcwd(buf, sizeof(buf)));
523 fprintf(mf.fp, "TARGET %s\n", tname); 523 fprintf(mf.fp, "TARGET %s\n", tname);
524 cp = Var_Value(".OODATE", gn, &p[i++]); 524 cp = Var_Value(".OODATE", gn, &p[i++]);
525 if (cp && *cp) { 525 if (cp && *cp) {
526 fprintf(mf.fp, "OODATE %s\n", cp); 526 fprintf(mf.fp, "OODATE %s\n", cp);
527 } 527 }
528 if (metaEnv) { 528 if (metaEnv) {
529 for (ptr = environ; *ptr != NULL; ptr++) 529 for (ptr = environ; *ptr != NULL; ptr++)
530 fprintf(mf.fp, "ENV %s\n", *ptr); 530 fprintf(mf.fp, "ENV %s\n", *ptr);
531 } 531 }
532 532
533 fprintf(mf.fp, "-- command output --\n"); 533 fprintf(mf.fp, "-- command output --\n");
534 fflush(mf.fp); 534 fflush(mf.fp);
535 535
536 Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL); 536 Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
537 Var_Append(".MAKE.META.CREATED", fname, VAR_GLOBAL); 537 Var_Append(".MAKE.META.CREATED", fname, VAR_GLOBAL);
538 538
539 gn->type |= OP_META; /* in case anyone wants to know */ 539 gn->type |= OP_META; /* in case anyone wants to know */
540 if (metaSilent) { 540 if (metaSilent) {
541 gn->type |= OP_SILENT; 541 gn->type |= OP_SILENT;
542 } 542 }
543 out: 543 out:
544 for (i--; i >= 0; i--) { 544 for (i--; i >= 0; i--) {
545 bmake_free(p[i]); 545 bmake_free(p[i]);
546 } 546 }
547 547
548 return mf.fp; 548 return mf.fp;
549} 549}
550 550
551static Boolean 551static Boolean
552boolValue(char *s) 552boolValue(char *s)
553{ 553{
554 switch(*s) { 554 switch(*s) {
555 case '0': 555 case '0':
556 case 'N': 556 case 'N':
557 case 'n': 557 case 'n':
558 case 'F': 558 case 'F':
559 case 'f': 559 case 'f':
560 return FALSE; 560 return FALSE;
561 } 561 }
562 return TRUE; 562 return TRUE;
563} 563}
564 564
565/* 565/*
566 * Initialization we need before reading makefiles. 566 * Initialization we need before reading makefiles.
567 */ 567 */
568void 568void
569meta_init(void) 569meta_init(void)
570{ 570{
571#ifdef USE_FILEMON 571#ifdef USE_FILEMON
572 /* this allows makefiles to test if we have filemon support */ 572 /* this allows makefiles to test if we have filemon support */
573 Var_Set(".MAKE.PATH_FILEMON", filemon_path(), VAR_GLOBAL); 573 Var_Set(".MAKE.PATH_FILEMON", filemon_path(), VAR_GLOBAL);
574#endif 574#endif
575} 575}
576 576
577 577
578#define get_mode_bf(bf, token) \ 578#define get_mode_bf(bf, token) \
579 if ((cp = strstr(make_mode, token))) \ 579 if ((cp = strstr(make_mode, token))) \
580 bf = boolValue(&cp[sizeof(token) - 1]) 580 bf = boolValue(&cp[sizeof(token) - 1])
581 581
582/* 582/*
583 * Initialization we need after reading makefiles. 583 * Initialization we need after reading makefiles.
584 */ 584 */
585void 585void
586meta_mode_init(const char *make_mode) 586meta_mode_init(const char *make_mode)
587{ 587{
588 static int once = 0; 588 static int once = 0;
589 char *cp; 589 char *cp;
590 590
591 useMeta = TRUE; 591 useMeta = TRUE;
592 useFilemon = TRUE; 592 useFilemon = TRUE;
593 writeMeta = TRUE; 593 writeMeta = TRUE;
594 594
595 if (make_mode) { 595 if (make_mode) {
596 if (strstr(make_mode, "env")) 596 if (strstr(make_mode, "env"))
597 metaEnv = TRUE; 597 metaEnv = TRUE;
598 if (strstr(make_mode, "verb")) 598 if (strstr(make_mode, "verb"))
599 metaVerbose = TRUE; 599 metaVerbose = TRUE;
600 if (strstr(make_mode, "read")) 600 if (strstr(make_mode, "read"))
601 writeMeta = FALSE; 601 writeMeta = FALSE;
602 if (strstr(make_mode, "nofilemon")) 602 if (strstr(make_mode, "nofilemon"))
603 useFilemon = FALSE; 603 useFilemon = FALSE;
604 if (strstr(make_mode, "ignore-cmd")) 604 if (strstr(make_mode, "ignore-cmd"))
605 metaIgnoreCMDs = TRUE; 605 metaIgnoreCMDs = TRUE;
606 if (useFilemon) 606 if (useFilemon)
607 get_mode_bf(filemonMissing, "missing-filemon="); 607 get_mode_bf(filemonMissing, "missing-filemon=");
608 get_mode_bf(metaCurdirOk, "curdirok="); 608 get_mode_bf(metaCurdirOk, "curdirok=");
609 get_mode_bf(metaMissing, "missing-meta="); 609 get_mode_bf(metaMissing, "missing-meta=");
610 get_mode_bf(metaSilent, "silent="); 610 get_mode_bf(metaSilent, "silent=");
611 } 611 }
612 if (metaVerbose && !Var_Exists(MAKE_META_PREFIX, VAR_GLOBAL)) { 612 if (metaVerbose && !Var_Exists(MAKE_META_PREFIX, VAR_GLOBAL)) {
613 /* 613 /*
614 * The default value for MAKE_META_PREFIX 614 * The default value for MAKE_META_PREFIX
615 * prints the absolute path of the target. 615 * prints the absolute path of the target.
616 * This works be cause :H will generate '.' if there is no / 616 * This works be cause :H will generate '.' if there is no /
617 * and :tA will resolve that to cwd. 617 * and :tA will resolve that to cwd.
618 */ 618 */
619 Var_Set(MAKE_META_PREFIX, "Building ${.TARGET:H:tA}/${.TARGET:T}", VAR_GLOBAL); 619 Var_Set(MAKE_META_PREFIX, "Building ${.TARGET:H:tA}/${.TARGET:T}", VAR_GLOBAL);
620 } 620 }
621 if (once) 621 if (once)
622 return; 622 return;
623 once = 1; 623 once = 1;
624 memset(&Mybm, 0, sizeof(Mybm)); 624 memset(&Mybm, 0, sizeof(Mybm));
625 /* 625 /*
626 * We consider ourselves master of all within ${.MAKE.META.BAILIWICK} 626 * We consider ourselves master of all within ${.MAKE.META.BAILIWICK}
627 */ 627 */
628 metaBailiwick = Lst_Init(); 628 metaBailiwick = Lst_Init();
629 metaBailiwickStr = Var_Subst("${.MAKE.META.BAILIWICK:O:u:tA}", 629 metaBailiwickStr = Var_Subst("${.MAKE.META.BAILIWICK:O:u:tA}",
630 VAR_GLOBAL, VARE_WANTRES); 630 VAR_GLOBAL, VARE_WANTRES);
631 if (metaBailiwickStr) { 631 if (metaBailiwickStr) {
632 str2Lst_Append(metaBailiwick, metaBailiwickStr, NULL); 632 str2Lst_Append(metaBailiwick, metaBailiwickStr, NULL);
633 } 633 }
634 /* 634 /*
635 * We ignore any paths that start with ${.MAKE.META.IGNORE_PATHS} 635 * We ignore any paths that start with ${.MAKE.META.IGNORE_PATHS}
636 */ 636 */
637 metaIgnorePaths = Lst_Init(); 637 metaIgnorePaths = Lst_Init();
638 Var_Append(MAKE_META_IGNORE_PATHS, 638 Var_Append(MAKE_META_IGNORE_PATHS,
639 "/dev /etc /proc /tmp /var/run /var/tmp ${TMPDIR}", VAR_GLOBAL); 639 "/dev /etc /proc /tmp /var/run /var/tmp ${TMPDIR}", VAR_GLOBAL);
640 metaIgnorePathsStr = Var_Subst("${" MAKE_META_IGNORE_PATHS ":O:u:tA}", 640 metaIgnorePathsStr = Var_Subst("${" MAKE_META_IGNORE_PATHS ":O:u:tA}",
641 VAR_GLOBAL, VARE_WANTRES); 641 VAR_GLOBAL, VARE_WANTRES);
642 if (metaIgnorePathsStr) { 642 if (metaIgnorePathsStr) {
643 str2Lst_Append(metaIgnorePaths, metaIgnorePathsStr, NULL); 643 str2Lst_Append(metaIgnorePaths, metaIgnorePathsStr, NULL);
644 } 644 }
645 645
646 /* 646 /*
647 * We ignore any paths that match ${.MAKE.META.IGNORE_PATTERNS} 647 * We ignore any paths that match ${.MAKE.META.IGNORE_PATTERNS}
648 */ 648 */
649 cp = NULL; 649 cp = NULL;
650 if (Var_Value(MAKE_META_IGNORE_PATTERNS, VAR_GLOBAL, &cp)) { 650 if (Var_Value(MAKE_META_IGNORE_PATTERNS, VAR_GLOBAL, &cp)) {
651 metaIgnorePatterns = TRUE; 651 metaIgnorePatterns = TRUE;
652 bmake_free(cp); 652 bmake_free(cp);
653 } 653 }
654 cp = NULL; 654 cp = NULL;
655 if (Var_Value(MAKE_META_IGNORE_FILTER, VAR_GLOBAL, &cp)) { 655 if (Var_Value(MAKE_META_IGNORE_FILTER, VAR_GLOBAL, &cp)) {
656 metaIgnoreFilter = TRUE; 656 metaIgnoreFilter = TRUE;
657 bmake_free(cp); 657 bmake_free(cp);
658 } 658 }
659} 659}
660 660
661/* 661/*
662 * In each case below we allow for job==NULL 662 * In each case below we allow for job==NULL
663 */ 663 */
664void 664void
665meta_job_start(Job *job, GNode *gn) 665meta_job_start(Job *job, GNode *gn)
666{ 666{
667 BuildMon *pbm; 667 BuildMon *pbm;
668 668
669 if (job != NULL) { 669 if (job != NULL) {
670 pbm = &job->bm; 670 pbm = &job->bm;
671 } else { 671 } else {
672 pbm = &Mybm; 672 pbm = &Mybm;
673 } 673 }
674 pbm->mfp = meta_create(pbm, gn); 674 pbm->mfp = meta_create(pbm, gn);
675#ifdef USE_FILEMON_ONCE 675#ifdef USE_FILEMON_ONCE
676 /* compat mode we open the filemon dev once per command */ 676 /* compat mode we open the filemon dev once per command */
677 if (job == NULL) 677 if (job == NULL)
678 return; 678 return;
679#endif 679#endif
680#ifdef USE_FILEMON 680#ifdef USE_FILEMON
681 if (pbm->mfp != NULL && useFilemon) { 681 if (pbm->mfp != NULL && useFilemon) {
682 meta_open_filemon(pbm); 682 meta_open_filemon(pbm);
683 } else { 683 } else {
684 pbm->mon_fd = -1; 684 pbm->mon_fd = -1;
685 pbm->filemon = NULL; 685 pbm->filemon = NULL;
686 } 686 }
687#endif 687#endif
688} 688}
689 689
690/* 690/*
691 * The child calls this before doing anything. 691 * The child calls this before doing anything.
692 * It does not disturb our state. 692 * It does not disturb our state.
693 */ 693 */
694void 694void
695meta_job_child(Job *job) 695meta_job_child(Job *job)
696{ 696{
697#ifdef USE_FILEMON 697#ifdef USE_FILEMON
698 BuildMon *pbm; 698 BuildMon *pbm;
699 699
700 if (job != NULL) { 700 if (job != NULL) {
701 pbm = &job->bm; 701 pbm = &job->bm;
702 } else { 702 } else {
703 pbm = &Mybm; 703 pbm = &Mybm;
704 } 704 }
705 if (pbm->mfp != NULL) { 705 if (pbm->mfp != NULL) {
706 close(fileno(pbm->mfp)); 706 close(fileno(pbm->mfp));
707 if (useFilemon && pbm->filemon) { 707 if (useFilemon && pbm->filemon) {
708 pid_t pid; 708 pid_t pid;
709 709
710 pid = getpid(); 710 pid = getpid();
711 if (filemon_setpid_child(pbm->filemon, pid) == -1) { 711 if (filemon_setpid_child(pbm->filemon, pid) == -1) {
712 err(1, "Could not set filemon pid!"); 712 err(1, "Could not set filemon pid!");
713 } 713 }
714 } 714 }
715 } 715 }
716#endif 716#endif
717} 717}
718 718
719void 719void
720meta_job_parent(Job *job, pid_t pid) 720meta_job_parent(Job *job, pid_t pid)
721{ 721{
722#if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) 722#if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
723 BuildMon *pbm; 723 BuildMon *pbm;
724 724
725 if (job != NULL) { 725 if (job != NULL) {
726 pbm = &job->bm; 726 pbm = &job->bm;
727 } else { 727 } else {
728 pbm = &Mybm; 728 pbm = &Mybm;
729 } 729 }
730 if (useFilemon && pbm->filemon) { 730 if (useFilemon && pbm->filemon) {
731 filemon_setpid_parent(pbm->filemon, pid); 731 filemon_setpid_parent(pbm->filemon, pid);
732 } 732 }
733#endif 733#endif
734} 734}
735 735
736int 736int
737meta_job_fd(Job *job) 737meta_job_fd(Job *job)
738{ 738{
739#if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) 739#if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
740 BuildMon *pbm; 740 BuildMon *pbm;
741 741
742 if (job != NULL) { 742 if (job != NULL) {
743 pbm = &job->bm; 743 pbm = &job->bm;
744 } else { 744 } else {
745 pbm = &Mybm; 745 pbm = &Mybm;
746 } 746 }
747 if (useFilemon && pbm->filemon) { 747 if (useFilemon && pbm->filemon) {
748 return filemon_readfd(pbm->filemon); 748 return filemon_readfd(pbm->filemon);
749 } 749 }
750#endif 750#endif
751 return -1; 751 return -1;
752} 752}
753 753
754int 754int
755meta_job_event(Job *job) 755meta_job_event(Job *job)
756{ 756{
757#if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) 757#if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
758 BuildMon *pbm; 758 BuildMon *pbm;
759 759
760 if (job != NULL) { 760 if (job != NULL) {
761 pbm = &job->bm; 761 pbm = &job->bm;
762 } else { 762 } else {
763 pbm = &Mybm; 763 pbm = &Mybm;
764 } 764 }
765 if (useFilemon && pbm->filemon) { 765 if (useFilemon && pbm->filemon) {
766 return filemon_process(pbm->filemon); 766 return filemon_process(pbm->filemon);
767 } 767 }
768#endif 768#endif
769 return 0; 769 return 0;
770} 770}
771 771
772void 772void
773meta_job_error(Job *job, GNode *gn, int flags, int status) 773meta_job_error(Job *job, GNode *gn, int flags, int status)
774{ 774{
775 char cwd[MAXPATHLEN]; 775 char cwd[MAXPATHLEN];
776 BuildMon *pbm; 776 BuildMon *pbm;
777 777
778 if (job != NULL) { 778 if (job != NULL) {
779 pbm = &job->bm; 779 pbm = &job->bm;
780 if (!gn) 780 if (!gn)
781 gn = job->node; 781 gn = job->node;
782 } else { 782 } else {
783 pbm = &Mybm; 783 pbm = &Mybm;
784 } 784 }
785 if (pbm->mfp != NULL) { 785 if (pbm->mfp != NULL) {
786 fprintf(pbm->mfp, "\n*** Error code %d%s\n", 786 fprintf(pbm->mfp, "\n*** Error code %d%s\n",
787 status, 787 status,
788 (flags & JOB_IGNERR) ? 788 (flags & JOB_IGNERR) ?
789 "(ignored)" : ""); 789 "(ignored)" : "");
790 } 790 }
791 if (gn) { 791 if (gn) {
792 Var_Set(".ERROR_TARGET", gn->path ? gn->path : gn->name, VAR_GLOBAL); 792 Var_Set(".ERROR_TARGET", gn->path ? gn->path : gn->name, VAR_GLOBAL);
793 } 793 }
794 getcwd(cwd, sizeof(cwd)); 794 getcwd(cwd, sizeof(cwd));
795 Var_Set(".ERROR_CWD", cwd, VAR_GLOBAL); 795 Var_Set(".ERROR_CWD", cwd, VAR_GLOBAL);
796 if (pbm->meta_fname[0]) { 796 if (pbm->meta_fname[0]) {
797 Var_Set(".ERROR_META_FILE", pbm->meta_fname, VAR_GLOBAL); 797 Var_Set(".ERROR_META_FILE", pbm->meta_fname, VAR_GLOBAL);
798 } 798 }
799 meta_job_finish(job); 799 meta_job_finish(job);
800} 800}
801 801
802void 802void
803meta_job_output(Job *job, char *cp, const char *nl) 803meta_job_output(Job *job, char *cp, const char *nl)
804{ 804{
805 BuildMon *pbm; 805 BuildMon *pbm;
806 806
807 if (job != NULL) { 807 if (job != NULL) {
808 pbm = &job->bm; 808 pbm = &job->bm;
809 } else { 809 } else {
810 pbm = &Mybm; 810 pbm = &Mybm;
811 } 811 }
812 if (pbm->mfp != NULL) { 812 if (pbm->mfp != NULL) {
813 if (metaVerbose) { 813 if (metaVerbose) {
814 static char *meta_prefix = NULL; 814 static char *meta_prefix = NULL;
815 static int meta_prefix_len; 815 static int meta_prefix_len;
816 816
817 if (!meta_prefix) { 817 if (!meta_prefix) {
818 char *cp2; 818 char *cp2;
819 819
820 meta_prefix = Var_Subst("${" MAKE_META_PREFIX "}", 820 meta_prefix = Var_Subst("${" MAKE_META_PREFIX "}",
821 VAR_GLOBAL, VARE_WANTRES); 821 VAR_GLOBAL, VARE_WANTRES);
822 if ((cp2 = strchr(meta_prefix, '$'))) 822 if ((cp2 = strchr(meta_prefix, '$')))
823 meta_prefix_len = cp2 - meta_prefix; 823 meta_prefix_len = cp2 - meta_prefix;
824 else 824 else
825 meta_prefix_len = strlen(meta_prefix); 825 meta_prefix_len = strlen(meta_prefix);
826 } 826 }
827 if (strncmp(cp, meta_prefix, meta_prefix_len) == 0) { 827 if (strncmp(cp, meta_prefix, meta_prefix_len) == 0) {
828 cp = strchr(cp+1, '\n'); 828 cp = strchr(cp+1, '\n');
829 if (!cp++) 829 if (!cp++)
830 return; 830 return;
831 } 831 }
832 } 832 }
833 fprintf(pbm->mfp, "%s%s", cp, nl); 833 fprintf(pbm->mfp, "%s%s", cp, nl);
834 } 834 }
835} 835}
836 836
837int 837int
838meta_cmd_finish(void *pbmp) 838meta_cmd_finish(void *pbmp)
839{ 839{
840 int error = 0; 840 int error = 0;
841 BuildMon *pbm = pbmp; 841 BuildMon *pbm = pbmp;
842#ifdef USE_FILEMON 842#ifdef USE_FILEMON
843 int x; 843 int x;
844#endif 844#endif
845 845
846 if (!pbm) 846 if (!pbm)
847 pbm = &Mybm; 847 pbm = &Mybm;
848 848
849#ifdef USE_FILEMON 849#ifdef USE_FILEMON
850 if (pbm->filemon) { 850 if (pbm->filemon) {
851 while (filemon_process(pbm->filemon) > 0) 851 while (filemon_process(pbm->filemon) > 0)
852 continue; 852 continue;
853 if (filemon_close(pbm->filemon) == -1) 853 if (filemon_close(pbm->filemon) == -1)
854 error = errno; 854 error = errno;
855 x = filemon_read(pbm->mfp, pbm->mon_fd); 855 x = filemon_read(pbm->mfp, pbm->mon_fd);
856 if (error == 0 && x != 0) 856 if (error == 0 && x != 0)
857 error = x; 857 error = x;
858 pbm->mon_fd = -1; 858 pbm->mon_fd = -1;
859 pbm->filemon = NULL; 859 pbm->filemon = NULL;
860 } else 860 } else
861#endif 861#endif
862 fprintf(pbm->mfp, "\n"); /* ensure end with newline */ 862 fprintf(pbm->mfp, "\n"); /* ensure end with newline */
863 return error; 863 return error;
864} 864}
865 865
866int 866int
867meta_job_finish(Job *job) 867meta_job_finish(Job *job)
868{ 868{
869 BuildMon *pbm; 869 BuildMon *pbm;
870 int error = 0; 870 int error = 0;
871 int x; 871 int x;
872 872
873 if (job != NULL) { 873 if (job != NULL) {
874 pbm = &job->bm; 874 pbm = &job->bm;
875 } else { 875 } else {
876 pbm = &Mybm; 876 pbm = &Mybm;
877 } 877 }
878 if (pbm->mfp != NULL) { 878 if (pbm->mfp != NULL) {
879 error = meta_cmd_finish(pbm); 879 error = meta_cmd_finish(pbm);
880 x = fclose(pbm->mfp); 880 x = fclose(pbm->mfp);
881 if (error == 0 && x != 0) 881 if (error == 0 && x != 0)
882 error = errno; 882 error = errno;
883 pbm->mfp = NULL; 883 pbm->mfp = NULL;
884 pbm->meta_fname[0] = '\0'; 884 pbm->meta_fname[0] = '\0';
885 } 885 }
886 return error; 886 return error;
887} 887}
888 888
889void 889void
890meta_finish(void) 890meta_finish(void)
891{ 891{
892 if (metaBailiwick != NULL) 892 if (metaBailiwick != NULL)
893 Lst_Free(metaBailiwick); 893 Lst_Free(metaBailiwick);
894 free(metaBailiwickStr); 894 free(metaBailiwickStr);
895 if (metaIgnorePaths != NULL) 895 if (metaIgnorePaths != NULL)
896 Lst_Free(metaIgnorePaths); 896 Lst_Free(metaIgnorePaths);
897 free(metaIgnorePathsStr); 897 free(metaIgnorePathsStr);
898} 898}
899 899
900/* 900/*
901 * Fetch a full line from fp - growing bufp if needed 901 * Fetch a full line from fp - growing bufp if needed
902 * Return length in bufp. 902 * Return length in bufp.
903 */ 903 */
904static int 904static int
905fgetLine(char **bufp, size_t *szp, int o, FILE *fp) 905fgetLine(char **bufp, size_t *szp, int o, FILE *fp)
906{ 906{
907 char *buf = *bufp; 907 char *buf = *bufp;
908 size_t bufsz = *szp; 908 size_t bufsz = *szp;
909 struct stat fs; 909 struct stat fs;
910 int x; 910 int x;
911 911
912 if (fgets(&buf[o], bufsz - o, fp) != NULL) { 912 if (fgets(&buf[o], bufsz - o, fp) != NULL) {
913 check_newline: 913 check_newline:
914 x = o + strlen(&buf[o]); 914 x = o + strlen(&buf[o]);
915 if (buf[x - 1] == '\n') 915 if (buf[x - 1] == '\n')
916 return x; 916 return x;
917 /* 917 /*
918 * We need to grow the buffer. 918 * We need to grow the buffer.
919 * The meta file can give us a clue. 919 * The meta file can give us a clue.
920 */ 920 */
921 if (fstat(fileno(fp), &fs) == 0) { 921 if (fstat(fileno(fp), &fs) == 0) {
922 size_t newsz; 922 size_t newsz;
923 char *p; 923 char *p;
924 924
925 newsz = ROUNDUP((fs.st_size / 2), BUFSIZ); 925 newsz = ROUNDUP((fs.st_size / 2), BUFSIZ);
926 if (newsz <= bufsz) 926 if (newsz <= bufsz)
927 newsz = ROUNDUP(fs.st_size, BUFSIZ); 927 newsz = ROUNDUP(fs.st_size, BUFSIZ);
928 if (newsz <= bufsz) 928 if (newsz <= bufsz)
929 return x; /* truncated */ 929 return x; /* truncated */
930 if (DEBUG(META)) 930 if (DEBUG(META))
931 fprintf(debug_file, "growing buffer %zu -> %zu\n", 931 fprintf(debug_file, "growing buffer %zu -> %zu\n",
932 bufsz, newsz); 932 bufsz, newsz);
933 p = bmake_realloc(buf, newsz); 933 p = bmake_realloc(buf, newsz);
934 if (p) { 934 if (p) {
935 *bufp = buf = p; 935 *bufp = buf = p;
936 *szp = bufsz = newsz; 936 *szp = bufsz = newsz;
937 /* fetch the rest */ 937 /* fetch the rest */
938 if (!fgets(&buf[x], bufsz - x, fp)) 938 if (!fgets(&buf[x], bufsz - x, fp))
939 return x; /* truncated! */ 939 return x; /* truncated! */
940 goto check_newline; 940 goto check_newline;
941 } 941 }
942 } 942 }
943 } 943 }
944 return 0; 944 return 0;
945} 945}
946 946
947/* Lst_ForEach wants 1 to stop search */ 947/* Lst_ForEach wants 1 to stop search */
948static int 948static int
949prefix_match(void *p, void *q) 949prefix_match(void *p, void *q)
950{ 950{
951 const char *prefix = p; 951 const char *prefix = p;
952 const char *path = q; 952 const char *path = q;
953 size_t n = strlen(prefix); 953 size_t n = strlen(prefix);
954 954
955 return strncmp(path, prefix, n) == 0; 955 return strncmp(path, prefix, n) == 0;
956} 956}
957 957
958/* See if the path equals prefix or starts with "prefix/". */ 958/* See if the path equals prefix or starts with "prefix/". */
959static Boolean 959static Boolean
960path_match(const void *p, const void *q) 960path_match(const void *p, const void *q)
961{ 961{
962 const char *path = p; 962 const char *path = p;
963 const char *prefix = q; 963 const char *prefix = q;
964 size_t n = strlen(prefix); 964 size_t n = strlen(prefix);
965 965
966 if (strncmp(path, prefix, n) != 0) 966 if (strncmp(path, prefix, n) != 0)
967 return FALSE; 967 return FALSE;
968 return path[n] == '\0' || path[n] == '/'; 968 return path[n] == '\0' || path[n] == '/';
969} 969}
970 970
971static Boolean 971static Boolean
972string_match(const void *p, const void *q) 972string_match(const void *p, const void *q)
973{ 973{
974 return strcmp(p, q) == 0; 974 return strcmp(p, q) == 0;
975} 975}
976 976
977 977
978static int 978static int
979meta_ignore(GNode *gn, const char *p) 979meta_ignore(GNode *gn, const char *p)
980{ 980{
981 char fname[MAXPATHLEN]; 981 char fname[MAXPATHLEN];
982 982
983 if (p == NULL) 983 if (p == NULL)
984 return TRUE; 984 return TRUE;
985 985
986 if (*p == '/') { 986 if (*p == '/') {
987 cached_realpath(p, fname); /* clean it up */ 987 cached_realpath(p, fname); /* clean it up */
988 if (Lst_ForEach(metaIgnorePaths, prefix_match, fname)) { 988 if (Lst_ForEach(metaIgnorePaths, prefix_match, fname)) {
989#ifdef DEBUG_META_MODE 989#ifdef DEBUG_META_MODE
990 if (DEBUG(META)) 990 if (DEBUG(META))
991 fprintf(debug_file, "meta_oodate: ignoring path: %s\n", 991 fprintf(debug_file, "meta_oodate: ignoring path: %s\n",
992 p); 992 p);
993#endif 993#endif
994 return TRUE; 994 return TRUE;
995 } 995 }
996 } 996 }
997 997
998 if (metaIgnorePatterns) { 998 if (metaIgnorePatterns) {
999 const char *expr; 999 const char *expr;
1000 char *pm; 1000 char *pm;
1001 1001
1002 Var_Set(".p.", p, gn); 1002 Var_Set(".p.", p, gn);
1003 expr = "${" MAKE_META_IGNORE_PATTERNS ":@m@${.p.:M$m}@}"; 1003 expr = "${" MAKE_META_IGNORE_PATTERNS ":@m@${.p.:M$m}@}";
1004 pm = Var_Subst(expr, gn, VARE_WANTRES); 1004 pm = Var_Subst(expr, gn, VARE_WANTRES);
1005 if (*pm) { 1005 if (*pm) {
1006#ifdef DEBUG_META_MODE 1006#ifdef DEBUG_META_MODE
1007 if (DEBUG(META)) 1007 if (DEBUG(META))
1008 fprintf(debug_file, "meta_oodate: ignoring pattern: %s\n", 1008 fprintf(debug_file, "meta_oodate: ignoring pattern: %s\n",
1009 p); 1009 p);
1010#endif 1010#endif
1011 free(pm); 1011 free(pm);
1012 return TRUE; 1012 return TRUE;
1013 } 1013 }
1014 free(pm); 1014 free(pm);
1015 } 1015 }
1016 1016
1017 if (metaIgnoreFilter) { 1017 if (metaIgnoreFilter) {
1018 char *fm; 1018 char *fm;
1019 1019
1020 /* skip if filter result is empty */ 1020 /* skip if filter result is empty */
1021 snprintf(fname, sizeof(fname), 1021 snprintf(fname, sizeof(fname),
1022 "${%s:L:${%s:ts:}}", 1022 "${%s:L:${%s:ts:}}",
1023 p, MAKE_META_IGNORE_FILTER); 1023 p, MAKE_META_IGNORE_FILTER);
1024 fm = Var_Subst(fname, gn, VARE_WANTRES); 1024 fm = Var_Subst(fname, gn, VARE_WANTRES);
1025 if (*fm == '\0') { 1025 if (*fm == '\0') {
1026#ifdef DEBUG_META_MODE 1026#ifdef DEBUG_META_MODE
1027 if (DEBUG(META)) 1027 if (DEBUG(META))
1028 fprintf(debug_file, "meta_oodate: ignoring filtered: %s\n", 1028 fprintf(debug_file, "meta_oodate: ignoring filtered: %s\n",
1029 p); 1029 p);
1030#endif 1030#endif
1031 free(fm); 1031 free(fm);
1032 return TRUE; 1032 return TRUE;
1033 } 1033 }
1034 free(fm); 1034 free(fm);
1035 } 1035 }
1036 return FALSE; 1036 return FALSE;
1037} 1037}
1038 1038
1039/* 1039/*
1040 * When running with 'meta' functionality, a target can be out-of-date 1040 * When running with 'meta' functionality, a target can be out-of-date
1041 * if any of the references in its meta data file is more recent. 1041 * if any of the references in its meta data file is more recent.
1042 * We have to track the latestdir on a per-process basis. 1042 * We have to track the latestdir on a per-process basis.
1043 */ 1043 */
1044#define LCWD_VNAME_FMT ".meta.%d.lcwd" 1044#define LCWD_VNAME_FMT ".meta.%d.lcwd"
1045#define LDIR_VNAME_FMT ".meta.%d.ldir" 1045#define LDIR_VNAME_FMT ".meta.%d.ldir"
1046 1046
1047/* 1047/*
1048 * It is possible that a .meta file is corrupted, 1048 * It is possible that a .meta file is corrupted,
1049 * if we detect this we want to reproduce it. 1049 * if we detect this we want to reproduce it.
1050 * Setting oodate TRUE will have that effect. 1050 * Setting oodate TRUE will have that effect.
1051 */ 1051 */
1052#define CHECK_VALID_META(p) if (!(p && *p)) { \ 1052#define CHECK_VALID_META(p) if (!(p && *p)) { \
1053 warnx("%s: %d: malformed", fname, lineno); \ 1053 warnx("%s: %d: malformed", fname, lineno); \
1054 oodate = TRUE; \ 1054 oodate = TRUE; \
1055 continue; \ 1055 continue; \
1056 } 1056 }
1057 1057
1058#define DEQUOTE(p) if (*p == '\'') { \ 1058#define DEQUOTE(p) if (*p == '\'') { \
1059 char *ep; \ 1059 char *ep; \
1060 p++; \ 1060 p++; \
1061 if ((ep = strchr(p, '\''))) \ 1061 if ((ep = strchr(p, '\''))) \
1062 *ep = '\0'; \ 1062 *ep = '\0'; \
1063 } 1063 }
1064 1064
1065Boolean 1065Boolean
1066meta_oodate(GNode *gn, Boolean oodate) 1066meta_oodate(GNode *gn, Boolean oodate)
1067{ 1067{
1068 static char *tmpdir = NULL; 1068 static char *tmpdir = NULL;
1069 static char cwd[MAXPATHLEN]; 1069 static char cwd[MAXPATHLEN];
1070 char lcwd_vname[64]; 1070 char lcwd_vname[64];
1071 char ldir_vname[64]; 1071 char ldir_vname[64];
1072 char lcwd[MAXPATHLEN]; 1072 char lcwd[MAXPATHLEN];
1073 char latestdir[MAXPATHLEN]; 1073 char latestdir[MAXPATHLEN];
1074 char fname[MAXPATHLEN]; 1074 char fname[MAXPATHLEN];
1075 char fname1[MAXPATHLEN]; 1075 char fname1[MAXPATHLEN];
1076 char fname2[MAXPATHLEN]; 1076 char fname2[MAXPATHLEN];
1077 char fname3[MAXPATHLEN]; 1077 char fname3[MAXPATHLEN];
1078 const char *dname; 1078 const char *dname;
1079 const char *tname; 1079 const char *tname;
1080 char *p; 1080 char *p;
1081 char *cp; 1081 char *cp;
1082 char *link_src; 1082 char *link_src;
1083 char *move_target; 1083 char *move_target;
1084 static size_t cwdlen = 0; 1084 static size_t cwdlen = 0;
1085 static size_t tmplen = 0; 1085 static size_t tmplen = 0;
1086 FILE *fp; 1086 FILE *fp;
1087 Boolean needOODATE = FALSE; 1087 Boolean needOODATE = FALSE;
1088 Lst missingFiles; 1088 Lst missingFiles;
1089 char *pa[4]; /* >= possible uses */ 1089 char *pa[4]; /* >= possible uses */
1090 int i; 1090 int i;
1091 int have_filemon = FALSE; 1091 int have_filemon = FALSE;
1092 1092
1093 if (oodate) 1093 if (oodate)
1094 return oodate; /* we're done */ 1094 return oodate; /* we're done */
1095 1095
1096 i = 0; 1096 i = 0;
1097 1097
1098 dname = Var_Value(".OBJDIR", gn, &pa[i++]); 1098 dname = Var_Value(".OBJDIR", gn, &pa[i++]);
1099 tname = Var_Value(TARGET, gn, &pa[i++]); 1099 tname = Var_Value(TARGET, gn, &pa[i++]);
1100 1100
1101 /* if this succeeds fname3 is realpath of dname */ 1101 /* if this succeeds fname3 is realpath of dname */
1102 if (!meta_needed(gn, dname, tname, fname3, FALSE)) 1102 if (!meta_needed(gn, dname, tname, fname3, FALSE))
1103 goto oodate_out; 1103 goto oodate_out;
1104 dname = fname3; 1104 dname = fname3;
1105 1105
1106 missingFiles = Lst_Init(); 1106 missingFiles = Lst_Init();
1107 1107
1108 /* 1108 /*
1109 * We need to check if the target is out-of-date. This includes 1109 * We need to check if the target is out-of-date. This includes
1110 * checking if the expanded command has changed. This in turn 1110 * checking if the expanded command has changed. This in turn
1111 * requires that all variables are set in the same way that they 1111 * requires that all variables are set in the same way that they
1112 * would be if the target needs to be re-built. 1112 * would be if the target needs to be re-built.
1113 */ 1113 */
1114 Make_DoAllVar(gn); 1114 Make_DoAllVar(gn);
1115 1115
1116 meta_name(gn, fname, sizeof(fname), dname, tname, dname); 1116 meta_name(gn, fname, sizeof(fname), dname, tname, dname);
1117 1117
1118#ifdef DEBUG_META_MODE 1118#ifdef DEBUG_META_MODE
1119 if (DEBUG(META)) 1119 if (DEBUG(META))
1120 fprintf(debug_file, "meta_oodate: %s\n", fname); 1120 fprintf(debug_file, "meta_oodate: %s\n", fname);
1121#endif 1121#endif
1122 1122
1123 if ((fp = fopen(fname, "r")) != NULL) { 1123 if ((fp = fopen(fname, "r")) != NULL) {
1124 static char *buf = NULL; 1124 static char *buf = NULL;
1125 static size_t bufsz; 1125 static size_t bufsz;
1126 int lineno = 0; 1126 int lineno = 0;
1127 int lastpid = 0; 1127 int lastpid = 0;
1128 int pid; 1128 int pid;
1129 int x; 1129 int x;
1130 LstNode ln; 1130 LstNode ln;
1131 struct stat fs; 1131 struct stat fs;
1132 1132
1133 if (!buf) { 1133 if (!buf) {
1134 bufsz = 8 * BUFSIZ; 1134 bufsz = 8 * BUFSIZ;
1135 buf = bmake_malloc(bufsz); 1135 buf = bmake_malloc(bufsz);
1136 } 1136 }
1137 1137
1138 if (!cwdlen) { 1138 if (!cwdlen) {
1139 if (getcwd(cwd, sizeof(cwd)) == NULL) 1139 if (getcwd(cwd, sizeof(cwd)) == NULL)
1140 err(1, "Could not get current working directory"); 1140 err(1, "Could not get current working directory");
1141 cwdlen = strlen(cwd); 1141 cwdlen = strlen(cwd);
1142 } 1142 }
1143 strlcpy(lcwd, cwd, sizeof(lcwd)); 1143 strlcpy(lcwd, cwd, sizeof(lcwd));
1144 strlcpy(latestdir, cwd, sizeof(latestdir)); 1144 strlcpy(latestdir, cwd, sizeof(latestdir));
1145 1145
1146 if (!tmpdir) { 1146 if (!tmpdir) {
1147 tmpdir = getTmpdir(); 1147 tmpdir = getTmpdir();
1148 tmplen = strlen(tmpdir); 1148 tmplen = strlen(tmpdir);
1149 } 1149 }
1150 1150
1151 /* we want to track all the .meta we read */ 1151 /* we want to track all the .meta we read */
1152 Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL); 1152 Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
1153 1153
1154 ln = Lst_First(gn->commands); 1154 ln = Lst_First(gn->commands);
1155 while (!oodate && (x = fgetLine(&buf, &bufsz, 0, fp)) > 0) { 1155 while (!oodate && (x = fgetLine(&buf, &bufsz, 0, fp)) > 0) {
1156 lineno++; 1156 lineno++;
1157 if (buf[x - 1] == '\n') 1157 if (buf[x - 1] == '\n')
1158 buf[x - 1] = '\0'; 1158 buf[x - 1] = '\0';
1159 else { 1159 else {
1160 warnx("%s: %d: line truncated at %u", fname, lineno, x); 1160 warnx("%s: %d: line truncated at %u", fname, lineno, x);
1161 oodate = TRUE; 1161 oodate = TRUE;
1162 break; 1162 break;
1163 } 1163 }
1164 link_src = NULL; 1164 link_src = NULL;
1165 move_target = NULL; 1165 move_target = NULL;
1166 /* Find the start of the build monitor section. */ 1166 /* Find the start of the build monitor section. */
1167 if (!have_filemon) { 1167 if (!have_filemon) {
1168 if (strncmp(buf, "-- filemon", 10) == 0) { 1168 if (strncmp(buf, "-- filemon", 10) == 0) {
1169 have_filemon = TRUE; 1169 have_filemon = TRUE;
1170 continue; 1170 continue;
1171 } 1171 }
1172 if (strncmp(buf, "# buildmon", 10) == 0) { 1172 if (strncmp(buf, "# buildmon", 10) == 0) {
1173 have_filemon = TRUE; 1173 have_filemon = TRUE;
1174 continue; 1174 continue;
1175 } 1175 }
1176 } 1176 }
1177 1177
1178 /* Delimit the record type. */ 1178 /* Delimit the record type. */
1179 p = buf; 1179 p = buf;
1180#ifdef DEBUG_META_MODE 1180#ifdef DEBUG_META_MODE
1181 if (DEBUG(META)) 1181 if (DEBUG(META))
1182 fprintf(debug_file, "%s: %d: %s\n", fname, lineno, buf); 1182 fprintf(debug_file, "%s: %d: %s\n", fname, lineno, buf);
1183#endif 1183#endif
1184 strsep(&p, " "); 1184 strsep(&p, " ");
1185 if (have_filemon) { 1185 if (have_filemon) {
1186 /* 1186 /*
1187 * We are in the 'filemon' output section. 1187 * We are in the 'filemon' output section.
1188 * Each record from filemon follows the general form: 1188 * Each record from filemon follows the general form:
1189 * 1189 *
1190 * <key> <pid> <data> 1190 * <key> <pid> <data>
1191 * 1191 *
1192 * Where: 1192 * Where:
1193 * <key> is a single letter, denoting the syscall. 1193 * <key> is a single letter, denoting the syscall.
1194 * <pid> is the process that made the syscall. 1194 * <pid> is the process that made the syscall.
1195 * <data> is the arguments (of interest). 1195 * <data> is the arguments (of interest).
1196 */ 1196 */
1197 switch(buf[0]) { 1197 switch(buf[0]) {
1198 case '#': /* comment */ 1198 case '#': /* comment */
1199 case 'V': /* version */ 1199 case 'V': /* version */
1200 break; 1200 break;
1201 default: 1201 default:
1202 /* 1202 /*
1203 * We need to track pathnames per-process. 1203 * We need to track pathnames per-process.
1204 * 1204 *
1205 * Each process run by make, starts off in the 'CWD' 1205 * Each process run by make, starts off in the 'CWD'
1206 * recorded in the .meta file, if it chdirs ('C') 1206 * recorded in the .meta file, if it chdirs ('C')
1207 * elsewhere we need to track that - but only for 1207 * elsewhere we need to track that - but only for
1208 * that process. If it forks ('F'), we initialize 1208 * that process. If it forks ('F'), we initialize
1209 * the child to have the same cwd as its parent. 1209 * the child to have the same cwd as its parent.
1210 * 1210 *
1211 * We also need to track the 'latestdir' of 1211 * We also need to track the 'latestdir' of
1212 * interest. This is usually the same as cwd, but 1212 * interest. This is usually the same as cwd, but
1213 * not if a process is reading directories. 1213 * not if a process is reading directories.
1214 * 1214 *
1215 * Each time we spot a different process ('pid') 1215 * Each time we spot a different process ('pid')
1216 * we save the current value of 'latestdir' in a 1216 * we save the current value of 'latestdir' in a
1217 * variable qualified by 'lastpid', and 1217 * variable qualified by 'lastpid', and
1218 * re-initialize 'latestdir' to any pre-saved 1218 * re-initialize 'latestdir' to any pre-saved
1219 * value for the current 'pid' and 'CWD' if none. 1219 * value for the current 'pid' and 'CWD' if none.
1220 */ 1220 */
1221 CHECK_VALID_META(p); 1221 CHECK_VALID_META(p);
1222 pid = atoi(p); 1222 pid = atoi(p);
1223 if (pid > 0 && pid != lastpid) { 1223 if (pid > 0 && pid != lastpid) {
1224 const char *ldir; 1224 const char *ldir;
1225 char *tp; 1225 char *tp;
1226 1226
1227 if (lastpid > 0) { 1227 if (lastpid > 0) {
1228 /* We need to remember these. */ 1228 /* We need to remember these. */
1229 Var_Set(lcwd_vname, lcwd, VAR_GLOBAL); 1229 Var_Set(lcwd_vname, lcwd, VAR_GLOBAL);
1230 Var_Set(ldir_vname, latestdir, VAR_GLOBAL); 1230 Var_Set(ldir_vname, latestdir, VAR_GLOBAL);
1231 } 1231 }
1232 snprintf(lcwd_vname, sizeof(lcwd_vname), LCWD_VNAME_FMT, pid); 1232 snprintf(lcwd_vname, sizeof(lcwd_vname), LCWD_VNAME_FMT, pid);
1233 snprintf(ldir_vname, sizeof(ldir_vname), LDIR_VNAME_FMT, pid); 1233 snprintf(ldir_vname, sizeof(ldir_vname), LDIR_VNAME_FMT, pid);
1234 lastpid = pid; 1234 lastpid = pid;
1235 ldir = Var_Value(ldir_vname, VAR_GLOBAL, &tp); 1235 ldir = Var_Value(ldir_vname, VAR_GLOBAL, &tp);
1236 if (ldir) { 1236 if (ldir) {
1237 strlcpy(latestdir, ldir, sizeof(latestdir)); 1237 strlcpy(latestdir, ldir, sizeof(latestdir));
1238 bmake_free(tp); 1238 bmake_free(tp);
1239 } 1239 }
1240 ldir = Var_Value(lcwd_vname, VAR_GLOBAL, &tp); 1240 ldir = Var_Value(lcwd_vname, VAR_GLOBAL, &tp);
1241 if (ldir) { 1241 if (ldir) {
1242 strlcpy(lcwd, ldir, sizeof(lcwd)); 1242 strlcpy(lcwd, ldir, sizeof(lcwd));
1243 bmake_free(tp); 1243 bmake_free(tp);
1244 } 1244 }
1245 } 1245 }
1246 /* Skip past the pid. */ 1246 /* Skip past the pid. */
1247 if (strsep(&p, " ") == NULL) 1247 if (strsep(&p, " ") == NULL)
1248 continue; 1248 continue;
1249#ifdef DEBUG_META_MODE 1249#ifdef DEBUG_META_MODE
1250 if (DEBUG(META)) 1250 if (DEBUG(META))
1251 fprintf(debug_file, "%s: %d: %d: %c: cwd=%s lcwd=%s ldir=%s\n", 1251 fprintf(debug_file, "%s: %d: %d: %c: cwd=%s lcwd=%s ldir=%s\n",
1252 fname, lineno, 1252 fname, lineno,
1253 pid, buf[0], cwd, lcwd, latestdir); 1253 pid, buf[0], cwd, lcwd, latestdir);
1254#endif 1254#endif
1255 break; 1255 break;
1256 } 1256 }
1257 1257
1258 CHECK_VALID_META(p); 1258 CHECK_VALID_META(p);
1259 1259
1260 /* Process according to record type. */ 1260 /* Process according to record type. */
1261 switch (buf[0]) { 1261 switch (buf[0]) {
1262 case 'X': /* eXit */ 1262 case 'X': /* eXit */
1263 Var_Delete(lcwd_vname, VAR_GLOBAL); 1263 Var_Delete(lcwd_vname, VAR_GLOBAL);
1264 Var_Delete(ldir_vname, VAR_GLOBAL); 1264 Var_Delete(ldir_vname, VAR_GLOBAL);
1265 lastpid = 0; /* no need to save ldir_vname */ 1265 lastpid = 0; /* no need to save ldir_vname */
1266 break; 1266 break;
1267 1267
1268 case 'F': /* [v]Fork */ 1268 case 'F': /* [v]Fork */
1269 { 1269 {
1270 char cldir[64]; 1270 char cldir[64];
1271 int child; 1271 int child;
1272 1272
1273 child = atoi(p); 1273 child = atoi(p);
1274 if (child > 0) { 1274 if (child > 0) {
1275 snprintf(cldir, sizeof(cldir), LCWD_VNAME_FMT, child); 1275 snprintf(cldir, sizeof(cldir), LCWD_VNAME_FMT, child);
1276 Var_Set(cldir, lcwd, VAR_GLOBAL); 1276 Var_Set(cldir, lcwd, VAR_GLOBAL);
1277 snprintf(cldir, sizeof(cldir), LDIR_VNAME_FMT, child); 1277 snprintf(cldir, sizeof(cldir), LDIR_VNAME_FMT, child);
1278 Var_Set(cldir, latestdir, VAR_GLOBAL); 1278 Var_Set(cldir, latestdir, VAR_GLOBAL);
1279#ifdef DEBUG_META_MODE 1279#ifdef DEBUG_META_MODE
1280 if (DEBUG(META)) 1280 if (DEBUG(META))
1281 fprintf(debug_file, "%s: %d: %d: cwd=%s lcwd=%s ldir=%s\n", 1281 fprintf(debug_file, "%s: %d: %d: cwd=%s lcwd=%s ldir=%s\n",
1282 fname, lineno, 1282 fname, lineno,
1283 child, cwd, lcwd, latestdir); 1283 child, cwd, lcwd, latestdir);
1284#endif 1284#endif
1285 } 1285 }
1286 } 1286 }
1287 break; 1287 break;
1288 1288
1289 case 'C': /* Chdir */ 1289 case 'C': /* Chdir */
1290 /* Update lcwd and latest directory. */ 1290 /* Update lcwd and latest directory. */
1291 strlcpy(latestdir, p, sizeof(latestdir)); 1291 strlcpy(latestdir, p, sizeof(latestdir));
1292 strlcpy(lcwd, p, sizeof(lcwd)); 1292 strlcpy(lcwd, p, sizeof(lcwd));
1293 Var_Set(lcwd_vname, lcwd, VAR_GLOBAL); 1293 Var_Set(lcwd_vname, lcwd, VAR_GLOBAL);
1294 Var_Set(ldir_vname, lcwd, VAR_GLOBAL); 1294 Var_Set(ldir_vname, lcwd, VAR_GLOBAL);
1295#ifdef DEBUG_META_MODE 1295#ifdef DEBUG_META_MODE
1296 if (DEBUG(META)) 1296 if (DEBUG(META))
1297 fprintf(debug_file, "%s: %d: cwd=%s ldir=%s\n", fname, lineno, cwd, lcwd); 1297 fprintf(debug_file, "%s: %d: cwd=%s ldir=%s\n", fname, lineno, cwd, lcwd);
1298#endif 1298#endif
1299 break; 1299 break;
1300 1300
1301 case 'M': /* renaMe */ 1301 case 'M': /* renaMe */
1302 /* 1302 /*
1303 * For 'M'oves we want to check 1303 * For 'M'oves we want to check
1304 * the src as for 'R'ead 1304 * the src as for 'R'ead
1305 * and the target as for 'W'rite. 1305 * and the target as for 'W'rite.
1306 */ 1306 */
1307 cp = p; /* save this for a second */ 1307 cp = p; /* save this for a second */
1308 /* now get target */ 1308 /* now get target */
1309 if (strsep(&p, " ") == NULL) 1309 if (strsep(&p, " ") == NULL)
1310 continue; 1310 continue;
1311 CHECK_VALID_META(p); 1311 CHECK_VALID_META(p);
1312 move_target = p; 1312 move_target = p;
1313 p = cp; 1313 p = cp;
1314 /* 'L' and 'M' put single quotes around the args */ 1314 /* 'L' and 'M' put single quotes around the args */
1315 DEQUOTE(p); 1315 DEQUOTE(p);
1316 DEQUOTE(move_target); 1316 DEQUOTE(move_target);
1317 /* FALLTHROUGH */ 1317 /* FALLTHROUGH */
1318 case 'D': /* unlink */ 1318 case 'D': /* unlink */
1319 if (*p == '/' && !Lst_IsEmpty(missingFiles)) { 1319 if (*p == '/' && !Lst_IsEmpty(missingFiles)) {
1320 /* remove any missingFiles entries that match p */ 1320 /* remove any missingFiles entries that match p */
1321 ln = Lst_Find(missingFiles, path_match, p); 1321 ln = Lst_Find(missingFiles, path_match, p);
1322 if (ln != NULL) { 1322 if (ln != NULL) {
1323 LstNode nln; 1323 LstNode nln;
1324 char *tp; 1324 char *tp;
1325 1325
1326 do { 1326 do {
1327 nln = Lst_FindFrom(missingFiles, Lst_Succ(ln), 1327 nln = Lst_FindFrom(missingFiles,
1328 path_match, p); 1328 LstNode_Next(ln),
 1329 path_match, p);
1329 tp = Lst_Datum(ln); 1330 tp = Lst_Datum(ln);
1330 Lst_Remove(missingFiles, ln); 1331 Lst_Remove(missingFiles, ln);
1331 free(tp); 1332 free(tp);
1332 } while ((ln = nln) != NULL); 1333 } while ((ln = nln) != NULL);
1333 } 1334 }
1334 } 1335 }
1335 if (buf[0] == 'M') { 1336 if (buf[0] == 'M') {
1336 /* the target of the mv is a file 'W'ritten */ 1337 /* the target of the mv is a file 'W'ritten */
1337#ifdef DEBUG_META_MODE 1338#ifdef DEBUG_META_MODE
1338 if (DEBUG(META)) 1339 if (DEBUG(META))
1339 fprintf(debug_file, "meta_oodate: M %s -> %s\n", 1340 fprintf(debug_file, "meta_oodate: M %s -> %s\n",
1340 p, move_target); 1341 p, move_target);
1341#endif 1342#endif
1342 p = move_target; 1343 p = move_target;
1343 goto check_write; 1344 goto check_write;
1344 } 1345 }
1345 break; 1346 break;
1346 case 'L': /* Link */ 1347 case 'L': /* Link */
1347 /* 1348 /*
1348 * For 'L'inks check 1349 * For 'L'inks check
1349 * the src as for 'R'ead 1350 * the src as for 'R'ead
1350 * and the target as for 'W'rite. 1351 * and the target as for 'W'rite.
1351 */ 1352 */
1352 link_src = p; 1353 link_src = p;
1353 /* now get target */ 1354 /* now get target */
1354 if (strsep(&p, " ") == NULL) 1355 if (strsep(&p, " ") == NULL)
1355 continue; 1356 continue;
1356 CHECK_VALID_META(p); 1357 CHECK_VALID_META(p);
1357 /* 'L' and 'M' put single quotes around the args */ 1358 /* 'L' and 'M' put single quotes around the args */
1358 DEQUOTE(p); 1359 DEQUOTE(p);
1359 DEQUOTE(link_src); 1360 DEQUOTE(link_src);
1360#ifdef DEBUG_META_MODE 1361#ifdef DEBUG_META_MODE
1361 if (DEBUG(META)) 1362 if (DEBUG(META))
1362 fprintf(debug_file, "meta_oodate: L %s -> %s\n", 1363 fprintf(debug_file, "meta_oodate: L %s -> %s\n",
1363 link_src, p); 1364 link_src, p);
1364#endif 1365#endif
1365 /* FALLTHROUGH */ 1366 /* FALLTHROUGH */
1366 case 'W': /* Write */ 1367 case 'W': /* Write */
1367 check_write: 1368 check_write:
1368 /* 1369 /*
1369 * If a file we generated within our bailiwick 1370 * If a file we generated within our bailiwick
1370 * but outside of .OBJDIR is missing, 1371 * but outside of .OBJDIR is missing,
1371 * we need to do it again. 1372 * we need to do it again.
1372 */ 1373 */
1373 /* ignore non-absolute paths */ 1374 /* ignore non-absolute paths */
1374 if (*p != '/') 1375 if (*p != '/')
1375 break; 1376 break;
1376 1377
1377 if (Lst_IsEmpty(metaBailiwick)) 1378 if (Lst_IsEmpty(metaBailiwick))
1378 break; 1379 break;
1379 1380
1380 /* ignore cwd - normal dependencies handle those */ 1381 /* ignore cwd - normal dependencies handle those */
1381 if (strncmp(p, cwd, cwdlen) == 0) 1382 if (strncmp(p, cwd, cwdlen) == 0)
1382 break; 1383 break;
1383 1384
1384 if (!Lst_ForEach(metaBailiwick, prefix_match, p)) 1385 if (!Lst_ForEach(metaBailiwick, prefix_match, p))
1385 break; 1386 break;
1386 1387
1387 /* tmpdir might be within */ 1388 /* tmpdir might be within */
1388 if (tmplen > 0 && strncmp(p, tmpdir, tmplen) == 0) 1389 if (tmplen > 0 && strncmp(p, tmpdir, tmplen) == 0)
1389 break; 1390 break;
1390 1391
1391 /* ignore anything containing the string "tmp" */ 1392 /* ignore anything containing the string "tmp" */
1392 if ((strstr("tmp", p))) 1393 if ((strstr("tmp", p)))
1393 break; 1394 break;
1394 1395
1395 if ((link_src != NULL && cached_lstat(p, &fs) < 0) || 1396 if ((link_src != NULL && cached_lstat(p, &fs) < 0) ||
1396 (link_src == NULL && cached_stat(p, &fs) < 0)) { 1397 (link_src == NULL && cached_stat(p, &fs) < 0)) {
1397 if (!meta_ignore(gn, p)) { 1398 if (!meta_ignore(gn, p)) {
1398 if (Lst_Find(missingFiles, string_match, p) == NULL) 1399 if (Lst_Find(missingFiles, string_match, p) == NULL)
1399 Lst_Append(missingFiles, bmake_strdup(p)); 1400 Lst_Append(missingFiles, bmake_strdup(p));
1400 } 1401 }
1401 } 1402 }
1402 break; 1403 break;
1403 check_link_src: 1404 check_link_src:
1404 p = link_src; 1405 p = link_src;
1405 link_src = NULL; 1406 link_src = NULL;
1406#ifdef DEBUG_META_MODE 1407#ifdef DEBUG_META_MODE
1407 if (DEBUG(META)) 1408 if (DEBUG(META))
1408 fprintf(debug_file, "meta_oodate: L src %s\n", p); 1409 fprintf(debug_file, "meta_oodate: L src %s\n", p);
1409#endif 1410#endif
1410 /* FALLTHROUGH */ 1411 /* FALLTHROUGH */
1411 case 'R': /* Read */ 1412 case 'R': /* Read */
1412 case 'E': /* Exec */ 1413 case 'E': /* Exec */
1413 /* 1414 /*
1414 * Check for runtime files that can't 1415 * Check for runtime files that can't
1415 * be part of the dependencies because 1416 * be part of the dependencies because
1416 * they are _expected_ to change. 1417 * they are _expected_ to change.
1417 */ 1418 */
1418 if (meta_ignore(gn, p)) 1419 if (meta_ignore(gn, p))
1419 break; 1420 break;
1420 1421
1421 /* 1422 /*
1422 * The rest of the record is the file name. 1423 * The rest of the record is the file name.
1423 * Check if it's not an absolute path. 1424 * Check if it's not an absolute path.
1424 */ 1425 */
1425 { 1426 {
1426 char *sdirs[4]; 1427 char *sdirs[4];
1427 char **sdp; 1428 char **sdp;
1428 int sdx = 0; 1429 int sdx = 0;
1429 int found = 0; 1430 int found = 0;
1430 1431
1431 if (*p == '/') { 1432 if (*p == '/') {
1432 sdirs[sdx++] = p; /* done */ 1433 sdirs[sdx++] = p; /* done */
1433 } else { 1434 } else {
1434 if (strcmp(".", p) == 0) 1435 if (strcmp(".", p) == 0)
1435 continue; /* no point */ 1436 continue; /* no point */
1436 1437
1437 /* Check vs latestdir */ 1438 /* Check vs latestdir */
1438 snprintf(fname1, sizeof(fname1), "%s/%s", latestdir, p); 1439 snprintf(fname1, sizeof(fname1), "%s/%s", latestdir, p);
1439 sdirs[sdx++] = fname1; 1440 sdirs[sdx++] = fname1;
1440 1441
1441 if (strcmp(latestdir, lcwd) != 0) { 1442 if (strcmp(latestdir, lcwd) != 0) {
1442 /* Check vs lcwd */ 1443 /* Check vs lcwd */
1443 snprintf(fname2, sizeof(fname2), "%s/%s", lcwd, p); 1444 snprintf(fname2, sizeof(fname2), "%s/%s", lcwd, p);
1444 sdirs[sdx++] = fname2; 1445 sdirs[sdx++] = fname2;
1445 } 1446 }
1446 if (strcmp(lcwd, cwd) != 0) { 1447 if (strcmp(lcwd, cwd) != 0) {
1447 /* Check vs cwd */ 1448 /* Check vs cwd */
1448 snprintf(fname3, sizeof(fname3), "%s/%s", cwd, p); 1449 snprintf(fname3, sizeof(fname3), "%s/%s", cwd, p);
1449 sdirs[sdx++] = fname3; 1450 sdirs[sdx++] = fname3;
1450 } 1451 }
1451 } 1452 }
1452 sdirs[sdx++] = NULL; 1453 sdirs[sdx++] = NULL;
1453 1454
1454 for (sdp = sdirs; *sdp && !found; sdp++) { 1455 for (sdp = sdirs; *sdp && !found; sdp++) {
1455#ifdef DEBUG_META_MODE 1456#ifdef DEBUG_META_MODE
1456 if (DEBUG(META)) 1457 if (DEBUG(META))
1457 fprintf(debug_file, "%s: %d: looking for: %s\n", fname, lineno, *sdp); 1458 fprintf(debug_file, "%s: %d: looking for: %s\n", fname, lineno, *sdp);
1458#endif 1459#endif
1459 if (cached_stat(*sdp, &fs) == 0) { 1460 if (cached_stat(*sdp, &fs) == 0) {
1460 found = 1; 1461 found = 1;
1461 p = *sdp; 1462 p = *sdp;
1462 } 1463 }
1463 } 1464 }
1464 if (found) { 1465 if (found) {
1465#ifdef DEBUG_META_MODE 1466#ifdef DEBUG_META_MODE
1466 if (DEBUG(META)) 1467 if (DEBUG(META))
1467 fprintf(debug_file, "%s: %d: found: %s\n", fname, lineno, p); 1468 fprintf(debug_file, "%s: %d: found: %s\n", fname, lineno, p);
1468#endif 1469#endif
1469 if (!S_ISDIR(fs.st_mode) && 1470 if (!S_ISDIR(fs.st_mode) &&
1470 fs.st_mtime > gn->mtime) { 1471 fs.st_mtime > gn->mtime) {
1471 if (DEBUG(META)) 1472 if (DEBUG(META))
1472 fprintf(debug_file, "%s: %d: file '%s' is newer than the target...\n", fname, lineno, p); 1473 fprintf(debug_file, "%s: %d: file '%s' is newer than the target...\n", fname, lineno, p);
1473 oodate = TRUE; 1474 oodate = TRUE;
1474 } else if (S_ISDIR(fs.st_mode)) { 1475 } else if (S_ISDIR(fs.st_mode)) {
1475 /* Update the latest directory. */ 1476 /* Update the latest directory. */
1476 cached_realpath(p, latestdir); 1477 cached_realpath(p, latestdir);
1477 } 1478 }
1478 } else if (errno == ENOENT && *p == '/' && 1479 } else if (errno == ENOENT && *p == '/' &&
1479 strncmp(p, cwd, cwdlen) != 0) { 1480 strncmp(p, cwd, cwdlen) != 0) {
1480 /* 1481 /*
1481 * A referenced file outside of CWD is missing. 1482 * A referenced file outside of CWD is missing.
1482 * We cannot catch every eventuality here... 1483 * We cannot catch every eventuality here...
1483 */ 1484 */
1484 if (Lst_Find(missingFiles, string_match, p) == NULL) 1485 if (Lst_Find(missingFiles, string_match, p) == NULL)
1485 Lst_Append(missingFiles, bmake_strdup(p)); 1486 Lst_Append(missingFiles, bmake_strdup(p));
1486 } 1487 }
1487 } 1488 }
1488 if (buf[0] == 'E') { 1489 if (buf[0] == 'E') {
1489 /* previous latestdir is no longer relevant */ 1490 /* previous latestdir is no longer relevant */
1490 strlcpy(latestdir, lcwd, sizeof(latestdir)); 1491 strlcpy(latestdir, lcwd, sizeof(latestdir));
1491 } 1492 }
1492 break; 1493 break;
1493 default: 1494 default:
1494 break; 1495 break;
1495 } 1496 }
1496 if (!oodate && buf[0] == 'L' && link_src != NULL) 1497 if (!oodate && buf[0] == 'L' && link_src != NULL)
1497 goto check_link_src; 1498 goto check_link_src;
1498 } else if (strcmp(buf, "CMD") == 0) { 1499 } else if (strcmp(buf, "CMD") == 0) {
1499 /* 1500 /*
1500 * Compare the current command with the one in the 1501 * Compare the current command with the one in the
1501 * meta data file. 1502 * meta data file.
1502 */ 1503 */
1503 if (ln == NULL) { 1504 if (ln == NULL) {
1504 if (DEBUG(META)) 1505 if (DEBUG(META))
1505 fprintf(debug_file, "%s: %d: there were more build commands in the meta data file than there are now...\n", fname, lineno); 1506 fprintf(debug_file, "%s: %d: there were more build commands in the meta data file than there are now...\n", fname, lineno);
1506 oodate = TRUE; 1507 oodate = TRUE;
1507 } else { 1508 } else {
1508 char *cmd = Lst_Datum(ln); 1509 char *cmd = Lst_Datum(ln);
1509 Boolean hasOODATE = FALSE; 1510 Boolean hasOODATE = FALSE;
1510 1511
1511 if (strstr(cmd, "$?")) 1512 if (strstr(cmd, "$?"))
1512 hasOODATE = TRUE; 1513 hasOODATE = TRUE;
1513 else if ((cp = strstr(cmd, ".OODATE"))) { 1514 else if ((cp = strstr(cmd, ".OODATE"))) {
1514 /* check for $[{(].OODATE[:)}] */ 1515 /* check for $[{(].OODATE[:)}] */
1515 if (cp > cmd + 2 && cp[-2] == '$') 1516 if (cp > cmd + 2 && cp[-2] == '$')
1516 hasOODATE = TRUE; 1517 hasOODATE = TRUE;
1517 } 1518 }
1518 if (hasOODATE) { 1519 if (hasOODATE) {
1519 needOODATE = TRUE; 1520 needOODATE = TRUE;
1520 if (DEBUG(META)) 1521 if (DEBUG(META))
1521 fprintf(debug_file, "%s: %d: cannot compare command using .OODATE\n", fname, lineno); 1522 fprintf(debug_file, "%s: %d: cannot compare command using .OODATE\n", fname, lineno);
1522 } 1523 }
1523 cmd = Var_Subst(cmd, gn, VARE_WANTRES|VARE_UNDEFERR); 1524 cmd = Var_Subst(cmd, gn, VARE_WANTRES|VARE_UNDEFERR);
1524 1525
1525 if ((cp = strchr(cmd, '\n'))) { 1526 if ((cp = strchr(cmd, '\n'))) {
1526 int n; 1527 int n;
1527 1528
1528 /* 1529 /*
1529 * This command contains newlines, we need to 1530 * This command contains newlines, we need to
1530 * fetch more from the .meta file before we 1531 * fetch more from the .meta file before we
1531 * attempt a comparison. 1532 * attempt a comparison.
1532 */ 1533 */
1533 /* first put the newline back at buf[x - 1] */ 1534 /* first put the newline back at buf[x - 1] */
1534 buf[x - 1] = '\n'; 1535 buf[x - 1] = '\n';
1535 do { 1536 do {
1536 /* now fetch the next line */ 1537 /* now fetch the next line */
1537 if ((n = fgetLine(&buf, &bufsz, x, fp)) <= 0) 1538 if ((n = fgetLine(&buf, &bufsz, x, fp)) <= 0)
1538 break; 1539 break;
1539 x = n; 1540 x = n;
1540 lineno++; 1541 lineno++;
1541 if (buf[x - 1] != '\n') { 1542 if (buf[x - 1] != '\n') {
1542 warnx("%s: %d: line truncated at %u", fname, lineno, x); 1543 warnx("%s: %d: line truncated at %u", fname, lineno, x);
1543 break; 1544 break;
1544 } 1545 }
1545 cp = strchr(++cp, '\n'); 1546 cp = strchr(++cp, '\n');
1546 } while (cp); 1547 } while (cp);
1547 if (buf[x - 1] == '\n') 1548 if (buf[x - 1] == '\n')
1548 buf[x - 1] = '\0'; 1549 buf[x - 1] = '\0';
1549 } 1550 }
1550 if (p && 1551 if (p &&
1551 !hasOODATE && 1552 !hasOODATE &&
1552 !(gn->type & OP_NOMETA_CMP) && 1553 !(gn->type & OP_NOMETA_CMP) &&
1553 strcmp(p, cmd) != 0) { 1554 strcmp(p, cmd) != 0) {
1554 if (DEBUG(META)) 1555 if (DEBUG(META))
1555 fprintf(debug_file, "%s: %d: a build command has changed\n%s\nvs\n%s\n", fname, lineno, p, cmd); 1556 fprintf(debug_file, "%s: %d: a build command has changed\n%s\nvs\n%s\n", fname, lineno, p, cmd);
1556 if (!metaIgnoreCMDs) 1557 if (!metaIgnoreCMDs)
1557 oodate = TRUE; 1558 oodate = TRUE;
1558 } 1559 }
1559 free(cmd); 1560 free(cmd);
1560 ln = Lst_Succ(ln); 1561 ln = LstNode_Next(ln);
1561 } 1562 }
1562 } else if (strcmp(buf, "CWD") == 0) { 1563 } else if (strcmp(buf, "CWD") == 0) {
1563 /* 1564 /*
1564 * Check if there are extra commands now 1565 * Check if there are extra commands now
1565 * that weren't in the meta data file. 1566 * that weren't in the meta data file.
1566 */ 1567 */
1567 if (!oodate && ln != NULL) { 1568 if (!oodate && ln != NULL) {
1568 if (DEBUG(META)) 1569 if (DEBUG(META))
1569 fprintf(debug_file, "%s: %d: there are extra build commands now that weren't in the meta data file\n", fname, lineno); 1570 fprintf(debug_file, "%s: %d: there are extra build commands now that weren't in the meta data file\n", fname, lineno);
1570 oodate = TRUE; 1571 oodate = TRUE;
1571 } 1572 }
1572 CHECK_VALID_META(p); 1573 CHECK_VALID_META(p);
1573 if (strcmp(p, cwd) != 0) { 1574 if (strcmp(p, cwd) != 0) {
1574 if (DEBUG(META)) 1575 if (DEBUG(META))
1575 fprintf(debug_file, "%s: %d: the current working directory has changed from '%s' to '%s'\n", fname, lineno, p, curdir); 1576 fprintf(debug_file, "%s: %d: the current working directory has changed from '%s' to '%s'\n", fname, lineno, p, curdir);
1576 oodate = TRUE; 1577 oodate = TRUE;
1577 } 1578 }
1578 } 1579 }
1579 } 1580 }
1580 1581
1581 fclose(fp); 1582 fclose(fp);
1582 if (!Lst_IsEmpty(missingFiles)) { 1583 if (!Lst_IsEmpty(missingFiles)) {
1583 if (DEBUG(META)) 1584 if (DEBUG(META))
1584 fprintf(debug_file, "%s: missing files: %s...\n", 1585 fprintf(debug_file, "%s: missing files: %s...\n",
1585 fname, (char *)Lst_Datum(Lst_First(missingFiles))); 1586 fname, (char *)Lst_Datum(Lst_First(missingFiles)));
1586 oodate = TRUE; 1587 oodate = TRUE;
1587 } 1588 }
1588 if (!oodate && !have_filemon && filemonMissing) { 1589 if (!oodate && !have_filemon && filemonMissing) {
1589 if (DEBUG(META)) 1590 if (DEBUG(META))
1590 fprintf(debug_file, "%s: missing filemon data\n", fname); 1591 fprintf(debug_file, "%s: missing filemon data\n", fname);
1591 oodate = TRUE; 1592 oodate = TRUE;
1592 } 1593 }
1593 } else { 1594 } else {
1594 if (writeMeta && (metaMissing || (gn->type & OP_META))) { 1595 if (writeMeta && (metaMissing || (gn->type & OP_META))) {
1595 cp = NULL; 1596 cp = NULL;
1596 1597
1597 /* if target is in .CURDIR we do not need a meta file */ 1598 /* if target is in .CURDIR we do not need a meta file */
1598 if (gn->path && (cp = strrchr(gn->path, '/')) && cp > gn->path) { 1599 if (gn->path && (cp = strrchr(gn->path, '/')) && cp > gn->path) {
1599 if (strncmp(curdir, gn->path, (cp - gn->path)) != 0) { 1600 if (strncmp(curdir, gn->path, (cp - gn->path)) != 0) {
1600 cp = NULL; /* not in .CURDIR */ 1601 cp = NULL; /* not in .CURDIR */
1601 } 1602 }
1602 } 1603 }
1603 if (!cp) { 1604 if (!cp) {
1604 if (DEBUG(META)) 1605 if (DEBUG(META))
1605 fprintf(debug_file, "%s: required but missing\n", fname); 1606 fprintf(debug_file, "%s: required but missing\n", fname);
1606 oodate = TRUE; 1607 oodate = TRUE;
1607 needOODATE = TRUE; /* assume the worst */ 1608 needOODATE = TRUE; /* assume the worst */
1608 } 1609 }
1609 } 1610 }
1610 } 1611 }
1611 1612
1612 Lst_Destroy(missingFiles, free); 1613 Lst_Destroy(missingFiles, free);
1613 1614
1614 if (oodate && needOODATE) { 1615 if (oodate && needOODATE) {
1615 /* 1616 /*
1616 * Target uses .OODATE which is empty; or we wouldn't be here. 1617 * Target uses .OODATE which is empty; or we wouldn't be here.
1617 * We have decided it is oodate, so .OODATE needs to be set. 1618 * We have decided it is oodate, so .OODATE needs to be set.
1618 * All we can sanely do is set it to .ALLSRC. 1619 * All we can sanely do is set it to .ALLSRC.
1619 */ 1620 */
1620 Var_Delete(OODATE, gn); 1621 Var_Delete(OODATE, gn);
1621 Var_Set(OODATE, Var_Value(ALLSRC, gn, &cp), gn); 1622 Var_Set(OODATE, Var_Value(ALLSRC, gn, &cp), gn);
1622 bmake_free(cp); 1623 bmake_free(cp);
1623 } 1624 }
1624 1625
1625 oodate_out: 1626 oodate_out:
1626 for (i--; i >= 0; i--) { 1627 for (i--; i >= 0; i--) {
1627 bmake_free(pa[i]); 1628 bmake_free(pa[i]);
1628 } 1629 }
1629 return oodate; 1630 return oodate;
1630} 1631}
1631 1632
1632/* support for compat mode */ 1633/* support for compat mode */
1633 1634
1634static int childPipe[2]; 1635static int childPipe[2];
1635 1636
1636void 1637void
1637meta_compat_start(void) 1638meta_compat_start(void)
1638{ 1639{
1639#ifdef USE_FILEMON_ONCE 1640#ifdef USE_FILEMON_ONCE
1640 /* 1641 /*
1641 * We need to re-open filemon for each cmd. 1642 * We need to re-open filemon for each cmd.
1642 */ 1643 */
1643 BuildMon *pbm = &Mybm; 1644 BuildMon *pbm = &Mybm;
1644 1645
1645 if (pbm->mfp != NULL && useFilemon) { 1646 if (pbm->mfp != NULL && useFilemon) {
1646 meta_open_filemon(pbm); 1647 meta_open_filemon(pbm);
1647 } else { 1648 } else {
1648 pbm->mon_fd = -1; 1649 pbm->mon_fd = -1;
1649 pbm->filemon = NULL; 1650 pbm->filemon = NULL;
1650 } 1651 }
1651#endif 1652#endif
1652 if (pipe(childPipe) < 0) 1653 if (pipe(childPipe) < 0)
1653 Punt("Cannot create pipe: %s", strerror(errno)); 1654 Punt("Cannot create pipe: %s", strerror(errno));
1654 /* Set close-on-exec flag for both */ 1655 /* Set close-on-exec flag for both */
1655 (void)fcntl(childPipe[0], F_SETFD, FD_CLOEXEC); 1656 (void)fcntl(childPipe[0], F_SETFD, FD_CLOEXEC);
1656 (void)fcntl(childPipe[1], F_SETFD, FD_CLOEXEC); 1657 (void)fcntl(childPipe[1], F_SETFD, FD_CLOEXEC);
1657} 1658}
1658 1659
1659void 1660void
1660meta_compat_child(void) 1661meta_compat_child(void)
1661{ 1662{
1662 meta_job_child(NULL); 1663 meta_job_child(NULL);
1663 if (dup2(childPipe[1], 1) < 0 || 1664 if (dup2(childPipe[1], 1) < 0 ||
1664 dup2(1, 2) < 0) { 1665 dup2(1, 2) < 0) {
1665 execError("dup2", "pipe"); 1666 execError("dup2", "pipe");
1666 _exit(1); 1667 _exit(1);
1667 } 1668 }
1668} 1669}
1669 1670
1670void 1671void
1671meta_compat_parent(pid_t child) 1672meta_compat_parent(pid_t child)
1672{ 1673{
1673 int outfd, metafd, maxfd, nfds; 1674 int outfd, metafd, maxfd, nfds;
1674 char buf[BUFSIZ+1]; 1675 char buf[BUFSIZ+1];
1675 fd_set readfds; 1676 fd_set readfds;
1676 1677
1677 meta_job_parent(NULL, child); 1678 meta_job_parent(NULL, child);
1678 close(childPipe[1]); /* child side */ 1679 close(childPipe[1]); /* child side */
1679 outfd = childPipe[0]; 1680 outfd = childPipe[0];
1680#ifdef USE_FILEMON 1681#ifdef USE_FILEMON
1681 metafd = Mybm.filemon ? filemon_readfd(Mybm.filemon) : -1; 1682 metafd = Mybm.filemon ? filemon_readfd(Mybm.filemon) : -1;
1682#else 1683#else
1683 metafd = -1; 1684 metafd = -1;
1684#endif 1685#endif
1685 maxfd = -1; 1686 maxfd = -1;
1686 if (outfd > maxfd) 1687 if (outfd > maxfd)
1687 maxfd = outfd; 1688 maxfd = outfd;
1688 if (metafd > maxfd) 1689 if (metafd > maxfd)
1689 maxfd = metafd; 1690 maxfd = metafd;
1690 1691
1691 while (outfd != -1 || metafd != -1) { 1692 while (outfd != -1 || metafd != -1) {
1692 FD_ZERO(&readfds); 1693 FD_ZERO(&readfds);
1693 if (outfd != -1) { 1694 if (outfd != -1) {
1694 FD_SET(outfd, &readfds); 1695 FD_SET(outfd, &readfds);
1695 } 1696 }
1696 if (metafd != -1) { 1697 if (metafd != -1) {
1697 FD_SET(metafd, &readfds); 1698 FD_SET(metafd, &readfds);
1698 } 1699 }
1699 nfds = select(maxfd + 1, &readfds, NULL, NULL, NULL); 1700 nfds = select(maxfd + 1, &readfds, NULL, NULL, NULL);
1700 if (nfds == -1) { 1701 if (nfds == -1) {
1701 if (errno == EINTR) 1702 if (errno == EINTR)
1702 continue; 1703 continue;
1703 err(1, "select"); 1704 err(1, "select");
1704 } 1705 }
1705 1706
1706 if (outfd != -1 && FD_ISSET(outfd, &readfds)) do { 1707 if (outfd != -1 && FD_ISSET(outfd, &readfds)) do {
1707 /* XXX this is not line-buffered */ 1708 /* XXX this is not line-buffered */
1708 ssize_t nread = read(outfd, buf, sizeof(buf) - 1); 1709 ssize_t nread = read(outfd, buf, sizeof(buf) - 1);
1709 if (nread == -1) 1710 if (nread == -1)
1710 err(1, "read"); 1711 err(1, "read");
1711 if (nread == 0) { 1712 if (nread == 0) {
1712 close(outfd); 1713 close(outfd);
1713 outfd = -1; 1714 outfd = -1;
1714 break; 1715 break;
1715 } 1716 }
1716 fwrite(buf, 1, (size_t)nread, stdout); 1717 fwrite(buf, 1, (size_t)nread, stdout);
1717 fflush(stdout); 1718 fflush(stdout);
1718 buf[nread] = '\0'; 1719 buf[nread] = '\0';
1719 meta_job_output(NULL, buf, ""); 1720 meta_job_output(NULL, buf, "");
1720 } while (0); 1721 } while (0);
1721 if (metafd != -1 && FD_ISSET(metafd, &readfds)) { 1722 if (metafd != -1 && FD_ISSET(metafd, &readfds)) {
1722 if (meta_job_event(NULL) <= 0) 1723 if (meta_job_event(NULL) <= 0)
1723 metafd = -1; 1724 metafd = -1;
1724 } 1725 }
1725 } 1726 }
1726} 1727}
1727 1728
1728#endif /* USE_META */ 1729#endif /* USE_META */

cvs diff -r1.130 -r1.131 src/usr.bin/make/suff.c (switch to unified diff)

--- src/usr.bin/make/suff.c 2020/08/29 10:12:06 1.130
+++ src/usr.bin/make/suff.c 2020/08/29 10:41:12 1.131
@@ -1,2541 +1,2541 @@ @@ -1,2541 +1,2541 @@
1/* $NetBSD: suff.c,v 1.130 2020/08/29 10:12:06 rillig Exp $ */ 1/* $NetBSD: suff.c,v 1.131 2020/08/29 10:41:12 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#ifndef MAKE_NATIVE 71#ifndef MAKE_NATIVE
72static char rcsid[] = "$NetBSD: suff.c,v 1.130 2020/08/29 10:12:06 rillig Exp $"; 72static char rcsid[] = "$NetBSD: suff.c,v 1.131 2020/08/29 10:41:12 rillig Exp $";
73#else 73#else
74#include <sys/cdefs.h> 74#include <sys/cdefs.h>
75#ifndef lint 75#ifndef lint
76#if 0 76#if 0
77static char sccsid[] = "@(#)suff.c 8.4 (Berkeley) 3/21/94"; 77static char sccsid[] = "@(#)suff.c 8.4 (Berkeley) 3/21/94";
78#else 78#else
79__RCSID("$NetBSD: suff.c,v 1.130 2020/08/29 10:12:06 rillig Exp $"); 79__RCSID("$NetBSD: suff.c,v 1.131 2020/08/29 10:41:12 rillig Exp $");
80#endif 80#endif
81#endif /* not lint */ 81#endif /* not lint */
82#endif 82#endif
83 83
84/*- 84/*-
85 * suff.c -- 85 * suff.c --
86 * Functions to maintain suffix lists and find implicit dependents 86 * Functions to maintain suffix lists and find implicit dependents
87 * using suffix transformation rules 87 * using suffix transformation rules
88 * 88 *
89 * Interface: 89 * Interface:
90 * Suff_Init Initialize all things to do with suffixes. 90 * Suff_Init Initialize all things to do with suffixes.
91 * 91 *
92 * Suff_End Cleanup the module 92 * Suff_End Cleanup the module
93 * 93 *
94 * Suff_DoPaths This function is used to make life easier 94 * Suff_DoPaths This function is used to make life easier
95 * when searching for a file according to its 95 * when searching for a file according to its
96 * suffix. It takes the global search path, 96 * suffix. It takes the global search path,
97 * as defined using the .PATH: target, and appends 97 * as defined using the .PATH: target, and appends
98 * its directories to the path of each of the 98 * its directories to the path of each of the
99 * defined suffixes, as specified using 99 * defined suffixes, as specified using
100 * .PATH<suffix>: targets. In addition, all 100 * .PATH<suffix>: targets. In addition, all
101 * directories given for suffixes labeled as 101 * directories given for suffixes labeled as
102 * include files or libraries, using the .INCLUDES 102 * include files or libraries, using the .INCLUDES
103 * or .LIBS targets, are played with using 103 * or .LIBS targets, are played with using
104 * Dir_MakeFlags to create the .INCLUDES and 104 * Dir_MakeFlags to create the .INCLUDES and
105 * .LIBS global variables. 105 * .LIBS global variables.
106 * 106 *
107 * Suff_ClearSuffixes Clear out all the suffixes and defined 107 * Suff_ClearSuffixes Clear out all the suffixes and defined
108 * transformations. 108 * transformations.
109 * 109 *
110 * Suff_IsTransform Return TRUE if the passed string is the lhs 110 * Suff_IsTransform Return TRUE if the passed string is the lhs
111 * of a transformation rule. 111 * of a transformation rule.
112 * 112 *
113 * Suff_AddSuffix Add the passed string as another known suffix. 113 * Suff_AddSuffix Add the passed string as another known suffix.
114 * 114 *
115 * Suff_GetPath Return the search path for the given suffix. 115 * Suff_GetPath Return the search path for the given suffix.
116 * 116 *
117 * Suff_AddInclude Mark the given suffix as denoting an include 117 * Suff_AddInclude Mark the given suffix as denoting an include
118 * file. 118 * file.
119 * 119 *
120 * Suff_AddLib Mark the given suffix as denoting a library. 120 * Suff_AddLib Mark the given suffix as denoting a library.
121 * 121 *
122 * Suff_AddTransform Add another transformation to the suffix 122 * Suff_AddTransform Add another transformation to the suffix
123 * graph. Returns GNode suitable for framing, I 123 * graph. Returns GNode suitable for framing, I
124 * mean, tacking commands, attributes, etc. on. 124 * mean, tacking commands, attributes, etc. on.
125 * 125 *
126 * Suff_SetNull Define the suffix to consider the suffix of 126 * Suff_SetNull Define the suffix to consider the suffix of
127 * any file that doesn't have a known one. 127 * any file that doesn't have a known one.
128 * 128 *
129 * Suff_FindDeps Find implicit sources for and the location of 129 * Suff_FindDeps Find implicit sources for and the location of
130 * a target based on its suffix. Returns the 130 * a target based on its suffix. Returns the
131 * bottom-most node added to the graph or NULL 131 * bottom-most node added to the graph or NULL
132 * if the target had no implicit sources. 132 * if the target had no implicit sources.
133 * 133 *
134 * Suff_FindPath Return the appropriate path to search in 134 * Suff_FindPath Return the appropriate path to search in
135 * order to find the node. 135 * order to find the node.
136 */ 136 */
137 137
138#include "make.h" 138#include "make.h"
139#include "dir.h" 139#include "dir.h"
140 140
141static Lst sufflist; /* Lst of suffixes */ 141static Lst sufflist; /* Lst of suffixes */
142#ifdef CLEANUP 142#ifdef CLEANUP
143static Lst suffClean; /* Lst of suffixes to be cleaned */ 143static Lst suffClean; /* Lst of suffixes to be cleaned */
144#endif 144#endif
145static Lst srclist; /* Lst of sources */ 145static Lst srclist; /* Lst of sources */
146static Lst transforms; /* Lst of transformation rules */ 146static Lst transforms; /* Lst of transformation rules */
147 147
148static int sNum = 0; /* Counter for assigning suffix numbers */ 148static int sNum = 0; /* Counter for assigning suffix numbers */
149 149
150typedef enum { 150typedef enum {
151 SUFF_INCLUDE = 0x01, /* One which is #include'd */ 151 SUFF_INCLUDE = 0x01, /* One which is #include'd */
152 SUFF_LIBRARY = 0x02, /* One which contains a library */ 152 SUFF_LIBRARY = 0x02, /* One which contains a library */
153 SUFF_NULL = 0x04 /* The empty suffix */ 153 SUFF_NULL = 0x04 /* The empty suffix */
154 /* XXX: Why is SUFF_NULL needed? Wouldn't nameLen == 0 mean the same? */ 154 /* XXX: Why is SUFF_NULL needed? Wouldn't nameLen == 0 mean the same? */
155} SuffFlags; 155} SuffFlags;
156 156
157ENUM_FLAGS_RTTI_3(SuffFlags, 157ENUM_FLAGS_RTTI_3(SuffFlags,
158 SUFF_INCLUDE, SUFF_LIBRARY, SUFF_NULL); 158 SUFF_INCLUDE, SUFF_LIBRARY, SUFF_NULL);
159 159
160/* 160/*
161 * Structure describing an individual suffix. 161 * Structure describing an individual suffix.
162 */ 162 */
163typedef struct Suff { 163typedef struct Suff {
164 char *name; /* The suffix itself, such as ".c" */ 164 char *name; /* The suffix itself, such as ".c" */
165 int nameLen; /* Length of the name, to avoid strlen calls */ 165 int nameLen; /* Length of the name, to avoid strlen calls */
166 SuffFlags flags; /* Type of suffix */ 166 SuffFlags flags; /* Type of suffix */
167 Lst searchPath; /* The path along which files of this suffix 167 Lst searchPath; /* The path along which files of this suffix
168 * may be found */ 168 * may be found */
169 int sNum; /* The suffix number */ 169 int sNum; /* The suffix number */
170 int refCount; /* Reference count of list membership */ 170 int refCount; /* Reference count of list membership */
171 Lst parents; /* Suffixes we have a transformation to */ 171 Lst parents; /* Suffixes we have a transformation to */
172 Lst children; /* Suffixes we have a transformation from */ 172 Lst children; /* Suffixes we have a transformation from */
173 Lst ref; /* List of lists this suffix is referenced */ 173 Lst ref; /* List of lists this suffix is referenced */
174} Suff; 174} Suff;
175 175
176/* 176/*
177 * Structure used in the search for implied sources. 177 * Structure used in the search for implied sources.
178 */ 178 */
179typedef struct _Src { 179typedef struct _Src {
180 char *file; /* The file to look for */ 180 char *file; /* The file to look for */
181 char *pref; /* Prefix from which file was formed */ 181 char *pref; /* Prefix from which file was formed */
182 Suff *suff; /* The suffix on the file */ 182 Suff *suff; /* The suffix on the file */
183 struct _Src *parent; /* The Src for which this is a source */ 183 struct _Src *parent; /* The Src for which this is a source */
184 GNode *node; /* The node describing the file */ 184 GNode *node; /* The node describing the file */
185 int children; /* Count of existing children (so we don't free 185 int children; /* Count of existing children (so we don't free
186 * this thing too early or never nuke it) */ 186 * this thing too early or never nuke it) */
187#ifdef DEBUG_SRC 187#ifdef DEBUG_SRC
188 Lst cp; /* Debug; children list */ 188 Lst cp; /* Debug; children list */
189#endif 189#endif
190} Src; 190} Src;
191 191
192/* 192/*
193 * A structure for passing more than one argument to the Lst-library-invoked 193 * A structure for passing more than one argument to the Lst-library-invoked
194 * function... 194 * function...
195 */ 195 */
196typedef struct { 196typedef struct {
197 Lst l; 197 Lst l;
198 Src *s; 198 Src *s;
199} LstSrc; 199} LstSrc;
200 200
201typedef struct { 201typedef struct {
202 GNode **gn; 202 GNode **gn;
203 Suff *s; 203 Suff *s;
204 Boolean r; 204 Boolean r;
205} GNodeSuff; 205} GNodeSuff;
206 206
207static Suff *suffNull; /* The NULL suffix for this run */ 207static Suff *suffNull; /* The NULL suffix for this run */
208static Suff *emptySuff; /* The empty suffix required for POSIX 208static Suff *emptySuff; /* The empty suffix required for POSIX
209 * single-suffix transformation rules */ 209 * single-suffix transformation rules */
210 210
211 211
212static void SuffUnRef(void *, void *); 212static void SuffUnRef(void *, void *);
213static void SuffFree(void *); 213static void SuffFree(void *);
214static void SuffInsert(Lst, Suff *); 214static void SuffInsert(Lst, Suff *);
215static void SuffRemove(Lst, Suff *); 215static void SuffRemove(Lst, Suff *);
216static Boolean SuffParseTransform(char *, Suff **, Suff **); 216static Boolean SuffParseTransform(char *, Suff **, Suff **);
217static int SuffRebuildGraph(void *, void *); 217static int SuffRebuildGraph(void *, void *);
218static int SuffScanTargets(void *, void *); 218static int SuffScanTargets(void *, void *);
219static int SuffAddSrc(void *, void *); 219static int SuffAddSrc(void *, void *);
220static int SuffRemoveSrc(Lst); 220static int SuffRemoveSrc(Lst);
221static void SuffAddLevel(Lst, Src *); 221static void SuffAddLevel(Lst, Src *);
222static Src *SuffFindCmds(Src *, Lst); 222static Src *SuffFindCmds(Src *, Lst);
223static void SuffExpandChildren(LstNode, GNode *); 223static void SuffExpandChildren(LstNode, GNode *);
224static void SuffExpandWildcards(LstNode, GNode *); 224static void SuffExpandWildcards(LstNode, GNode *);
225static Boolean SuffApplyTransform(GNode *, GNode *, Suff *, Suff *); 225static Boolean SuffApplyTransform(GNode *, GNode *, Suff *, Suff *);
226static void SuffFindDeps(GNode *, Lst); 226static void SuffFindDeps(GNode *, Lst);
227static void SuffFindArchiveDeps(GNode *, Lst); 227static void SuffFindArchiveDeps(GNode *, Lst);
228static void SuffFindNormalDeps(GNode *, Lst); 228static void SuffFindNormalDeps(GNode *, Lst);
229static int SuffPrintName(void *, void *); 229static int SuffPrintName(void *, void *);
230static int SuffPrintSuff(void *, void *); 230static int SuffPrintSuff(void *, void *);
231static int SuffPrintTrans(void *, void *); 231static int SuffPrintTrans(void *, void *);
232 232
233 /*************** Lst Predicates ****************/ 233 /*************** Lst Predicates ****************/
234/*- 234/*-
235 *----------------------------------------------------------------------- 235 *-----------------------------------------------------------------------
236 * SuffStrIsPrefix -- 236 * SuffStrIsPrefix --
237 * See if pref is a prefix of str. 237 * See if pref is a prefix of str.
238 * 238 *
239 * Input: 239 * Input:
240 * pref possible prefix 240 * pref possible prefix
241 * str string to check 241 * str string to check
242 * 242 *
243 * Results: 243 * Results:
244 * NULL if it ain't, pointer to character in str after prefix if so 244 * NULL if it ain't, pointer to character in str after prefix if so
245 * 245 *
246 * Side Effects: 246 * Side Effects:
247 * None 247 * None
248 *----------------------------------------------------------------------- 248 *-----------------------------------------------------------------------
249 */ 249 */
250static const char * 250static const char *
251SuffStrIsPrefix(const char *pref, const char *str) 251SuffStrIsPrefix(const char *pref, const char *str)
252{ 252{
253 while (*str && *pref == *str) { 253 while (*str && *pref == *str) {
254 pref++; 254 pref++;
255 str++; 255 str++;
256 } 256 }
257 257
258 return *pref ? NULL : str; 258 return *pref ? NULL : str;
259} 259}
260 260
261typedef struct { 261typedef struct {
262 char *ename; /* The end of the name */ 262 char *ename; /* The end of the name */
263 int len; /* Length of the name */ 263 int len; /* Length of the name */
264} SuffSuffGetSuffixArgs; 264} SuffSuffGetSuffixArgs;
265 265
266/* See if suff is a suffix of str. str->ename should point to THE END 266/* See if suff is a suffix of str. str->ename should point to THE END
267 * of the string to check. (THE END == the null byte) 267 * of the string to check. (THE END == the null byte)
268 * 268 *
269 * Input: 269 * Input:
270 * s possible suffix 270 * s possible suffix
271 * str string to examine 271 * str string to examine
272 * 272 *
273 * Results: 273 * Results:
274 * NULL if it ain't, pointer to character in str before suffix if 274 * NULL if it ain't, pointer to character in str before suffix if
275 * it is. 275 * it is.
276 */ 276 */
277static char * 277static char *
278SuffSuffGetSuffix(const Suff *s, const SuffSuffGetSuffixArgs *str) 278SuffSuffGetSuffix(const Suff *s, const SuffSuffGetSuffixArgs *str)
279{ 279{
280 char *p1; /* Pointer into suffix name */ 280 char *p1; /* Pointer into suffix name */
281 char *p2; /* Pointer into string being examined */ 281 char *p2; /* Pointer into string being examined */
282 282
283 if (str->len < s->nameLen) 283 if (str->len < s->nameLen)
284 return NULL; /* this string is shorter than the suffix */ 284 return NULL; /* this string is shorter than the suffix */
285 285
286 p1 = s->name + s->nameLen; 286 p1 = s->name + s->nameLen;
287 p2 = str->ename; 287 p2 = str->ename;
288 288
289 while (p1 >= s->name && *p1 == *p2) { 289 while (p1 >= s->name && *p1 == *p2) {
290 p1--; 290 p1--;
291 p2--; 291 p2--;
292 } 292 }
293 293
294 return p1 == s->name - 1 ? p2 : NULL; 294 return p1 == s->name - 1 ? p2 : NULL;
295} 295}
296 296
297/* Predicate form of SuffSuffGetSuffix, for Lst_Find. */ 297/* Predicate form of SuffSuffGetSuffix, for Lst_Find. */
298static Boolean 298static Boolean
299SuffSuffIsSuffix(const void *s, const void *sd) 299SuffSuffIsSuffix(const void *s, const void *sd)
300{ 300{
301 return SuffSuffGetSuffix(s, sd) != NULL; 301 return SuffSuffGetSuffix(s, sd) != NULL;
302} 302}
303 303
304/* See if the suffix has the desired name. */ 304/* See if the suffix has the desired name. */
305static Boolean 305static Boolean
306SuffSuffHasName(const void *s, const void *desiredName) 306SuffSuffHasName(const void *s, const void *desiredName)
307{ 307{
308 return strcmp(((const Suff *)s)->name, desiredName) == 0; 308 return strcmp(((const Suff *)s)->name, desiredName) == 0;
309} 309}
310 310
311/* See if the suffix name is a prefix of the string. Care must be taken when 311/* See if the suffix name is a prefix of the string. Care must be taken when
312 * using this to search for transformations and what-not, since there could 312 * using this to search for transformations and what-not, since there could
313 * well be two suffixes, one of which is a prefix of the other... */ 313 * well be two suffixes, one of which is a prefix of the other... */
314static Boolean 314static Boolean
315SuffSuffIsPrefix(const void *s, const void *str) 315SuffSuffIsPrefix(const void *s, const void *str)
316{ 316{
317 return SuffStrIsPrefix(((const Suff *)s)->name, str) != NULL; 317 return SuffStrIsPrefix(((const Suff *)s)->name, str) != NULL;
318} 318}
319 319
320/* See if the graph node has the desired name. */ 320/* See if the graph node has the desired name. */
321static Boolean 321static Boolean
322SuffGNHasName(const void *gn, const void *desiredName) 322SuffGNHasName(const void *gn, const void *desiredName)
323{ 323{
324 return strcmp(((const GNode *)gn)->name, desiredName) == 0; 324 return strcmp(((const GNode *)gn)->name, desiredName) == 0;
325} 325}
326 326
327 /*********** Maintenance Functions ************/ 327 /*********** Maintenance Functions ************/
328 328
329static void 329static void
330SuffUnRef(void *lp, void *sp) 330SuffUnRef(void *lp, void *sp)
331{ 331{
332 Lst l = (Lst) lp; 332 Lst l = (Lst) lp;
333 333
334 LstNode ln = Lst_Member(l, sp); 334 LstNode ln = Lst_Member(l, sp);
335 if (ln != NULL) { 335 if (ln != NULL) {
336 Lst_Remove(l, ln); 336 Lst_Remove(l, ln);
337 ((Suff *)sp)->refCount--; 337 ((Suff *)sp)->refCount--;
338 } 338 }
339} 339}
340 340
341/*- 341/*-
342 *----------------------------------------------------------------------- 342 *-----------------------------------------------------------------------
343 * SuffFree -- 343 * SuffFree --
344 * Free up all memory associated with the given suffix structure. 344 * Free up all memory associated with the given suffix structure.
345 * 345 *
346 * Results: 346 * Results:
347 * none 347 * none
348 * 348 *
349 * Side Effects: 349 * Side Effects:
350 * the suffix entry is detroyed 350 * the suffix entry is detroyed
351 *----------------------------------------------------------------------- 351 *-----------------------------------------------------------------------
352 */ 352 */
353static void 353static void
354SuffFree(void *sp) 354SuffFree(void *sp)
355{ 355{
356 Suff *s = (Suff *)sp; 356 Suff *s = (Suff *)sp;
357 357
358 if (s == suffNull) 358 if (s == suffNull)
359 suffNull = NULL; 359 suffNull = NULL;
360 360
361 if (s == emptySuff) 361 if (s == emptySuff)
362 emptySuff = NULL; 362 emptySuff = NULL;
363 363
364#ifdef notdef 364#ifdef notdef
365 /* We don't delete suffixes in order, so we cannot use this */ 365 /* We don't delete suffixes in order, so we cannot use this */
366 if (s->refCount) 366 if (s->refCount)
367 Punt("Internal error deleting suffix `%s' with refcount = %d", s->name, 367 Punt("Internal error deleting suffix `%s' with refcount = %d", s->name,
368 s->refCount); 368 s->refCount);
369#endif 369#endif
370 370
371 Lst_Free(s->ref); 371 Lst_Free(s->ref);
372 Lst_Free(s->children); 372 Lst_Free(s->children);
373 Lst_Free(s->parents); 373 Lst_Free(s->parents);
374 Lst_Destroy(s->searchPath, Dir_Destroy); 374 Lst_Destroy(s->searchPath, Dir_Destroy);
375 375
376 free(s->name); 376 free(s->name);
377 free(s); 377 free(s);
378} 378}
379 379
380/*- 380/*-
381 *----------------------------------------------------------------------- 381 *-----------------------------------------------------------------------
382 * SuffRemove -- 382 * SuffRemove --
383 * Remove the suffix into the list 383 * Remove the suffix into the list
384 * 384 *
385 * Results: 385 * Results:
386 * None 386 * None
387 * 387 *
388 * Side Effects: 388 * Side Effects:
389 * The reference count for the suffix is decremented and the 389 * The reference count for the suffix is decremented and the
390 * suffix is possibly freed 390 * suffix is possibly freed
391 *----------------------------------------------------------------------- 391 *-----------------------------------------------------------------------
392 */ 392 */
393static void 393static void
394SuffRemove(Lst l, Suff *s) 394SuffRemove(Lst l, Suff *s)
395{ 395{
396 SuffUnRef(l, s); 396 SuffUnRef(l, s);
397 if (s->refCount == 0) { 397 if (s->refCount == 0) {
398 SuffUnRef(sufflist, s); 398 SuffUnRef(sufflist, s);
399 SuffFree(s); 399 SuffFree(s);
400 } 400 }
401} 401}
402 402
403/*- 403/*-
404 *----------------------------------------------------------------------- 404 *-----------------------------------------------------------------------
405 * SuffInsert -- 405 * SuffInsert --
406 * Insert the suffix into the list keeping the list ordered by suffix 406 * Insert the suffix into the list keeping the list ordered by suffix
407 * numbers. 407 * numbers.
408 * 408 *
409 * Input: 409 * Input:
410 * l the list where in s should be inserted 410 * l the list where in s should be inserted
411 * s the suffix to insert 411 * s the suffix to insert
412 * 412 *
413 * Results: 413 * Results:
414 * None 414 * None
415 * 415 *
416 * Side Effects: 416 * Side Effects:
417 * The reference count of the suffix is incremented 417 * The reference count of the suffix is incremented
418 *----------------------------------------------------------------------- 418 *-----------------------------------------------------------------------
419 */ 419 */
420static void 420static void
421SuffInsert(Lst l, Suff *s) 421SuffInsert(Lst l, Suff *s)
422{ 422{
423 LstNode ln; /* current element in l we're examining */ 423 LstNode ln; /* current element in l we're examining */
424 Suff *s2 = NULL; /* the suffix descriptor in this element */ 424 Suff *s2 = NULL; /* the suffix descriptor in this element */
425 425
426 Lst_Open(l); 426 Lst_Open(l);
427 while ((ln = Lst_Next(l)) != NULL) { 427 while ((ln = Lst_Next(l)) != NULL) {
428 s2 = Lst_Datum(ln); 428 s2 = Lst_Datum(ln);
429 if (s2->sNum >= s->sNum) { 429 if (s2->sNum >= s->sNum) {
430 break; 430 break;
431 } 431 }
432 } 432 }
433 Lst_Close(l); 433 Lst_Close(l);
434 434
435 if (DEBUG(SUFF)) { 435 if (DEBUG(SUFF)) {
436 fprintf(debug_file, "inserting %s(%d)...", s->name, s->sNum); 436 fprintf(debug_file, "inserting %s(%d)...", s->name, s->sNum);
437 } 437 }
438 if (ln == NULL) { 438 if (ln == NULL) {
439 if (DEBUG(SUFF)) { 439 if (DEBUG(SUFF)) {
440 fprintf(debug_file, "at end of list\n"); 440 fprintf(debug_file, "at end of list\n");
441 } 441 }
442 Lst_Append(l, s); 442 Lst_Append(l, s);
443 s->refCount++; 443 s->refCount++;
444 Lst_Append(s->ref, l); 444 Lst_Append(s->ref, l);
445 } else if (s2->sNum != s->sNum) { 445 } else if (s2->sNum != s->sNum) {
446 if (DEBUG(SUFF)) { 446 if (DEBUG(SUFF)) {
447 fprintf(debug_file, "before %s(%d)\n", s2->name, s2->sNum); 447 fprintf(debug_file, "before %s(%d)\n", s2->name, s2->sNum);
448 } 448 }
449 Lst_InsertBefore(l, ln, s); 449 Lst_InsertBefore(l, ln, s);
450 s->refCount++; 450 s->refCount++;
451 Lst_Append(s->ref, l); 451 Lst_Append(s->ref, l);
452 } else if (DEBUG(SUFF)) { 452 } else if (DEBUG(SUFF)) {
453 fprintf(debug_file, "already there\n"); 453 fprintf(debug_file, "already there\n");
454 } 454 }
455} 455}
456 456
457static Suff * 457static Suff *
458SuffNew(const char *name) 458SuffNew(const char *name)
459{ 459{
460 Suff *s = bmake_malloc(sizeof(Suff)); 460 Suff *s = bmake_malloc(sizeof(Suff));
461 461
462 s->name = bmake_strdup(name); 462 s->name = bmake_strdup(name);
463 s->nameLen = strlen(s->name); 463 s->nameLen = strlen(s->name);
464 s->searchPath = Lst_Init(); 464 s->searchPath = Lst_Init();
465 s->children = Lst_Init(); 465 s->children = Lst_Init();
466 s->parents = Lst_Init(); 466 s->parents = Lst_Init();
467 s->ref = Lst_Init(); 467 s->ref = Lst_Init();
468 s->sNum = sNum++; 468 s->sNum = sNum++;
469 s->flags = 0; 469 s->flags = 0;
470 s->refCount = 1; 470 s->refCount = 1;
471 471
472 return s; 472 return s;
473} 473}
474 474
475/*- 475/*-
476 *----------------------------------------------------------------------- 476 *-----------------------------------------------------------------------
477 * Suff_ClearSuffixes -- 477 * Suff_ClearSuffixes --
478 * This is gross. Nuke the list of suffixes but keep all transformation 478 * This is gross. Nuke the list of suffixes but keep all transformation
479 * rules around. The transformation graph is destroyed in this process, 479 * rules around. The transformation graph is destroyed in this process,
480 * but we leave the list of rules so when a new graph is formed the rules 480 * but we leave the list of rules so when a new graph is formed the rules
481 * will remain. 481 * will remain.
482 * This function is called from the parse module when a 482 * This function is called from the parse module when a
483 * .SUFFIXES:\n line is encountered. 483 * .SUFFIXES:\n line is encountered.
484 * 484 *
485 * Results: 485 * Results:
486 * none 486 * none
487 * 487 *
488 * Side Effects: 488 * Side Effects:
489 * the sufflist and its graph nodes are destroyed 489 * the sufflist and its graph nodes are destroyed
490 *----------------------------------------------------------------------- 490 *-----------------------------------------------------------------------
491 */ 491 */
492void 492void
493Suff_ClearSuffixes(void) 493Suff_ClearSuffixes(void)
494{ 494{
495#ifdef CLEANUP 495#ifdef CLEANUP
496 Lst_MoveAll(suffClean, sufflist); 496 Lst_MoveAll(suffClean, sufflist);
497#endif 497#endif
498 sufflist = Lst_Init(); 498 sufflist = Lst_Init();
499 sNum = 0; 499 sNum = 0;
500 if (suffNull) 500 if (suffNull)
501 SuffFree(suffNull); 501 SuffFree(suffNull);
502 emptySuff = suffNull = SuffNew(""); 502 emptySuff = suffNull = SuffNew("");
503 503
504 Dir_Concat(suffNull->searchPath, dirSearchPath); 504 Dir_Concat(suffNull->searchPath, dirSearchPath);
505 suffNull->flags = SUFF_NULL; 505 suffNull->flags = SUFF_NULL;
506} 506}
507 507
508/*- 508/*-
509 *----------------------------------------------------------------------- 509 *-----------------------------------------------------------------------
510 * SuffParseTransform -- 510 * SuffParseTransform --
511 * Parse a transformation string to find its two component suffixes. 511 * Parse a transformation string to find its two component suffixes.
512 * 512 *
513 * Input: 513 * Input:
514 * str String being parsed 514 * str String being parsed
515 * srcPtr Place to store source of trans. 515 * srcPtr Place to store source of trans.
516 * targPtr Place to store target of trans. 516 * targPtr Place to store target of trans.
517 * 517 *
518 * Results: 518 * Results:
519 * TRUE if the string is a valid transformation and FALSE otherwise. 519 * TRUE if the string is a valid transformation and FALSE otherwise.
520 * 520 *
521 * Side Effects: 521 * Side Effects:
522 * The passed pointers are overwritten. 522 * The passed pointers are overwritten.
523 * 523 *
524 *----------------------------------------------------------------------- 524 *-----------------------------------------------------------------------
525 */ 525 */
526static Boolean 526static Boolean
527SuffParseTransform(char *str, Suff **srcPtr, Suff **targPtr) 527SuffParseTransform(char *str, Suff **srcPtr, Suff **targPtr)
528{ 528{
529 LstNode srcLn; /* element in suffix list of trans source*/ 529 LstNode srcLn; /* element in suffix list of trans source*/
530 Suff *src; /* Source of transformation */ 530 Suff *src; /* Source of transformation */
531 LstNode targLn; /* element in suffix list of trans target*/ 531 LstNode targLn; /* element in suffix list of trans target*/
532 char *str2; /* Extra pointer (maybe target suffix) */ 532 char *str2; /* Extra pointer (maybe target suffix) */
533 LstNode singleLn; /* element in suffix list of any suffix 533 LstNode singleLn; /* element in suffix list of any suffix
534 * that exactly matches str */ 534 * that exactly matches str */
535 Suff *single = NULL;/* Source of possible transformation to 535 Suff *single = NULL;/* Source of possible transformation to
536 * null suffix */ 536 * null suffix */
537 537
538 srcLn = NULL; 538 srcLn = NULL;
539 singleLn = NULL; 539 singleLn = NULL;
540 540
541 /* 541 /*
542 * Loop looking first for a suffix that matches the start of the 542 * Loop looking first for a suffix that matches the start of the
543 * string and then for one that exactly matches the rest of it. If 543 * string and then for one that exactly matches the rest of it. If
544 * we can find two that meet these criteria, we've successfully 544 * we can find two that meet these criteria, we've successfully
545 * parsed the string. 545 * parsed the string.
546 */ 546 */
547 for (;;) { 547 for (;;) {
548 if (srcLn == NULL) { 548 if (srcLn == NULL) {
549 srcLn = Lst_Find(sufflist, SuffSuffIsPrefix, str); 549 srcLn = Lst_Find(sufflist, SuffSuffIsPrefix, str);
550 } else { 550 } else {
551 srcLn = Lst_FindFrom(sufflist, Lst_Succ(srcLn), 551 srcLn = Lst_FindFrom(sufflist, LstNode_Next(srcLn),
552 SuffSuffIsPrefix, str); 552 SuffSuffIsPrefix, str);
553 } 553 }
554 if (srcLn == NULL) { 554 if (srcLn == NULL) {
555 /* 555 /*
556 * Ran out of source suffixes -- no such rule 556 * Ran out of source suffixes -- no such rule
557 */ 557 */
558 if (singleLn != NULL) { 558 if (singleLn != NULL) {
559 /* 559 /*
560 * Not so fast Mr. Smith! There was a suffix that encompassed 560 * Not so fast Mr. Smith! There was a suffix that encompassed
561 * the entire string, so we assume it was a transformation 561 * the entire string, so we assume it was a transformation
562 * to the null suffix (thank you POSIX). We still prefer to 562 * to the null suffix (thank you POSIX). We still prefer to
563 * find a double rule over a singleton, hence we leave this 563 * find a double rule over a singleton, hence we leave this
564 * check until the end. 564 * check until the end.
565 * 565 *
566 * XXX: Use emptySuff over suffNull? 566 * XXX: Use emptySuff over suffNull?
567 */ 567 */
568 *srcPtr = single; 568 *srcPtr = single;
569 *targPtr = suffNull; 569 *targPtr = suffNull;
570 return TRUE; 570 return TRUE;
571 } 571 }
572 return FALSE; 572 return FALSE;
573 } 573 }
574 src = Lst_Datum(srcLn); 574 src = Lst_Datum(srcLn);
575 str2 = str + src->nameLen; 575 str2 = str + src->nameLen;
576 if (*str2 == '\0') { 576 if (*str2 == '\0') {
577 single = src; 577 single = src;
578 singleLn = srcLn; 578 singleLn = srcLn;
579 } else { 579 } else {
580 targLn = Lst_Find(sufflist, SuffSuffHasName, str2); 580 targLn = Lst_Find(sufflist, SuffSuffHasName, str2);
581 if (targLn != NULL) { 581 if (targLn != NULL) {
582 *srcPtr = src; 582 *srcPtr = src;
583 *targPtr = Lst_Datum(targLn); 583 *targPtr = Lst_Datum(targLn);
584 return TRUE; 584 return TRUE;
585 } 585 }
586 } 586 }
587 } 587 }
588} 588}
589 589
590/*- 590/*-
591 *----------------------------------------------------------------------- 591 *-----------------------------------------------------------------------
592 * Suff_IsTransform -- 592 * Suff_IsTransform --
593 * Return TRUE if the given string is a transformation rule 593 * Return TRUE if the given string is a transformation rule
594 * 594 *
595 * 595 *
596 * Input: 596 * Input:
597 * str string to check 597 * str string to check
598 * 598 *
599 * Results: 599 * Results:
600 * TRUE if the string is a concatenation of two known suffixes. 600 * TRUE if the string is a concatenation of two known suffixes.
601 * FALSE otherwise 601 * FALSE otherwise
602 * 602 *
603 * Side Effects: 603 * Side Effects:
604 * None 604 * None
605 *----------------------------------------------------------------------- 605 *-----------------------------------------------------------------------
606 */ 606 */
607Boolean 607Boolean
608Suff_IsTransform(char *str) 608Suff_IsTransform(char *str)
609{ 609{
610 Suff *src, *targ; 610 Suff *src, *targ;
611 611
612 return SuffParseTransform(str, &src, &targ); 612 return SuffParseTransform(str, &src, &targ);
613} 613}
614 614
615/*- 615/*-
616 *----------------------------------------------------------------------- 616 *-----------------------------------------------------------------------
617 * Suff_AddTransform -- 617 * Suff_AddTransform --
618 * Add the transformation rule described by the line to the 618 * Add the transformation rule described by the line to the
619 * list of rules and place the transformation itself in the graph 619 * list of rules and place the transformation itself in the graph
620 * 620 *
621 * Input: 621 * Input:
622 * line name of transformation to add 622 * line name of transformation to add
623 * 623 *
624 * Results: 624 * Results:
625 * The node created for the transformation in the transforms list 625 * The node created for the transformation in the transforms list
626 * 626 *
627 * Side Effects: 627 * Side Effects:
628 * The node is placed on the end of the transforms Lst and links are 628 * The node is placed on the end of the transforms Lst and links are
629 * made between the two suffixes mentioned in the target name 629 * made between the two suffixes mentioned in the target name
630 *----------------------------------------------------------------------- 630 *-----------------------------------------------------------------------
631 */ 631 */
632GNode * 632GNode *
633Suff_AddTransform(char *line) 633Suff_AddTransform(char *line)
634{ 634{
635 GNode *gn; /* GNode of transformation rule */ 635 GNode *gn; /* GNode of transformation rule */
636 Suff *s, /* source suffix */ 636 Suff *s, /* source suffix */
637 *t; /* target suffix */ 637 *t; /* target suffix */
638 LstNode ln; /* Node for existing transformation */ 638 LstNode ln; /* Node for existing transformation */
639 639
640 ln = Lst_Find(transforms, SuffGNHasName, line); 640 ln = Lst_Find(transforms, SuffGNHasName, line);
641 if (ln == NULL) { 641 if (ln == NULL) {
642 /* 642 /*
643 * Make a new graph node for the transformation. It will be filled in 643 * Make a new graph node for the transformation. It will be filled in
644 * by the Parse module. 644 * by the Parse module.
645 */ 645 */
646 gn = Targ_NewGN(line); 646 gn = Targ_NewGN(line);
647 Lst_Append(transforms, gn); 647 Lst_Append(transforms, gn);
648 } else { 648 } else {
649 /* 649 /*
650 * New specification for transformation rule. Just nuke the old list 650 * New specification for transformation rule. Just nuke the old list
651 * of commands so they can be filled in again... We don't actually 651 * of commands so they can be filled in again... We don't actually
652 * free the commands themselves, because a given command can be 652 * free the commands themselves, because a given command can be
653 * attached to several different transformations. 653 * attached to several different transformations.
654 */ 654 */
655 gn = Lst_Datum(ln); 655 gn = Lst_Datum(ln);
656 Lst_Free(gn->commands); 656 Lst_Free(gn->commands);
657 Lst_Free(gn->children); 657 Lst_Free(gn->children);
658 gn->commands = Lst_Init(); 658 gn->commands = Lst_Init();
659 gn->children = Lst_Init(); 659 gn->children = Lst_Init();
660 } 660 }
661 661
662 gn->type = OP_TRANSFORM; 662 gn->type = OP_TRANSFORM;
663 663
664 (void)SuffParseTransform(line, &s, &t); 664 (void)SuffParseTransform(line, &s, &t);
665 665
666 /* 666 /*
667 * link the two together in the proper relationship and order 667 * link the two together in the proper relationship and order
668 */ 668 */
669 if (DEBUG(SUFF)) { 669 if (DEBUG(SUFF)) {
670 fprintf(debug_file, "defining transformation from `%s' to `%s'\n", 670 fprintf(debug_file, "defining transformation from `%s' to `%s'\n",
671 s->name, t->name); 671 s->name, t->name);
672 } 672 }
673 SuffInsert(t->children, s); 673 SuffInsert(t->children, s);
674 SuffInsert(s->parents, t); 674 SuffInsert(s->parents, t);
675 675
676 return gn; 676 return gn;
677} 677}
678 678
679/*- 679/*-
680 *----------------------------------------------------------------------- 680 *-----------------------------------------------------------------------
681 * Suff_EndTransform -- 681 * Suff_EndTransform --
682 * Handle the finish of a transformation definition, removing the 682 * Handle the finish of a transformation definition, removing the
683 * transformation from the graph if it has neither commands nor 683 * transformation from the graph if it has neither commands nor
684 * sources. This is a callback procedure for the Parse module via 684 * sources. This is a callback procedure for the Parse module via
685 * Lst_ForEach 685 * Lst_ForEach
686 * 686 *
687 * Input: 687 * Input:
688 * gnp Node for transformation 688 * gnp Node for transformation
689 * dummy Node for transformation 689 * dummy Node for transformation
690 * 690 *
691 * Results: 691 * Results:
692 * === 0 692 * === 0
693 * 693 *
694 * Side Effects: 694 * Side Effects:
695 * If the node has no commands or children, the children and parents 695 * If the node has no commands or children, the children and parents
696 * lists of the affected suffixes are altered. 696 * lists of the affected suffixes are altered.
697 * 697 *
698 *----------------------------------------------------------------------- 698 *-----------------------------------------------------------------------
699 */ 699 */
700int 700int
701Suff_EndTransform(void *gnp, void *dummy MAKE_ATTR_UNUSED) 701Suff_EndTransform(void *gnp, void *dummy MAKE_ATTR_UNUSED)
702{ 702{
703 GNode *gn = (GNode *)gnp; 703 GNode *gn = (GNode *)gnp;
704 704
705 if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(gn->cohorts)) 705 if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(gn->cohorts))
706 gn = Lst_Datum(Lst_Last(gn->cohorts)); 706 gn = Lst_Datum(Lst_Last(gn->cohorts));
707 if ((gn->type & OP_TRANSFORM) && Lst_IsEmpty(gn->commands) && 707 if ((gn->type & OP_TRANSFORM) && Lst_IsEmpty(gn->commands) &&
708 Lst_IsEmpty(gn->children)) 708 Lst_IsEmpty(gn->children))
709 { 709 {
710 Suff *s, *t; 710 Suff *s, *t;
711 711
712 /* 712 /*
713 * SuffParseTransform() may fail for special rules which are not 713 * SuffParseTransform() may fail for special rules which are not
714 * actual transformation rules. (e.g. .DEFAULT) 714 * actual transformation rules. (e.g. .DEFAULT)
715 */ 715 */
716 if (SuffParseTransform(gn->name, &s, &t)) { 716 if (SuffParseTransform(gn->name, &s, &t)) {
717 Lst p; 717 Lst p;
718 718
719 if (DEBUG(SUFF)) { 719 if (DEBUG(SUFF)) {
720 fprintf(debug_file, "deleting transformation from `%s' to `%s'\n", 720 fprintf(debug_file, "deleting transformation from `%s' to `%s'\n",
721 s->name, t->name); 721 s->name, t->name);
722 } 722 }
723 723
724 /* 724 /*
725 * Store s->parents because s could be deleted in SuffRemove 725 * Store s->parents because s could be deleted in SuffRemove
726 */ 726 */
727 p = s->parents; 727 p = s->parents;
728 728
729 /* 729 /*
730 * Remove the source from the target's children list. We check for a 730 * Remove the source from the target's children list. We check for a
731 * nil return to handle a beanhead saying something like 731 * nil return to handle a beanhead saying something like
732 * .c.o .c.o: 732 * .c.o .c.o:
733 * 733 *
734 * We'll be called twice when the next target is seen, but .c and .o 734 * We'll be called twice when the next target is seen, but .c and .o
735 * are only linked once... 735 * are only linked once...
736 */ 736 */
737 SuffRemove(t->children, s); 737 SuffRemove(t->children, s);
738 738
739 /* 739 /*
740 * Remove the target from the source's parents list 740 * Remove the target from the source's parents list
741 */ 741 */
742 SuffRemove(p, t); 742 SuffRemove(p, t);
743 } 743 }
744 } else if ((gn->type & OP_TRANSFORM) && DEBUG(SUFF)) { 744 } else if ((gn->type & OP_TRANSFORM) && DEBUG(SUFF)) {
745 fprintf(debug_file, "transformation %s complete\n", gn->name); 745 fprintf(debug_file, "transformation %s complete\n", gn->name);
746 } 746 }
747 747
748 return 0; 748 return 0;
749} 749}
750 750
751/*- 751/*-
752 *----------------------------------------------------------------------- 752 *-----------------------------------------------------------------------
753 * SuffRebuildGraph -- 753 * SuffRebuildGraph --
754 * Called from Suff_AddSuffix via Lst_ForEach to search through the 754 * Called from Suff_AddSuffix via Lst_ForEach to search through the
755 * list of existing transformation rules and rebuild the transformation 755 * list of existing transformation rules and rebuild the transformation
756 * graph when it has been destroyed by Suff_ClearSuffixes. If the 756 * graph when it has been destroyed by Suff_ClearSuffixes. If the
757 * given rule is a transformation involving this suffix and another, 757 * given rule is a transformation involving this suffix and another,
758 * existing suffix, the proper relationship is established between 758 * existing suffix, the proper relationship is established between
759 * the two. 759 * the two.
760 * 760 *
761 * Input: 761 * Input:
762 * transformp Transformation to test 762 * transformp Transformation to test
763 * sp Suffix to rebuild 763 * sp Suffix to rebuild
764 * 764 *
765 * Results: 765 * Results:
766 * Always 0. 766 * Always 0.
767 * 767 *
768 * Side Effects: 768 * Side Effects:
769 * The appropriate links will be made between this suffix and 769 * The appropriate links will be made between this suffix and
770 * others if transformation rules exist for it. 770 * others if transformation rules exist for it.
771 * 771 *
772 *----------------------------------------------------------------------- 772 *-----------------------------------------------------------------------
773 */ 773 */
774static int 774static int
775SuffRebuildGraph(void *transformp, void *sp) 775SuffRebuildGraph(void *transformp, void *sp)
776{ 776{
777 GNode *transform = (GNode *)transformp; 777 GNode *transform = (GNode *)transformp;
778 Suff *s = (Suff *)sp; 778 Suff *s = (Suff *)sp;
779 char *cp; 779 char *cp;
780 LstNode ln; 780 LstNode ln;
781 Suff *s2; 781 Suff *s2;
782 SuffSuffGetSuffixArgs sd; 782 SuffSuffGetSuffixArgs sd;
783 783
784 /* 784 /*
785 * First see if it is a transformation from this suffix. 785 * First see if it is a transformation from this suffix.
786 */ 786 */
787 cp = UNCONST(SuffStrIsPrefix(s->name, transform->name)); 787 cp = UNCONST(SuffStrIsPrefix(s->name, transform->name));
788 if (cp != NULL) { 788 if (cp != NULL) {
789 ln = Lst_Find(sufflist, SuffSuffHasName, cp); 789 ln = Lst_Find(sufflist, SuffSuffHasName, cp);
790 if (ln != NULL) { 790 if (ln != NULL) {
791 /* 791 /*
792 * Found target. Link in and return, since it can't be anything 792 * Found target. Link in and return, since it can't be anything
793 * else. 793 * else.
794 */ 794 */
795 s2 = Lst_Datum(ln); 795 s2 = Lst_Datum(ln);
796 SuffInsert(s2->children, s); 796 SuffInsert(s2->children, s);
797 SuffInsert(s->parents, s2); 797 SuffInsert(s->parents, s2);
798 return 0; 798 return 0;
799 } 799 }
800 } 800 }
801 801
802 /* 802 /*
803 * Not from, maybe to? 803 * Not from, maybe to?
804 */ 804 */
805 sd.len = strlen(transform->name); 805 sd.len = strlen(transform->name);
806 sd.ename = transform->name + sd.len; 806 sd.ename = transform->name + sd.len;
807 cp = SuffSuffGetSuffix(s, &sd); 807 cp = SuffSuffGetSuffix(s, &sd);
808 if (cp != NULL) { 808 if (cp != NULL) {
809 /* 809 /*
810 * Null-terminate the source suffix in order to find it. 810 * Null-terminate the source suffix in order to find it.
811 */ 811 */
812 cp[1] = '\0'; 812 cp[1] = '\0';
813 ln = Lst_Find(sufflist, SuffSuffHasName, transform->name); 813 ln = Lst_Find(sufflist, SuffSuffHasName, transform->name);
814 /* 814 /*
815 * Replace the start of the target suffix 815 * Replace the start of the target suffix
816 */ 816 */
817 cp[1] = s->name[0]; 817 cp[1] = s->name[0];
818 if (ln != NULL) { 818 if (ln != NULL) {
819 /* 819 /*
820 * Found it -- establish the proper relationship 820 * Found it -- establish the proper relationship
821 */ 821 */
822 s2 = Lst_Datum(ln); 822 s2 = Lst_Datum(ln);
823 SuffInsert(s->children, s2); 823 SuffInsert(s->children, s2);
824 SuffInsert(s2->parents, s); 824 SuffInsert(s2->parents, s);
825 } 825 }
826 } 826 }
827 return 0; 827 return 0;
828} 828}
829 829
830/*- 830/*-
831 *----------------------------------------------------------------------- 831 *-----------------------------------------------------------------------
832 * SuffScanTargets -- 832 * SuffScanTargets --
833 * Called from Suff_AddSuffix via Lst_ForEach to search through the 833 * Called from Suff_AddSuffix via Lst_ForEach to search through the
834 * list of existing targets and find if any of the existing targets 834 * list of existing targets and find if any of the existing targets
835 * can be turned into a transformation rule. 835 * can be turned into a transformation rule.
836 * 836 *
837 * Results: 837 * Results:
838 * 1 if a new main target has been selected, 0 otherwise. 838 * 1 if a new main target has been selected, 0 otherwise.
839 * 839 *
840 * Side Effects: 840 * Side Effects:
841 * If such a target is found and the target is the current main 841 * If such a target is found and the target is the current main
842 * target, the main target is set to NULL and the next target 842 * target, the main target is set to NULL and the next target
843 * examined (if that exists) becomes the main target. 843 * examined (if that exists) becomes the main target.
844 * 844 *
845 *----------------------------------------------------------------------- 845 *-----------------------------------------------------------------------
846 */ 846 */
847static int 847static int
848SuffScanTargets(void *targetp, void *gsp) 848SuffScanTargets(void *targetp, void *gsp)
849{ 849{
850 GNode *target = (GNode *)targetp; 850 GNode *target = (GNode *)targetp;
851 GNodeSuff *gs = (GNodeSuff *)gsp; 851 GNodeSuff *gs = (GNodeSuff *)gsp;
852 Suff *s, *t; 852 Suff *s, *t;
853 char *ptr; 853 char *ptr;
854 854
855 if (*gs->gn == NULL && gs->r && (target->type & OP_NOTARGET) == 0) { 855 if (*gs->gn == NULL && gs->r && (target->type & OP_NOTARGET) == 0) {
856 *gs->gn = target; 856 *gs->gn = target;
857 Targ_SetMain(target); 857 Targ_SetMain(target);
858 return 1; 858 return 1;
859 } 859 }
860 860
861 if (target->type == OP_TRANSFORM) 861 if (target->type == OP_TRANSFORM)
862 return 0; 862 return 0;
863 863
864 if ((ptr = strstr(target->name, gs->s->name)) == NULL || 864 if ((ptr = strstr(target->name, gs->s->name)) == NULL ||
865 ptr == target->name) 865 ptr == target->name)
866 return 0; 866 return 0;
867 867
868 if (SuffParseTransform(target->name, &s, &t)) { 868 if (SuffParseTransform(target->name, &s, &t)) {
869 if (*gs->gn == target) { 869 if (*gs->gn == target) {
870 gs->r = TRUE; 870 gs->r = TRUE;
871 *gs->gn = NULL; 871 *gs->gn = NULL;
872 Targ_SetMain(NULL); 872 Targ_SetMain(NULL);
873 } 873 }
874 Lst_Free(target->children); 874 Lst_Free(target->children);
875 target->children = Lst_Init(); 875 target->children = Lst_Init();
876 target->type = OP_TRANSFORM; 876 target->type = OP_TRANSFORM;
877 /* 877 /*
878 * link the two together in the proper relationship and order 878 * link the two together in the proper relationship and order
879 */ 879 */
880 if (DEBUG(SUFF)) { 880 if (DEBUG(SUFF)) {
881 fprintf(debug_file, "defining transformation from `%s' to `%s'\n", 881 fprintf(debug_file, "defining transformation from `%s' to `%s'\n",
882 s->name, t->name); 882 s->name, t->name);
883 } 883 }
884 SuffInsert(t->children, s); 884 SuffInsert(t->children, s);
885 SuffInsert(s->parents, t); 885 SuffInsert(s->parents, t);
886 } 886 }
887 return 0; 887 return 0;
888} 888}
889 889
890/*- 890/*-
891 *----------------------------------------------------------------------- 891 *-----------------------------------------------------------------------
892 * Suff_AddSuffix -- 892 * Suff_AddSuffix --
893 * Add the suffix in string to the end of the list of known suffixes. 893 * Add the suffix in string to the end of the list of known suffixes.
894 * Should we restructure the suffix graph? Make doesn't... 894 * Should we restructure the suffix graph? Make doesn't...
895 * 895 *
896 * Input: 896 * Input:
897 * str the name of the suffix to add 897 * str the name of the suffix to add
898 * 898 *
899 * Results: 899 * Results:
900 * None 900 * None
901 * 901 *
902 * Side Effects: 902 * Side Effects:
903 * A GNode is created for the suffix and a Suff structure is created and 903 * A GNode is created for the suffix and a Suff structure is created and
904 * added to the suffixes list unless the suffix was already known. 904 * added to the suffixes list unless the suffix was already known.
905 * The mainNode passed can be modified if a target mutated into a 905 * The mainNode passed can be modified if a target mutated into a
906 * transform and that target happened to be the main target. 906 * transform and that target happened to be the main target.
907 *----------------------------------------------------------------------- 907 *-----------------------------------------------------------------------
908 */ 908 */
909void 909void
910Suff_AddSuffix(char *str, GNode **gn) 910Suff_AddSuffix(char *str, GNode **gn)
911{ 911{
912 Suff *s; /* new suffix descriptor */ 912 Suff *s; /* new suffix descriptor */
913 LstNode ln; 913 LstNode ln;
914 GNodeSuff gs; 914 GNodeSuff gs;
915 915
916 ln = Lst_Find(sufflist, SuffSuffHasName, str); 916 ln = Lst_Find(sufflist, SuffSuffHasName, str);
917 if (ln == NULL) { 917 if (ln == NULL) {
918 s = SuffNew(str); 918 s = SuffNew(str);
919 919
920 Lst_Append(sufflist, s); 920 Lst_Append(sufflist, s);
921 /* 921 /*
922 * We also look at our existing targets list to see if adding 922 * We also look at our existing targets list to see if adding
923 * this suffix will make one of our current targets mutate into 923 * this suffix will make one of our current targets mutate into
924 * a suffix rule. This is ugly, but other makes treat all targets 924 * a suffix rule. This is ugly, but other makes treat all targets
925 * that start with a . as suffix rules. 925 * that start with a . as suffix rules.
926 */ 926 */
927 gs.gn = gn; 927 gs.gn = gn;
928 gs.s = s; 928 gs.s = s;
929 gs.r = FALSE; 929 gs.r = FALSE;
930 Lst_ForEach(Targ_List(), SuffScanTargets, &gs); 930 Lst_ForEach(Targ_List(), SuffScanTargets, &gs);
931 /* 931 /*
932 * Look for any existing transformations from or to this suffix. 932 * Look for any existing transformations from or to this suffix.
933 * XXX: Only do this after a Suff_ClearSuffixes? 933 * XXX: Only do this after a Suff_ClearSuffixes?
934 */ 934 */
935 Lst_ForEach(transforms, SuffRebuildGraph, s); 935 Lst_ForEach(transforms, SuffRebuildGraph, s);
936 } 936 }
937} 937}
938 938
939/*- 939/*-
940 *----------------------------------------------------------------------- 940 *-----------------------------------------------------------------------
941 * Suff_GetPath -- 941 * Suff_GetPath --
942 * Return the search path for the given suffix, if it's defined. 942 * Return the search path for the given suffix, if it's defined.
943 * 943 *
944 * Results: 944 * Results:
945 * The searchPath for the desired suffix or NULL if the suffix isn't 945 * The searchPath for the desired suffix or NULL if the suffix isn't
946 * defined. 946 * defined.
947 * 947 *
948 * Side Effects: 948 * Side Effects:
949 * None 949 * None
950 *----------------------------------------------------------------------- 950 *-----------------------------------------------------------------------
951 */ 951 */
952Lst 952Lst
953Suff_GetPath(char *sname) 953Suff_GetPath(char *sname)
954{ 954{
955 LstNode ln; 955 LstNode ln;
956 Suff *s; 956 Suff *s;
957 957
958 ln = Lst_Find(sufflist, SuffSuffHasName, sname); 958 ln = Lst_Find(sufflist, SuffSuffHasName, sname);
959 if (ln == NULL) { 959 if (ln == NULL) {
960 return NULL; 960 return NULL;
961 } else { 961 } else {
962 s = Lst_Datum(ln); 962 s = Lst_Datum(ln);
963 return s->searchPath; 963 return s->searchPath;
964 } 964 }
965} 965}
966 966
967/*- 967/*-
968 *----------------------------------------------------------------------- 968 *-----------------------------------------------------------------------
969 * Suff_DoPaths -- 969 * Suff_DoPaths --
970 * Extend the search paths for all suffixes to include the default 970 * Extend the search paths for all suffixes to include the default
971 * search path. 971 * search path.
972 * 972 *
973 * Results: 973 * Results:
974 * None. 974 * None.
975 * 975 *
976 * Side Effects: 976 * Side Effects:
977 * The searchPath field of all the suffixes is extended by the 977 * The searchPath field of all the suffixes is extended by the
978 * directories in dirSearchPath. If paths were specified for the 978 * directories in dirSearchPath. If paths were specified for the
979 * ".h" suffix, the directories are stuffed into a global variable 979 * ".h" suffix, the directories are stuffed into a global variable
980 * called ".INCLUDES" with each directory preceded by a -I. The same 980 * called ".INCLUDES" with each directory preceded by a -I. The same
981 * is done for the ".a" suffix, except the variable is called 981 * is done for the ".a" suffix, except the variable is called
982 * ".LIBS" and the flag is -L. 982 * ".LIBS" and the flag is -L.
983 *----------------------------------------------------------------------- 983 *-----------------------------------------------------------------------
984 */ 984 */
985void 985void
986Suff_DoPaths(void) 986Suff_DoPaths(void)
987{ 987{
988 Suff *s; 988 Suff *s;
989 LstNode ln; 989 LstNode ln;
990 char *ptr; 990 char *ptr;
991 Lst inIncludes; /* Cumulative .INCLUDES path */ 991 Lst inIncludes; /* Cumulative .INCLUDES path */
992 Lst inLibs; /* Cumulative .LIBS path */ 992 Lst inLibs; /* Cumulative .LIBS path */
993 993
994 994
995 inIncludes = Lst_Init(); 995 inIncludes = Lst_Init();
996 inLibs = Lst_Init(); 996 inLibs = Lst_Init();
997 997
998 Lst_Open(sufflist); 998 Lst_Open(sufflist);
999 while ((ln = Lst_Next(sufflist)) != NULL) { 999 while ((ln = Lst_Next(sufflist)) != NULL) {
1000 s = Lst_Datum(ln); 1000 s = Lst_Datum(ln);
1001 if (!Lst_IsEmpty(s->searchPath)) { 1001 if (!Lst_IsEmpty(s->searchPath)) {
1002#ifdef INCLUDES 1002#ifdef INCLUDES
1003 if (s->flags & SUFF_INCLUDE) { 1003 if (s->flags & SUFF_INCLUDE) {
1004 Dir_Concat(inIncludes, s->searchPath); 1004 Dir_Concat(inIncludes, s->searchPath);
1005 } 1005 }
1006#endif /* INCLUDES */ 1006#endif /* INCLUDES */
1007#ifdef LIBRARIES 1007#ifdef LIBRARIES
1008 if (s->flags & SUFF_LIBRARY) { 1008 if (s->flags & SUFF_LIBRARY) {
1009 Dir_Concat(inLibs, s->searchPath); 1009 Dir_Concat(inLibs, s->searchPath);
1010 } 1010 }
1011#endif /* LIBRARIES */ 1011#endif /* LIBRARIES */
1012 Dir_Concat(s->searchPath, dirSearchPath); 1012 Dir_Concat(s->searchPath, dirSearchPath);
1013 } else { 1013 } else {
1014 Lst_Destroy(s->searchPath, Dir_Destroy); 1014 Lst_Destroy(s->searchPath, Dir_Destroy);
1015 s->searchPath = Lst_Copy(dirSearchPath, Dir_CopyDir); 1015 s->searchPath = Lst_Copy(dirSearchPath, Dir_CopyDir);
1016 } 1016 }
1017 } 1017 }
1018 Lst_Close(sufflist); 1018 Lst_Close(sufflist);
1019 1019
1020 Var_Set(".INCLUDES", ptr = Dir_MakeFlags("-I", inIncludes), VAR_GLOBAL); 1020 Var_Set(".INCLUDES", ptr = Dir_MakeFlags("-I", inIncludes), VAR_GLOBAL);
1021 free(ptr); 1021 free(ptr);
1022 Var_Set(".LIBS", ptr = Dir_MakeFlags("-L", inLibs), VAR_GLOBAL); 1022 Var_Set(".LIBS", ptr = Dir_MakeFlags("-L", inLibs), VAR_GLOBAL);
1023 free(ptr); 1023 free(ptr);
1024 1024
1025 Lst_Destroy(inIncludes, Dir_Destroy); 1025 Lst_Destroy(inIncludes, Dir_Destroy);
1026 Lst_Destroy(inLibs, Dir_Destroy); 1026 Lst_Destroy(inLibs, Dir_Destroy);
1027} 1027}
1028 1028
1029/*- 1029/*-
1030 *----------------------------------------------------------------------- 1030 *-----------------------------------------------------------------------
1031 * Suff_AddInclude -- 1031 * Suff_AddInclude --
1032 * Add the given suffix as a type of file which gets included. 1032 * Add the given suffix as a type of file which gets included.
1033 * Called from the parse module when a .INCLUDES line is parsed. 1033 * Called from the parse module when a .INCLUDES line is parsed.
1034 * The suffix must have already been defined. 1034 * The suffix must have already been defined.
1035 * 1035 *
1036 * Input: 1036 * Input:
1037 * sname Name of the suffix to mark 1037 * sname Name of the suffix to mark
1038 * 1038 *
1039 * Results: 1039 * Results:
1040 * None. 1040 * None.
1041 * 1041 *
1042 * Side Effects: 1042 * Side Effects:
1043 * The SUFF_INCLUDE bit is set in the suffix's flags field 1043 * The SUFF_INCLUDE bit is set in the suffix's flags field
1044 * 1044 *
1045 *----------------------------------------------------------------------- 1045 *-----------------------------------------------------------------------
1046 */ 1046 */
1047void 1047void
1048Suff_AddInclude(char *sname) 1048Suff_AddInclude(char *sname)
1049{ 1049{
1050 LstNode ln; 1050 LstNode ln;
1051 Suff *s; 1051 Suff *s;
1052 1052
1053 ln = Lst_Find(sufflist, SuffSuffHasName, sname); 1053 ln = Lst_Find(sufflist, SuffSuffHasName, sname);
1054 if (ln != NULL) { 1054 if (ln != NULL) {
1055 s = Lst_Datum(ln); 1055 s = Lst_Datum(ln);
1056 s->flags |= SUFF_INCLUDE; 1056 s->flags |= SUFF_INCLUDE;
1057 } 1057 }
1058} 1058}
1059 1059
1060/*- 1060/*-
1061 *----------------------------------------------------------------------- 1061 *-----------------------------------------------------------------------
1062 * Suff_AddLib -- 1062 * Suff_AddLib --
1063 * Add the given suffix as a type of file which is a library. 1063 * Add the given suffix as a type of file which is a library.
1064 * Called from the parse module when parsing a .LIBS line. The 1064 * Called from the parse module when parsing a .LIBS line. The
1065 * suffix must have been defined via .SUFFIXES before this is 1065 * suffix must have been defined via .SUFFIXES before this is
1066 * called. 1066 * called.
1067 * 1067 *
1068 * Input: 1068 * Input:
1069 * sname Name of the suffix to mark 1069 * sname Name of the suffix to mark
1070 * 1070 *
1071 * Results: 1071 * Results:
1072 * None. 1072 * None.
1073 * 1073 *
1074 * Side Effects: 1074 * Side Effects:
1075 * The SUFF_LIBRARY bit is set in the suffix's flags field 1075 * The SUFF_LIBRARY bit is set in the suffix's flags field
1076 * 1076 *
1077 *----------------------------------------------------------------------- 1077 *-----------------------------------------------------------------------
1078 */ 1078 */
1079void 1079void
1080Suff_AddLib(char *sname) 1080Suff_AddLib(char *sname)
1081{ 1081{
1082 LstNode ln; 1082 LstNode ln;
1083 Suff *s; 1083 Suff *s;
1084 1084
1085 ln = Lst_Find(sufflist, SuffSuffHasName, sname); 1085 ln = Lst_Find(sufflist, SuffSuffHasName, sname);
1086 if (ln != NULL) { 1086 if (ln != NULL) {
1087 s = Lst_Datum(ln); 1087 s = Lst_Datum(ln);
1088 s->flags |= SUFF_LIBRARY; 1088 s->flags |= SUFF_LIBRARY;
1089 } 1089 }
1090} 1090}
1091 1091
1092 /********** Implicit Source Search Functions *********/ 1092 /********** Implicit Source Search Functions *********/
1093 1093
1094/*- 1094/*-
1095 *----------------------------------------------------------------------- 1095 *-----------------------------------------------------------------------
1096 * SuffAddSrc -- 1096 * SuffAddSrc --
1097 * Add a suffix as a Src structure to the given list with its parent 1097 * Add a suffix as a Src structure to the given list with its parent
1098 * being the given Src structure. If the suffix is the null suffix, 1098 * being the given Src structure. If the suffix is the null suffix,
1099 * the prefix is used unaltered as the file name in the Src structure. 1099 * the prefix is used unaltered as the file name in the Src structure.
1100 * 1100 *
1101 * Input: 1101 * Input:
1102 * sp suffix for which to create a Src structure 1102 * sp suffix for which to create a Src structure
1103 * lsp list and parent for the new Src 1103 * lsp list and parent for the new Src
1104 * 1104 *
1105 * Results: 1105 * Results:
1106 * always returns 0 1106 * always returns 0
1107 * 1107 *
1108 * Side Effects: 1108 * Side Effects:
1109 * A Src structure is created and tacked onto the end of the list 1109 * A Src structure is created and tacked onto the end of the list
1110 *----------------------------------------------------------------------- 1110 *-----------------------------------------------------------------------
1111 */ 1111 */
1112static int 1112static int
1113SuffAddSrc(void *sp, void *lsp) 1113SuffAddSrc(void *sp, void *lsp)
1114{ 1114{
1115 Suff *s = (Suff *)sp; 1115 Suff *s = (Suff *)sp;
1116 LstSrc *ls = (LstSrc *)lsp; 1116 LstSrc *ls = (LstSrc *)lsp;
1117 Src *s2; /* new Src structure */ 1117 Src *s2; /* new Src structure */
1118 Src *targ; /* Target structure */ 1118 Src *targ; /* Target structure */
1119 1119
1120 targ = ls->s; 1120 targ = ls->s;
1121 1121
1122 if ((s->flags & SUFF_NULL) && (*s->name != '\0')) { 1122 if ((s->flags & SUFF_NULL) && (*s->name != '\0')) {
1123 /* 1123 /*
1124 * If the suffix has been marked as the NULL suffix, also create a Src 1124 * If the suffix has been marked as the NULL suffix, also create a Src
1125 * structure for a file with no suffix attached. Two birds, and all 1125 * structure for a file with no suffix attached. Two birds, and all
1126 * that... 1126 * that...
1127 */ 1127 */
1128 s2 = bmake_malloc(sizeof(Src)); 1128 s2 = bmake_malloc(sizeof(Src));
1129 s2->file = bmake_strdup(targ->pref); 1129 s2->file = bmake_strdup(targ->pref);
1130 s2->pref = targ->pref; 1130 s2->pref = targ->pref;
1131 s2->parent = targ; 1131 s2->parent = targ;
1132 s2->node = NULL; 1132 s2->node = NULL;
1133 s2->suff = s; 1133 s2->suff = s;
1134 s->refCount++; 1134 s->refCount++;
1135 s2->children = 0; 1135 s2->children = 0;
1136 targ->children += 1; 1136 targ->children += 1;
1137 Lst_Append(ls->l, s2); 1137 Lst_Append(ls->l, s2);
1138#ifdef DEBUG_SRC 1138#ifdef DEBUG_SRC
1139 s2->cp = Lst_Init(); 1139 s2->cp = Lst_Init();
1140 Lst_Append(targ->cp, s2); 1140 Lst_Append(targ->cp, s2);
1141 fprintf(debug_file, "1 add %p %p to %p:", targ, s2, ls->l); 1141 fprintf(debug_file, "1 add %p %p to %p:", targ, s2, ls->l);
1142 Lst_ForEach(ls->l, PrintAddr, NULL); 1142 Lst_ForEach(ls->l, PrintAddr, NULL);
1143 fprintf(debug_file, "\n"); 1143 fprintf(debug_file, "\n");
1144#endif 1144#endif
1145 } 1145 }
1146 s2 = bmake_malloc(sizeof(Src)); 1146 s2 = bmake_malloc(sizeof(Src));
1147 s2->file = str_concat2(targ->pref, s->name); 1147 s2->file = str_concat2(targ->pref, s->name);
1148 s2->pref = targ->pref; 1148 s2->pref = targ->pref;
1149 s2->parent = targ; 1149 s2->parent = targ;
1150 s2->node = NULL; 1150 s2->node = NULL;
1151 s2->suff = s; 1151 s2->suff = s;
1152 s->refCount++; 1152 s->refCount++;
1153 s2->children = 0; 1153 s2->children = 0;
1154 targ->children += 1; 1154 targ->children += 1;
1155 Lst_Append(ls->l, s2); 1155 Lst_Append(ls->l, s2);
1156#ifdef DEBUG_SRC 1156#ifdef DEBUG_SRC
1157 s2->cp = Lst_Init(); 1157 s2->cp = Lst_Init();
1158 Lst_Append(targ->cp, s2); 1158 Lst_Append(targ->cp, s2);
1159 fprintf(debug_file, "2 add %p %p to %p:", targ, s2, ls->l); 1159 fprintf(debug_file, "2 add %p %p to %p:", targ, s2, ls->l);
1160 Lst_ForEach(ls->l, PrintAddr, NULL); 1160 Lst_ForEach(ls->l, PrintAddr, NULL);
1161 fprintf(debug_file, "\n"); 1161 fprintf(debug_file, "\n");
1162#endif 1162#endif
1163 1163
1164 return 0; 1164 return 0;
1165} 1165}
1166 1166
1167/*- 1167/*-
1168 *----------------------------------------------------------------------- 1168 *-----------------------------------------------------------------------
1169 * SuffAddLevel -- 1169 * SuffAddLevel --
1170 * Add all the children of targ as Src structures to the given list 1170 * Add all the children of targ as Src structures to the given list
1171 * 1171 *
1172 * Input: 1172 * Input:
1173 * l list to which to add the new level 1173 * l list to which to add the new level
1174 * targ Src structure to use as the parent 1174 * targ Src structure to use as the parent
1175 * 1175 *
1176 * Results: 1176 * Results:
1177 * None 1177 * None
1178 * 1178 *
1179 * Side Effects: 1179 * Side Effects:
1180 * Lots of structures are created and added to the list 1180 * Lots of structures are created and added to the list
1181 *----------------------------------------------------------------------- 1181 *-----------------------------------------------------------------------
1182 */ 1182 */
1183static void 1183static void
1184SuffAddLevel(Lst l, Src *targ) 1184SuffAddLevel(Lst l, Src *targ)
1185{ 1185{
1186 LstSrc ls; 1186 LstSrc ls;
1187 1187
1188 ls.s = targ; 1188 ls.s = targ;
1189 ls.l = l; 1189 ls.l = l;
1190 1190
1191 Lst_ForEach(targ->suff->children, SuffAddSrc, &ls); 1191 Lst_ForEach(targ->suff->children, SuffAddSrc, &ls);
1192} 1192}
1193 1193
1194/*- 1194/*-
1195 *---------------------------------------------------------------------- 1195 *----------------------------------------------------------------------
1196 * SuffRemoveSrc -- 1196 * SuffRemoveSrc --
1197 * Free all src structures in list that don't have a reference count 1197 * Free all src structures in list that don't have a reference count
1198 * 1198 *
1199 * Results: 1199 * Results:
1200 * Ture if an src was removed 1200 * Ture if an src was removed
1201 * 1201 *
1202 * Side Effects: 1202 * Side Effects:
1203 * The memory is free'd. 1203 * The memory is free'd.
1204 *---------------------------------------------------------------------- 1204 *----------------------------------------------------------------------
1205 */ 1205 */
1206static int 1206static int
1207SuffRemoveSrc(Lst l) 1207SuffRemoveSrc(Lst l)
1208{ 1208{
1209 LstNode ln; 1209 LstNode ln;
1210 Src *s; 1210 Src *s;
1211 int t = 0; 1211 int t = 0;
1212 1212
1213 Lst_Open(l); 1213 Lst_Open(l);
1214 1214
1215#ifdef DEBUG_SRC 1215#ifdef DEBUG_SRC
1216 fprintf(debug_file, "cleaning %lx: ", (unsigned long) l); 1216 fprintf(debug_file, "cleaning %lx: ", (unsigned long) l);
1217 Lst_ForEach(l, PrintAddr, NULL); 1217 Lst_ForEach(l, PrintAddr, NULL);
1218 fprintf(debug_file, "\n"); 1218 fprintf(debug_file, "\n");
1219#endif 1219#endif
1220 1220
1221 1221
1222 while ((ln = Lst_Next(l)) != NULL) { 1222 while ((ln = Lst_Next(l)) != NULL) {
1223 s = Lst_Datum(ln); 1223 s = Lst_Datum(ln);
1224 if (s->children == 0) { 1224 if (s->children == 0) {
1225 free(s->file); 1225 free(s->file);
1226 if (!s->parent) 1226 if (!s->parent)
1227 free(s->pref); 1227 free(s->pref);
1228 else { 1228 else {
1229#ifdef DEBUG_SRC 1229#ifdef DEBUG_SRC
1230 LstNode ln2 = Lst_Member(s->parent->cp, s); 1230 LstNode ln2 = Lst_Member(s->parent->cp, s);
1231 if (ln2 != NULL) 1231 if (ln2 != NULL)
1232 Lst_Remove(s->parent->cp, ln2); 1232 Lst_Remove(s->parent->cp, ln2);
1233#endif 1233#endif
1234 --s->parent->children; 1234 --s->parent->children;
1235 } 1235 }
1236#ifdef DEBUG_SRC 1236#ifdef DEBUG_SRC
1237 fprintf(debug_file, "free: [l=%p] p=%p %d\n", l, s, s->children); 1237 fprintf(debug_file, "free: [l=%p] p=%p %d\n", l, s, s->children);
1238 Lst_Free(s->cp); 1238 Lst_Free(s->cp);
1239#endif 1239#endif
1240 Lst_Remove(l, ln); 1240 Lst_Remove(l, ln);
1241 free(s); 1241 free(s);
1242 t |= 1; 1242 t |= 1;
1243 Lst_Close(l); 1243 Lst_Close(l);
1244 return TRUE; 1244 return TRUE;
1245 } 1245 }
1246#ifdef DEBUG_SRC 1246#ifdef DEBUG_SRC
1247 else { 1247 else {
1248 fprintf(debug_file, "keep: [l=%p] p=%p %d: ", l, s, s->children); 1248 fprintf(debug_file, "keep: [l=%p] p=%p %d: ", l, s, s->children);
1249 Lst_ForEach(s->cp, PrintAddr, NULL); 1249 Lst_ForEach(s->cp, PrintAddr, NULL);
1250 fprintf(debug_file, "\n"); 1250 fprintf(debug_file, "\n");
1251 } 1251 }
1252#endif 1252#endif
1253 } 1253 }
1254 1254
1255 Lst_Close(l); 1255 Lst_Close(l);
1256 1256
1257 return t; 1257 return t;
1258} 1258}
1259 1259
1260/*- 1260/*-
1261 *----------------------------------------------------------------------- 1261 *-----------------------------------------------------------------------
1262 * SuffFindThem -- 1262 * SuffFindThem --
1263 * Find the first existing file/target in the list srcs 1263 * Find the first existing file/target in the list srcs
1264 * 1264 *
1265 * Input: 1265 * Input:
1266 * srcs list of Src structures to search through 1266 * srcs list of Src structures to search through
1267 * 1267 *
1268 * Results: 1268 * Results:
1269 * The lowest structure in the chain of transformations 1269 * The lowest structure in the chain of transformations
1270 * 1270 *
1271 * Side Effects: 1271 * Side Effects:
1272 * None 1272 * None
1273 *----------------------------------------------------------------------- 1273 *-----------------------------------------------------------------------
1274 */ 1274 */
1275static Src * 1275static Src *
1276SuffFindThem(Lst srcs, Lst slst) 1276SuffFindThem(Lst srcs, Lst slst)
1277{ 1277{
1278 Src *s; /* current Src */ 1278 Src *s; /* current Src */
1279 Src *rs; /* returned Src */ 1279 Src *rs; /* returned Src */
1280 char *ptr; 1280 char *ptr;
1281 1281
1282 rs = NULL; 1282 rs = NULL;
1283 1283
1284 while (!Lst_IsEmpty(srcs)) { 1284 while (!Lst_IsEmpty(srcs)) {
1285 s = Lst_Dequeue(srcs); 1285 s = Lst_Dequeue(srcs);
1286 1286
1287 if (DEBUG(SUFF)) { 1287 if (DEBUG(SUFF)) {
1288 fprintf(debug_file, "\ttrying %s...", s->file); 1288 fprintf(debug_file, "\ttrying %s...", s->file);
1289 } 1289 }
1290 1290
1291 /* 1291 /*
1292 * A file is considered to exist if either a node exists in the 1292 * A file is considered to exist if either a node exists in the
1293 * graph for it or the file actually exists. 1293 * graph for it or the file actually exists.
1294 */ 1294 */
1295 if (Targ_FindNode(s->file, TARG_NOCREATE) != NULL) { 1295 if (Targ_FindNode(s->file, TARG_NOCREATE) != NULL) {
1296#ifdef DEBUG_SRC 1296#ifdef DEBUG_SRC
1297 fprintf(debug_file, "remove %p from %p\n", s, srcs); 1297 fprintf(debug_file, "remove %p from %p\n", s, srcs);
1298#endif 1298#endif
1299 rs = s; 1299 rs = s;
1300 break; 1300 break;
1301 } 1301 }
1302 1302
1303 if ((ptr = Dir_FindFile(s->file, s->suff->searchPath)) != NULL) { 1303 if ((ptr = Dir_FindFile(s->file, s->suff->searchPath)) != NULL) {
1304 rs = s; 1304 rs = s;
1305#ifdef DEBUG_SRC 1305#ifdef DEBUG_SRC
1306 fprintf(debug_file, "remove %p from %p\n", s, srcs); 1306 fprintf(debug_file, "remove %p from %p\n", s, srcs);
1307#endif 1307#endif
1308 free(ptr); 1308 free(ptr);
1309 break; 1309 break;
1310 } 1310 }
1311 1311
1312 if (DEBUG(SUFF)) { 1312 if (DEBUG(SUFF)) {
1313 fprintf(debug_file, "not there\n"); 1313 fprintf(debug_file, "not there\n");
1314 } 1314 }
1315 1315
1316 SuffAddLevel(srcs, s); 1316 SuffAddLevel(srcs, s);
1317 Lst_Append(slst, s); 1317 Lst_Append(slst, s);
1318 } 1318 }
1319 1319
1320 if (DEBUG(SUFF) && rs) { 1320 if (DEBUG(SUFF) && rs) {
1321 fprintf(debug_file, "got it\n"); 1321 fprintf(debug_file, "got it\n");
1322 } 1322 }
1323 return rs; 1323 return rs;
1324} 1324}
1325 1325
1326/*- 1326/*-
1327 *----------------------------------------------------------------------- 1327 *-----------------------------------------------------------------------
1328 * SuffFindCmds -- 1328 * SuffFindCmds --
1329 * See if any of the children of the target in the Src structure is 1329 * See if any of the children of the target in the Src structure is
1330 * one from which the target can be transformed. If there is one, 1330 * one from which the target can be transformed. If there is one,
1331 * a Src structure is put together for it and returned. 1331 * a Src structure is put together for it and returned.
1332 * 1332 *
1333 * Input: 1333 * Input:
1334 * targ Src structure to play with 1334 * targ Src structure to play with
1335 * 1335 *
1336 * Results: 1336 * Results:
1337 * The Src structure of the "winning" child, or NULL if no such beast. 1337 * The Src structure of the "winning" child, or NULL if no such beast.
1338 * 1338 *
1339 * Side Effects: 1339 * Side Effects:
1340 * A Src structure may be allocated. 1340 * A Src structure may be allocated.
1341 * 1341 *
1342 *----------------------------------------------------------------------- 1342 *-----------------------------------------------------------------------
1343 */ 1343 */
1344static Src * 1344static Src *
1345SuffFindCmds(Src *targ, Lst slst) 1345SuffFindCmds(Src *targ, Lst slst)
1346{ 1346{
1347 LstNode ln; /* General-purpose list node */ 1347 LstNode ln; /* General-purpose list node */
1348 GNode *t, /* Target GNode */ 1348 GNode *t, /* Target GNode */
1349 *s; /* Source GNode */ 1349 *s; /* Source GNode */
1350 int prefLen;/* The length of the defined prefix */ 1350 int prefLen;/* The length of the defined prefix */
1351 Suff *suff; /* Suffix on matching beastie */ 1351 Suff *suff; /* Suffix on matching beastie */
1352 Src *ret; /* Return value */ 1352 Src *ret; /* Return value */
1353 char *cp; 1353 char *cp;
1354 1354
1355 t = targ->node; 1355 t = targ->node;
1356 Lst_Open(t->children); 1356 Lst_Open(t->children);
1357 prefLen = strlen(targ->pref); 1357 prefLen = strlen(targ->pref);
1358 1358
1359 for (;;) { 1359 for (;;) {
1360 ln = Lst_Next(t->children); 1360 ln = Lst_Next(t->children);
1361 if (ln == NULL) { 1361 if (ln == NULL) {
1362 Lst_Close(t->children); 1362 Lst_Close(t->children);
1363 return NULL; 1363 return NULL;
1364 } 1364 }
1365 s = Lst_Datum(ln); 1365 s = Lst_Datum(ln);
1366 1366
1367 if (s->type & OP_OPTIONAL && Lst_IsEmpty(t->commands)) { 1367 if (s->type & OP_OPTIONAL && Lst_IsEmpty(t->commands)) {
1368 /* 1368 /*
1369 * We haven't looked to see if .OPTIONAL files exist yet, so 1369 * We haven't looked to see if .OPTIONAL files exist yet, so
1370 * don't use one as the implicit source. 1370 * don't use one as the implicit source.
1371 * This allows us to use .OPTIONAL in .depend files so make won't 1371 * This allows us to use .OPTIONAL in .depend files so make won't
1372 * complain "don't know how to make xxx.h' when a dependent file 1372 * complain "don't know how to make xxx.h' when a dependent file
1373 * has been moved/deleted. 1373 * has been moved/deleted.
1374 */ 1374 */
1375 continue; 1375 continue;
1376 } 1376 }
1377 1377
1378 cp = strrchr(s->name, '/'); 1378 cp = strrchr(s->name, '/');
1379 if (cp == NULL) { 1379 if (cp == NULL) {
1380 cp = s->name; 1380 cp = s->name;
1381 } else { 1381 } else {
1382 cp++; 1382 cp++;
1383 } 1383 }
1384 if (strncmp(cp, targ->pref, prefLen) != 0) 1384 if (strncmp(cp, targ->pref, prefLen) != 0)
1385 continue; 1385 continue;
1386 /* 1386 /*
1387 * The node matches the prefix ok, see if it has a known 1387 * The node matches the prefix ok, see if it has a known
1388 * suffix. 1388 * suffix.
1389 */ 1389 */
1390 ln = Lst_Find(sufflist, SuffSuffHasName, &cp[prefLen]); 1390 ln = Lst_Find(sufflist, SuffSuffHasName, &cp[prefLen]);
1391 if (ln == NULL) 1391 if (ln == NULL)
1392 continue; 1392 continue;
1393 /* 1393 /*
1394 * It even has a known suffix, see if there's a transformation 1394 * It even has a known suffix, see if there's a transformation
1395 * defined between the node's suffix and the target's suffix. 1395 * defined between the node's suffix and the target's suffix.
1396 * 1396 *
1397 * XXX: Handle multi-stage transformations here, too. 1397 * XXX: Handle multi-stage transformations here, too.
1398 */ 1398 */
1399 suff = Lst_Datum(ln); 1399 suff = Lst_Datum(ln);
1400 1400
1401 /* XXX: Can targ->suff be NULL here? */ 1401 /* XXX: Can targ->suff be NULL here? */
1402 if (targ->suff != NULL && 1402 if (targ->suff != NULL &&
1403 Lst_Member(suff->parents, targ->suff) != NULL) 1403 Lst_Member(suff->parents, targ->suff) != NULL)
1404 break; 1404 break;
1405 } 1405 }
1406 1406
1407 /* 1407 /*
1408 * Hot Damn! Create a new Src structure to describe 1408 * Hot Damn! Create a new Src structure to describe
1409 * this transformation (making sure to duplicate the 1409 * this transformation (making sure to duplicate the
1410 * source node's name so Suff_FindDeps can free it 1410 * source node's name so Suff_FindDeps can free it
1411 * again (ick)), and return the new structure. 1411 * again (ick)), and return the new structure.
1412 */ 1412 */
1413 ret = bmake_malloc(sizeof(Src)); 1413 ret = bmake_malloc(sizeof(Src));
1414 ret->file = bmake_strdup(s->name); 1414 ret->file = bmake_strdup(s->name);
1415 ret->pref = targ->pref; 1415 ret->pref = targ->pref;
1416 ret->suff = suff; 1416 ret->suff = suff;
1417 suff->refCount++; 1417 suff->refCount++;
1418 ret->parent = targ; 1418 ret->parent = targ;
1419 ret->node = s; 1419 ret->node = s;
1420 ret->children = 0; 1420 ret->children = 0;
1421 targ->children += 1; 1421 targ->children += 1;
1422#ifdef DEBUG_SRC 1422#ifdef DEBUG_SRC
1423 ret->cp = Lst_Init(); 1423 ret->cp = Lst_Init();
1424 fprintf(debug_file, "3 add %p %p\n", targ, ret); 1424 fprintf(debug_file, "3 add %p %p\n", targ, ret);
1425 Lst_Append(targ->cp, ret); 1425 Lst_Append(targ->cp, ret);
1426#endif 1426#endif
1427 Lst_Append(slst, ret); 1427 Lst_Append(slst, ret);
1428 if (DEBUG(SUFF)) { 1428 if (DEBUG(SUFF)) {
1429 fprintf(debug_file, "\tusing existing source %s\n", s->name); 1429 fprintf(debug_file, "\tusing existing source %s\n", s->name);
1430 } 1430 }
1431 return ret; 1431 return ret;
1432} 1432}
1433 1433
1434/*- 1434/*-
1435 *----------------------------------------------------------------------- 1435 *-----------------------------------------------------------------------
1436 * SuffExpandChildren -- 1436 * SuffExpandChildren --
1437 * Expand the names of any children of a given node that contain 1437 * Expand the names of any children of a given node that contain
1438 * variable invocations or file wildcards into actual targets. 1438 * variable invocations or file wildcards into actual targets.
1439 * 1439 *
1440 * Input: 1440 * Input:
1441 * cln Child to examine 1441 * cln Child to examine
1442 * pgn Parent node being processed 1442 * pgn Parent node being processed
1443 * 1443 *
1444 * Results: 1444 * Results:
1445 * === 0 (continue) 1445 * === 0 (continue)
1446 * 1446 *
1447 * Side Effects: 1447 * Side Effects:
1448 * The expanded node is removed from the parent's list of children, 1448 * The expanded node is removed from the parent's list of children,
1449 * and the parent's unmade counter is decremented, but other nodes 1449 * and the parent's unmade counter is decremented, but other nodes
1450 * may be added. 1450 * may be added.
1451 * 1451 *
1452 *----------------------------------------------------------------------- 1452 *-----------------------------------------------------------------------
1453 */ 1453 */
1454static void 1454static void
1455SuffExpandChildren(LstNode cln, GNode *pgn) 1455SuffExpandChildren(LstNode cln, GNode *pgn)
1456{ 1456{
1457 GNode *cgn = Lst_Datum(cln); 1457 GNode *cgn = Lst_Datum(cln);
1458 GNode *gn; /* New source 8) */ 1458 GNode *gn; /* New source 8) */
1459 char *cp; /* Expanded value */ 1459 char *cp; /* Expanded value */
1460 1460
1461 if (!Lst_IsEmpty(cgn->order_pred) || !Lst_IsEmpty(cgn->order_succ)) 1461 if (!Lst_IsEmpty(cgn->order_pred) || !Lst_IsEmpty(cgn->order_succ))
1462 /* It is all too hard to process the result of .ORDER */ 1462 /* It is all too hard to process the result of .ORDER */
1463 return; 1463 return;
1464 1464
1465 if (cgn->type & OP_WAIT) 1465 if (cgn->type & OP_WAIT)
1466 /* Ignore these (& OP_PHONY ?) */ 1466 /* Ignore these (& OP_PHONY ?) */
1467 return; 1467 return;
1468 1468
1469 /* 1469 /*
1470 * First do variable expansion -- this takes precedence over 1470 * First do variable expansion -- this takes precedence over
1471 * wildcard expansion. If the result contains wildcards, they'll be gotten 1471 * wildcard expansion. If the result contains wildcards, they'll be gotten
1472 * to later since the resulting words are tacked on to the end of 1472 * to later since the resulting words are tacked on to the end of
1473 * the children list. 1473 * the children list.
1474 */ 1474 */
1475 if (strchr(cgn->name, '$') == NULL) { 1475 if (strchr(cgn->name, '$') == NULL) {
1476 SuffExpandWildcards(cln, pgn); 1476 SuffExpandWildcards(cln, pgn);
1477 return; 1477 return;
1478 } 1478 }
1479 1479
1480 if (DEBUG(SUFF)) { 1480 if (DEBUG(SUFF)) {
1481 fprintf(debug_file, "Expanding \"%s\"...", cgn->name); 1481 fprintf(debug_file, "Expanding \"%s\"...", cgn->name);
1482 } 1482 }
1483 cp = Var_Subst(cgn->name, pgn, VARE_UNDEFERR|VARE_WANTRES); 1483 cp = Var_Subst(cgn->name, pgn, VARE_UNDEFERR|VARE_WANTRES);
1484 1484
1485 if (cp != NULL) { 1485 if (cp != NULL) {
1486 Lst members = Lst_Init(); 1486 Lst members = Lst_Init();
1487 1487
1488 if (cgn->type & OP_ARCHV) { 1488 if (cgn->type & OP_ARCHV) {
1489 /* 1489 /*
1490 * Node was an archive(member) target, so we want to call 1490 * Node was an archive(member) target, so we want to call
1491 * on the Arch module to find the nodes for us, expanding 1491 * on the Arch module to find the nodes for us, expanding
1492 * variables in the parent's context. 1492 * variables in the parent's context.
1493 */ 1493 */
1494 char *sacrifice = cp; 1494 char *sacrifice = cp;
1495 1495
1496 (void)Arch_ParseArchive(&sacrifice, members, pgn); 1496 (void)Arch_ParseArchive(&sacrifice, members, pgn);
1497 } else { 1497 } else {
1498 /* 1498 /*
1499 * Break the result into a vector of strings whose nodes 1499 * Break the result into a vector of strings whose nodes
1500 * we can find, then add those nodes to the members list. 1500 * we can find, then add those nodes to the members list.
1501 * Unfortunately, we can't use brk_string b/c it 1501 * Unfortunately, we can't use brk_string b/c it
1502 * doesn't understand about variable specifications with 1502 * doesn't understand about variable specifications with
1503 * spaces in them... 1503 * spaces in them...
1504 */ 1504 */
1505 char *start; 1505 char *start;
1506 char *initcp = cp; /* For freeing... */ 1506 char *initcp = cp; /* For freeing... */
1507 1507
1508 for (start = cp; *start == ' ' || *start == '\t'; start++) 1508 for (start = cp; *start == ' ' || *start == '\t'; start++)
1509 continue; 1509 continue;
1510 for (cp = start; *cp != '\0'; cp++) { 1510 for (cp = start; *cp != '\0'; cp++) {
1511 if (*cp == ' ' || *cp == '\t') { 1511 if (*cp == ' ' || *cp == '\t') {
1512 /* 1512 /*
1513 * White-space -- terminate element, find the node, 1513 * White-space -- terminate element, find the node,
1514 * add it, skip any further spaces. 1514 * add it, skip any further spaces.
1515 */ 1515 */
1516 *cp++ = '\0'; 1516 *cp++ = '\0';
1517 gn = Targ_FindNode(start, TARG_CREATE); 1517 gn = Targ_FindNode(start, TARG_CREATE);
1518 Lst_Append(members, gn); 1518 Lst_Append(members, gn);
1519 while (*cp == ' ' || *cp == '\t') { 1519 while (*cp == ' ' || *cp == '\t') {
1520 cp++; 1520 cp++;
1521 } 1521 }
1522 /* 1522 /*
1523 * Adjust cp for increment at start of loop, but 1523 * Adjust cp for increment at start of loop, but
1524 * set start to first non-space. 1524 * set start to first non-space.
1525 */ 1525 */
1526 start = cp--; 1526 start = cp--;
1527 } else if (*cp == '$') { 1527 } else if (*cp == '$') {
1528 /* 1528 /*
1529 * Start of a variable spec -- contact variable module 1529 * Start of a variable spec -- contact variable module
1530 * to find the end so we can skip over it. 1530 * to find the end so we can skip over it.
1531 */ 1531 */
1532 const char *junk; 1532 const char *junk;
1533 int len; 1533 int len;
1534 void *freeIt; 1534 void *freeIt;
1535 1535
1536 junk = Var_Parse(cp, pgn, VARE_UNDEFERR|VARE_WANTRES, 1536 junk = Var_Parse(cp, pgn, VARE_UNDEFERR|VARE_WANTRES,
1537 &len, &freeIt); 1537 &len, &freeIt);
1538 if (junk != var_Error) { 1538 if (junk != var_Error) {
1539 cp += len - 1; 1539 cp += len - 1;
1540 } 1540 }
1541 1541
1542 free(freeIt); 1542 free(freeIt);
1543 } else if (*cp == '\\' && cp[1] != '\0') { 1543 } else if (*cp == '\\' && cp[1] != '\0') {
1544 /* 1544 /*
1545 * Escaped something -- skip over it 1545 * Escaped something -- skip over it
1546 */ 1546 */
1547 cp++; 1547 cp++;
1548 } 1548 }
1549 } 1549 }
1550 1550
1551 if (cp != start) { 1551 if (cp != start) {
1552 /* 1552 /*
1553 * Stuff left over -- add it to the list too 1553 * Stuff left over -- add it to the list too
1554 */ 1554 */
1555 gn = Targ_FindNode(start, TARG_CREATE); 1555 gn = Targ_FindNode(start, TARG_CREATE);
1556 Lst_Append(members, gn); 1556 Lst_Append(members, gn);
1557 } 1557 }
1558 /* 1558 /*
1559 * Point cp back at the beginning again so the variable value 1559 * Point cp back at the beginning again so the variable value
1560 * can be freed. 1560 * can be freed.
1561 */ 1561 */
1562 cp = initcp; 1562 cp = initcp;
1563 } 1563 }
1564 1564
1565 /* 1565 /*
1566 * Add all elements of the members list to the parent node. 1566 * Add all elements of the members list to the parent node.
1567 */ 1567 */
1568 while(!Lst_IsEmpty(members)) { 1568 while(!Lst_IsEmpty(members)) {
1569 gn = Lst_Dequeue(members); 1569 gn = Lst_Dequeue(members);
1570 1570
1571 if (DEBUG(SUFF)) { 1571 if (DEBUG(SUFF)) {
1572 fprintf(debug_file, "%s...", gn->name); 1572 fprintf(debug_file, "%s...", gn->name);
1573 } 1573 }
1574 /* Add gn to the parents child list before the original child */ 1574 /* Add gn to the parents child list before the original child */
1575 Lst_InsertBefore(pgn->children, cln, gn); 1575 Lst_InsertBefore(pgn->children, cln, gn);
1576 Lst_Append(gn->parents, pgn); 1576 Lst_Append(gn->parents, pgn);
1577 pgn->unmade++; 1577 pgn->unmade++;
1578 /* Expand wildcards on new node */ 1578 /* Expand wildcards on new node */
1579 SuffExpandWildcards(Lst_Prev(cln), pgn); 1579 SuffExpandWildcards(LstNode_Prev(cln), pgn);
1580 } 1580 }
1581 Lst_Free(members); 1581 Lst_Free(members);
1582 1582
1583 /* 1583 /*
1584 * Free the result 1584 * Free the result
1585 */ 1585 */
1586 free(cp); 1586 free(cp);
1587 } 1587 }
1588 if (DEBUG(SUFF)) { 1588 if (DEBUG(SUFF)) {
1589 fprintf(debug_file, "\n"); 1589 fprintf(debug_file, "\n");
1590 } 1590 }
1591 1591
1592 /* 1592 /*
1593 * Now the source is expanded, remove it from the list of children to 1593 * Now the source is expanded, remove it from the list of children to
1594 * keep it from being processed. 1594 * keep it from being processed.
1595 */ 1595 */
1596 pgn->unmade--; 1596 pgn->unmade--;
1597 Lst_Remove(pgn->children, cln); 1597 Lst_Remove(pgn->children, cln);
1598 Lst_Remove(cgn->parents, Lst_Member(cgn->parents, pgn)); 1598 Lst_Remove(cgn->parents, Lst_Member(cgn->parents, pgn));
1599} 1599}
1600 1600
1601static void 1601static void
1602SuffExpandWildcards(LstNode cln, GNode *pgn) 1602SuffExpandWildcards(LstNode cln, GNode *pgn)
1603{ 1603{
1604 GNode *cgn = Lst_Datum(cln); 1604 GNode *cgn = Lst_Datum(cln);
1605 GNode *gn; /* New source 8) */ 1605 GNode *gn; /* New source 8) */
1606 char *cp; /* Expanded value */ 1606 char *cp; /* Expanded value */
1607 Lst explist; /* List of expansions */ 1607 Lst explist; /* List of expansions */
1608 1608
1609 if (!Dir_HasWildcards(cgn->name)) 1609 if (!Dir_HasWildcards(cgn->name))
1610 return; 1610 return;
1611 1611
1612 /* 1612 /*
1613 * Expand the word along the chosen path 1613 * Expand the word along the chosen path
1614 */ 1614 */
1615 explist = Lst_Init(); 1615 explist = Lst_Init();
1616 Dir_Expand(cgn->name, Suff_FindPath(cgn), explist); 1616 Dir_Expand(cgn->name, Suff_FindPath(cgn), explist);
1617 1617
1618 while (!Lst_IsEmpty(explist)) { 1618 while (!Lst_IsEmpty(explist)) {
1619 /* 1619 /*
1620 * Fetch next expansion off the list and find its GNode 1620 * Fetch next expansion off the list and find its GNode
1621 */ 1621 */
1622 cp = Lst_Dequeue(explist); 1622 cp = Lst_Dequeue(explist);
1623 1623
1624 if (DEBUG(SUFF)) { 1624 if (DEBUG(SUFF)) {
1625 fprintf(debug_file, "%s...", cp); 1625 fprintf(debug_file, "%s...", cp);
1626 } 1626 }
1627 gn = Targ_FindNode(cp, TARG_CREATE); 1627 gn = Targ_FindNode(cp, TARG_CREATE);
1628 1628
1629 /* Add gn to the parents child list before the original child */ 1629 /* Add gn to the parents child list before the original child */
1630 Lst_InsertBefore(pgn->children, cln, gn); 1630 Lst_InsertBefore(pgn->children, cln, gn);
1631 Lst_Append(gn->parents, pgn); 1631 Lst_Append(gn->parents, pgn);
1632 pgn->unmade++; 1632 pgn->unmade++;
1633 } 1633 }
1634 1634
1635 Lst_Free(explist); 1635 Lst_Free(explist);
1636 1636
1637 if (DEBUG(SUFF)) { 1637 if (DEBUG(SUFF)) {
1638 fprintf(debug_file, "\n"); 1638 fprintf(debug_file, "\n");
1639 } 1639 }
1640 1640
1641 /* 1641 /*
1642 * Now the source is expanded, remove it from the list of children to 1642 * Now the source is expanded, remove it from the list of children to
1643 * keep it from being processed. 1643 * keep it from being processed.
1644 */ 1644 */
1645 pgn->unmade--; 1645 pgn->unmade--;
1646 Lst_Remove(pgn->children, cln); 1646 Lst_Remove(pgn->children, cln);
1647 Lst_Remove(cgn->parents, Lst_Member(cgn->parents, pgn)); 1647 Lst_Remove(cgn->parents, Lst_Member(cgn->parents, pgn));
1648} 1648}
1649 1649
1650/*- 1650/*-
1651 *----------------------------------------------------------------------- 1651 *-----------------------------------------------------------------------
1652 * Suff_FindPath -- 1652 * Suff_FindPath --
1653 * Find a path along which to expand the node. 1653 * Find a path along which to expand the node.
1654 * 1654 *
1655 * If the word has a known suffix, use that path. 1655 * If the word has a known suffix, use that path.
1656 * If it has no known suffix, use the default system search path. 1656 * If it has no known suffix, use the default system search path.
1657 * 1657 *
1658 * Input: 1658 * Input:
1659 * gn Node being examined 1659 * gn Node being examined
1660 * 1660 *
1661 * Results: 1661 * Results:
1662 * The appropriate path to search for the GNode. 1662 * The appropriate path to search for the GNode.
1663 * 1663 *
1664 * Side Effects: 1664 * Side Effects:
1665 * XXX: We could set the suffix here so that we don't have to scan 1665 * XXX: We could set the suffix here so that we don't have to scan
1666 * again. 1666 * again.
1667 * 1667 *
1668 *----------------------------------------------------------------------- 1668 *-----------------------------------------------------------------------
1669 */ 1669 */
1670Lst 1670Lst
1671Suff_FindPath(GNode* gn) 1671Suff_FindPath(GNode* gn)
1672{ 1672{
1673 Suff *suff = gn->suffix; 1673 Suff *suff = gn->suffix;
1674 1674
1675 if (suff == NULL) { 1675 if (suff == NULL) {
1676 SuffSuffGetSuffixArgs sd; /* Search string data */ 1676 SuffSuffGetSuffixArgs sd; /* Search string data */
1677 LstNode ln; 1677 LstNode ln;
1678 sd.len = strlen(gn->name); 1678 sd.len = strlen(gn->name);
1679 sd.ename = gn->name + sd.len; 1679 sd.ename = gn->name + sd.len;
1680 ln = Lst_Find(sufflist, SuffSuffIsSuffix, &sd); 1680 ln = Lst_Find(sufflist, SuffSuffIsSuffix, &sd);
1681 1681
1682 if (DEBUG(SUFF)) { 1682 if (DEBUG(SUFF)) {
1683 fprintf(debug_file, "Wildcard expanding \"%s\"...", gn->name); 1683 fprintf(debug_file, "Wildcard expanding \"%s\"...", gn->name);
1684 } 1684 }
1685 if (ln != NULL) 1685 if (ln != NULL)
1686 suff = Lst_Datum(ln); 1686 suff = Lst_Datum(ln);
1687 /* XXX: Here we can save the suffix so we don't have to do this again */ 1687 /* XXX: Here we can save the suffix so we don't have to do this again */
1688 } 1688 }
1689 1689
1690 if (suff != NULL) { 1690 if (suff != NULL) {
1691 if (DEBUG(SUFF)) { 1691 if (DEBUG(SUFF)) {
1692 fprintf(debug_file, "suffix is \"%s\"...", suff->name); 1692 fprintf(debug_file, "suffix is \"%s\"...", suff->name);
1693 } 1693 }
1694 return suff->searchPath; 1694 return suff->searchPath;
1695 } else { 1695 } else {
1696 /* 1696 /*
1697 * Use default search path 1697 * Use default search path
1698 */ 1698 */
1699 return dirSearchPath; 1699 return dirSearchPath;
1700 } 1700 }
1701} 1701}
1702 1702
1703/*- 1703/*-
1704 *----------------------------------------------------------------------- 1704 *-----------------------------------------------------------------------
1705 * SuffApplyTransform -- 1705 * SuffApplyTransform --
1706 * Apply a transformation rule, given the source and target nodes 1706 * Apply a transformation rule, given the source and target nodes
1707 * and suffixes. 1707 * and suffixes.
1708 * 1708 *
1709 * Input: 1709 * Input:
1710 * tGn Target node 1710 * tGn Target node
1711 * sGn Source node 1711 * sGn Source node
1712 * t Target suffix 1712 * t Target suffix
1713 * s Source suffix 1713 * s Source suffix
1714 * 1714 *
1715 * Results: 1715 * Results:
1716 * TRUE if successful, FALSE if not. 1716 * TRUE if successful, FALSE if not.
1717 * 1717 *
1718 * Side Effects: 1718 * Side Effects:
1719 * The source and target are linked and the commands from the 1719 * The source and target are linked and the commands from the
1720 * transformation are added to the target node's commands list. 1720 * transformation are added to the target node's commands list.
1721 * All attributes but OP_DEPMASK and OP_TRANSFORM are applied 1721 * All attributes but OP_DEPMASK and OP_TRANSFORM are applied
1722 * to the target. The target also inherits all the sources for 1722 * to the target. The target also inherits all the sources for
1723 * the transformation rule. 1723 * the transformation rule.
1724 * 1724 *
1725 *----------------------------------------------------------------------- 1725 *-----------------------------------------------------------------------
1726 */ 1726 */
1727static Boolean 1727static Boolean
1728SuffApplyTransform(GNode *tGn, GNode *sGn, Suff *t, Suff *s) 1728SuffApplyTransform(GNode *tGn, GNode *sGn, Suff *t, Suff *s)
1729{ 1729{
1730 LstNode ln, nln; /* General node */ 1730 LstNode ln, nln; /* General node */
1731 char *tname; /* Name of transformation rule */ 1731 char *tname; /* Name of transformation rule */
1732 GNode *gn; /* Node for same */ 1732 GNode *gn; /* Node for same */
1733 1733
1734 /* 1734 /*
1735 * Form the proper links between the target and source. 1735 * Form the proper links between the target and source.
1736 */ 1736 */
1737 Lst_Append(tGn->children, sGn); 1737 Lst_Append(tGn->children, sGn);
1738 Lst_Append(sGn->parents, tGn); 1738 Lst_Append(sGn->parents, tGn);
1739 tGn->unmade += 1; 1739 tGn->unmade += 1;
1740 1740
1741 /* 1741 /*
1742 * Locate the transformation rule itself 1742 * Locate the transformation rule itself
1743 */ 1743 */
1744 tname = str_concat2(s->name, t->name); 1744 tname = str_concat2(s->name, t->name);
1745 ln = Lst_Find(transforms, SuffGNHasName, tname); 1745 ln = Lst_Find(transforms, SuffGNHasName, tname);
1746 free(tname); 1746 free(tname);
1747 1747
1748 if (ln == NULL) { 1748 if (ln == NULL) {
1749 /* 1749 /*
1750 * Not really such a transformation rule (can happen when we're 1750 * Not really such a transformation rule (can happen when we're
1751 * called to link an OP_MEMBER and OP_ARCHV node), so return 1751 * called to link an OP_MEMBER and OP_ARCHV node), so return
1752 * FALSE. 1752 * FALSE.
1753 */ 1753 */
1754 return FALSE; 1754 return FALSE;
1755 } 1755 }
1756 1756
1757 gn = Lst_Datum(ln); 1757 gn = Lst_Datum(ln);
1758 1758
1759 if (DEBUG(SUFF)) { 1759 if (DEBUG(SUFF)) {
1760 fprintf(debug_file, "\tapplying %s -> %s to \"%s\"\n", s->name, t->name, tGn->name); 1760 fprintf(debug_file, "\tapplying %s -> %s to \"%s\"\n", s->name, t->name, tGn->name);
1761 } 1761 }
1762 1762
1763 /* 1763 /*
1764 * Record last child for expansion purposes 1764 * Record last child for expansion purposes
1765 */ 1765 */
1766 ln = Lst_Last(tGn->children); 1766 ln = Lst_Last(tGn->children);
1767 1767
1768 /* 1768 /*
1769 * Pass the buck to Make_HandleUse to apply the rule 1769 * Pass the buck to Make_HandleUse to apply the rule
1770 */ 1770 */
1771 (void)Make_HandleUse(gn, tGn); 1771 (void)Make_HandleUse(gn, tGn);
1772 1772
1773 /* 1773 /*
1774 * Deal with wildcards and variables in any acquired sources 1774 * Deal with wildcards and variables in any acquired sources
1775 */ 1775 */
1776 for (ln = ln != NULL ? Lst_Succ(ln) : NULL; ln != NULL; ln = nln) { 1776 for (ln = ln != NULL ? LstNode_Next(ln) : NULL; ln != NULL; ln = nln) {
1777 nln = Lst_Succ(ln); 1777 nln = LstNode_Next(ln);
1778 SuffExpandChildren(ln, tGn); 1778 SuffExpandChildren(ln, tGn);
1779 } 1779 }
1780 1780
1781 /* 1781 /*
1782 * Keep track of another parent to which this beast is transformed so 1782 * Keep track of another parent to which this beast is transformed so
1783 * the .IMPSRC variable can be set correctly for the parent. 1783 * the .IMPSRC variable can be set correctly for the parent.
1784 */ 1784 */
1785 Lst_Append(sGn->iParents, tGn); 1785 Lst_Append(sGn->iParents, tGn);
1786 1786
1787 return TRUE; 1787 return TRUE;
1788} 1788}
1789 1789
1790 1790
1791/*- 1791/*-
1792 *----------------------------------------------------------------------- 1792 *-----------------------------------------------------------------------
1793 * SuffFindArchiveDeps -- 1793 * SuffFindArchiveDeps --
1794 * Locate dependencies for an OP_ARCHV node. 1794 * Locate dependencies for an OP_ARCHV node.
1795 * 1795 *
1796 * Input: 1796 * Input:
1797 * gn Node for which to locate dependencies 1797 * gn Node for which to locate dependencies
1798 * 1798 *
1799 * Results: 1799 * Results:
1800 * None 1800 * None
1801 * 1801 *
1802 * Side Effects: 1802 * Side Effects:
1803 * Same as Suff_FindDeps 1803 * Same as Suff_FindDeps
1804 * 1804 *
1805 *----------------------------------------------------------------------- 1805 *-----------------------------------------------------------------------
1806 */ 1806 */
1807static void 1807static void
1808SuffFindArchiveDeps(GNode *gn, Lst slst) 1808SuffFindArchiveDeps(GNode *gn, Lst slst)
1809{ 1809{
1810 char *eoarch; /* End of archive portion */ 1810 char *eoarch; /* End of archive portion */
1811 char *eoname; /* End of member portion */ 1811 char *eoname; /* End of member portion */
1812 GNode *mem; /* Node for member */ 1812 GNode *mem; /* Node for member */
1813 LstNode ln, nln; /* Next suffix node to check */ 1813 LstNode ln, nln; /* Next suffix node to check */
1814 Suff *ms; /* Suffix descriptor for member */ 1814 Suff *ms; /* Suffix descriptor for member */
1815 char *name; /* Start of member's name */ 1815 char *name; /* Start of member's name */
1816 1816
1817 /* 1817 /*
1818 * The node is an archive(member) pair. so we must find a 1818 * The node is an archive(member) pair. so we must find a
1819 * suffix for both of them. 1819 * suffix for both of them.
1820 */ 1820 */
1821 eoarch = strchr(gn->name, '('); 1821 eoarch = strchr(gn->name, '(');
1822 eoname = strchr(eoarch, ')'); 1822 eoname = strchr(eoarch, ')');
1823 1823
1824 /* 1824 /*
1825 * Caller guarantees the format `libname(member)', via 1825 * Caller guarantees the format `libname(member)', via
1826 * Arch_ParseArchive. 1826 * Arch_ParseArchive.
1827 */ 1827 */
1828 assert(eoarch != NULL); 1828 assert(eoarch != NULL);
1829 assert(eoname != NULL); 1829 assert(eoname != NULL);
1830 1830
1831 *eoname = '\0'; /* Nuke parentheses during suffix search */ 1831 *eoname = '\0'; /* Nuke parentheses during suffix search */
1832 *eoarch = '\0'; /* So a suffix can be found */ 1832 *eoarch = '\0'; /* So a suffix can be found */
1833 1833
1834 name = eoarch + 1; 1834 name = eoarch + 1;
1835 1835
1836 /* 1836 /*
1837 * To simplify things, call Suff_FindDeps recursively on the member now, 1837 * To simplify things, call Suff_FindDeps recursively on the member now,
1838 * so we can simply compare the member's .PREFIX and .TARGET variables 1838 * so we can simply compare the member's .PREFIX and .TARGET variables
1839 * to locate its suffix. This allows us to figure out the suffix to 1839 * to locate its suffix. This allows us to figure out the suffix to
1840 * use for the archive without having to do a quadratic search over the 1840 * use for the archive without having to do a quadratic search over the
1841 * suffix list, backtracking for each one... 1841 * suffix list, backtracking for each one...
1842 */ 1842 */
1843 mem = Targ_FindNode(name, TARG_CREATE); 1843 mem = Targ_FindNode(name, TARG_CREATE);
1844 SuffFindDeps(mem, slst); 1844 SuffFindDeps(mem, slst);
1845 1845
1846 /* 1846 /*
1847 * Create the link between the two nodes right off 1847 * Create the link between the two nodes right off
1848 */ 1848 */
1849 Lst_Append(gn->children, mem); 1849 Lst_Append(gn->children, mem);
1850 Lst_Append(mem->parents, gn); 1850 Lst_Append(mem->parents, gn);
1851 gn->unmade += 1; 1851 gn->unmade += 1;
1852 1852
1853 /* 1853 /*
1854 * Copy in the variables from the member node to this one. 1854 * Copy in the variables from the member node to this one.
1855 */ 1855 */
1856 { 1856 {
1857 char *freeIt; 1857 char *freeIt;
1858 Var_Set(PREFIX, Var_Value(PREFIX, mem, &freeIt), gn); 1858 Var_Set(PREFIX, Var_Value(PREFIX, mem, &freeIt), gn);
1859 bmake_free(freeIt); 1859 bmake_free(freeIt);
1860 Var_Set(TARGET, Var_Value(TARGET, mem, &freeIt), gn); 1860 Var_Set(TARGET, Var_Value(TARGET, mem, &freeIt), gn);
1861 bmake_free(freeIt); 1861 bmake_free(freeIt);
1862 } 1862 }
1863 1863
1864 ms = mem->suffix; 1864 ms = mem->suffix;
1865 if (ms == NULL) { 1865 if (ms == NULL) {
1866 /* 1866 /*
1867 * Didn't know what it was -- use .NULL suffix if not in make mode 1867 * Didn't know what it was -- use .NULL suffix if not in make mode
1868 */ 1868 */
1869 if (DEBUG(SUFF)) { 1869 if (DEBUG(SUFF)) {
1870 fprintf(debug_file, "using null suffix\n"); 1870 fprintf(debug_file, "using null suffix\n");
1871 } 1871 }
1872 ms = suffNull; 1872 ms = suffNull;
1873 } 1873 }
1874 1874
1875 1875
1876 /* 1876 /*
1877 * Set the other two local variables required for this target. 1877 * Set the other two local variables required for this target.
1878 */ 1878 */
1879 Var_Set(MEMBER, name, gn); 1879 Var_Set(MEMBER, name, gn);
1880 Var_Set(ARCHIVE, gn->name, gn); 1880 Var_Set(ARCHIVE, gn->name, gn);
1881 1881
1882 /* 1882 /*
1883 * Set $@ for compatibility with other makes 1883 * Set $@ for compatibility with other makes
1884 */ 1884 */
1885 Var_Set(TARGET, gn->name, gn); 1885 Var_Set(TARGET, gn->name, gn);
1886 1886
1887 /* 1887 /*
1888 * Now we've got the important local variables set, expand any sources 1888 * Now we've got the important local variables set, expand any sources
1889 * that still contain variables or wildcards in their names. 1889 * that still contain variables or wildcards in their names.
1890 */ 1890 */
1891 for (ln = Lst_First(gn->children); ln != NULL; ln = nln) { 1891 for (ln = Lst_First(gn->children); ln != NULL; ln = nln) {
1892 nln = Lst_Succ(ln); 1892 nln = LstNode_Next(ln);
1893 SuffExpandChildren(ln, gn); 1893 SuffExpandChildren(ln, gn);
1894 } 1894 }
1895 1895
1896 if (ms != NULL) { 1896 if (ms != NULL) {
1897 /* 1897 /*
1898 * Member has a known suffix, so look for a transformation rule from 1898 * Member has a known suffix, so look for a transformation rule from
1899 * it to a possible suffix of the archive. Rather than searching 1899 * it to a possible suffix of the archive. Rather than searching
1900 * through the entire list, we just look at suffixes to which the 1900 * through the entire list, we just look at suffixes to which the
1901 * member's suffix may be transformed... 1901 * member's suffix may be transformed...
1902 */ 1902 */
1903 SuffSuffGetSuffixArgs sd; /* Search string data */ 1903 SuffSuffGetSuffixArgs sd; /* Search string data */
1904 1904
1905 /* 1905 /*
1906 * Use first matching suffix... 1906 * Use first matching suffix...
1907 */ 1907 */
1908 sd.len = eoarch - gn->name; 1908 sd.len = eoarch - gn->name;
1909 sd.ename = eoarch; 1909 sd.ename = eoarch;
1910 ln = Lst_Find(ms->parents, SuffSuffIsSuffix, &sd); 1910 ln = Lst_Find(ms->parents, SuffSuffIsSuffix, &sd);
1911 1911
1912 if (ln != NULL) { 1912 if (ln != NULL) {
1913 /* 1913 /*
1914 * Got one -- apply it 1914 * Got one -- apply it
1915 */ 1915 */
1916 if (!SuffApplyTransform(gn, mem, (Suff *)Lst_Datum(ln), ms) && 1916 if (!SuffApplyTransform(gn, mem, (Suff *)Lst_Datum(ln), ms) &&
1917 DEBUG(SUFF)) 1917 DEBUG(SUFF))
1918 { 1918 {
1919 fprintf(debug_file, "\tNo transformation from %s -> %s\n", 1919 fprintf(debug_file, "\tNo transformation from %s -> %s\n",
1920 ms->name, ((Suff *)Lst_Datum(ln))->name); 1920 ms->name, ((Suff *)Lst_Datum(ln))->name);
1921 } 1921 }
1922 } 1922 }
1923 } 1923 }
1924 1924
1925 /* 1925 /*
1926 * Replace the opening and closing parens now we've no need of the separate 1926 * Replace the opening and closing parens now we've no need of the separate
1927 * pieces. 1927 * pieces.
1928 */ 1928 */
1929 *eoarch = '('; *eoname = ')'; 1929 *eoarch = '('; *eoname = ')';
1930 1930
1931 /* 1931 /*
1932 * Pretend gn appeared to the left of a dependency operator so 1932 * Pretend gn appeared to the left of a dependency operator so
1933 * the user needn't provide a transformation from the member to the 1933 * the user needn't provide a transformation from the member to the
1934 * archive. 1934 * archive.
1935 */ 1935 */
1936 if (OP_NOP(gn->type)) { 1936 if (OP_NOP(gn->type)) {
1937 gn->type |= OP_DEPENDS; 1937 gn->type |= OP_DEPENDS;
1938 } 1938 }
1939 1939
1940 /* 1940 /*
1941 * Flag the member as such so we remember to look in the archive for 1941 * Flag the member as such so we remember to look in the archive for
1942 * its modification time. The OP_JOIN | OP_MADE is needed because this 1942 * its modification time. The OP_JOIN | OP_MADE is needed because this
1943 * target should never get made. 1943 * target should never get made.
1944 */ 1944 */
1945 mem->type |= OP_MEMBER | OP_JOIN | OP_MADE; 1945 mem->type |= OP_MEMBER | OP_JOIN | OP_MADE;
1946} 1946}
1947 1947
1948/*- 1948/*-
1949 *----------------------------------------------------------------------- 1949 *-----------------------------------------------------------------------
1950 * SuffFindNormalDeps -- 1950 * SuffFindNormalDeps --
1951 * Locate implicit dependencies for regular targets. 1951 * Locate implicit dependencies for regular targets.
1952 * 1952 *
1953 * Input: 1953 * Input:
1954 * gn Node for which to find sources 1954 * gn Node for which to find sources
1955 * 1955 *
1956 * Results: 1956 * Results:
1957 * None. 1957 * None.
1958 * 1958 *
1959 * Side Effects: 1959 * Side Effects:
1960 * Same as Suff_FindDeps... 1960 * Same as Suff_FindDeps...
1961 * 1961 *
1962 *----------------------------------------------------------------------- 1962 *-----------------------------------------------------------------------
1963 */ 1963 */
1964static void 1964static void
1965SuffFindNormalDeps(GNode *gn, Lst slst) 1965SuffFindNormalDeps(GNode *gn, Lst slst)
1966{ 1966{
1967 char *eoname; /* End of name */ 1967 char *eoname; /* End of name */
1968 char *sopref; /* Start of prefix */ 1968 char *sopref; /* Start of prefix */
1969 LstNode ln, nln; /* Next suffix node to check */ 1969 LstNode ln, nln; /* Next suffix node to check */
1970 Lst srcs; /* List of sources at which to look */ 1970 Lst srcs; /* List of sources at which to look */
1971 Lst targs; /* List of targets to which things can be 1971 Lst targs; /* List of targets to which things can be
1972 * transformed. They all have the same file, 1972 * transformed. They all have the same file,
1973 * but different suff and pref fields */ 1973 * but different suff and pref fields */
1974 Src *bottom; /* Start of found transformation path */ 1974 Src *bottom; /* Start of found transformation path */
1975 Src *src; /* General Src pointer */ 1975 Src *src; /* General Src pointer */
1976 char *pref; /* Prefix to use */ 1976 char *pref; /* Prefix to use */
1977 Src *targ; /* General Src target pointer */ 1977 Src *targ; /* General Src target pointer */
1978 SuffSuffGetSuffixArgs sd; /* Search string data */ 1978 SuffSuffGetSuffixArgs sd; /* Search string data */
1979 1979
1980 1980
1981 sd.len = strlen(gn->name); 1981 sd.len = strlen(gn->name);
1982 sd.ename = eoname = gn->name + sd.len; 1982 sd.ename = eoname = gn->name + sd.len;
1983 1983
1984 sopref = gn->name; 1984 sopref = gn->name;
1985 1985
1986 /* 1986 /*
1987 * Begin at the beginning... 1987 * Begin at the beginning...
1988 */ 1988 */
1989 ln = Lst_First(sufflist); 1989 ln = Lst_First(sufflist);
1990 srcs = Lst_Init(); 1990 srcs = Lst_Init();
1991 targs = Lst_Init(); 1991 targs = Lst_Init();
1992 1992
1993 /* 1993 /*
1994 * We're caught in a catch-22 here. On the one hand, we want to use any 1994 * We're caught in a catch-22 here. On the one hand, we want to use any
1995 * transformation implied by the target's sources, but we can't examine 1995 * transformation implied by the target's sources, but we can't examine
1996 * the sources until we've expanded any variables/wildcards they may hold, 1996 * the sources until we've expanded any variables/wildcards they may hold,
1997 * and we can't do that until we've set up the target's local variables 1997 * and we can't do that until we've set up the target's local variables
1998 * and we can't do that until we know what the proper suffix for the 1998 * and we can't do that until we know what the proper suffix for the
1999 * target is (in case there are two suffixes one of which is a suffix of 1999 * target is (in case there are two suffixes one of which is a suffix of
2000 * the other) and we can't know that until we've found its implied 2000 * the other) and we can't know that until we've found its implied
2001 * source, which we may not want to use if there's an existing source 2001 * source, which we may not want to use if there's an existing source
2002 * that implies a different transformation. 2002 * that implies a different transformation.
2003 * 2003 *
2004 * In an attempt to get around this, which may not work all the time, 2004 * In an attempt to get around this, which may not work all the time,
2005 * but should work most of the time, we look for implied sources first, 2005 * but should work most of the time, we look for implied sources first,
2006 * checking transformations to all possible suffixes of the target, 2006 * checking transformations to all possible suffixes of the target,
2007 * use what we find to set the target's local variables, expand the 2007 * use what we find to set the target's local variables, expand the
2008 * children, then look for any overriding transformations they imply. 2008 * children, then look for any overriding transformations they imply.
2009 * Should we find one, we discard the one we found before. 2009 * Should we find one, we discard the one we found before.
2010 */ 2010 */
2011 bottom = NULL; 2011 bottom = NULL;
2012 targ = NULL; 2012 targ = NULL;
2013 2013
2014 if (!(gn->type & OP_PHONY)) { 2014 if (!(gn->type & OP_PHONY)) {
2015 2015
2016 while (ln != NULL) { 2016 while (ln != NULL) {
2017 /* 2017 /*
2018 * Look for next possible suffix... 2018 * Look for next possible suffix...
2019 */ 2019 */
2020 ln = Lst_FindFrom(sufflist, ln, SuffSuffIsSuffix, &sd); 2020 ln = Lst_FindFrom(sufflist, ln, SuffSuffIsSuffix, &sd);
2021 2021
2022 if (ln != NULL) { 2022 if (ln != NULL) {
2023 int prefLen; /* Length of the prefix */ 2023 int prefLen; /* Length of the prefix */
2024 2024
2025 /* 2025 /*
2026 * Allocate a Src structure to which things can be transformed 2026 * Allocate a Src structure to which things can be transformed
2027 */ 2027 */
2028 targ = bmake_malloc(sizeof(Src)); 2028 targ = bmake_malloc(sizeof(Src));
2029 targ->file = bmake_strdup(gn->name); 2029 targ->file = bmake_strdup(gn->name);
2030 targ->suff = Lst_Datum(ln); 2030 targ->suff = Lst_Datum(ln);
2031 targ->suff->refCount++; 2031 targ->suff->refCount++;
2032 targ->node = gn; 2032 targ->node = gn;
2033 targ->parent = NULL; 2033 targ->parent = NULL;
2034 targ->children = 0; 2034 targ->children = 0;
2035#ifdef DEBUG_SRC 2035#ifdef DEBUG_SRC
2036 targ->cp = Lst_Init(); 2036 targ->cp = Lst_Init();
2037#endif 2037#endif
2038 2038
2039 /* 2039 /*
2040 * Allocate room for the prefix, whose end is found by 2040 * Allocate room for the prefix, whose end is found by
2041 * subtracting the length of the suffix from 2041 * subtracting the length of the suffix from
2042 * the end of the name. 2042 * the end of the name.
2043 */ 2043 */
2044 prefLen = (eoname - targ->suff->nameLen) - sopref; 2044 prefLen = (eoname - targ->suff->nameLen) - sopref;
2045 targ->pref = bmake_malloc(prefLen + 1); 2045 targ->pref = bmake_malloc(prefLen + 1);
2046 memcpy(targ->pref, sopref, prefLen); 2046 memcpy(targ->pref, sopref, prefLen);
2047 targ->pref[prefLen] = '\0'; 2047 targ->pref[prefLen] = '\0';
2048 2048
2049 /* 2049 /*
2050 * Add nodes from which the target can be made 2050 * Add nodes from which the target can be made
2051 */ 2051 */
2052 SuffAddLevel(srcs, targ); 2052 SuffAddLevel(srcs, targ);
2053 2053
2054 /* 2054 /*
2055 * Record the target so we can nuke it 2055 * Record the target so we can nuke it
2056 */ 2056 */
2057 Lst_Append(targs, targ); 2057 Lst_Append(targs, targ);
2058 2058
2059 /* 2059 /*
2060 * Search from this suffix's successor... 2060 * Search from this suffix's successor...
2061 */ 2061 */
2062 ln = Lst_Succ(ln); 2062 ln = LstNode_Next(ln);
2063 } 2063 }
2064 } 2064 }
2065 2065
2066 /* 2066 /*
2067 * Handle target of unknown suffix... 2067 * Handle target of unknown suffix...
2068 */ 2068 */
2069 if (Lst_IsEmpty(targs) && suffNull != NULL) { 2069 if (Lst_IsEmpty(targs) && suffNull != NULL) {
2070 if (DEBUG(SUFF)) { 2070 if (DEBUG(SUFF)) {
2071 fprintf(debug_file, "\tNo known suffix on %s. Using .NULL suffix\n", gn->name); 2071 fprintf(debug_file, "\tNo known suffix on %s. Using .NULL suffix\n", gn->name);
2072 } 2072 }
2073 2073
2074 targ = bmake_malloc(sizeof(Src)); 2074 targ = bmake_malloc(sizeof(Src));
2075 targ->file = bmake_strdup(gn->name); 2075 targ->file = bmake_strdup(gn->name);
2076 targ->suff = suffNull; 2076 targ->suff = suffNull;
2077 targ->suff->refCount++; 2077 targ->suff->refCount++;
2078 targ->node = gn; 2078 targ->node = gn;
2079 targ->parent = NULL; 2079 targ->parent = NULL;
2080 targ->children = 0; 2080 targ->children = 0;
2081 targ->pref = bmake_strdup(sopref); 2081 targ->pref = bmake_strdup(sopref);
2082#ifdef DEBUG_SRC 2082#ifdef DEBUG_SRC
2083 targ->cp = Lst_Init(); 2083 targ->cp = Lst_Init();
2084#endif 2084#endif
2085 2085
2086 /* 2086 /*
2087 * Only use the default suffix rules if we don't have commands 2087 * Only use the default suffix rules if we don't have commands
2088 * defined for this gnode; traditional make programs used to 2088 * defined for this gnode; traditional make programs used to
2089 * not define suffix rules if the gnode had children but we 2089 * not define suffix rules if the gnode had children but we
2090 * don't do this anymore. 2090 * don't do this anymore.
2091 */ 2091 */
2092 if (Lst_IsEmpty(gn->commands)) 2092 if (Lst_IsEmpty(gn->commands))
2093 SuffAddLevel(srcs, targ); 2093 SuffAddLevel(srcs, targ);
2094 else { 2094 else {
2095 if (DEBUG(SUFF)) 2095 if (DEBUG(SUFF))
2096 fprintf(debug_file, "not "); 2096 fprintf(debug_file, "not ");
2097 } 2097 }
2098 2098
2099 if (DEBUG(SUFF)) 2099 if (DEBUG(SUFF))
2100 fprintf(debug_file, "adding suffix rules\n"); 2100 fprintf(debug_file, "adding suffix rules\n");
2101 2101
2102 Lst_Append(targs, targ); 2102 Lst_Append(targs, targ);
2103 } 2103 }
2104 2104
2105 /* 2105 /*
2106 * Using the list of possible sources built up from the target 2106 * Using the list of possible sources built up from the target
2107 * suffix(es), try and find an existing file/target that matches. 2107 * suffix(es), try and find an existing file/target that matches.
2108 */ 2108 */
2109 bottom = SuffFindThem(srcs, slst); 2109 bottom = SuffFindThem(srcs, slst);
2110 2110
2111 if (bottom == NULL) { 2111 if (bottom == NULL) {
2112 /* 2112 /*
2113 * No known transformations -- use the first suffix found 2113 * No known transformations -- use the first suffix found
2114 * for setting the local variables. 2114 * for setting the local variables.
2115 */ 2115 */
2116 if (!Lst_IsEmpty(targs)) { 2116 if (!Lst_IsEmpty(targs)) {
2117 targ = Lst_Datum(Lst_First(targs)); 2117 targ = Lst_Datum(Lst_First(targs));
2118 } else { 2118 } else {
2119 targ = NULL; 2119 targ = NULL;
2120 } 2120 }
2121 } else { 2121 } else {
2122 /* 2122 /*
2123 * Work up the transformation path to find the suffix of the 2123 * Work up the transformation path to find the suffix of the
2124 * target to which the transformation was made. 2124 * target to which the transformation was made.
2125 */ 2125 */
2126 for (targ = bottom; targ->parent != NULL; targ = targ->parent) 2126 for (targ = bottom; targ->parent != NULL; targ = targ->parent)
2127 continue; 2127 continue;
2128 } 2128 }
2129 } 2129 }
2130 2130
2131 Var_Set(TARGET, gn->path ? gn->path : gn->name, gn); 2131 Var_Set(TARGET, gn->path ? gn->path : gn->name, gn);
2132 2132
2133 pref = (targ != NULL) ? targ->pref : gn->name; 2133 pref = (targ != NULL) ? targ->pref : gn->name;
2134 Var_Set(PREFIX, pref, gn); 2134 Var_Set(PREFIX, pref, gn);
2135 2135
2136 /* 2136 /*
2137 * Now we've got the important local variables set, expand any sources 2137 * Now we've got the important local variables set, expand any sources
2138 * that still contain variables or wildcards in their names. 2138 * that still contain variables or wildcards in their names.
2139 */ 2139 */
2140 for (ln = Lst_First(gn->children); ln != NULL; ln = nln) { 2140 for (ln = Lst_First(gn->children); ln != NULL; ln = nln) {
2141 nln = Lst_Succ(ln); 2141 nln = LstNode_Next(ln);
2142 SuffExpandChildren(ln, gn); 2142 SuffExpandChildren(ln, gn);
2143 } 2143 }
2144 2144
2145 if (targ == NULL) { 2145 if (targ == NULL) {
2146 if (DEBUG(SUFF)) { 2146 if (DEBUG(SUFF)) {
2147 fprintf(debug_file, "\tNo valid suffix on %s\n", gn->name); 2147 fprintf(debug_file, "\tNo valid suffix on %s\n", gn->name);
2148 } 2148 }
2149 2149
2150sfnd_abort: 2150sfnd_abort:
2151 /* 2151 /*
2152 * Deal with finding the thing on the default search path. We 2152 * Deal with finding the thing on the default search path. We
2153 * always do that, not only if the node is only a source (not 2153 * always do that, not only if the node is only a source (not
2154 * on the lhs of a dependency operator or [XXX] it has neither 2154 * on the lhs of a dependency operator or [XXX] it has neither
2155 * children or commands) as the old pmake did. 2155 * children or commands) as the old pmake did.
2156 */ 2156 */
2157 if ((gn->type & (OP_PHONY|OP_NOPATH)) == 0) { 2157 if ((gn->type & (OP_PHONY|OP_NOPATH)) == 0) {
2158 free(gn->path); 2158 free(gn->path);
2159 gn->path = Dir_FindFile(gn->name, 2159 gn->path = Dir_FindFile(gn->name,
2160 (targ == NULL ? dirSearchPath : 2160 (targ == NULL ? dirSearchPath :
2161 targ->suff->searchPath)); 2161 targ->suff->searchPath));
2162 if (gn->path != NULL) { 2162 if (gn->path != NULL) {
2163 char *ptr; 2163 char *ptr;
2164 Var_Set(TARGET, gn->path, gn); 2164 Var_Set(TARGET, gn->path, gn);
2165 2165
2166 if (targ != NULL) { 2166 if (targ != NULL) {
2167 /* 2167 /*
2168 * Suffix known for the thing -- trim the suffix off 2168 * Suffix known for the thing -- trim the suffix off
2169 * the path to form the proper .PREFIX variable. 2169 * the path to form the proper .PREFIX variable.
2170 */ 2170 */
2171 int savep = strlen(gn->path) - targ->suff->nameLen; 2171 int savep = strlen(gn->path) - targ->suff->nameLen;
2172 char savec; 2172 char savec;
2173 2173
2174 if (gn->suffix) 2174 if (gn->suffix)
2175 gn->suffix->refCount--; 2175 gn->suffix->refCount--;
2176 gn->suffix = targ->suff; 2176 gn->suffix = targ->suff;
2177 gn->suffix->refCount++; 2177 gn->suffix->refCount++;
2178 2178
2179 savec = gn->path[savep]; 2179 savec = gn->path[savep];
2180 gn->path[savep] = '\0'; 2180 gn->path[savep] = '\0';
2181 2181
2182 if ((ptr = strrchr(gn->path, '/')) != NULL) 2182 if ((ptr = strrchr(gn->path, '/')) != NULL)
2183 ptr++; 2183 ptr++;
2184 else 2184 else
2185 ptr = gn->path; 2185 ptr = gn->path;
2186 2186
2187 Var_Set(PREFIX, ptr, gn); 2187 Var_Set(PREFIX, ptr, gn);
2188 2188
2189 gn->path[savep] = savec; 2189 gn->path[savep] = savec;
2190 } else { 2190 } else {
2191 /* 2191 /*
2192 * The .PREFIX gets the full path if the target has 2192 * The .PREFIX gets the full path if the target has
2193 * no known suffix. 2193 * no known suffix.
2194 */ 2194 */
2195 if (gn->suffix) 2195 if (gn->suffix)
2196 gn->suffix->refCount--; 2196 gn->suffix->refCount--;
2197 gn->suffix = NULL; 2197 gn->suffix = NULL;
2198 2198
2199 if ((ptr = strrchr(gn->path, '/')) != NULL) 2199 if ((ptr = strrchr(gn->path, '/')) != NULL)
2200 ptr++; 2200 ptr++;
2201 else 2201 else
2202 ptr = gn->path; 2202 ptr = gn->path;
2203 2203
2204 Var_Set(PREFIX, ptr, gn); 2204 Var_Set(PREFIX, ptr, gn);
2205 } 2205 }
2206 } 2206 }
2207 } 2207 }
2208 2208
2209 goto sfnd_return; 2209 goto sfnd_return;
2210 } 2210 }
2211 2211
2212 /* 2212 /*
2213 * If the suffix indicates that the target is a library, mark that in 2213 * If the suffix indicates that the target is a library, mark that in
2214 * the node's type field. 2214 * the node's type field.
2215 */ 2215 */
2216 if (targ->suff->flags & SUFF_LIBRARY) { 2216 if (targ->suff->flags & SUFF_LIBRARY) {
2217 gn->type |= OP_LIB; 2217 gn->type |= OP_LIB;
2218 } 2218 }
2219 2219
2220 /* 2220 /*
2221 * Check for overriding transformation rule implied by sources 2221 * Check for overriding transformation rule implied by sources
2222 */ 2222 */
2223 if (!Lst_IsEmpty(gn->children)) { 2223 if (!Lst_IsEmpty(gn->children)) {
2224 src = SuffFindCmds(targ, slst); 2224 src = SuffFindCmds(targ, slst);
2225 2225
2226 if (src != NULL) { 2226 if (src != NULL) {
2227 /* 2227 /*
2228 * Free up all the Src structures in the transformation path 2228 * Free up all the Src structures in the transformation path
2229 * up to, but not including, the parent node. 2229 * up to, but not including, the parent node.
2230 */ 2230 */
2231 while (bottom && bottom->parent != NULL) { 2231 while (bottom && bottom->parent != NULL) {
2232 if (Lst_Member(slst, bottom) == NULL) { 2232 if (Lst_Member(slst, bottom) == NULL) {
2233 Lst_Append(slst, bottom); 2233 Lst_Append(slst, bottom);
2234 } 2234 }
2235 bottom = bottom->parent; 2235 bottom = bottom->parent;
2236 } 2236 }
2237 bottom = src; 2237 bottom = src;
2238 } 2238 }
2239 } 2239 }
2240 2240
2241 if (bottom == NULL) { 2241 if (bottom == NULL) {
2242 /* 2242 /*
2243 * No idea from where it can come -- return now. 2243 * No idea from where it can come -- return now.
2244 */ 2244 */
2245 goto sfnd_abort; 2245 goto sfnd_abort;
2246 } 2246 }
2247 2247
2248 /* 2248 /*
2249 * We now have a list of Src structures headed by 'bottom' and linked via 2249 * We now have a list of Src structures headed by 'bottom' and linked via
2250 * their 'parent' pointers. What we do next is create links between 2250 * their 'parent' pointers. What we do next is create links between
2251 * source and target nodes (which may or may not have been created) 2251 * source and target nodes (which may or may not have been created)
2252 * and set the necessary local variables in each target. The 2252 * and set the necessary local variables in each target. The
2253 * commands for each target are set from the commands of the 2253 * commands for each target are set from the commands of the
2254 * transformation rule used to get from the src suffix to the targ 2254 * transformation rule used to get from the src suffix to the targ
2255 * suffix. Note that this causes the commands list of the original 2255 * suffix. Note that this causes the commands list of the original
2256 * node, gn, to be replaced by the commands of the final 2256 * node, gn, to be replaced by the commands of the final
2257 * transformation rule. Also, the unmade field of gn is incremented. 2257 * transformation rule. Also, the unmade field of gn is incremented.
2258 * Etc. 2258 * Etc.
2259 */ 2259 */
2260 if (bottom->node == NULL) { 2260 if (bottom->node == NULL) {
2261 bottom->node = Targ_FindNode(bottom->file, TARG_CREATE); 2261 bottom->node = Targ_FindNode(bottom->file, TARG_CREATE);
2262 } 2262 }
2263 2263
2264 for (src = bottom; src->parent != NULL; src = src->parent) { 2264 for (src = bottom; src->parent != NULL; src = src->parent) {
2265 targ = src->parent; 2265 targ = src->parent;
2266 2266
2267 if (src->node->suffix) 2267 if (src->node->suffix)
2268 src->node->suffix->refCount--; 2268 src->node->suffix->refCount--;
2269 src->node->suffix = src->suff; 2269 src->node->suffix = src->suff;
2270 src->node->suffix->refCount++; 2270 src->node->suffix->refCount++;
2271 2271
2272 if (targ->node == NULL) { 2272 if (targ->node == NULL) {
2273 targ->node = Targ_FindNode(targ->file, TARG_CREATE); 2273 targ->node = Targ_FindNode(targ->file, TARG_CREATE);
2274 } 2274 }
2275 2275
2276 SuffApplyTransform(targ->node, src->node, 2276 SuffApplyTransform(targ->node, src->node,
2277 targ->suff, src->suff); 2277 targ->suff, src->suff);
2278 2278
2279 if (targ->node != gn) { 2279 if (targ->node != gn) {
2280 /* 2280 /*
2281 * Finish off the dependency-search process for any nodes 2281 * Finish off the dependency-search process for any nodes
2282 * between bottom and gn (no point in questing around the 2282 * between bottom and gn (no point in questing around the
2283 * filesystem for their implicit source when it's already 2283 * filesystem for their implicit source when it's already
2284 * known). Note that the node can't have any sources that 2284 * known). Note that the node can't have any sources that
2285 * need expanding, since SuffFindThem will stop on an existing 2285 * need expanding, since SuffFindThem will stop on an existing
2286 * node, so all we need to do is set the standard and System V 2286 * node, so all we need to do is set the standard and System V
2287 * variables. 2287 * variables.
2288 */ 2288 */
2289 targ->node->type |= OP_DEPS_FOUND; 2289 targ->node->type |= OP_DEPS_FOUND;
2290 2290
2291 Var_Set(PREFIX, targ->pref, targ->node); 2291 Var_Set(PREFIX, targ->pref, targ->node);
2292 2292
2293 Var_Set(TARGET, targ->node->name, targ->node); 2293 Var_Set(TARGET, targ->node->name, targ->node);
2294 } 2294 }
2295 } 2295 }
2296 2296
2297 if (gn->suffix) 2297 if (gn->suffix)
2298 gn->suffix->refCount--; 2298 gn->suffix->refCount--;
2299 gn->suffix = src->suff; 2299 gn->suffix = src->suff;
2300 gn->suffix->refCount++; 2300 gn->suffix->refCount++;
2301 2301
2302 /* 2302 /*
2303 * Nuke the transformation path and the Src structures left over in the 2303 * Nuke the transformation path and the Src structures left over in the
2304 * two lists. 2304 * two lists.
2305 */ 2305 */
2306sfnd_return: 2306sfnd_return:
2307 if (bottom) 2307 if (bottom)
2308 if (Lst_Member(slst, bottom) == NULL) 2308 if (Lst_Member(slst, bottom) == NULL)
2309 Lst_Append(slst, bottom); 2309 Lst_Append(slst, bottom);
2310 2310
2311 while (SuffRemoveSrc(srcs) || SuffRemoveSrc(targs)) 2311 while (SuffRemoveSrc(srcs) || SuffRemoveSrc(targs))
2312 continue; 2312 continue;
2313 2313
2314 Lst_MoveAll(slst, srcs); 2314 Lst_MoveAll(slst, srcs);
2315 Lst_MoveAll(slst, targs); 2315 Lst_MoveAll(slst, targs);
2316} 2316}
2317 2317
2318 2318
2319/*- 2319/*-
2320 *----------------------------------------------------------------------- 2320 *-----------------------------------------------------------------------
2321 * Suff_FindDeps -- 2321 * Suff_FindDeps --
2322 * Find implicit sources for the target described by the graph node 2322 * Find implicit sources for the target described by the graph node
2323 * gn 2323 * gn
2324 * 2324 *
2325 * Results: 2325 * Results:
2326 * Nothing. 2326 * Nothing.
2327 * 2327 *
2328 * Side Effects: 2328 * Side Effects:
2329 * Nodes are added to the graph below the passed-in node. The nodes 2329 * Nodes are added to the graph below the passed-in node. The nodes
2330 * are marked to have their IMPSRC variable filled in. The 2330 * are marked to have their IMPSRC variable filled in. The
2331 * PREFIX variable is set for the given node and all its 2331 * PREFIX variable is set for the given node and all its
2332 * implied children. 2332 * implied children.
2333 * 2333 *
2334 * Notes: 2334 * Notes:
2335 * The path found by this target is the shortest path in the 2335 * The path found by this target is the shortest path in the
2336 * transformation graph, which may pass through non-existent targets, 2336 * transformation graph, which may pass through non-existent targets,
2337 * to an existing target. The search continues on all paths from the 2337 * to an existing target. The search continues on all paths from the
2338 * root suffix until a file is found. I.e. if there's a path 2338 * root suffix until a file is found. I.e. if there's a path
2339 * .o -> .c -> .l -> .l,v from the root and the .l,v file exists but 2339 * .o -> .c -> .l -> .l,v from the root and the .l,v file exists but
2340 * the .c and .l files don't, the search will branch out in 2340 * the .c and .l files don't, the search will branch out in
2341 * all directions from .o and again from all the nodes on the 2341 * all directions from .o and again from all the nodes on the
2342 * next level until the .l,v node is encountered. 2342 * next level until the .l,v node is encountered.
2343 * 2343 *
2344 *----------------------------------------------------------------------- 2344 *-----------------------------------------------------------------------
2345 */ 2345 */
2346 2346
2347void 2347void
2348Suff_FindDeps(GNode *gn) 2348Suff_FindDeps(GNode *gn)
2349{ 2349{
2350 2350
2351 SuffFindDeps(gn, srclist); 2351 SuffFindDeps(gn, srclist);
2352 while (SuffRemoveSrc(srclist)) 2352 while (SuffRemoveSrc(srclist))
2353 continue; 2353 continue;
2354} 2354}
2355 2355
2356 2356
2357static void 2357static void
2358SuffFindDeps(GNode *gn, Lst slst) 2358SuffFindDeps(GNode *gn, Lst slst)
2359{ 2359{
2360 if (gn->type & OP_DEPS_FOUND) 2360 if (gn->type & OP_DEPS_FOUND)
2361 return; 2361 return;
2362 gn->type |= OP_DEPS_FOUND; 2362 gn->type |= OP_DEPS_FOUND;
2363 2363
2364 /* 2364 /*
2365 * Make sure we have these set, may get revised below. 2365 * Make sure we have these set, may get revised below.
2366 */ 2366 */
2367 Var_Set(TARGET, gn->path ? gn->path : gn->name, gn); 2367 Var_Set(TARGET, gn->path ? gn->path : gn->name, gn);
2368 Var_Set(PREFIX, gn->name, gn); 2368 Var_Set(PREFIX, gn->name, gn);
2369 2369
2370 if (DEBUG(SUFF)) { 2370 if (DEBUG(SUFF)) {
2371 fprintf(debug_file, "SuffFindDeps (%s)\n", gn->name); 2371 fprintf(debug_file, "SuffFindDeps (%s)\n", gn->name);
2372 } 2372 }
2373 2373
2374 if (gn->type & OP_ARCHV) { 2374 if (gn->type & OP_ARCHV) {
2375 SuffFindArchiveDeps(gn, slst); 2375 SuffFindArchiveDeps(gn, slst);
2376 } else if (gn->type & OP_LIB) { 2376 } else if (gn->type & OP_LIB) {
2377 /* 2377 /*
2378 * If the node is a library, it is the arch module's job to find it 2378 * If the node is a library, it is the arch module's job to find it
2379 * and set the TARGET variable accordingly. We merely provide the 2379 * and set the TARGET variable accordingly. We merely provide the
2380 * search path, assuming all libraries end in ".a" (if the suffix 2380 * search path, assuming all libraries end in ".a" (if the suffix
2381 * hasn't been defined, there's nothing we can do for it, so we just 2381 * hasn't been defined, there's nothing we can do for it, so we just
2382 * set the TARGET variable to the node's name in order to give it a 2382 * set the TARGET variable to the node's name in order to give it a
2383 * value). 2383 * value).
2384 */ 2384 */
2385 LstNode ln; 2385 LstNode ln;
2386 Suff *s; 2386 Suff *s;
2387 2387
2388 ln = Lst_Find(sufflist, SuffSuffHasName, LIBSUFF); 2388 ln = Lst_Find(sufflist, SuffSuffHasName, LIBSUFF);
2389 if (gn->suffix) 2389 if (gn->suffix)
2390 gn->suffix->refCount--; 2390 gn->suffix->refCount--;
2391 if (ln != NULL) { 2391 if (ln != NULL) {
2392 gn->suffix = s = Lst_Datum(ln); 2392 gn->suffix = s = Lst_Datum(ln);
2393 gn->suffix->refCount++; 2393 gn->suffix->refCount++;
2394 Arch_FindLib(gn, s->searchPath); 2394 Arch_FindLib(gn, s->searchPath);
2395 } else { 2395 } else {
2396 gn->suffix = NULL; 2396 gn->suffix = NULL;
2397 Var_Set(TARGET, gn->name, gn); 2397 Var_Set(TARGET, gn->name, gn);
2398 } 2398 }
2399 /* 2399 /*
2400 * Because a library (-lfoo) target doesn't follow the standard 2400 * Because a library (-lfoo) target doesn't follow the standard
2401 * filesystem conventions, we don't set the regular variables for 2401 * filesystem conventions, we don't set the regular variables for
2402 * the thing. .PREFIX is simply made empty... 2402 * the thing. .PREFIX is simply made empty...
2403 */ 2403 */
2404 Var_Set(PREFIX, "", gn); 2404 Var_Set(PREFIX, "", gn);
2405 } else { 2405 } else {
2406 SuffFindNormalDeps(gn, slst); 2406 SuffFindNormalDeps(gn, slst);
2407 } 2407 }
2408} 2408}
2409 2409
2410/*- 2410/*-
2411 *----------------------------------------------------------------------- 2411 *-----------------------------------------------------------------------
2412 * Suff_SetNull -- 2412 * Suff_SetNull --
2413 * Define which suffix is the null suffix. 2413 * Define which suffix is the null suffix.
2414 * 2414 *
2415 * Input: 2415 * Input:
2416 * name Name of null suffix 2416 * name Name of null suffix
2417 * 2417 *
2418 * Side Effects: 2418 * Side Effects:
2419 * 'suffNull' is altered. 2419 * 'suffNull' is altered.
2420 * 2420 *
2421 * Notes: 2421 * Notes:
2422 * Need to handle the changing of the null suffix gracefully so the 2422 * Need to handle the changing of the null suffix gracefully so the
2423 * old transformation rules don't just go away. 2423 * old transformation rules don't just go away.
2424 *----------------------------------------------------------------------- 2424 *-----------------------------------------------------------------------
2425 */ 2425 */
2426void 2426void
2427Suff_SetNull(char *name) 2427Suff_SetNull(char *name)
2428{ 2428{
2429 Suff *s; 2429 Suff *s;
2430 LstNode ln; 2430 LstNode ln;
2431 2431
2432 ln = Lst_Find(sufflist, SuffSuffHasName, name); 2432 ln = Lst_Find(sufflist, SuffSuffHasName, name);
2433 if (ln != NULL) { 2433 if (ln != NULL) {
2434 s = Lst_Datum(ln); 2434 s = Lst_Datum(ln);
2435 if (suffNull != NULL) { 2435 if (suffNull != NULL) {
2436 suffNull->flags &= ~SUFF_NULL; 2436 suffNull->flags &= ~SUFF_NULL;
2437 } 2437 }
2438 s->flags |= SUFF_NULL; 2438 s->flags |= SUFF_NULL;
2439 /* 2439 /*
2440 * XXX: Here's where the transformation mangling would take place 2440 * XXX: Here's where the transformation mangling would take place
2441 */ 2441 */
2442 suffNull = s; 2442 suffNull = s;
2443 } else { 2443 } else {
2444 Parse_Error(PARSE_WARNING, "Desired null suffix %s not defined.", 2444 Parse_Error(PARSE_WARNING, "Desired null suffix %s not defined.",
2445 name); 2445 name);
2446 } 2446 }
2447} 2447}
2448 2448
2449/* Initialize the suffixes module. */ 2449/* Initialize the suffixes module. */
2450void 2450void
2451Suff_Init(void) 2451Suff_Init(void)
2452{ 2452{
2453#ifdef CLEANUP 2453#ifdef CLEANUP
2454 suffClean = Lst_Init(); 2454 suffClean = Lst_Init();
2455 sufflist = Lst_Init(); 2455 sufflist = Lst_Init();
2456#endif 2456#endif
2457 srclist = Lst_Init(); 2457 srclist = Lst_Init();
2458 transforms = Lst_Init(); 2458 transforms = Lst_Init();
2459 2459
2460 /* 2460 /*
2461 * Create null suffix for single-suffix rules (POSIX). The thing doesn't 2461 * Create null suffix for single-suffix rules (POSIX). The thing doesn't
2462 * actually go on the suffix list or everyone will think that's its 2462 * actually go on the suffix list or everyone will think that's its
2463 * suffix. 2463 * suffix.
2464 */ 2464 */
2465 Suff_ClearSuffixes(); 2465 Suff_ClearSuffixes();
2466} 2466}
2467 2467
2468 2468
2469/* Clean up the suffixes module. */ 2469/* Clean up the suffixes module. */
2470void 2470void
2471Suff_End(void) 2471Suff_End(void)
2472{ 2472{
2473#ifdef CLEANUP 2473#ifdef CLEANUP
2474 Lst_Destroy(sufflist, SuffFree); 2474 Lst_Destroy(sufflist, SuffFree);
2475 Lst_Destroy(suffClean, SuffFree); 2475 Lst_Destroy(suffClean, SuffFree);
2476 if (suffNull) 2476 if (suffNull)
2477 SuffFree(suffNull); 2477 SuffFree(suffNull);
2478 Lst_Free(srclist); 2478 Lst_Free(srclist);
2479 Lst_Free(transforms); 2479 Lst_Free(transforms);
2480#endif 2480#endif
2481} 2481}
2482 2482
2483 2483
2484/********************* DEBUGGING FUNCTIONS **********************/ 2484/********************* DEBUGGING FUNCTIONS **********************/
2485 2485
2486static int SuffPrintName(void *s, void *dummy MAKE_ATTR_UNUSED) 2486static int SuffPrintName(void *s, void *dummy MAKE_ATTR_UNUSED)
2487{ 2487{
2488 2488
2489 fprintf(debug_file, "%s ", ((Suff *)s)->name); 2489 fprintf(debug_file, "%s ", ((Suff *)s)->name);
2490 return 0; 2490 return 0;
2491} 2491}
2492 2492
2493static int 2493static int
2494SuffPrintSuff(void *sp, void *dummy MAKE_ATTR_UNUSED) 2494SuffPrintSuff(void *sp, void *dummy MAKE_ATTR_UNUSED)
2495{ 2495{
2496 Suff *s = (Suff *)sp; 2496 Suff *s = (Suff *)sp;
2497 2497
2498 fprintf(debug_file, "# `%s' [%d] ", s->name, s->refCount); 2498 fprintf(debug_file, "# `%s' [%d] ", s->name, s->refCount);
2499 2499
2500 if (s->flags != 0) { 2500 if (s->flags != 0) {
2501 char flags_buf[SuffFlags_ToStringSize]; 2501 char flags_buf[SuffFlags_ToStringSize];
2502 2502
2503 fprintf(debug_file, " (%s)", 2503 fprintf(debug_file, " (%s)",
2504 Enum_FlagsToString(flags_buf, sizeof flags_buf, 2504 Enum_FlagsToString(flags_buf, sizeof flags_buf,
2505 s->flags, SuffFlags_ToStringSpecs)); 2505 s->flags, SuffFlags_ToStringSpecs));
2506 } 2506 }
2507 fputc('\n', debug_file); 2507 fputc('\n', debug_file);
2508 fprintf(debug_file, "#\tTo: "); 2508 fprintf(debug_file, "#\tTo: ");
2509 Lst_ForEach(s->parents, SuffPrintName, NULL); 2509 Lst_ForEach(s->parents, SuffPrintName, NULL);
2510 fputc('\n', debug_file); 2510 fputc('\n', debug_file);
2511 fprintf(debug_file, "#\tFrom: "); 2511 fprintf(debug_file, "#\tFrom: ");
2512 Lst_ForEach(s->children, SuffPrintName, NULL); 2512 Lst_ForEach(s->children, SuffPrintName, NULL);
2513 fputc('\n', debug_file); 2513 fputc('\n', debug_file);
2514 fprintf(debug_file, "#\tSearch Path: "); 2514 fprintf(debug_file, "#\tSearch Path: ");
2515 Dir_PrintPath(s->searchPath); 2515 Dir_PrintPath(s->searchPath);
2516 fputc('\n', debug_file); 2516 fputc('\n', debug_file);
2517 return 0; 2517 return 0;
2518} 2518}
2519 2519
2520static int 2520static int
2521SuffPrintTrans(void *tp, void *dummy MAKE_ATTR_UNUSED) 2521SuffPrintTrans(void *tp, void *dummy MAKE_ATTR_UNUSED)
2522{ 2522{
2523 GNode *t = (GNode *)tp; 2523 GNode *t = (GNode *)tp;
2524 2524
2525 fprintf(debug_file, "%-16s: ", t->name); 2525 fprintf(debug_file, "%-16s: ", t->name);
2526 Targ_PrintType(t->type); 2526 Targ_PrintType(t->type);
2527 fputc('\n', debug_file); 2527 fputc('\n', debug_file);
2528 Lst_ForEach(t->commands, Targ_PrintCmd, NULL); 2528 Lst_ForEach(t->commands, Targ_PrintCmd, NULL);
2529 fputc('\n', debug_file); 2529 fputc('\n', debug_file);
2530 return 0; 2530 return 0;
2531} 2531}
2532 2532
2533void 2533void
2534Suff_PrintAll(void) 2534Suff_PrintAll(void)
2535{ 2535{
2536 fprintf(debug_file, "#*** Suffixes:\n"); 2536 fprintf(debug_file, "#*** Suffixes:\n");
2537 Lst_ForEach(sufflist, SuffPrintSuff, NULL); 2537 Lst_ForEach(sufflist, SuffPrintSuff, NULL);
2538 2538
2539 fprintf(debug_file, "#*** Transformations:\n"); 2539 fprintf(debug_file, "#*** Transformations:\n");
2540 Lst_ForEach(transforms, SuffPrintTrans, NULL); 2540 Lst_ForEach(transforms, SuffPrintTrans, NULL);
2541} 2541}