Thu Aug 27 06:28:44 2020 UTC ()
make(1): migrate remaining code from Lst_Open to Lst_OpenS


(rillig)
diff -r1.111 -r1.112 src/usr.bin/make/dir.c
diff -r1.42 -r1.43 src/usr.bin/make/lst.c
diff -r1.45 -r1.46 src/usr.bin/make/lst.h

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

--- src/usr.bin/make/dir.c 2020/08/26 22:55:46 1.111
+++ src/usr.bin/make/dir.c 2020/08/27 06:28:44 1.112
@@ -1,1812 +1,1815 @@ @@ -1,1812 +1,1815 @@
1/* $NetBSD: dir.c,v 1.111 2020/08/26 22:55:46 rillig Exp $ */ 1/* $NetBSD: dir.c,v 1.112 2020/08/27 06:28:44 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.111 2020/08/26 22:55:46 rillig Exp $"; 73static char rcsid[] = "$NetBSD: dir.c,v 1.112 2020/08/27 06:28:44 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.111 2020/08/26 22:55:46 rillig Exp $"); 80__RCSID("$NetBSD: dir.c,v 1.112 2020/08/27 06:28:44 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 int DirFindName(const void *, const void *); 259static int DirFindName(const void *, const void *);
260static void DirExpandCurly(const char *, const char *, Lst, Lst); 260static void DirExpandCurly(const char *, const char *, Lst, Lst);
261static void DirExpandInt(const char *, Lst, Lst); 261static void DirExpandInt(const char *, Lst, Lst);
262static int DirPrintWord(void *, void *); 262static int DirPrintWord(void *, void *);
263static int DirPrintDir(void *, void *); 263static int DirPrintDir(void *, void *);
264static char *DirLookup(Path *, const char *, const char *, Boolean); 264static char *DirLookup(Path *, const char *, const char *, Boolean);
265static char *DirLookupSubdir(Path *, const char *); 265static char *DirLookupSubdir(Path *, const char *);
266static char *DirFindDot(Boolean, const char *, const char *); 266static char *DirFindDot(Boolean, const char *, const char *);
267static char *DirLookupAbs(Path *, const char *, const char *); 267static char *DirLookupAbs(Path *, const char *, const char *);
268 268
269 269
270/* 270/*
271 * We use stat(2) a lot, cache the results. 271 * We use stat(2) a lot, cache the results.
272 * mtime and mode are all we care about. 272 * mtime and mode are all we care about.
273 */ 273 */
274struct cache_st { 274struct cache_st {
275 time_t lmtime; /* lstat */ 275 time_t lmtime; /* lstat */
276 time_t mtime; /* stat */ 276 time_t mtime; /* stat */
277 mode_t mode; 277 mode_t mode;
278}; 278};
279 279
280/* minimize changes below */ 280/* minimize changes below */
281typedef enum { 281typedef enum {
282 CST_LSTAT = 0x01, /* call lstat(2) instead of stat(2) */ 282 CST_LSTAT = 0x01, /* call lstat(2) instead of stat(2) */
283 CST_UPDATE = 0x02 /* ignore existing cached entry */ 283 CST_UPDATE = 0x02 /* ignore existing cached entry */
284} CachedStatsFlags; 284} CachedStatsFlags;
285 285
286/* Returns 0 and the result of stat(2) or lstat(2) in *st, or -1 on error. 286/* Returns 0 and the result of stat(2) or lstat(2) in *st, or -1 on error.
287 * Only st->st_mode and st->st_mtime are filled. */ 287 * Only st->st_mode and st->st_mtime are filled. */
288static int 288static int
289cached_stats(Hash_Table *htp, const char *pathname, struct stat *st, 289cached_stats(Hash_Table *htp, const char *pathname, struct stat *st,
290 CachedStatsFlags flags) 290 CachedStatsFlags flags)
291{ 291{
292 Hash_Entry *entry; 292 Hash_Entry *entry;
293 struct cache_st *cst; 293 struct cache_st *cst;
294 int rc; 294 int rc;
295 295
296 if (!pathname || !pathname[0]) 296 if (!pathname || !pathname[0])
297 return -1; 297 return -1;
298 298
299 entry = Hash_FindEntry(htp, pathname); 299 entry = Hash_FindEntry(htp, pathname);
300 300
301 if (entry && !(flags & CST_UPDATE)) { 301 if (entry && !(flags & CST_UPDATE)) {
302 cst = entry->clientPtr; 302 cst = entry->clientPtr;
303 303
304 memset(st, 0, sizeof(*st)); 304 memset(st, 0, sizeof(*st));
305 st->st_mode = cst->mode; 305 st->st_mode = cst->mode;
306 st->st_mtime = (flags & CST_LSTAT) ? cst->lmtime : cst->mtime; 306 st->st_mtime = (flags & CST_LSTAT) ? cst->lmtime : cst->mtime;
307 if (st->st_mtime) { 307 if (st->st_mtime) {
308 DIR_DEBUG2("Using cached time %s for %s\n", 308 DIR_DEBUG2("Using cached time %s for %s\n",
309 Targ_FmtTime(st->st_mtime), pathname); 309 Targ_FmtTime(st->st_mtime), pathname);
310 return 0; 310 return 0;
311 } 311 }
312 } 312 }
313 313
314 rc = (flags & CST_LSTAT) ? lstat(pathname, st) : stat(pathname, st); 314 rc = (flags & CST_LSTAT) ? lstat(pathname, st) : stat(pathname, st);
315 if (rc == -1) 315 if (rc == -1)
316 return -1; 316 return -1;
317 317
318 if (st->st_mtime == 0) 318 if (st->st_mtime == 0)
319 st->st_mtime = 1; /* avoid confusion with missing file */ 319 st->st_mtime = 1; /* avoid confusion with missing file */
320 320
321 if (!entry) 321 if (!entry)
322 entry = Hash_CreateEntry(htp, pathname, NULL); 322 entry = Hash_CreateEntry(htp, pathname, NULL);
323 if (!entry->clientPtr) { 323 if (!entry->clientPtr) {
324 entry->clientPtr = bmake_malloc(sizeof(*cst)); 324 entry->clientPtr = bmake_malloc(sizeof(*cst));
325 memset(entry->clientPtr, 0, sizeof(*cst)); 325 memset(entry->clientPtr, 0, sizeof(*cst));
326 } 326 }
327 cst = entry->clientPtr; 327 cst = entry->clientPtr;
328 if (flags & CST_LSTAT) { 328 if (flags & CST_LSTAT) {
329 cst->lmtime = st->st_mtime; 329 cst->lmtime = st->st_mtime;
330 } else { 330 } else {
331 cst->mtime = st->st_mtime; 331 cst->mtime = st->st_mtime;
332 } 332 }
333 cst->mode = st->st_mode; 333 cst->mode = st->st_mode;
334 DIR_DEBUG2(" Caching %s for %s\n", 334 DIR_DEBUG2(" Caching %s for %s\n",
335 Targ_FmtTime(st->st_mtime), pathname); 335 Targ_FmtTime(st->st_mtime), pathname);
336 336
337 return 0; 337 return 0;
338} 338}
339 339
340int 340int
341cached_stat(const char *pathname, void *st) 341cached_stat(const char *pathname, void *st)
342{ 342{
343 return cached_stats(&mtimes, pathname, st, 0); 343 return cached_stats(&mtimes, pathname, st, 0);
344} 344}
345 345
346int 346int
347cached_lstat(const char *pathname, void *st) 347cached_lstat(const char *pathname, void *st)
348{ 348{
349 return cached_stats(&lmtimes, pathname, st, CST_LSTAT); 349 return cached_stats(&lmtimes, pathname, st, CST_LSTAT);
350} 350}
351 351
352/* Initialize things for this module. */ 352/* Initialize things for this module. */
353void 353void
354Dir_Init(void) 354Dir_Init(void)
355{ 355{
356 dirSearchPath = Lst_Init(); 356 dirSearchPath = Lst_Init();
357 openDirectories = Lst_Init(); 357 openDirectories = Lst_Init();
358 Hash_InitTable(&mtimes, 0); 358 Hash_InitTable(&mtimes, 0);
359 Hash_InitTable(&lmtimes, 0); 359 Hash_InitTable(&lmtimes, 0);
360} 360}
361 361
362void 362void
363Dir_InitDir(const char *cdname) 363Dir_InitDir(const char *cdname)
364{ 364{
365 Dir_InitCur(cdname); 365 Dir_InitCur(cdname);
366 366
367 dotLast = bmake_malloc(sizeof(Path)); 367 dotLast = bmake_malloc(sizeof(Path));
368 dotLast->refCount = 1; 368 dotLast->refCount = 1;
369 dotLast->hits = 0; 369 dotLast->hits = 0;
370 dotLast->name = bmake_strdup(".DOTLAST"); 370 dotLast->name = bmake_strdup(".DOTLAST");
371 Hash_InitTable(&dotLast->files, -1); 371 Hash_InitTable(&dotLast->files, -1);
372} 372}
373 373
374/* 374/*
375 * Called by Dir_InitDir and whenever .CURDIR is assigned to. 375 * Called by Dir_InitDir and whenever .CURDIR is assigned to.
376 */ 376 */
377void 377void
378Dir_InitCur(const char *cdname) 378Dir_InitCur(const char *cdname)
379{ 379{
380 Path *p; 380 Path *p;
381 381
382 if (cdname != NULL) { 382 if (cdname != NULL) {
383 /* 383 /*
384 * Our build directory is not the same as our source directory. 384 * Our build directory is not the same as our source directory.
385 * Keep this one around too. 385 * Keep this one around too.
386 */ 386 */
387 if ((p = Dir_AddDir(NULL, cdname))) { 387 if ((p = Dir_AddDir(NULL, cdname))) {
388 p->refCount += 1; 388 p->refCount += 1;
389 if (cur && cur != p) { 389 if (cur && cur != p) {
390 /* 390 /*
391 * We've been here before, cleanup. 391 * We've been here before, cleanup.
392 */ 392 */
393 cur->refCount -= 1; 393 cur->refCount -= 1;
394 Dir_Destroy(cur); 394 Dir_Destroy(cur);
395 } 395 }
396 cur = p; 396 cur = p;
397 } 397 }
398 } 398 }
399} 399}
400 400
401/*- 401/*-
402 *----------------------------------------------------------------------- 402 *-----------------------------------------------------------------------
403 * Dir_InitDot -- 403 * Dir_InitDot --
404 * (re)initialize "dot" (current/object directory) path hash 404 * (re)initialize "dot" (current/object directory) path hash
405 * 405 *
406 * Results: 406 * Results:
407 * none 407 * none
408 * 408 *
409 * Side Effects: 409 * Side Effects:
410 * some directories may be opened. 410 * some directories may be opened.
411 *----------------------------------------------------------------------- 411 *-----------------------------------------------------------------------
412 */ 412 */
413void 413void
414Dir_InitDot(void) 414Dir_InitDot(void)
415{ 415{
416 if (dot != NULL) { 416 if (dot != NULL) {
417 LstNode ln; 417 LstNode ln;
418 418
419 /* Remove old entry from openDirectories, but do not destroy. */ 419 /* Remove old entry from openDirectories, but do not destroy. */
420 ln = Lst_MemberS(openDirectories, dot); 420 ln = Lst_MemberS(openDirectories, dot);
421 Lst_RemoveS(openDirectories, ln); 421 Lst_RemoveS(openDirectories, ln);
422 } 422 }
423 423
424 dot = Dir_AddDir(NULL, "."); 424 dot = Dir_AddDir(NULL, ".");
425 425
426 if (dot == NULL) { 426 if (dot == NULL) {
427 Error("Cannot open `.' (%s)", strerror(errno)); 427 Error("Cannot open `.' (%s)", strerror(errno));
428 exit(1); 428 exit(1);
429 } 429 }
430 430
431 /* 431 /*
432 * We always need to have dot around, so we increment its reference count 432 * We always need to have dot around, so we increment its reference count
433 * to make sure it's not destroyed. 433 * to make sure it's not destroyed.
434 */ 434 */
435 dot->refCount += 1; 435 dot->refCount += 1;
436 Dir_SetPATH(); /* initialize */ 436 Dir_SetPATH(); /* initialize */
437} 437}
438 438
439/*- 439/*-
440 *----------------------------------------------------------------------- 440 *-----------------------------------------------------------------------
441 * Dir_End -- 441 * Dir_End --
442 * cleanup things for this module 442 * cleanup things for this module
443 * 443 *
444 * Results: 444 * Results:
445 * none 445 * none
446 * 446 *
447 * Side Effects: 447 * Side Effects:
448 * none 448 * none
449 *----------------------------------------------------------------------- 449 *-----------------------------------------------------------------------
450 */ 450 */
451void 451void
452Dir_End(void) 452Dir_End(void)
453{ 453{
454#ifdef CLEANUP 454#ifdef CLEANUP
455 if (cur) { 455 if (cur) {
456 cur->refCount -= 1; 456 cur->refCount -= 1;
457 Dir_Destroy(cur); 457 Dir_Destroy(cur);
458 } 458 }
459 dot->refCount -= 1; 459 dot->refCount -= 1;
460 dotLast->refCount -= 1; 460 dotLast->refCount -= 1;
461 Dir_Destroy(dotLast); 461 Dir_Destroy(dotLast);
462 Dir_Destroy(dot); 462 Dir_Destroy(dot);
463 Dir_ClearPath(dirSearchPath); 463 Dir_ClearPath(dirSearchPath);
464 Lst_FreeS(dirSearchPath); 464 Lst_FreeS(dirSearchPath);
465 Dir_ClearPath(openDirectories); 465 Dir_ClearPath(openDirectories);
466 Lst_FreeS(openDirectories); 466 Lst_FreeS(openDirectories);
467 Hash_DeleteTable(&mtimes); 467 Hash_DeleteTable(&mtimes);
468#endif 468#endif
469} 469}
470 470
471/* 471/*
472 * We want ${.PATH} to indicate the order in which we will actually 472 * We want ${.PATH} to indicate the order in which we will actually
473 * search, so we rebuild it after any .PATH: target. 473 * search, so we rebuild it after any .PATH: target.
474 * This is the simplest way to deal with the effect of .DOTLAST. 474 * This is the simplest way to deal with the effect of .DOTLAST.
475 */ 475 */
476void 476void
477Dir_SetPATH(void) 477Dir_SetPATH(void)
478{ 478{
479 LstNode ln; /* a list element */ 479 LstNode ln; /* a list element */
480 Path *p; 480 Path *p;
481 Boolean hasLastDot = FALSE; /* true if we should search dot last */ 481 Boolean hasLastDot = FALSE; /* true if we should search dot last */
482 482
483 Var_Delete(".PATH", VAR_GLOBAL); 483 Var_Delete(".PATH", VAR_GLOBAL);
484 484
485 Lst_OpenS(dirSearchPath); 485 Lst_OpenS(dirSearchPath);
486 if ((ln = Lst_First(dirSearchPath)) != NULL) { 486 if ((ln = Lst_First(dirSearchPath)) != NULL) {
487 p = Lst_DatumS(ln); 487 p = Lst_DatumS(ln);
488 if (p == dotLast) { 488 if (p == dotLast) {
489 hasLastDot = TRUE; 489 hasLastDot = TRUE;
490 Var_Append(".PATH", dotLast->name, VAR_GLOBAL); 490 Var_Append(".PATH", dotLast->name, VAR_GLOBAL);
491 } 491 }
492 } 492 }
493 493
494 if (!hasLastDot) { 494 if (!hasLastDot) {
495 if (dot) 495 if (dot)
496 Var_Append(".PATH", dot->name, VAR_GLOBAL); 496 Var_Append(".PATH", dot->name, VAR_GLOBAL);
497 if (cur) 497 if (cur)
498 Var_Append(".PATH", cur->name, VAR_GLOBAL); 498 Var_Append(".PATH", cur->name, VAR_GLOBAL);
499 } 499 }
500 500
501 while ((ln = Lst_NextS(dirSearchPath)) != NULL) { 501 while ((ln = Lst_NextS(dirSearchPath)) != NULL) {
502 p = Lst_DatumS(ln); 502 p = Lst_DatumS(ln);
503 if (p == dotLast) 503 if (p == dotLast)
504 continue; 504 continue;
505 if (p == dot && hasLastDot) 505 if (p == dot && hasLastDot)
506 continue; 506 continue;
507 Var_Append(".PATH", p->name, VAR_GLOBAL); 507 Var_Append(".PATH", p->name, VAR_GLOBAL);
508 } 508 }
509 509
510 if (hasLastDot) { 510 if (hasLastDot) {
511 if (dot) 511 if (dot)
512 Var_Append(".PATH", dot->name, VAR_GLOBAL); 512 Var_Append(".PATH", dot->name, VAR_GLOBAL);
513 if (cur) 513 if (cur)
514 Var_Append(".PATH", cur->name, VAR_GLOBAL); 514 Var_Append(".PATH", cur->name, VAR_GLOBAL);
515 } 515 }
516 Lst_CloseS(dirSearchPath); 516 Lst_CloseS(dirSearchPath);
517} 517}
518 518
519/*- 519/*-
520 *----------------------------------------------------------------------- 520 *-----------------------------------------------------------------------
521 * DirFindName -- 521 * DirFindName --
522 * See if the Path structure describes the same directory as the 522 * See if the Path structure describes the same directory as the
523 * given one by comparing their names. Called from Dir_AddDir via 523 * given one by comparing their names. Called from Dir_AddDir via
524 * Lst_Find when searching the list of open directories. 524 * Lst_Find when searching the list of open directories.
525 * 525 *
526 * Input: 526 * Input:
527 * p Current name 527 * p Current name
528 * dname Desired name 528 * dname Desired name
529 * 529 *
530 * Results: 530 * Results:
531 * 0 if it is the same. Non-zero otherwise 531 * 0 if it is the same. Non-zero otherwise
532 * 532 *
533 * Side Effects: 533 * Side Effects:
534 * None 534 * None
535 *----------------------------------------------------------------------- 535 *-----------------------------------------------------------------------
536 */ 536 */
537static int 537static int
538DirFindName(const void *p, const void *dname) 538DirFindName(const void *p, const void *dname)
539{ 539{
540 return strcmp(((const Path *)p)->name, dname); 540 return strcmp(((const Path *)p)->name, dname);
541} 541}
542 542
543/*- 543/*-
544 *----------------------------------------------------------------------- 544 *-----------------------------------------------------------------------
545 * Dir_HasWildcards -- 545 * Dir_HasWildcards --
546 * see if the given name has any wildcard characters in it 546 * see if the given name has any wildcard characters in it
547 * be careful not to expand unmatching brackets or braces. 547 * be careful not to expand unmatching brackets or braces.
548 * XXX: This code is not 100% correct. ([^]] fails etc.) 548 * XXX: This code is not 100% correct. ([^]] fails etc.)
549 * I really don't think that make(1) should be expanding 549 * I really don't think that make(1) should be expanding
550 * patterns, because then you have to set a mechanism for 550 * patterns, because then you have to set a mechanism for
551 * escaping the expansion! 551 * escaping the expansion!
552 * 552 *
553 * Input: 553 * Input:
554 * name name to check 554 * name name to check
555 * 555 *
556 * Results: 556 * Results:
557 * returns TRUE if the word should be expanded, FALSE otherwise 557 * returns TRUE if the word should be expanded, FALSE otherwise
558 * 558 *
559 * Side Effects: 559 * Side Effects:
560 * none 560 * none
561 *----------------------------------------------------------------------- 561 *-----------------------------------------------------------------------
562 */ 562 */
563Boolean 563Boolean
564Dir_HasWildcards(char *name) 564Dir_HasWildcards(char *name)
565{ 565{
566 char *cp; 566 char *cp;
567 int wild = 0, brace = 0, bracket = 0; 567 int wild = 0, brace = 0, bracket = 0;
568 568
569 for (cp = name; *cp; cp++) { 569 for (cp = name; *cp; cp++) {
570 switch (*cp) { 570 switch (*cp) {
571 case '{': 571 case '{':
572 brace++; 572 brace++;
573 wild = 1; 573 wild = 1;
574 break; 574 break;
575 case '}': 575 case '}':
576 brace--; 576 brace--;
577 break; 577 break;
578 case '[': 578 case '[':
579 bracket++; 579 bracket++;
580 wild = 1; 580 wild = 1;
581 break; 581 break;
582 case ']': 582 case ']':
583 bracket--; 583 bracket--;
584 break; 584 break;
585 case '?': 585 case '?':
586 case '*': 586 case '*':
587 wild = 1; 587 wild = 1;
588 break; 588 break;
589 default: 589 default:
590 break; 590 break;
591 } 591 }
592 } 592 }
593 return wild && bracket == 0 && brace == 0; 593 return wild && bracket == 0 && brace == 0;
594} 594}
595 595
596/*- 596/*-
597 *----------------------------------------------------------------------- 597 *-----------------------------------------------------------------------
598 * DirMatchFiles -- 598 * DirMatchFiles --
599 * Given a pattern and a Path structure, see if any files 599 * Given a pattern and a Path structure, see if any files
600 * match the pattern and add their names to the 'expansions' list if 600 * match the pattern and add their names to the 'expansions' list if
601 * any do. This is incomplete -- it doesn't take care of patterns like 601 * any do. This is incomplete -- it doesn't take care of patterns like
602 * src / *src / *.c properly (just *.c on any of the directories), but it 602 * src / *src / *.c properly (just *.c on any of the directories), but it
603 * will do for now. 603 * will do for now.
604 * 604 *
605 * Input: 605 * Input:
606 * pattern Pattern to look for 606 * pattern Pattern to look for
607 * p Directory to search 607 * p Directory to search
608 * expansion Place to store the results 608 * expansion Place to store the results
609 * 609 *
610 * Side Effects: 610 * Side Effects:
611 * File names are added to the expansions lst. The directory will be 611 * File names are added to the expansions lst. The directory will be
612 * fully hashed when this is done. 612 * fully hashed when this is done.
613 *----------------------------------------------------------------------- 613 *-----------------------------------------------------------------------
614 */ 614 */
615static void 615static void
616DirMatchFiles(const char *pattern, Path *p, Lst expansions) 616DirMatchFiles(const char *pattern, Path *p, Lst expansions)
617{ 617{
618 Hash_Search search; /* Index into the directory's table */ 618 Hash_Search search; /* Index into the directory's table */
619 Hash_Entry *entry; /* Current entry in the table */ 619 Hash_Entry *entry; /* Current entry in the table */
620 Boolean isDot; /* TRUE if the directory being searched is . */ 620 Boolean isDot; /* TRUE if the directory being searched is . */
621 621
622 isDot = (*p->name == '.' && p->name[1] == '\0'); 622 isDot = (*p->name == '.' && p->name[1] == '\0');
623 623
624 for (entry = Hash_EnumFirst(&p->files, &search); 624 for (entry = Hash_EnumFirst(&p->files, &search);
625 entry != NULL; 625 entry != NULL;
626 entry = Hash_EnumNext(&search)) 626 entry = Hash_EnumNext(&search))
627 { 627 {
628 /* 628 /*
629 * See if the file matches the given pattern. Note we follow the UNIX 629 * See if the file matches the given pattern. Note we follow the UNIX
630 * convention that dot files will only be found if the pattern 630 * convention that dot files will only be found if the pattern
631 * begins with a dot (note also that as a side effect of the hashing 631 * begins with a dot (note also that as a side effect of the hashing
632 * scheme, .* won't match . or .. since they aren't hashed). 632 * scheme, .* won't match . or .. since they aren't hashed).
633 */ 633 */
634 if (Str_Match(entry->name, pattern) && 634 if (Str_Match(entry->name, pattern) &&
635 ((entry->name[0] != '.') || 635 ((entry->name[0] != '.') ||
636 (pattern[0] == '.'))) 636 (pattern[0] == '.')))
637 { 637 {
638 Lst_AppendS(expansions, 638 Lst_AppendS(expansions,
639 (isDot ? bmake_strdup(entry->name) : 639 (isDot ? bmake_strdup(entry->name) :
640 str_concat3(p->name, "/", entry->name))); 640 str_concat3(p->name, "/", entry->name)));
641 } 641 }
642 } 642 }
643} 643}
644 644
645/* Find the next closing brace in the string, taking nested braces into 645/* Find the next closing brace in the string, taking nested braces into
646 * account. */ 646 * account. */
647static const char * 647static const char *
648closing_brace(const char *p) 648closing_brace(const char *p)
649{ 649{
650 int nest = 0; 650 int nest = 0;
651 while (*p != '\0') { 651 while (*p != '\0') {
652 if (*p == '}' && nest == 0) 652 if (*p == '}' && nest == 0)
653 break; 653 break;
654 if (*p == '{') 654 if (*p == '{')
655 nest++; 655 nest++;
656 if (*p == '}') 656 if (*p == '}')
657 nest--; 657 nest--;
658 p++; 658 p++;
659 } 659 }
660 return p; 660 return p;
661} 661}
662 662
663/* Find the next closing brace or comma in the string, taking nested braces 663/* Find the next closing brace or comma in the string, taking nested braces
664 * into account. */ 664 * into account. */
665static const char * 665static const char *
666separator_comma(const char *p) 666separator_comma(const char *p)
667{ 667{
668 int nest = 0; 668 int nest = 0;
669 while (*p != '\0') { 669 while (*p != '\0') {
670 if ((*p == '}' || *p == ',') && nest == 0) 670 if ((*p == '}' || *p == ',') && nest == 0)
671 break; 671 break;
672 if (*p == '{') 672 if (*p == '{')
673 nest++; 673 nest++;
674 if (*p == '}') 674 if (*p == '}')
675 nest--; 675 nest--;
676 p++; 676 p++;
677 } 677 }
678 return p; 678 return p;
679} 679}
680 680
681static Boolean 681static Boolean
682contains_wildcard(const char *p) 682contains_wildcard(const char *p)
683{ 683{
684 for (; *p != '\0'; p++) { 684 for (; *p != '\0'; p++) {
685 switch (*p) { 685 switch (*p) {
686 case '*': 686 case '*':
687 case '?': 687 case '?':
688 case '{': 688 case '{':
689 case '[': 689 case '[':
690 return TRUE; 690 return TRUE;
691 } 691 }
692 } 692 }
693 return FALSE; 693 return FALSE;
694} 694}
695 695
696static char * 696static char *
697concat3(const char *a, size_t a_len, const char *b, size_t b_len, 697concat3(const char *a, size_t a_len, const char *b, size_t b_len,
698 const char *c, size_t c_len) 698 const char *c, size_t c_len)
699{ 699{
700 size_t s_len = a_len + b_len + c_len; 700 size_t s_len = a_len + b_len + c_len;
701 char *s = bmake_malloc(s_len + 1); 701 char *s = bmake_malloc(s_len + 1);
702 memcpy(s, a, a_len); 702 memcpy(s, a, a_len);
703 memcpy(s + a_len, b, b_len); 703 memcpy(s + a_len, b, b_len);
704 memcpy(s + a_len + b_len, c, c_len); 704 memcpy(s + a_len + b_len, c, c_len);
705 s[s_len] = '\0'; 705 s[s_len] = '\0';
706 return s; 706 return s;
707} 707}
708 708
709/*- 709/*-
710 *----------------------------------------------------------------------- 710 *-----------------------------------------------------------------------
711 * DirExpandCurly -- 711 * DirExpandCurly --
712 * Expand curly braces like the C shell. Does this recursively. 712 * Expand curly braces like the C shell. Does this recursively.
713 * Note the special case: if after the piece of the curly brace is 713 * Note the special case: if after the piece of the curly brace is
714 * done there are no wildcard characters in the result, the result is 714 * done there are no wildcard characters in the result, the result is
715 * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE. 715 * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE.
716 * 716 *
717 * Input: 717 * Input:
718 * word Entire word to expand 718 * word Entire word to expand
719 * brace First curly brace in it 719 * brace First curly brace in it
720 * path Search path to use 720 * path Search path to use
721 * expansions Place to store the expansions 721 * expansions Place to store the expansions
722 * 722 *
723 * Results: 723 * Results:
724 * None. 724 * None.
725 * 725 *
726 * Side Effects: 726 * Side Effects:
727 * The given list is filled with the expansions... 727 * The given list is filled with the expansions...
728 * 728 *
729 *----------------------------------------------------------------------- 729 *-----------------------------------------------------------------------
730 */ 730 */
731static void 731static void
732DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions) 732DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions)
733{ 733{
734 const char *prefix, *middle, *piece, *middle_end, *suffix; 734 const char *prefix, *middle, *piece, *middle_end, *suffix;
735 size_t prefix_len, suffix_len; 735 size_t prefix_len, suffix_len;
736 736
737 /* Split the word into prefix '{' middle '}' suffix. */ 737 /* Split the word into prefix '{' middle '}' suffix. */
738 738
739 middle = brace + 1; 739 middle = brace + 1;
740 middle_end = closing_brace(middle); 740 middle_end = closing_brace(middle);
741 if (*middle_end == '\0') { 741 if (*middle_end == '\0') {
742 Error("Unterminated {} clause \"%s\"", middle); 742 Error("Unterminated {} clause \"%s\"", middle);
743 return; 743 return;
744 } 744 }
745 745
746 prefix = word; 746 prefix = word;
747 prefix_len = (size_t)(brace - prefix); 747 prefix_len = (size_t)(brace - prefix);
748 suffix = middle_end + 1; 748 suffix = middle_end + 1;
749 suffix_len = strlen(suffix); 749 suffix_len = strlen(suffix);
750 750
751 /* Split the middle into pieces, separated by commas. */ 751 /* Split the middle into pieces, separated by commas. */
752 752
753 piece = middle; 753 piece = middle;
754 while (piece < middle_end + 1) { 754 while (piece < middle_end + 1) {
755 const char *piece_end = separator_comma(piece); 755 const char *piece_end = separator_comma(piece);
756 size_t piece_len = (size_t)(piece_end - piece); 756 size_t piece_len = (size_t)(piece_end - piece);
757 757
758 char *file = concat3(prefix, prefix_len, piece, piece_len, 758 char *file = concat3(prefix, prefix_len, piece, piece_len,
759 suffix, suffix_len); 759 suffix, suffix_len);
760 760
761 if (contains_wildcard(file)) { 761 if (contains_wildcard(file)) {
762 Dir_Expand(file, path, expansions); 762 Dir_Expand(file, path, expansions);
763 free(file); 763 free(file);
764 } else { 764 } else {
765 Lst_AppendS(expansions, file); 765 Lst_AppendS(expansions, file);
766 } 766 }
767 767
768 piece = piece_end + 1; /* skip over the comma or closing brace */ 768 piece = piece_end + 1; /* skip over the comma or closing brace */
769 } 769 }
770} 770}
771 771
772 772
773/*- 773/*-
774 *----------------------------------------------------------------------- 774 *-----------------------------------------------------------------------
775 * DirExpandInt -- 775 * DirExpandInt --
776 * Internal expand routine. Passes through the directories in the 776 * Internal expand routine. Passes through the directories in the
777 * path one by one, calling DirMatchFiles for each. NOTE: This still 777 * path one by one, calling DirMatchFiles for each. NOTE: This still
778 * doesn't handle patterns in directories... 778 * doesn't handle patterns in directories...
779 * 779 *
780 * Input: 780 * Input:
781 * word Word to expand 781 * word Word to expand
782 * path Path on which to look 782 * path Path on which to look
783 * expansions Place to store the result 783 * expansions Place to store the result
784 * 784 *
785 * Results: 785 * Results:
786 * None. 786 * None.
787 * 787 *
788 * Side Effects: 788 * Side Effects:
789 * Things are added to the expansions list. 789 * Things are added to the expansions list.
790 * 790 *
791 *----------------------------------------------------------------------- 791 *-----------------------------------------------------------------------
792 */ 792 */
793static void 793static void
794DirExpandInt(const char *word, Lst path, Lst expansions) 794DirExpandInt(const char *word, Lst path, Lst expansions)
795{ 795{
796 LstNode ln; /* Current node */ 796 LstNode ln; /* Current node */
797 797
798 if (Lst_Open(path) == SUCCESS) { 798 Lst_OpenS(path);
799 while ((ln = Lst_NextS(path)) != NULL) { 799 while ((ln = Lst_NextS(path)) != NULL) {
800 Path *p = Lst_DatumS(ln); 800 Path *p = Lst_DatumS(ln);
801 DirMatchFiles(word, p, expansions); 801 DirMatchFiles(word, p, expansions);
802 } 
803 Lst_CloseS(path); 
804 } 802 }
 803 Lst_CloseS(path);
805} 804}
806 805
807/* Print a word in the list of expansions. 806/* Print a word in the list of expansions.
808 * Callback for Dir_Expand when DEBUG(DIR), via Lst_ForEach. */ 807 * Callback for Dir_Expand when DEBUG(DIR), via Lst_ForEach. */
809static int 808static int
810DirPrintWord(void *word, void *dummy MAKE_ATTR_UNUSED) 809DirPrintWord(void *word, void *dummy MAKE_ATTR_UNUSED)
811{ 810{
812 fprintf(debug_file, "%s ", (char *)word); 811 fprintf(debug_file, "%s ", (char *)word);
813 812
814 return 0; 813 return 0;
815} 814}
816 815
817/*- 816/*-
818 *----------------------------------------------------------------------- 817 *-----------------------------------------------------------------------
819 * Dir_Expand -- 818 * Dir_Expand --
820 * Expand the given word into a list of words by globbing it looking 819 * Expand the given word into a list of words by globbing it looking
821 * in the directories on the given search path. 820 * in the directories on the given search path.
822 * 821 *
823 * Input: 822 * Input:
824 * word the word to expand 823 * word the word to expand
825 * path the list of directories in which to find the 824 * path the list of directories in which to find the
826 * resulting files 825 * resulting files
827 * expansions the list on which to place the results 826 * expansions the list on which to place the results
828 * 827 *
829 * Results: 828 * Results:
830 * A list of words consisting of the files which exist along the search 829 * A list of words consisting of the files which exist along the search
831 * path matching the given pattern. 830 * path matching the given pattern.
832 * 831 *
833 * Side Effects: 832 * Side Effects:
834 * Directories may be opened. Who knows? 833 * Directories may be opened. Who knows?
835 * Undefined behavior if the word is really in read-only memory. 834 * Undefined behavior if the word is really in read-only memory.
836 *----------------------------------------------------------------------- 835 *-----------------------------------------------------------------------
837 */ 836 */
838void 837void
839Dir_Expand(const char *word, Lst path, Lst expansions) 838Dir_Expand(const char *word, Lst path, Lst expansions)
840{ 839{
841 const char *cp; 840 const char *cp;
842 841
 842 assert(path != NULL);
 843 assert(expansions != NULL);
 844
843 DIR_DEBUG1("Expanding \"%s\"... ", word); 845 DIR_DEBUG1("Expanding \"%s\"... ", word);
844 846
845 cp = strchr(word, '{'); 847 cp = strchr(word, '{');
846 if (cp) { 848 if (cp) {
847 DirExpandCurly(word, cp, path, expansions); 849 DirExpandCurly(word, cp, path, expansions);
848 } else { 850 } else {
849 cp = strchr(word, '/'); 851 cp = strchr(word, '/');
850 if (cp) { 852 if (cp) {
851 /* 853 /*
852 * The thing has a directory component -- find the first wildcard 854 * The thing has a directory component -- find the first wildcard
853 * in the string. 855 * in the string.
854 */ 856 */
855 for (cp = word; *cp; cp++) { 857 for (cp = word; *cp; cp++) {
856 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') { 858 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') {
857 break; 859 break;
858 } 860 }
859 } 861 }
860 if (*cp == '{') { 862 if (*cp == '{') {
861 /* 863 /*
862 * This one will be fun. 864 * This one will be fun.
863 */ 865 */
864 DirExpandCurly(word, cp, path, expansions); 866 DirExpandCurly(word, cp, path, expansions);
865 return; 867 return;
866 } else if (*cp != '\0') { 868 } else if (*cp != '\0') {
867 /* 869 /*
868 * Back up to the start of the component 870 * Back up to the start of the component
869 */ 871 */
870 while (cp > word && *cp != '/') { 872 while (cp > word && *cp != '/') {
871 cp--; 873 cp--;
872 } 874 }
873 if (cp != word) { 875 if (cp != word) {
874 char sc; 876 char sc;
875 char *dirpath; 877 char *dirpath;
876 /* 878 /*
877 * If the glob isn't in the first component, try and find 879 * If the glob isn't in the first component, try and find
878 * all the components up to the one with a wildcard. 880 * all the components up to the one with a wildcard.
879 */ 881 */
880 sc = cp[1]; 882 sc = cp[1];
881 ((char *)UNCONST(cp))[1] = '\0'; 883 ((char *)UNCONST(cp))[1] = '\0';
882 dirpath = Dir_FindFile(word, path); 884 dirpath = Dir_FindFile(word, path);
883 ((char *)UNCONST(cp))[1] = sc; 885 ((char *)UNCONST(cp))[1] = sc;
884 /* 886 /*
885 * dirpath is null if can't find the leading component 887 * dirpath is null if can't find the leading component
886 * XXX: Dir_FindFile won't find internal components. 888 * XXX: Dir_FindFile won't find internal components.
887 * i.e. if the path contains ../Etc/Object and we're 889 * i.e. if the path contains ../Etc/Object and we're
888 * looking for Etc, it won't be found. Ah well. 890 * looking for Etc, it won't be found. Ah well.
889 * Probably not important. 891 * Probably not important.
890 */ 892 */
891 if (dirpath != NULL) { 893 if (dirpath != NULL) {
892 char *dp = &dirpath[strlen(dirpath) - 1]; 894 char *dp = &dirpath[strlen(dirpath) - 1];
893 if (*dp == '/') 895 if (*dp == '/')
894 *dp = '\0'; 896 *dp = '\0';
895 path = Lst_Init(); 897 path = Lst_Init();
896 (void)Dir_AddDir(path, dirpath); 898 (void)Dir_AddDir(path, dirpath);
897 DirExpandInt(cp + 1, path, expansions); 899 DirExpandInt(cp + 1, path, expansions);
898 Lst_FreeS(path); 900 Lst_FreeS(path);
899 } 901 }
900 } else { 902 } else {
901 /* 903 /*
902 * Start the search from the local directory 904 * Start the search from the local directory
903 */ 905 */
904 DirExpandInt(word, path, expansions); 906 DirExpandInt(word, path, expansions);
905 } 907 }
906 } else { 908 } else {
907 /* 909 /*
908 * Return the file -- this should never happen. 910 * Return the file -- this should never happen.
909 */ 911 */
910 DirExpandInt(word, path, expansions); 912 DirExpandInt(word, path, expansions);
911 } 913 }
912 } else { 914 } else {
913 /* 915 /*
914 * First the files in dot 916 * First the files in dot
915 */ 917 */
916 DirMatchFiles(word, dot, expansions); 918 DirMatchFiles(word, dot, expansions);
917 919
918 /* 920 /*
919 * Then the files in every other directory on the path. 921 * Then the files in every other directory on the path.
920 */ 922 */
921 DirExpandInt(word, path, expansions); 923 DirExpandInt(word, path, expansions);
922 } 924 }
923 } 925 }
924 if (DEBUG(DIR)) { 926 if (DEBUG(DIR)) {
925 Lst_ForEach(expansions, DirPrintWord, NULL); 927 Lst_ForEach(expansions, DirPrintWord, NULL);
926 fprintf(debug_file, "\n"); 928 fprintf(debug_file, "\n");
927 } 929 }
928} 930}
929 931
930/*- 932/*-
931 *----------------------------------------------------------------------- 933 *-----------------------------------------------------------------------
932 * DirLookup -- 934 * DirLookup --
933 * Find if the file with the given name exists in the given path. 935 * Find if the file with the given name exists in the given path.
934 * 936 *
935 * Results: 937 * Results:
936 * The path to the file or NULL. This path is guaranteed to be in a 938 * The path to the file or NULL. This path is guaranteed to be in a
937 * different part of memory than name and so may be safely free'd. 939 * different part of memory than name and so may be safely free'd.
938 * 940 *
939 * Side Effects: 941 * Side Effects:
940 * None. 942 * None.
941 *----------------------------------------------------------------------- 943 *-----------------------------------------------------------------------
942 */ 944 */
943static char * 945static char *
944DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp, 946DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp,
945 Boolean hasSlash MAKE_ATTR_UNUSED) 947 Boolean hasSlash MAKE_ATTR_UNUSED)
946{ 948{
947 char *file; /* the current filename to check */ 949 char *file; /* the current filename to check */
948 950
949 DIR_DEBUG1(" %s ...\n", p->name); 951 DIR_DEBUG1(" %s ...\n", p->name);
950 952
951 if (Hash_FindEntry(&p->files, cp) == NULL) 953 if (Hash_FindEntry(&p->files, cp) == NULL)
952 return NULL; 954 return NULL;
953 955
954 file = str_concat3(p->name, "/", cp); 956 file = str_concat3(p->name, "/", cp);
955 DIR_DEBUG1(" returning %s\n", file); 957 DIR_DEBUG1(" returning %s\n", file);
956 p->hits += 1; 958 p->hits += 1;
957 hits += 1; 959 hits += 1;
958 return file; 960 return file;
959} 961}
960 962
961 963
962/*- 964/*-
963 *----------------------------------------------------------------------- 965 *-----------------------------------------------------------------------
964 * DirLookupSubdir -- 966 * DirLookupSubdir --
965 * Find if the file with the given name exists in the given path. 967 * Find if the file with the given name exists in the given path.
966 * 968 *
967 * Results: 969 * Results:
968 * The path to the file or NULL. This path is guaranteed to be in a 970 * The path to the file or NULL. This path is guaranteed to be in a
969 * different part of memory than name and so may be safely free'd. 971 * different part of memory than name and so may be safely free'd.
970 * 972 *
971 * Side Effects: 973 * Side Effects:
972 * If the file is found, it is added in the modification times hash 974 * If the file is found, it is added in the modification times hash
973 * table. 975 * table.
974 *----------------------------------------------------------------------- 976 *-----------------------------------------------------------------------
975 */ 977 */
976static char * 978static char *
977DirLookupSubdir(Path *p, const char *name) 979DirLookupSubdir(Path *p, const char *name)
978{ 980{
979 struct stat stb; /* Buffer for stat, if necessary */ 981 struct stat stb; /* Buffer for stat, if necessary */
980 char *file; /* the current filename to check */ 982 char *file; /* the current filename to check */
981 983
982 if (p != dot) { 984 if (p != dot) {
983 file = str_concat3(p->name, "/", name); 985 file = str_concat3(p->name, "/", name);
984 } else { 986 } else {
985 /* 987 /*
986 * Checking in dot -- DON'T put a leading ./ on the thing. 988 * Checking in dot -- DON'T put a leading ./ on the thing.
987 */ 989 */
988 file = bmake_strdup(name); 990 file = bmake_strdup(name);
989 } 991 }
990 992
991 DIR_DEBUG1("checking %s ...\n", file); 993 DIR_DEBUG1("checking %s ...\n", file);
992 994
993 if (cached_stat(file, &stb) == 0) { 995 if (cached_stat(file, &stb) == 0) {
994 nearmisses += 1; 996 nearmisses += 1;
995 return file; 997 return file;
996 } 998 }
997 free(file); 999 free(file);
998 return NULL; 1000 return NULL;
999} 1001}
1000 1002
1001/*- 1003/*-
1002 *----------------------------------------------------------------------- 1004 *-----------------------------------------------------------------------
1003 * DirLookupAbs -- 1005 * DirLookupAbs --
1004 * Find if the file with the given name exists in the given path. 1006 * Find if the file with the given name exists in the given path.
1005 * 1007 *
1006 * Results: 1008 * Results:
1007 * The path to the file, the empty string or NULL. If the file is 1009 * The path to the file, the empty string or NULL. If the file is
1008 * the empty string, the search should be terminated. 1010 * the empty string, the search should be terminated.
1009 * This path is guaranteed to be in a different part of memory 1011 * This path is guaranteed to be in a different part of memory
1010 * than name and so may be safely free'd. 1012 * than name and so may be safely free'd.
1011 * 1013 *
1012 * Side Effects: 1014 * Side Effects:
1013 * None. 1015 * None.
1014 *----------------------------------------------------------------------- 1016 *-----------------------------------------------------------------------
1015 */ 1017 */
1016static char * 1018static char *
1017DirLookupAbs(Path *p, const char *name, const char *cp) 1019DirLookupAbs(Path *p, const char *name, const char *cp)
1018{ 1020{
1019 char *p1; /* pointer into p->name */ 1021 char *p1; /* pointer into p->name */
1020 const char *p2; /* pointer into name */ 1022 const char *p2; /* pointer into name */
1021 1023
1022 DIR_DEBUG1(" %s ...\n", p->name); 1024 DIR_DEBUG1(" %s ...\n", p->name);
1023 1025
1024 /* 1026 /*
1025 * If the file has a leading path component and that component 1027 * If the file has a leading path component and that component
1026 * exactly matches the entire name of the current search 1028 * exactly matches the entire name of the current search
1027 * directory, we can attempt another cache lookup. And if we don't 1029 * directory, we can attempt another cache lookup. And if we don't
1028 * have a hit, we can safely assume the file does not exist at all. 1030 * have a hit, we can safely assume the file does not exist at all.
1029 */ 1031 */
1030 for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) { 1032 for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
1031 continue; 1033 continue;
1032 } 1034 }
1033 if (*p1 != '\0' || p2 != cp - 1) { 1035 if (*p1 != '\0' || p2 != cp - 1) {
1034 return NULL; 1036 return NULL;
1035 } 1037 }
1036 1038
1037 if (Hash_FindEntry(&p->files, cp) == NULL) { 1039 if (Hash_FindEntry(&p->files, cp) == NULL) {
1038 DIR_DEBUG0(" must be here but isn't -- returning\n"); 1040 DIR_DEBUG0(" must be here but isn't -- returning\n");
1039 /* Return empty string: terminates search */ 1041 /* Return empty string: terminates search */
1040 return bmake_strdup(""); 1042 return bmake_strdup("");
1041 } 1043 }
1042 1044
1043 p->hits += 1; 1045 p->hits += 1;
1044 hits += 1; 1046 hits += 1;
1045 DIR_DEBUG1(" returning %s\n", name); 1047 DIR_DEBUG1(" returning %s\n", name);
1046 return bmake_strdup(name); 1048 return bmake_strdup(name);
1047} 1049}
1048 1050
1049/*- 1051/*-
1050 *----------------------------------------------------------------------- 1052 *-----------------------------------------------------------------------
1051 * DirFindDot -- 1053 * DirFindDot --
1052 * Find the file given on "." or curdir 1054 * Find the file given on "." or curdir
1053 * 1055 *
1054 * Results: 1056 * Results:
1055 * The path to the file or NULL. This path is guaranteed to be in a 1057 * The path to the file or NULL. This path is guaranteed to be in a
1056 * different part of memory than name and so may be safely free'd. 1058 * different part of memory than name and so may be safely free'd.
1057 * 1059 *
1058 * Side Effects: 1060 * Side Effects:
1059 * Hit counts change 1061 * Hit counts change
1060 *----------------------------------------------------------------------- 1062 *-----------------------------------------------------------------------
1061 */ 1063 */
1062static char * 1064static char *
1063DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp) 1065DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp)
1064{ 1066{
1065 1067
1066 if (Hash_FindEntry(&dot->files, cp) != NULL) { 1068 if (Hash_FindEntry(&dot->files, cp) != NULL) {
1067 DIR_DEBUG0(" in '.'\n"); 1069 DIR_DEBUG0(" in '.'\n");
1068 hits += 1; 1070 hits += 1;
1069 dot->hits += 1; 1071 dot->hits += 1;
1070 return bmake_strdup(name); 1072 return bmake_strdup(name);
1071 } 1073 }
1072 if (cur && Hash_FindEntry(&cur->files, cp) != NULL) { 1074 if (cur && Hash_FindEntry(&cur->files, cp) != NULL) {
1073 DIR_DEBUG1(" in ${.CURDIR} = %s\n", cur->name); 1075 DIR_DEBUG1(" in ${.CURDIR} = %s\n", cur->name);
1074 hits += 1; 1076 hits += 1;
1075 cur->hits += 1; 1077 cur->hits += 1;
1076 return str_concat3(cur->name, "/", cp); 1078 return str_concat3(cur->name, "/", cp);
1077 } 1079 }
1078 1080
1079 return NULL; 1081 return NULL;
1080} 1082}
1081 1083
1082/*- 1084/*-
1083 *----------------------------------------------------------------------- 1085 *-----------------------------------------------------------------------
1084 * Dir_FindFile -- 1086 * Dir_FindFile --
1085 * Find the file with the given name along the given search path. 1087 * Find the file with the given name along the given search path.
1086 * 1088 *
1087 * Input: 1089 * Input:
1088 * name the file to find 1090 * name the file to find
1089 * path the Lst of directories to search 1091 * path the Lst of directories to search
1090 * 1092 *
1091 * Results: 1093 * Results:
1092 * The path to the file or NULL. This path is guaranteed to be in a 1094 * The path to the file or NULL. This path is guaranteed to be in a
1093 * different part of memory than name and so may be safely free'd. 1095 * different part of memory than name and so may be safely free'd.
1094 * 1096 *
1095 * Side Effects: 1097 * Side Effects:
1096 * If the file is found in a directory which is not on the path 1098 * If the file is found in a directory which is not on the path
1097 * already (either 'name' is absolute or it is a relative path 1099 * already (either 'name' is absolute or it is a relative path
1098 * [ dir1/.../dirn/file ] which exists below one of the directories 1100 * [ dir1/.../dirn/file ] which exists below one of the directories
1099 * already on the search path), its directory is added to the end 1101 * already on the search path), its directory is added to the end
1100 * of the path on the assumption that there will be more files in 1102 * of the path on the assumption that there will be more files in
1101 * that directory later on. Sometimes this is true. Sometimes not. 1103 * that directory later on. Sometimes this is true. Sometimes not.
1102 *----------------------------------------------------------------------- 1104 *-----------------------------------------------------------------------
1103 */ 1105 */
1104char * 1106char *
1105Dir_FindFile(const char *name, Lst path) 1107Dir_FindFile(const char *name, Lst path)
1106{ 1108{
1107 LstNode ln; /* a list element */ 1109 LstNode ln; /* a list element */
1108 char *file; /* the current filename to check */ 1110 char *file; /* the current filename to check */
1109 Path *p; /* current path member */ 1111 Path *p; /* current path member */
1110 const char *cp; /* Terminal name of file */ 1112 const char *cp; /* Terminal name of file */
1111 Boolean hasLastDot = FALSE; /* true we should search dot last */ 1113 Boolean hasLastDot = FALSE; /* true we should search dot last */
1112 Boolean hasSlash; /* true if 'name' contains a / */ 1114 Boolean hasSlash; /* true if 'name' contains a / */
1113 struct stat stb; /* Buffer for stat, if necessary */ 1115 struct stat stb; /* Buffer for stat, if necessary */
1114 const char *trailing_dot = "."; 1116 const char *trailing_dot = ".";
1115 1117
1116 /* 1118 /*
1117 * Find the final component of the name and note whether it has a 1119 * Find the final component of the name and note whether it has a
1118 * slash in it (the name, I mean) 1120 * slash in it (the name, I mean)
1119 */ 1121 */
1120 cp = strrchr(name, '/'); 1122 cp = strrchr(name, '/');
1121 if (cp) { 1123 if (cp) {
1122 hasSlash = TRUE; 1124 hasSlash = TRUE;
1123 cp += 1; 1125 cp += 1;
1124 } else { 1126 } else {
1125 hasSlash = FALSE; 1127 hasSlash = FALSE;
1126 cp = name; 1128 cp = name;
1127 } 1129 }
1128 1130
1129 DIR_DEBUG1("Searching for %s ...", name); 1131 DIR_DEBUG1("Searching for %s ...", name);
1130 1132
1131 if (Lst_Open(path) == FAILURE) { 1133 if (path == NULL) {
1132 DIR_DEBUG0("couldn't open path, file not found\n"); 1134 DIR_DEBUG0("couldn't open path, file not found\n");
1133 misses += 1; 1135 misses += 1;
1134 return NULL; 1136 return NULL;
1135 } 1137 }
1136 1138
 1139 Lst_OpenS(path);
1137 if ((ln = Lst_First(path)) != NULL) { 1140 if ((ln = Lst_First(path)) != NULL) {
1138 p = Lst_DatumS(ln); 1141 p = Lst_DatumS(ln);
1139 if (p == dotLast) { 1142 if (p == dotLast) {
1140 hasLastDot = TRUE; 1143 hasLastDot = TRUE;
1141 DIR_DEBUG0("[dot last]..."); 1144 DIR_DEBUG0("[dot last]...");
1142 } 1145 }
1143 } 1146 }
1144 DIR_DEBUG0("\n"); 1147 DIR_DEBUG0("\n");
1145 1148
1146 /* 1149 /*
1147 * If there's no leading directory components or if the leading 1150 * If there's no leading directory components or if the leading
1148 * directory component is exactly `./', consult the cached contents 1151 * directory component is exactly `./', consult the cached contents
1149 * of each of the directories on the search path. 1152 * of each of the directories on the search path.
1150 */ 1153 */
1151 if (!hasSlash || (cp - name == 2 && *name == '.')) { 1154 if (!hasSlash || (cp - name == 2 && *name == '.')) {
1152 /* 1155 /*
1153 * We look through all the directories on the path seeking one which 1156 * We look through all the directories on the path seeking one which
1154 * contains the final component of the given name. If such a beast 1157 * contains the final component of the given name. If such a beast
1155 * is found, we concatenate the directory name and the final 1158 * is found, we concatenate the directory name and the final
1156 * component and return the resulting string. If we don't find any 1159 * component and return the resulting string. If we don't find any
1157 * such thing, we go on to phase two... 1160 * such thing, we go on to phase two...
1158 * 1161 *
1159 * No matter what, we always look for the file in the current 1162 * No matter what, we always look for the file in the current
1160 * directory before anywhere else (unless we found the magic 1163 * directory before anywhere else (unless we found the magic
1161 * DOTLAST path, in which case we search it last) and we *do not* 1164 * DOTLAST path, in which case we search it last) and we *do not*
1162 * add the ./ to it if it exists. 1165 * add the ./ to it if it exists.
1163 * This is so there are no conflicts between what the user 1166 * This is so there are no conflicts between what the user
1164 * specifies (fish.c) and what pmake finds (./fish.c). 1167 * specifies (fish.c) and what pmake finds (./fish.c).
1165 */ 1168 */
1166 if (!hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) { 1169 if (!hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) {
1167 Lst_CloseS(path); 1170 Lst_CloseS(path);
1168 return file; 1171 return file;
1169 } 1172 }
1170 1173
1171 while ((ln = Lst_NextS(path)) != NULL) { 1174 while ((ln = Lst_NextS(path)) != NULL) {
1172 p = Lst_DatumS(ln); 1175 p = Lst_DatumS(ln);
1173 if (p == dotLast) 1176 if (p == dotLast)
1174 continue; 1177 continue;
1175 if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) { 1178 if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) {
1176 Lst_CloseS(path); 1179 Lst_CloseS(path);
1177 return file; 1180 return file;
1178 } 1181 }
1179 } 1182 }
1180 1183
1181 if (hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) { 1184 if (hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) {
1182 Lst_CloseS(path); 1185 Lst_CloseS(path);
1183 return file; 1186 return file;
1184 } 1187 }
1185 } 1188 }
1186 Lst_CloseS(path); 1189 Lst_CloseS(path);
1187 1190
1188 /* 1191 /*
1189 * We didn't find the file on any directory in the search path. 1192 * We didn't find the file on any directory in the search path.
1190 * If the name doesn't contain a slash, that means it doesn't exist. 1193 * If the name doesn't contain a slash, that means it doesn't exist.
1191 * If it *does* contain a slash, however, there is still hope: it 1194 * If it *does* contain a slash, however, there is still hope: it
1192 * could be in a subdirectory of one of the members of the search 1195 * could be in a subdirectory of one of the members of the search
1193 * path. (eg. /usr/include and sys/types.h. The above search would 1196 * path. (eg. /usr/include and sys/types.h. The above search would
1194 * fail to turn up types.h in /usr/include, but it *is* in 1197 * fail to turn up types.h in /usr/include, but it *is* in
1195 * /usr/include/sys/types.h). 1198 * /usr/include/sys/types.h).
1196 * [ This no longer applies: If we find such a beast, we assume there 1199 * [ This no longer applies: If we find such a beast, we assume there
1197 * will be more (what else can we assume?) and add all but the last 1200 * will be more (what else can we assume?) and add all but the last
1198 * component of the resulting name onto the search path (at the 1201 * component of the resulting name onto the search path (at the
1199 * end).] 1202 * end).]
1200 * This phase is only performed if the file is *not* absolute. 1203 * This phase is only performed if the file is *not* absolute.
1201 */ 1204 */
1202 if (!hasSlash) { 1205 if (!hasSlash) {
1203 DIR_DEBUG0(" failed.\n"); 1206 DIR_DEBUG0(" failed.\n");
1204 misses += 1; 1207 misses += 1;
1205 return NULL; 1208 return NULL;
1206 } 1209 }
1207 1210
1208 if (*cp == '\0') { 1211 if (*cp == '\0') {
1209 /* we were given a trailing "/" */ 1212 /* we were given a trailing "/" */
1210 cp = trailing_dot; 1213 cp = trailing_dot;
1211 } 1214 }
1212 1215
1213 if (name[0] != '/') { 1216 if (name[0] != '/') {
1214 Boolean checkedDot = FALSE; 1217 Boolean checkedDot = FALSE;
1215 1218
1216 DIR_DEBUG0(" Trying subdirectories...\n"); 1219 DIR_DEBUG0(" Trying subdirectories...\n");
1217 1220
1218 if (!hasLastDot) { 1221 if (!hasLastDot) {
1219 if (dot) { 1222 if (dot) {
1220 checkedDot = TRUE; 1223 checkedDot = TRUE;
1221 if ((file = DirLookupSubdir(dot, name)) != NULL) 1224 if ((file = DirLookupSubdir(dot, name)) != NULL)
1222 return file; 1225 return file;
1223 } 1226 }
1224 if (cur && (file = DirLookupSubdir(cur, name)) != NULL) 1227 if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
1225 return file; 1228 return file;
1226 } 1229 }
1227 1230
1228 Lst_OpenS(path); 1231 Lst_OpenS(path);
1229 while ((ln = Lst_NextS(path)) != NULL) { 1232 while ((ln = Lst_NextS(path)) != NULL) {
1230 p = Lst_DatumS(ln); 1233 p = Lst_DatumS(ln);
1231 if (p == dotLast) 1234 if (p == dotLast)
1232 continue; 1235 continue;
1233 if (p == dot) { 1236 if (p == dot) {
1234 if (checkedDot) 1237 if (checkedDot)
1235 continue; 1238 continue;
1236 checkedDot = TRUE; 1239 checkedDot = TRUE;
1237 } 1240 }
1238 if ((file = DirLookupSubdir(p, name)) != NULL) { 1241 if ((file = DirLookupSubdir(p, name)) != NULL) {
1239 Lst_CloseS(path); 1242 Lst_CloseS(path);
1240 return file; 1243 return file;
1241 } 1244 }
1242 } 1245 }
1243 Lst_CloseS(path); 1246 Lst_CloseS(path);
1244 1247
1245 if (hasLastDot) { 1248 if (hasLastDot) {
1246 if (dot && !checkedDot) { 1249 if (dot && !checkedDot) {
1247 checkedDot = TRUE; 1250 checkedDot = TRUE;
1248 if ((file = DirLookupSubdir(dot, name)) != NULL) 1251 if ((file = DirLookupSubdir(dot, name)) != NULL)
1249 return file; 1252 return file;
1250 } 1253 }
1251 if (cur && (file = DirLookupSubdir(cur, name)) != NULL) 1254 if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
1252 return file; 1255 return file;
1253 } 1256 }
1254 1257
1255 if (checkedDot) { 1258 if (checkedDot) {
1256 /* 1259 /*
1257 * Already checked by the given name, since . was in the path, 1260 * Already checked by the given name, since . was in the path,
1258 * so no point in proceeding... 1261 * so no point in proceeding...
1259 */ 1262 */
1260 DIR_DEBUG0(" Checked . already, returning NULL\n"); 1263 DIR_DEBUG0(" Checked . already, returning NULL\n");
1261 return NULL; 1264 return NULL;
1262 } 1265 }
1263 1266
1264 } else { /* name[0] == '/' */ 1267 } else { /* name[0] == '/' */
1265 1268
1266 /* 1269 /*
1267 * For absolute names, compare directory path prefix against the 1270 * For absolute names, compare directory path prefix against the
1268 * the directory path of each member on the search path for an exact 1271 * the directory path of each member on the search path for an exact
1269 * match. If we have an exact match on any member of the search path, 1272 * match. If we have an exact match on any member of the search path,
1270 * use the cached contents of that member to lookup the final file 1273 * use the cached contents of that member to lookup the final file
1271 * component. If that lookup fails we can safely assume that the 1274 * component. If that lookup fails we can safely assume that the
1272 * file does not exist at all. This is signified by DirLookupAbs() 1275 * file does not exist at all. This is signified by DirLookupAbs()
1273 * returning an empty string. 1276 * returning an empty string.
1274 */ 1277 */
1275 DIR_DEBUG0(" Trying exact path matches...\n"); 1278 DIR_DEBUG0(" Trying exact path matches...\n");
1276 1279
1277 if (!hasLastDot && cur && 1280 if (!hasLastDot && cur &&
1278 ((file = DirLookupAbs(cur, name, cp)) != NULL)) { 1281 ((file = DirLookupAbs(cur, name, cp)) != NULL)) {
1279 if (file[0] == '\0') { 1282 if (file[0] == '\0') {
1280 free(file); 1283 free(file);
1281 return NULL; 1284 return NULL;
1282 } 1285 }
1283 return file; 1286 return file;
1284 } 1287 }
1285 1288
1286 Lst_OpenS(path); 1289 Lst_OpenS(path);
1287 while ((ln = Lst_NextS(path)) != NULL) { 1290 while ((ln = Lst_NextS(path)) != NULL) {
1288 p = Lst_DatumS(ln); 1291 p = Lst_DatumS(ln);
1289 if (p == dotLast) 1292 if (p == dotLast)
1290 continue; 1293 continue;
1291 if ((file = DirLookupAbs(p, name, cp)) != NULL) { 1294 if ((file = DirLookupAbs(p, name, cp)) != NULL) {
1292 Lst_CloseS(path); 1295 Lst_CloseS(path);
1293 if (file[0] == '\0') { 1296 if (file[0] == '\0') {
1294 free(file); 1297 free(file);
1295 return NULL; 1298 return NULL;
1296 } 1299 }
1297 return file; 1300 return file;
1298 } 1301 }
1299 } 1302 }
1300 Lst_CloseS(path); 1303 Lst_CloseS(path);
1301 1304
1302 if (hasLastDot && cur && 1305 if (hasLastDot && cur &&
1303 ((file = DirLookupAbs(cur, name, cp)) != NULL)) { 1306 ((file = DirLookupAbs(cur, name, cp)) != NULL)) {
1304 if (file[0] == '\0') { 1307 if (file[0] == '\0') {
1305 free(file); 1308 free(file);
1306 return NULL; 1309 return NULL;
1307 } 1310 }
1308 return file; 1311 return file;
1309 } 1312 }
1310 } 1313 }
1311 1314
1312 /* 1315 /*
1313 * Didn't find it that way, either. Sigh. Phase 3. Add its directory 1316 * Didn't find it that way, either. Sigh. Phase 3. Add its directory
1314 * onto the search path in any case, just in case, then look for the 1317 * onto the search path in any case, just in case, then look for the
1315 * thing in the hash table. If we find it, grand. We return a new 1318 * thing in the hash table. If we find it, grand. We return a new
1316 * copy of the name. Otherwise we sadly return a NULL pointer. Sigh. 1319 * copy of the name. Otherwise we sadly return a NULL pointer. Sigh.
1317 * Note that if the directory holding the file doesn't exist, this will 1320 * Note that if the directory holding the file doesn't exist, this will
1318 * do an extra search of the final directory on the path. Unless something 1321 * do an extra search of the final directory on the path. Unless something
1319 * weird happens, this search won't succeed and life will be groovy. 1322 * weird happens, this search won't succeed and life will be groovy.
1320 * 1323 *
1321 * Sigh. We cannot add the directory onto the search path because 1324 * Sigh. We cannot add the directory onto the search path because
1322 * of this amusing case: 1325 * of this amusing case:
1323 * $(INSTALLDIR)/$(FILE): $(FILE) 1326 * $(INSTALLDIR)/$(FILE): $(FILE)
1324 * 1327 *
1325 * $(FILE) exists in $(INSTALLDIR) but not in the current one. 1328 * $(FILE) exists in $(INSTALLDIR) but not in the current one.
1326 * When searching for $(FILE), we will find it in $(INSTALLDIR) 1329 * When searching for $(FILE), we will find it in $(INSTALLDIR)
1327 * b/c we added it here. This is not good... 1330 * b/c we added it here. This is not good...
1328 */ 1331 */
1329#ifdef notdef 1332#ifdef notdef
1330 if (cp == traling_dot) { 1333 if (cp == traling_dot) {
1331 cp = strrchr(name, '/'); 1334 cp = strrchr(name, '/');
1332 cp += 1; 1335 cp += 1;
1333 } 1336 }
1334 cp[-1] = '\0'; 1337 cp[-1] = '\0';
1335 (void)Dir_AddDir(path, name); 1338 (void)Dir_AddDir(path, name);
1336 cp[-1] = '/'; 1339 cp[-1] = '/';
1337 1340
1338 bigmisses += 1; 1341 bigmisses += 1;
1339 ln = Lst_Last(path); 1342 ln = Lst_Last(path);
1340 if (ln == NULL) { 1343 if (ln == NULL) {
1341 return NULL; 1344 return NULL;
1342 } else { 1345 } else {
1343 p = Lst_DatumS(ln); 1346 p = Lst_DatumS(ln);
1344 } 1347 }
1345 1348
1346 if (Hash_FindEntry(&p->files, cp) != NULL) { 1349 if (Hash_FindEntry(&p->files, cp) != NULL) {
1347 return bmake_strdup(name); 1350 return bmake_strdup(name);
1348 } else { 1351 } else {
1349 return NULL; 1352 return NULL;
1350 } 1353 }
1351#else /* !notdef */ 1354#else /* !notdef */
1352 DIR_DEBUG1(" Looking for \"%s\" ...\n", name); 1355 DIR_DEBUG1(" Looking for \"%s\" ...\n", name);
1353 1356
1354 bigmisses += 1; 1357 bigmisses += 1;
1355 if (cached_stat(name, &stb) == 0) { 1358 if (cached_stat(name, &stb) == 0) {
1356 return bmake_strdup(name); 1359 return bmake_strdup(name);
1357 } 1360 }
1358 1361
1359 DIR_DEBUG0(" failed. Returning NULL\n"); 1362 DIR_DEBUG0(" failed. Returning NULL\n");
1360 return NULL; 1363 return NULL;
1361#endif /* notdef */ 1364#endif /* notdef */
1362} 1365}
1363 1366
1364 1367
1365/*- 1368/*-
1366 *----------------------------------------------------------------------- 1369 *-----------------------------------------------------------------------
1367 * Dir_FindHereOrAbove -- 1370 * Dir_FindHereOrAbove --
1368 * search for a path starting at a given directory and then working 1371 * search for a path starting at a given directory and then working
1369 * our way up towards the root. 1372 * our way up towards the root.
1370 * 1373 *
1371 * Input: 1374 * Input:
1372 * here starting directory 1375 * here starting directory
1373 * search_path the path we are looking for 1376 * search_path the path we are looking for
1374 * result the result of a successful search is placed here 1377 * result the result of a successful search is placed here
1375 * rlen the length of the result buffer 1378 * rlen the length of the result buffer
1376 * (typically MAXPATHLEN + 1) 1379 * (typically MAXPATHLEN + 1)
1377 * 1380 *
1378 * Results: 1381 * Results:
1379 * 0 on failure, 1 on success [in which case the found path is put 1382 * 0 on failure, 1 on success [in which case the found path is put
1380 * in the result buffer]. 1383 * in the result buffer].
1381 * 1384 *
1382 * Side Effects: 1385 * Side Effects:
1383 *----------------------------------------------------------------------- 1386 *-----------------------------------------------------------------------
1384 */ 1387 */
1385int 1388int
1386Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen) 1389Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen)
1387{ 1390{
1388 struct stat st; 1391 struct stat st;
1389 char dirbase[MAXPATHLEN + 1], *db_end; 1392 char dirbase[MAXPATHLEN + 1], *db_end;
1390 char try[MAXPATHLEN + 1], *try_end; 1393 char try[MAXPATHLEN + 1], *try_end;
1391 1394
1392 /* copy out our starting point */ 1395 /* copy out our starting point */
1393 snprintf(dirbase, sizeof(dirbase), "%s", here); 1396 snprintf(dirbase, sizeof(dirbase), "%s", here);
1394 db_end = dirbase + strlen(dirbase); 1397 db_end = dirbase + strlen(dirbase);
1395 1398
1396 /* loop until we determine a result */ 1399 /* loop until we determine a result */
1397 while (1) { 1400 while (1) {
1398 1401
1399 /* try and stat(2) it ... */ 1402 /* try and stat(2) it ... */
1400 snprintf(try, sizeof(try), "%s/%s", dirbase, search_path); 1403 snprintf(try, sizeof(try), "%s/%s", dirbase, search_path);
1401 if (cached_stat(try, &st) != -1) { 1404 if (cached_stat(try, &st) != -1) {
1402 /* 1405 /*
1403 * success! if we found a file, chop off 1406 * success! if we found a file, chop off
1404 * the filename so we return a directory. 1407 * the filename so we return a directory.
1405 */ 1408 */
1406 if ((st.st_mode & S_IFMT) != S_IFDIR) { 1409 if ((st.st_mode & S_IFMT) != S_IFDIR) {
1407 try_end = try + strlen(try); 1410 try_end = try + strlen(try);
1408 while (try_end > try && *try_end != '/') 1411 while (try_end > try && *try_end != '/')
1409 try_end--; 1412 try_end--;
1410 if (try_end > try) 1413 if (try_end > try)
1411 *try_end = 0; /* chop! */ 1414 *try_end = 0; /* chop! */
1412 } 1415 }
1413 1416
1414 /* 1417 /*
1415 * done! 1418 * done!
1416 */ 1419 */
1417 snprintf(result, rlen, "%s", try); 1420 snprintf(result, rlen, "%s", try);
1418 return 1; 1421 return 1;
1419 } 1422 }
1420 1423
1421 /* 1424 /*
1422 * nope, we didn't find it. if we used up dirbase we've 1425 * nope, we didn't find it. if we used up dirbase we've
1423 * reached the root and failed. 1426 * reached the root and failed.
1424 */ 1427 */
1425 if (db_end == dirbase) 1428 if (db_end == dirbase)
1426 break; /* failed! */ 1429 break; /* failed! */
1427 1430
1428 /* 1431 /*
1429 * truncate dirbase from the end to move up a dir 1432 * truncate dirbase from the end to move up a dir
1430 */ 1433 */
1431 while (db_end > dirbase && *db_end != '/') 1434 while (db_end > dirbase && *db_end != '/')
1432 db_end--; 1435 db_end--;
1433 *db_end = 0; /* chop! */ 1436 *db_end = 0; /* chop! */
1434 1437
1435 } /* while (1) */ 1438 } /* while (1) */
1436 1439
1437 /* 1440 /*
1438 * we failed... 1441 * we failed...
1439 */ 1442 */
1440 return 0; 1443 return 0;
1441} 1444}
1442 1445
1443/*- 1446/*-
1444 *----------------------------------------------------------------------- 1447 *-----------------------------------------------------------------------
1445 * Dir_MTime -- 1448 * Dir_MTime --
1446 * Find the modification time of the file described by gn along the 1449 * Find the modification time of the file described by gn along the
1447 * search path dirSearchPath. 1450 * search path dirSearchPath.
1448 * 1451 *
1449 * Input: 1452 * Input:
1450 * gn the file whose modification time is desired 1453 * gn the file whose modification time is desired
1451 * 1454 *
1452 * Results: 1455 * Results:
1453 * The modification time or 0 if it doesn't exist 1456 * The modification time or 0 if it doesn't exist
1454 * 1457 *
1455 * Side Effects: 1458 * Side Effects:
1456 * The modification time is placed in the node's mtime slot. 1459 * The modification time is placed in the node's mtime slot.
1457 * If the node didn't have a path entry before, and Dir_FindFile 1460 * If the node didn't have a path entry before, and Dir_FindFile
1458 * found one for it, the full name is placed in the path slot. 1461 * found one for it, the full name is placed in the path slot.
1459 *----------------------------------------------------------------------- 1462 *-----------------------------------------------------------------------
1460 */ 1463 */
1461int 1464int
1462Dir_MTime(GNode *gn, Boolean recheck) 1465Dir_MTime(GNode *gn, Boolean recheck)
1463{ 1466{
1464 char *fullName; /* the full pathname of name */ 1467 char *fullName; /* the full pathname of name */
1465 struct stat stb; /* buffer for finding the mod time */ 1468 struct stat stb; /* buffer for finding the mod time */
1466 1469
1467 if (gn->type & OP_ARCHV) { 1470 if (gn->type & OP_ARCHV) {
1468 return Arch_MTime(gn); 1471 return Arch_MTime(gn);
1469 } else if (gn->type & OP_PHONY) { 1472 } else if (gn->type & OP_PHONY) {
1470 gn->mtime = 0; 1473 gn->mtime = 0;
1471 return 0; 1474 return 0;
1472 } else if (gn->path == NULL) { 1475 } else if (gn->path == NULL) {
1473 if (gn->type & OP_NOPATH) 1476 if (gn->type & OP_NOPATH)
1474 fullName = NULL; 1477 fullName = NULL;
1475 else { 1478 else {
1476 fullName = Dir_FindFile(gn->name, Suff_FindPath(gn)); 1479 fullName = Dir_FindFile(gn->name, Suff_FindPath(gn));
1477 if (fullName == NULL && gn->flags & FROM_DEPEND && 1480 if (fullName == NULL && gn->flags & FROM_DEPEND &&
1478 !Lst_IsEmpty(gn->iParents)) { 1481 !Lst_IsEmpty(gn->iParents)) {
1479 char *cp; 1482 char *cp;
1480 1483
1481 cp = strrchr(gn->name, '/'); 1484 cp = strrchr(gn->name, '/');
1482 if (cp) { 1485 if (cp) {
1483 /* 1486 /*
1484 * This is an implied source, and it may have moved, 1487 * This is an implied source, and it may have moved,
1485 * see if we can find it via the current .PATH 1488 * see if we can find it via the current .PATH
1486 */ 1489 */
1487 cp++; 1490 cp++;
1488 1491
1489 fullName = Dir_FindFile(cp, Suff_FindPath(gn)); 1492 fullName = Dir_FindFile(cp, Suff_FindPath(gn));
1490 if (fullName) { 1493 if (fullName) {
1491 /* 1494 /*
1492 * Put the found file in gn->path 1495 * Put the found file in gn->path
1493 * so that we give that to the compiler. 1496 * so that we give that to the compiler.
1494 */ 1497 */
1495 gn->path = bmake_strdup(fullName); 1498 gn->path = bmake_strdup(fullName);
1496 if (!Job_RunTarget(".STALE", gn->fname)) 1499 if (!Job_RunTarget(".STALE", gn->fname))
1497 fprintf(stdout, 1500 fprintf(stdout,
1498 "%s: %s, %d: ignoring stale %s for %s, " 1501 "%s: %s, %d: ignoring stale %s for %s, "
1499 "found %s\n", progname, gn->fname, 1502 "found %s\n", progname, gn->fname,
1500 gn->lineno, 1503 gn->lineno,
1501 makeDependfile, gn->name, fullName); 1504 makeDependfile, gn->name, fullName);
1502 } 1505 }
1503 } 1506 }
1504 } 1507 }
1505 DIR_DEBUG2("Found '%s' as '%s'\n", 1508 DIR_DEBUG2("Found '%s' as '%s'\n",
1506 gn->name, fullName ? fullName : "(not found)"); 1509 gn->name, fullName ? fullName : "(not found)");
1507 } 1510 }
1508 } else { 1511 } else {
1509 fullName = gn->path; 1512 fullName = gn->path;
1510 } 1513 }
1511 1514
1512 if (fullName == NULL) { 1515 if (fullName == NULL) {
1513 fullName = bmake_strdup(gn->name); 1516 fullName = bmake_strdup(gn->name);
1514 } 1517 }
1515 1518
1516 if (cached_stats(&mtimes, fullName, &stb, recheck ? CST_UPDATE : 0) < 0) { 1519 if (cached_stats(&mtimes, fullName, &stb, recheck ? CST_UPDATE : 0) < 0) {
1517 if (gn->type & OP_MEMBER) { 1520 if (gn->type & OP_MEMBER) {
1518 if (fullName != gn->path) 1521 if (fullName != gn->path)
1519 free(fullName); 1522 free(fullName);
1520 return Arch_MemMTime(gn); 1523 return Arch_MemMTime(gn);
1521 } else { 1524 } else {
1522 stb.st_mtime = 0; 1525 stb.st_mtime = 0;
1523 } 1526 }
1524 } 1527 }
1525 1528
1526 if (fullName && gn->path == NULL) { 1529 if (fullName && gn->path == NULL) {
1527 gn->path = fullName; 1530 gn->path = fullName;
1528 } 1531 }
1529 1532
1530 gn->mtime = stb.st_mtime; 1533 gn->mtime = stb.st_mtime;
1531 return gn->mtime; 1534 return gn->mtime;
1532} 1535}
1533 1536
1534/*- 1537/*-
1535 *----------------------------------------------------------------------- 1538 *-----------------------------------------------------------------------
1536 * Dir_AddDir -- 1539 * Dir_AddDir --
1537 * Add the given name to the end of the given path. The order of 1540 * Add the given name to the end of the given path. The order of
1538 * the arguments is backwards so ParseDoDependency can do a 1541 * the arguments is backwards so ParseDoDependency can do a
1539 * Lst_ForEach of its list of paths... 1542 * Lst_ForEach of its list of paths...
1540 * 1543 *
1541 * Input: 1544 * Input:
1542 * path the path to which the directory should be 1545 * path the path to which the directory should be
1543 * added 1546 * added
1544 * name the name of the directory to add 1547 * name the name of the directory to add
1545 * 1548 *
1546 * Results: 1549 * Results:
1547 * none 1550 * none
1548 * 1551 *
1549 * Side Effects: 1552 * Side Effects:
1550 * A structure is added to the list and the directory is 1553 * A structure is added to the list and the directory is
1551 * read and hashed. 1554 * read and hashed.
1552 *----------------------------------------------------------------------- 1555 *-----------------------------------------------------------------------
1553 */ 1556 */
1554Path * 1557Path *
1555Dir_AddDir(Lst path, const char *name) 1558Dir_AddDir(Lst path, const char *name)
1556{ 1559{
1557 LstNode ln = NULL; /* node in case Path structure is found */ 1560 LstNode ln = NULL; /* node in case Path structure is found */
1558 Path *p = NULL; /* pointer to new Path structure */ 1561 Path *p = NULL; /* pointer to new Path structure */
1559 DIR *d; /* for reading directory */ 1562 DIR *d; /* for reading directory */
1560 struct dirent *dp; /* entry in directory */ 1563 struct dirent *dp; /* entry in directory */
1561 1564
1562 if (strcmp(name, ".DOTLAST") == 0) { 1565 if (strcmp(name, ".DOTLAST") == 0) {
1563 ln = Lst_Find(path, DirFindName, name); 1566 ln = Lst_Find(path, DirFindName, name);
1564 if (ln != NULL) 1567 if (ln != NULL)
1565 return Lst_DatumS(ln); 1568 return Lst_DatumS(ln);
1566 else { 1569 else {
1567 /* XXX: It is wrong to increment the refCount if dotLast is not 1570 /* XXX: It is wrong to increment the refCount if dotLast is not
1568 * used afterwards. */ 1571 * used afterwards. */
1569 dotLast->refCount += 1; 1572 dotLast->refCount += 1;
1570 if (path != NULL) 1573 if (path != NULL)
1571 Lst_PrependS(path, dotLast); 1574 Lst_PrependS(path, dotLast);
1572 } 1575 }
1573 } 1576 }
1574 1577
1575 if (path) 1578 if (path)
1576 ln = Lst_Find(openDirectories, DirFindName, name); 1579 ln = Lst_Find(openDirectories, DirFindName, name);
1577 if (ln != NULL) { 1580 if (ln != NULL) {
1578 p = Lst_DatumS(ln); 1581 p = Lst_DatumS(ln);
1579 if (path && Lst_MemberS(path, p) == NULL) { 1582 if (path && Lst_MemberS(path, p) == NULL) {
1580 p->refCount += 1; 1583 p->refCount += 1;
1581 Lst_AppendS(path, p); 1584 Lst_AppendS(path, p);
1582 } 1585 }
1583 } else { 1586 } else {
1584 DIR_DEBUG1("Caching %s ...", name); 1587 DIR_DEBUG1("Caching %s ...", name);
1585 1588
1586 if ((d = opendir(name)) != NULL) { 1589 if ((d = opendir(name)) != NULL) {
1587 p = bmake_malloc(sizeof(Path)); 1590 p = bmake_malloc(sizeof(Path));
1588 p->name = bmake_strdup(name); 1591 p->name = bmake_strdup(name);
1589 p->hits = 0; 1592 p->hits = 0;
1590 p->refCount = 1; 1593 p->refCount = 1;
1591 Hash_InitTable(&p->files, -1); 1594 Hash_InitTable(&p->files, -1);
1592 1595
1593 while ((dp = readdir(d)) != NULL) { 1596 while ((dp = readdir(d)) != NULL) {
1594#if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ 1597#if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */
1595 /* 1598 /*
1596 * The sun directory library doesn't check for a 0 inode 1599 * The sun directory library doesn't check for a 0 inode
1597 * (0-inode slots just take up space), so we have to do 1600 * (0-inode slots just take up space), so we have to do
1598 * it ourselves. 1601 * it ourselves.
1599 */ 1602 */
1600 if (dp->d_fileno == 0) { 1603 if (dp->d_fileno == 0) {
1601 continue; 1604 continue;
1602 } 1605 }
1603#endif /* sun && d_ino */ 1606#endif /* sun && d_ino */
1604 (void)Hash_CreateEntry(&p->files, dp->d_name, NULL); 1607 (void)Hash_CreateEntry(&p->files, dp->d_name, NULL);
1605 } 1608 }
1606 (void)closedir(d); 1609 (void)closedir(d);
1607 Lst_AppendS(openDirectories, p); 1610 Lst_AppendS(openDirectories, p);
1608 if (path != NULL) 1611 if (path != NULL)
1609 Lst_AppendS(path, p); 1612 Lst_AppendS(path, p);
1610 } 1613 }
1611 DIR_DEBUG0("done\n"); 1614 DIR_DEBUG0("done\n");
1612 } 1615 }
1613 return p; 1616 return p;
1614} 1617}
1615 1618
1616/*- 1619/*-
1617 *----------------------------------------------------------------------- 1620 *-----------------------------------------------------------------------
1618 * Dir_CopyDir -- 1621 * Dir_CopyDir --
1619 * Callback function for duplicating a search path via Lst_CopyS. 1622 * Callback function for duplicating a search path via Lst_CopyS.
1620 * Ups the reference count for the directory. 1623 * Ups the reference count for the directory.
1621 * 1624 *
1622 * Results: 1625 * Results:
1623 * Returns the Path it was given. 1626 * Returns the Path it was given.
1624 *----------------------------------------------------------------------- 1627 *-----------------------------------------------------------------------
1625 */ 1628 */
1626void * 1629void *
1627Dir_CopyDir(void *p) 1630Dir_CopyDir(void *p)
1628{ 1631{
1629 ((Path *)p)->refCount += 1; 1632 ((Path *)p)->refCount += 1;
1630 1633
1631 return p; 1634 return p;
1632} 1635}
1633 1636
1634/*- 1637/*-
1635 *----------------------------------------------------------------------- 1638 *-----------------------------------------------------------------------
1636 * Dir_MakeFlags -- 1639 * Dir_MakeFlags --
1637 * Make a string by taking all the directories in the given search 1640 * Make a string by taking all the directories in the given search
1638 * path and preceding them by the given flag. Used by the suffix 1641 * path and preceding them by the given flag. Used by the suffix
1639 * module to create variables for compilers based on suffix search 1642 * module to create variables for compilers based on suffix search
1640 * paths. 1643 * paths.
1641 * 1644 *
1642 * Input: 1645 * Input:
1643 * flag flag which should precede each directory 1646 * flag flag which should precede each directory
1644 * path list of directories 1647 * path list of directories
1645 * 1648 *
1646 * Results: 1649 * Results:
1647 * The string mentioned above. Note that there is no space between 1650 * The string mentioned above. Note that there is no space between
1648 * the given flag and each directory. The empty string is returned if 1651 * the given flag and each directory. The empty string is returned if
1649 * Things don't go well. 1652 * Things don't go well.
1650 * 1653 *
1651 * Side Effects: 1654 * Side Effects:
1652 * None 1655 * None
1653 *----------------------------------------------------------------------- 1656 *-----------------------------------------------------------------------
1654 */ 1657 */
1655char * 1658char *
1656Dir_MakeFlags(const char *flag, Lst path) 1659Dir_MakeFlags(const char *flag, Lst path)
1657{ 1660{
1658 Buffer buf; 1661 Buffer buf;
1659 LstNode ln; /* the node of the current directory */ 1662 LstNode ln; /* the node of the current directory */
1660 1663
1661 Buf_Init(&buf, 0); 1664 Buf_Init(&buf, 0);
1662 1665
1663 if (Lst_Open(path) == SUCCESS) { 1666 if (path != NULL) {
 1667 Lst_OpenS(path);
1664 while ((ln = Lst_NextS(path)) != NULL) { 1668 while ((ln = Lst_NextS(path)) != NULL) {
1665 Path *p = Lst_DatumS(ln); 1669 Path *p = Lst_DatumS(ln);
1666 Buf_AddStr(&buf, " "); 1670 Buf_AddStr(&buf, " ");
1667 Buf_AddStr(&buf, flag); 1671 Buf_AddStr(&buf, flag);
1668 Buf_AddStr(&buf, p->name); 1672 Buf_AddStr(&buf, p->name);
1669 } 1673 }
1670 Lst_CloseS(path); 1674 Lst_CloseS(path);
1671 } 1675 }
1672 1676
1673 return Buf_Destroy(&buf, FALSE); 1677 return Buf_Destroy(&buf, FALSE);
1674} 1678}
1675 1679
1676/*- 1680/*-
1677 *----------------------------------------------------------------------- 1681 *-----------------------------------------------------------------------
1678 * Dir_Destroy -- 1682 * Dir_Destroy --
1679 * Nuke a directory descriptor, if possible. Callback procedure 1683 * Nuke a directory descriptor, if possible. Callback procedure
1680 * for the suffixes module when destroying a search path. 1684 * for the suffixes module when destroying a search path.
1681 * 1685 *
1682 * Input: 1686 * Input:
1683 * pp The directory descriptor to nuke 1687 * pp The directory descriptor to nuke
1684 * 1688 *
1685 * Results: 1689 * Results:
1686 * None. 1690 * None.
1687 * 1691 *
1688 * Side Effects: 1692 * Side Effects:
1689 * If no other path references this directory (refCount == 0), 1693 * If no other path references this directory (refCount == 0),
1690 * the Path and all its data are freed. 1694 * the Path and all its data are freed.
1691 * 1695 *
1692 *----------------------------------------------------------------------- 1696 *-----------------------------------------------------------------------
1693 */ 1697 */
1694void 1698void
1695Dir_Destroy(void *pp) 1699Dir_Destroy(void *pp)
1696{ 1700{
1697 Path *p = (Path *)pp; 1701 Path *p = (Path *)pp;
1698 p->refCount -= 1; 1702 p->refCount -= 1;
1699 1703
1700 if (p->refCount == 0) { 1704 if (p->refCount == 0) {
1701 LstNode ln; 1705 LstNode ln;
1702 1706
1703 ln = Lst_MemberS(openDirectories, p); 1707 ln = Lst_MemberS(openDirectories, p);
1704 Lst_RemoveS(openDirectories, ln); 1708 Lst_RemoveS(openDirectories, ln);
1705 1709
1706 Hash_DeleteTable(&p->files); 1710 Hash_DeleteTable(&p->files);
1707 free(p->name); 1711 free(p->name);
1708 free(p); 1712 free(p);
1709 } 1713 }
1710} 1714}
1711 1715
1712/*- 1716/*-
1713 *----------------------------------------------------------------------- 1717 *-----------------------------------------------------------------------
1714 * Dir_ClearPath -- 1718 * Dir_ClearPath --
1715 * Clear out all elements of the given search path. This is different 1719 * Clear out all elements of the given search path. This is different
1716 * from destroying the list, notice. 1720 * from destroying the list, notice.
1717 * 1721 *
1718 * Input: 1722 * Input:
1719 * path Path to clear 1723 * path Path to clear
1720 * 1724 *
1721 * Results: 1725 * Results:
1722 * None. 1726 * None.
1723 * 1727 *
1724 * Side Effects: 1728 * Side Effects:
1725 * The path is set to the empty list. 1729 * The path is set to the empty list.
1726 * 1730 *
1727 *----------------------------------------------------------------------- 1731 *-----------------------------------------------------------------------
1728 */ 1732 */
1729void 1733void
1730Dir_ClearPath(Lst path) 1734Dir_ClearPath(Lst path)
1731{ 1735{
1732 while (!Lst_IsEmpty(path)) { 1736 while (!Lst_IsEmpty(path)) {
1733 Path *p = Lst_DequeueS(path); 1737 Path *p = Lst_DequeueS(path);
1734 Dir_Destroy(p); 1738 Dir_Destroy(p);
1735 } 1739 }
1736} 1740}
1737 1741
1738 1742
1739/*- 1743/*-
1740 *----------------------------------------------------------------------- 1744 *-----------------------------------------------------------------------
1741 * Dir_Concat -- 1745 * Dir_Concat --
1742 * Concatenate two paths, adding the second to the end of the first. 1746 * Concatenate two paths, adding the second to the end of the first.
1743 * Makes sure to avoid duplicates. 1747 * Makes sure to avoid duplicates.
1744 * 1748 *
1745 * Input: 1749 * Input:
1746 * path1 Dest 1750 * path1 Dest
1747 * path2 Source 1751 * path2 Source
1748 * 1752 *
1749 * Results: 1753 * Results:
1750 * None 1754 * None
1751 * 1755 *
1752 * Side Effects: 1756 * Side Effects:
1753 * Reference counts for added dirs are upped. 1757 * Reference counts for added dirs are upped.
1754 * 1758 *
1755 *----------------------------------------------------------------------- 1759 *-----------------------------------------------------------------------
1756 */ 1760 */
1757void 1761void
1758Dir_Concat(Lst path1, Lst path2) 1762Dir_Concat(Lst path1, Lst path2)
1759{ 1763{
1760 LstNode ln; 1764 LstNode ln;
1761 Path *p; 1765 Path *p;
1762 1766
1763 for (ln = Lst_First(path2); ln != NULL; ln = Lst_Succ(ln)) { 1767 for (ln = Lst_First(path2); ln != NULL; ln = Lst_Succ(ln)) {
1764 p = Lst_DatumS(ln); 1768 p = Lst_DatumS(ln);
1765 if (Lst_MemberS(path1, p) == NULL) { 1769 if (Lst_MemberS(path1, p) == NULL) {
1766 p->refCount += 1; 1770 p->refCount += 1;
1767 Lst_AppendS(path1, p); 1771 Lst_AppendS(path1, p);
1768 } 1772 }
1769 } 1773 }
1770} 1774}
1771 1775
1772static int 1776static int
1773percentage(int num, int den) 1777percentage(int num, int den)
1774{ 1778{
1775 return den != 0 ? num * 100 / den : 0; 1779 return den != 0 ? num * 100 / den : 0;
1776} 1780}
1777 1781
1778/********** DEBUG INFO **********/ 1782/********** DEBUG INFO **********/
1779void 1783void
1780Dir_PrintDirectories(void) 1784Dir_PrintDirectories(void)
1781{ 1785{
1782 LstNode ln; 1786 LstNode ln;
1783 Path *p; 
1784 1787
1785 fprintf(debug_file, "#*** Directory Cache:\n"); 1788 fprintf(debug_file, "#*** Directory Cache:\n");
1786 fprintf(debug_file, 1789 fprintf(debug_file,
1787 "# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n", 1790 "# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n",
1788 hits, misses, nearmisses, bigmisses, 1791 hits, misses, nearmisses, bigmisses,
1789 percentage(hits, hits + bigmisses + nearmisses)); 1792 percentage(hits, hits + bigmisses + nearmisses));
1790 fprintf(debug_file, "# %-20s referenced\thits\n", "directory"); 1793 fprintf(debug_file, "# %-20s referenced\thits\n", "directory");
1791 if (Lst_Open(openDirectories) == SUCCESS) { 1794
1792 while ((ln = Lst_NextS(openDirectories)) != NULL) { 1795 Lst_OpenS(openDirectories);
1793 p = Lst_DatumS(ln); 1796 while ((ln = Lst_NextS(openDirectories)) != NULL) {
1794 fprintf(debug_file, "# %-20s %10d\t%4d\n", p->name, p->refCount, 1797 Path *p = Lst_DatumS(ln);
1795 p->hits); 1798 fprintf(debug_file, "# %-20s %10d\t%4d\n", p->name, p->refCount,
1796 } 1799 p->hits);
1797 Lst_CloseS(openDirectories); 
1798 } 1800 }
 1801 Lst_CloseS(openDirectories);
1799} 1802}
1800 1803
1801static int 1804static int
1802DirPrintDir(void *p, void *dummy MAKE_ATTR_UNUSED) 1805DirPrintDir(void *p, void *dummy MAKE_ATTR_UNUSED)
1803{ 1806{
1804 fprintf(debug_file, "%s ", ((Path *)p)->name); 1807 fprintf(debug_file, "%s ", ((Path *)p)->name);
1805 return 0; 1808 return 0;
1806} 1809}
1807 1810
1808void 1811void
1809Dir_PrintPath(Lst path) 1812Dir_PrintPath(Lst path)
1810{ 1813{
1811 Lst_ForEach(path, DirPrintDir, NULL); 1814 Lst_ForEach(path, DirPrintDir, NULL);
1812} 1815}

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

--- src/usr.bin/make/lst.c 2020/08/26 22:55:46 1.42
+++ src/usr.bin/make/lst.c 2020/08/27 06:28:44 1.43
@@ -1,749 +1,737 @@ @@ -1,749 +1,737 @@
1/* $NetBSD: lst.c,v 1.42 2020/08/26 22:55:46 rillig Exp $ */ 1/* $NetBSD: lst.c,v 1.43 2020/08/27 06:28:44 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.42 2020/08/26 22:55:46 rillig Exp $"; 40static char rcsid[] = "$NetBSD: lst.c,v 1.43 2020/08/27 06:28:44 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.42 2020/08/26 22:55:46 rillig Exp $"); 44__RCSID("$NetBSD: lst.c,v 1.43 2020/08/27 06:28:44 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
78static Boolean 78static Boolean
79LstIsValid(Lst list) 79LstIsValid(Lst list)
80{ 80{
81 return list != NULL; 81 return list != NULL;
82} 82}
83 83
84static Boolean 84static Boolean
85LstNodeIsValid(LstNode node) 85LstNodeIsValid(LstNode node)
86{ 86{
87 return node != NULL; 87 return node != NULL;
88} 88}
89 89
90/* Allocate and initialize a list node. 90/* Allocate and initialize a list node.
91 * 91 *
92 * The fields 'prev' and 'next' must be initialized by the caller. 92 * The fields 'prev' and 'next' must be initialized by the caller.
93 */ 93 */
94static LstNode 94static LstNode
95LstNodeNew(void *datum) 95LstNodeNew(void *datum)
96{ 96{
97 LstNode node = bmake_malloc(sizeof *node); 97 LstNode node = bmake_malloc(sizeof *node);
98 node->useCount = 0; 98 node->useCount = 0;
99 node->deleted = FALSE; 99 node->deleted = FALSE;
100 node->datum = datum; 100 node->datum = datum;
101 return node; 101 return node;
102} 102}
103 103
104static Boolean 104static Boolean
105LstIsEmpty(Lst list) 105LstIsEmpty(Lst list)
106{ 106{
107 return list->first == NULL; 107 return list->first == NULL;
108} 108}
109 109
110/* Create and initialize a new, empty list. */ 110/* Create and initialize a new, empty list. */
111Lst 111Lst
112Lst_Init(void) 112Lst_Init(void)
113{ 113{
114 Lst list = bmake_malloc(sizeof *list); 114 Lst list = bmake_malloc(sizeof *list);
115 115
116 list->first = NULL; 116 list->first = NULL;
117 list->last = NULL; 117 list->last = NULL;
118 list->isOpen = FALSE; 118 list->isOpen = FALSE;
119 list->lastAccess = Unknown; 119 list->lastAccess = Unknown;
120 120
121 return list; 121 return list;
122} 122}
123 123
124/* Duplicate an entire list, usually by copying the datum pointers. 124/* Duplicate an entire list, usually by copying the datum pointers.
125 * If copyProc is given, that function is used to create the new datum from the 125 * If copyProc is given, that function is used to create the new datum from the
126 * old datum, usually by creating a copy of it. */ 126 * old datum, usually by creating a copy of it. */
127Lst 127Lst
128Lst_CopyS(Lst list, LstCopyProc copyProc) 128Lst_CopyS(Lst list, LstCopyProc copyProc)
129{ 129{
130 Lst newList; 130 Lst newList;
131 LstNode node; 131 LstNode node;
132 132
133 assert(LstIsValid(list)); 133 assert(LstIsValid(list));
134 134
135 newList = Lst_Init(); 135 newList = Lst_Init();
136 136
137 for (node = list->first; node != NULL; node = node->next) { 137 for (node = list->first; node != NULL; node = node->next) {
138 void *datum = copyProc != NULL ? copyProc(node->datum) : node->datum; 138 void *datum = copyProc != NULL ? copyProc(node->datum) : node->datum;
139 Lst_AppendS(newList, datum); 139 Lst_AppendS(newList, datum);
140 } 140 }
141 141
142 return newList; 142 return newList;
143} 143}
144 144
145/* Free a list and all its nodes. The list data itself are not freed though. */ 145/* Free a list and all its nodes. The list data itself are not freed though. */
146void 146void
147Lst_FreeS(Lst list) 147Lst_FreeS(Lst list)
148{ 148{
149 LstNode node; 149 LstNode node;
150 LstNode next; 150 LstNode next;
151 151
152 assert(LstIsValid(list)); 152 assert(LstIsValid(list));
153 153
154 for (node = list->first; node != NULL; node = next) { 154 for (node = list->first; node != NULL; node = next) {
155 next = node->next; 155 next = node->next;
156 free(node); 156 free(node);
157 } 157 }
158 158
159 free(list); 159 free(list);
160} 160}
161 161
162/* Destroy a list and free all its resources. If the freeProc is given, it is 162/* Destroy a list and free all its resources. If the freeProc is given, it is
163 * called with the datum from each node in turn before the node is freed. */ 163 * called with the datum from each node in turn before the node is freed. */
164void 164void
165Lst_DestroyS(Lst list, LstFreeProc freeProc) 165Lst_DestroyS(Lst list, LstFreeProc freeProc)
166{ 166{
167 LstNode node; 167 LstNode node;
168 LstNode next; 168 LstNode next;
169 169
170 assert(LstIsValid(list)); 170 assert(LstIsValid(list));
171 assert(freeProc != NULL); 171 assert(freeProc != NULL);
172 172
173 for (node = list->first; node != NULL; node = next) { 173 for (node = list->first; node != NULL; node = next) {
174 next = node->next; 174 next = node->next;
175 freeProc(node->datum); 175 freeProc(node->datum);
176 free(node); 176 free(node);
177 } 177 }
178 178
179 free(list); 179 free(list);
180} 180}
181 181
182/* 182/*
183 * Functions to modify a list 183 * Functions to modify a list
184 */ 184 */
185 185
186/* Insert a new node with the given piece of data before the given node in the 186/* Insert a new node with the given piece of data before the given node in the
187 * given list. */ 187 * given list. */
188void 188void
189Lst_InsertBeforeS(Lst list, LstNode node, void *datum) 189Lst_InsertBeforeS(Lst list, LstNode node, void *datum)
190{ 190{
191 LstNode newNode; 191 LstNode newNode;
192 192
193 assert(LstIsValid(list)); 193 assert(LstIsValid(list));
194 assert(!LstIsEmpty(list)); 194 assert(!LstIsEmpty(list));
195 assert(LstNodeIsValid(node)); 195 assert(LstNodeIsValid(node));
196 assert(datum != NULL); 196 assert(datum != NULL);
197 197
198 newNode = LstNodeNew(datum); 198 newNode = LstNodeNew(datum);
199 newNode->prev = node->prev; 199 newNode->prev = node->prev;
200 newNode->next = node; 200 newNode->next = node;
201 201
202 if (node->prev != NULL) { 202 if (node->prev != NULL) {
203 node->prev->next = newNode; 203 node->prev->next = newNode;
204 } 204 }
205 node->prev = newNode; 205 node->prev = newNode;
206 206
207 if (node == list->first) { 207 if (node == list->first) {
208 list->first = newNode; 208 list->first = newNode;
209 } 209 }
210} 210}
211 211
212/* Add a piece of data at the start of the given list. */ 212/* Add a piece of data at the start of the given list. */
213void 213void
214Lst_PrependS(Lst list, void *datum) 214Lst_PrependS(Lst list, void *datum)
215{ 215{
216 LstNode node; 216 LstNode node;
217 217
218 assert(LstIsValid(list)); 218 assert(LstIsValid(list));
219 assert(datum != NULL); 219 assert(datum != NULL);
220 220
221 node = LstNodeNew(datum); 221 node = LstNodeNew(datum);
222 node->prev = NULL; 222 node->prev = NULL;
223 node->next = list->first; 223 node->next = list->first;
224 224
225 if (list->first == NULL) { 225 if (list->first == NULL) {
226 list->first = node; 226 list->first = node;
227 list->last = node; 227 list->last = node;
228 } else { 228 } else {
229 list->first->prev = node; 229 list->first->prev = node;
230 list->first = node; 230 list->first = node;
231 } 231 }
232} 232}
233 233
234/* Add a piece of data at the end of the given list. */ 234/* Add a piece of data at the end of the given list. */
235void 235void
236Lst_AppendS(Lst list, void *datum) 236Lst_AppendS(Lst list, void *datum)
237{ 237{
238 LstNode node; 238 LstNode node;
239 239
240 assert(LstIsValid(list)); 240 assert(LstIsValid(list));
241 assert(datum != NULL); 241 assert(datum != NULL);
242 242
243 node = LstNodeNew(datum); 243 node = LstNodeNew(datum);
244 node->prev = list->last; 244 node->prev = list->last;
245 node->next = NULL; 245 node->next = NULL;
246 246
247 if (list->last == NULL) { 247 if (list->last == NULL) {
248 list->first = node; 248 list->first = node;
249 list->last = node; 249 list->last = node;
250 } else { 250 } else {
251 list->last->next = node; 251 list->last->next = node;
252 list->last = node; 252 list->last = node;
253 } 253 }
254} 254}
255 255
256/* Remove the given node from the given list. 256/* Remove the given node from the given list.
257 * The datum stored in the node must be freed by the caller, if necessary. */ 257 * The datum stored in the node must be freed by the caller, if necessary. */
258void 258void
259Lst_RemoveS(Lst list, LstNode node) 259Lst_RemoveS(Lst list, LstNode node)
260{ 260{
261 assert(LstIsValid(list)); 261 assert(LstIsValid(list));
262 assert(LstNodeIsValid(node)); 262 assert(LstNodeIsValid(node));
263 263
264 /* 264 /*
265 * unlink it from the list 265 * unlink it from the list
266 */ 266 */
267 if (node->next != NULL) { 267 if (node->next != NULL) {
268 node->next->prev = node->prev; 268 node->next->prev = node->prev;
269 } 269 }
270 if (node->prev != NULL) { 270 if (node->prev != NULL) {
271 node->prev->next = node->next; 271 node->prev->next = node->next;
272 } 272 }
273 273
274 /* 274 /*
275 * if either the first or last of the list point to this node, 275 * if either the first or last of the list point to this node,
276 * adjust them accordingly 276 * adjust them accordingly
277 */ 277 */
278 if (list->first == node) { 278 if (list->first == node) {
279 list->first = node->next; 279 list->first = node->next;
280 } 280 }
281 if (list->last == node) { 281 if (list->last == node) {
282 list->last = node->prev; 282 list->last = node->prev;
283 } 283 }
284 284
285 /* 285 /*
286 * Sequential access stuff. If the node we're removing is the current 286 * Sequential access stuff. If the node we're removing is the current
287 * node in the list, reset the current node to the previous one. If the 287 * node in the list, reset the current node to the previous one. If the
288 * previous one was non-existent (prev == NULL), we set the 288 * previous one was non-existent (prev == NULL), we set the
289 * end to be Unknown, since it is. 289 * end to be Unknown, since it is.
290 */ 290 */
291 if (list->isOpen && list->curr == node) { 291 if (list->isOpen && list->curr == node) {
292 list->curr = list->prev; 292 list->curr = list->prev;
293 if (list->curr == NULL) { 293 if (list->curr == NULL) {
294 list->lastAccess = Unknown; 294 list->lastAccess = Unknown;
295 } 295 }
296 } 296 }
297 297
298 /* 298 /*
299 * note that the datum is unmolested. The caller must free it as 299 * note that the datum is unmolested. The caller must free it as
300 * necessary and as expected. 300 * necessary and as expected.
301 */ 301 */
302 if (node->useCount == 0) { 302 if (node->useCount == 0) {
303 free(node); 303 free(node);
304 } else { 304 } else {
305 node->deleted = TRUE; 305 node->deleted = TRUE;
306 } 306 }
307} 307}
308 308
309/* Replace the datum in the given node with the new datum. */ 309/* Replace the datum in the given node with the new datum. */
310void 310void
311LstNode_SetS(LstNode node, void *datum) 311LstNode_SetS(LstNode node, void *datum)
312{ 312{
313 assert(LstNodeIsValid(node)); 313 assert(LstNodeIsValid(node));
314 assert(datum != NULL); 314 assert(datum != NULL);
315 315
316 node->datum = datum; 316 node->datum = datum;
317} 317}
318 318
319/* Replace the datum in the given node to NULL. */ 319/* Replace the datum in the given node to NULL. */
320void 320void
321LstNode_SetNullS(LstNode node) 321LstNode_SetNullS(LstNode node)
322{ 322{
323 assert(LstNodeIsValid(node)); 323 assert(LstNodeIsValid(node));
324 324
325 node->datum = NULL; 325 node->datum = NULL;
326} 326}
327 327
328 328
329/* 329/*
330 * Node-specific functions 330 * Node-specific functions
331 */ 331 */
332 332
333/* Return the first node from the given list, or NULL if the list is empty or 333/* Return the first node from the given list, or NULL if the list is empty or
334 * invalid. */ 334 * invalid. */
335LstNode 335LstNode
336Lst_First(Lst list) 336Lst_First(Lst list)
337{ 337{
338 if (!LstIsValid(list) || LstIsEmpty(list)) { 338 if (!LstIsValid(list) || LstIsEmpty(list)) {
339 return NULL; 339 return NULL;
340 } else { 340 } else {
341 return list->first; 341 return list->first;
342 } 342 }
343} 343}
344 344
345/* Return the first node from the given list, or NULL if the list is empty. */ 345/* Return the first node from the given list, or NULL if the list is empty. */
346LstNode 346LstNode
347Lst_FirstS(Lst list) 347Lst_FirstS(Lst list)
348{ 348{
349 assert(LstIsValid(list)); 349 assert(LstIsValid(list));
350 350
351 return list->first; 351 return list->first;
352} 352}
353 353
354/* Return the last node from the given list, or NULL if the list is empty or 354/* Return the last node from the given list, or NULL if the list is empty or
355 * invalid. */ 355 * invalid. */
356LstNode 356LstNode
357Lst_Last(Lst list) 357Lst_Last(Lst list)
358{ 358{
359 if (!LstIsValid(list) || LstIsEmpty(list)) { 359 if (!LstIsValid(list) || LstIsEmpty(list)) {
360 return NULL; 360 return NULL;
361 } else { 361 } else {
362 return list->last; 362 return list->last;
363 } 363 }
364} 364}
365 365
366/* Return the last node from the given list, or NULL if the list is empty. */ 366/* Return the last node from the given list, or NULL if the list is empty. */
367LstNode 367LstNode
368Lst_LastS(Lst list) 368Lst_LastS(Lst list)
369{ 369{
370 assert(LstIsValid(list)); 370 assert(LstIsValid(list));
371 371
372 return list->last; 372 return list->last;
373} 373}
374 374
375/* Return the successor to the given node on its list, or NULL. */ 375/* Return the successor to the given node on its list, or NULL. */
376LstNode 376LstNode
377Lst_Succ(LstNode node) 377Lst_Succ(LstNode node)
378{ 378{
379 if (node == NULL) { 379 if (node == NULL) {
380 return NULL; 380 return NULL;
381 } else { 381 } else {
382 return node->next; 382 return node->next;
383 } 383 }
384} 384}
385 385
386/* Return the successor to the given node on its list, or NULL. */ 386/* Return the successor to the given node on its list, or NULL. */
387LstNode 387LstNode
388Lst_SuccS(LstNode node) 388Lst_SuccS(LstNode node)
389{ 389{
390 assert(LstNodeIsValid(node)); 390 assert(LstNodeIsValid(node));
391 391
392 return node->next; 392 return node->next;
393} 393}
394 394
395/* Return the predecessor to the given node on its list, or NULL. */ 395/* Return the predecessor to the given node on its list, or NULL. */
396LstNode 396LstNode
397Lst_PrevS(LstNode node) 397Lst_PrevS(LstNode node)
398{ 398{
399 assert(LstNodeIsValid(node)); 399 assert(LstNodeIsValid(node));
400 return node->prev; 400 return node->prev;
401} 401}
402 402
403/* Return the datum stored in the given node. */ 403/* Return the datum stored in the given node. */
404void * 404void *
405Lst_DatumS(LstNode node) 405Lst_DatumS(LstNode node)
406{ 406{
407 assert(LstNodeIsValid(node)); 407 assert(LstNodeIsValid(node));
408 return node->datum; 408 return node->datum;
409} 409}
410 410
411 411
412/* 412/*
413 * Functions for entire lists 413 * Functions for entire lists
414 */ 414 */
415 415
416/* Return TRUE if the given list is empty or invalid. */ 416/* Return TRUE if the given list is empty or invalid. */
417Boolean 417Boolean
418Lst_IsEmpty(Lst list) 418Lst_IsEmpty(Lst list)
419{ 419{
420 return !LstIsValid(list) || LstIsEmpty(list); 420 return !LstIsValid(list) || LstIsEmpty(list);
421} 421}
422 422
423/* Return TRUE if the given list is empty. */ 423/* Return TRUE if the given list is empty. */
424Boolean 424Boolean
425Lst_IsEmptyS(Lst list) 425Lst_IsEmptyS(Lst list)
426{ 426{
427 assert(LstIsValid(list)); 427 assert(LstIsValid(list));
428 428
429 return LstIsEmpty(list); 429 return LstIsEmpty(list);
430} 430}
431 431
432/* Return the first node from the given list for which the given comparison 432/* Return the first node from the given list for which the given comparison
433 * function returns 0, or NULL if none of the nodes matches. */ 433 * function returns 0, or NULL if none of the nodes matches. */
434LstNode 434LstNode
435Lst_Find(Lst list, LstFindProc cmp, const void *cmpData) 435Lst_Find(Lst list, LstFindProc cmp, const void *cmpData)
436{ 436{
437 return Lst_FindFrom(list, Lst_First(list), cmp, cmpData); 437 return Lst_FindFrom(list, Lst_First(list), cmp, cmpData);
438} 438}
439 439
440/* Return the first node from the given list for which the given comparison 440/* Return the first node from the given list for which the given comparison
441 * function returns 0, or NULL if none of the nodes matches. */ 441 * function returns 0, or NULL if none of the nodes matches. */
442LstNode 442LstNode
443Lst_FindS(Lst list, LstFindProc cmp, const void *cmpData) 443Lst_FindS(Lst list, LstFindProc cmp, const void *cmpData)
444{ 444{
445 if (LstIsEmpty(list)) 445 if (LstIsEmpty(list))
446 return NULL; 446 return NULL;
447 return Lst_FindFromS(list, Lst_FirstS(list), cmp, cmpData); 447 return Lst_FindFromS(list, Lst_FirstS(list), cmp, cmpData);
448} 448}
449 449
450/* Return the first node from the given list, starting at the given node, for 450/* Return the first node from the given list, starting at the given node, for
451 * which the given comparison function returns 0, or NULL if none of the nodes 451 * which the given comparison function returns 0, or NULL if none of the nodes
452 * matches. */ 452 * matches. */
453LstNode 453LstNode
454Lst_FindFrom(Lst list, LstNode node, LstFindProc cmp, const void *cmpData) 454Lst_FindFrom(Lst list, LstNode node, LstFindProc cmp, const void *cmpData)
455{ 455{
456 if (!LstIsValid(list) || LstIsEmpty(list) || !LstNodeIsValid(node)) { 456 if (!LstIsValid(list) || LstIsEmpty(list) || !LstNodeIsValid(node)) {
457 return NULL; 457 return NULL;
458 } 458 }
459 459
460 return Lst_FindFromS(list, node, cmp, cmpData); 460 return Lst_FindFromS(list, node, cmp, cmpData);
461} 461}
462 462
463/* Return the first node from the given list, starting at the given node, for 463/* Return the first node from the given list, starting at the given node, for
464 * which the given comparison function returns 0, or NULL if none of the nodes 464 * which the given comparison function returns 0, or NULL if none of the nodes
465 * matches. */ 465 * matches. */
466LstNode 466LstNode
467Lst_FindFromS(Lst list, LstNode node, LstFindProc cmp, const void *cmpData) 467Lst_FindFromS(Lst list, LstNode node, LstFindProc cmp, const void *cmpData)
468{ 468{
469 LstNode tln; 469 LstNode tln;
470 470
471 assert(LstIsValid(list)); 471 assert(LstIsValid(list));
472 assert(LstNodeIsValid(node)); 472 assert(LstNodeIsValid(node));
473 assert(cmp != NULL); 473 assert(cmp != NULL);
474 474
475 for (tln = node; tln != NULL; tln = tln->next) { 475 for (tln = node; tln != NULL; tln = tln->next) {
476 if (cmp(tln->datum, cmpData) == 0) 476 if (cmp(tln->datum, cmpData) == 0)
477 return tln; 477 return tln;
478 } 478 }
479 479
480 return NULL; 480 return NULL;
481} 481}
482 482
483/* Return the first node that contains the given datum, or NULL. */ 483/* Return the first node that contains the given datum, or NULL. */
484LstNode 484LstNode
485Lst_MemberS(Lst list, void *datum) 485Lst_MemberS(Lst list, void *datum)
486{ 486{
487 LstNode node; 487 LstNode node;
488 488
489 assert(LstIsValid(list)); 489 assert(LstIsValid(list));
490 assert(datum != NULL); 490 assert(datum != NULL);
491 491
492 for (node = list->first; node != NULL; node = node->next) { 492 for (node = list->first; node != NULL; node = node->next) {
493 if (node->datum == datum) { 493 if (node->datum == datum) {
494 return node; 494 return node;
495 } 495 }
496 } 496 }
497 497
498 return NULL; 498 return NULL;
499} 499}
500 500
501/* Apply the given function to each element of the given list. The function 501/* Apply the given function to each element of the given list. The function
502 * should return 0 if traversal should continue and non-zero if it should 502 * should return 0 if traversal should continue and non-zero if it should
503 * abort. */ 503 * abort. */
504int 504int
505Lst_ForEach(Lst list, LstActionProc proc, void *procData) 505Lst_ForEach(Lst list, LstActionProc proc, void *procData)
506{ 506{
507 return Lst_ForEachFrom(list, Lst_First(list), proc, procData); 507 return Lst_ForEachFrom(list, Lst_First(list), proc, procData);
508} 508}
509 509
510/* Apply the given function to each element of the given list. The function 510/* Apply the given function to each element of the given list. The function
511 * should return 0 if traversal should continue and non-zero if it should 511 * should return 0 if traversal should continue and non-zero if it should
512 * abort. */ 512 * abort. */
513int 513int
514Lst_ForEachS(Lst list, LstActionProc proc, void *procData) 514Lst_ForEachS(Lst list, LstActionProc proc, void *procData)
515{ 515{
516 if (LstIsEmpty(list)) 516 if (LstIsEmpty(list))
517 return 0; /* XXX: Document what this value means. */ 517 return 0; /* XXX: Document what this value means. */
518 return Lst_ForEachFromS(list, Lst_First(list), proc, procData); 518 return Lst_ForEachFromS(list, Lst_First(list), proc, procData);
519} 519}
520 520
521/* Apply the given function to each element of the given list, starting from 521/* Apply the given function to each element of the given list, starting from
522 * the given node. The function should return 0 if traversal should continue, 522 * the given node. The function should return 0 if traversal should continue,
523 * and non-zero if it should abort. */ 523 * and non-zero if it should abort. */
524int 524int
525Lst_ForEachFrom(Lst list, LstNode node, 525Lst_ForEachFrom(Lst list, LstNode node,
526 LstActionProc proc, void *procData) 526 LstActionProc proc, void *procData)
527{ 527{
528 if (!LstIsValid(list) || LstIsEmpty(list)) { 528 if (!LstIsValid(list) || LstIsEmpty(list)) {
529 return 0; 529 return 0;
530 } 530 }
531 531
532 return Lst_ForEachFromS(list, node, proc, procData); 532 return Lst_ForEachFromS(list, node, proc, procData);
533} 533}
534 534
535/* Apply the given function to each element of the given list, starting from 535/* Apply the given function to each element of the given list, starting from
536 * the given node. The function should return 0 if traversal should continue, 536 * the given node. The function should return 0 if traversal should continue,
537 * and non-zero if it should abort. */ 537 * and non-zero if it should abort. */
538int 538int
539Lst_ForEachFromS(Lst list, LstNode node, 539Lst_ForEachFromS(Lst list, LstNode node,
540 LstActionProc proc, void *procData) 540 LstActionProc proc, void *procData)
541{ 541{
542 LstNode tln = node; 542 LstNode tln = node;
543 LstNode next; 543 LstNode next;
544 Boolean done; 544 Boolean done;
545 int result; 545 int result;
546 546
547 assert(LstIsValid(list)); 547 assert(LstIsValid(list));
548 assert(LstNodeIsValid(node)); 548 assert(LstNodeIsValid(node));
549 assert(proc != NULL); 549 assert(proc != NULL);
550 550
551 do { 551 do {
552 /* 552 /*
553 * Take care of having the current element deleted out from under 553 * Take care of having the current element deleted out from under
554 * us. 554 * us.
555 */ 555 */
556 556
557 next = tln->next; 557 next = tln->next;
558 558
559 /* 559 /*
560 * We're done with the traversal if 560 * We're done with the traversal if
561 * - the next node to examine doesn't exist and 561 * - the next node to examine doesn't exist and
562 * - nothing's been added after the current node (check this 562 * - nothing's been added after the current node (check this
563 * after proc() has been called). 563 * after proc() has been called).
564 */ 564 */
565 done = next == NULL; 565 done = next == NULL;
566 566
567 tln->useCount++; 567 tln->useCount++;
568 result = (*proc)(tln->datum, procData); 568 result = (*proc)(tln->datum, procData);
569 tln->useCount--; 569 tln->useCount--;
570 570
571 /* 571 /*
572 * Now check whether a node has been added. 572 * Now check whether a node has been added.
573 * Note: this doesn't work if this node was deleted before 573 * Note: this doesn't work if this node was deleted before
574 * the new node was added. 574 * the new node was added.
575 */ 575 */
576 if (next != tln->next) { 576 if (next != tln->next) {
577 next = tln->next; 577 next = tln->next;
578 done = 0; 578 done = 0;
579 } 579 }
580 580
581 if (tln->deleted) { 581 if (tln->deleted) {
582 free((char *)tln); 582 free((char *)tln);
583 } 583 }
584 tln = next; 584 tln = next;
585 } while (!result && !LstIsEmpty(list) && !done); 585 } while (!result && !LstIsEmpty(list) && !done);
586 586
587 return result; 587 return result;
588} 588}
589 589
590/* Move all nodes from list2 to the end of list1. 590/* Move all nodes from list2 to the end of list1.
591 * List2 is destroyed and freed. */ 591 * List2 is destroyed and freed. */
592void 592void
593Lst_MoveAllS(Lst list1, Lst list2) 593Lst_MoveAllS(Lst list1, Lst list2)
594{ 594{
595 assert(LstIsValid(list1)); 595 assert(LstIsValid(list1));
596 assert(LstIsValid(list2)); 596 assert(LstIsValid(list2));
597 597
598 if (list2->first != NULL) { 598 if (list2->first != NULL) {
599 list2->first->prev = list1->last; 599 list2->first->prev = list1->last;
600 if (list1->last != NULL) { 600 if (list1->last != NULL) {
601 list1->last->next = list2->first; 601 list1->last->next = list2->first;
602 } else { 602 } else {
603 list1->first = list2->first; 603 list1->first = list2->first;
604 } 604 }
605 list1->last = list2->last; 605 list1->last = list2->last;
606 } 606 }
607 free(list2); 607 free(list2);
608} 608}
609 609
610/* Copy the element data from src to the start of dst. */ 610/* Copy the element data from src to the start of dst. */
611void 611void
612Lst_PrependAllS(Lst dst, Lst src) 612Lst_PrependAllS(Lst dst, Lst src)
613{ 613{
614 LstNode node; 614 LstNode node;
615 for (node = src->last; node != NULL; node = node->prev) 615 for (node = src->last; node != NULL; node = node->prev)
616 Lst_PrependS(dst, node->datum); 616 Lst_PrependS(dst, node->datum);
617} 617}
618 618
619/* Copy the element data from src to the end of dst. */ 619/* Copy the element data from src to the end of dst. */
620void 620void
621Lst_AppendAllS(Lst dst, Lst src) 621Lst_AppendAllS(Lst dst, Lst src)
622{ 622{
623 LstNode node; 623 LstNode node;
624 for (node = src->first; node != NULL; node = node->next) 624 for (node = src->first; node != NULL; node = node->next)
625 Lst_AppendS(dst, node->datum); 625 Lst_AppendS(dst, node->datum);
626} 626}
627 627
628/* 628/*
629 * these functions are for dealing with a list as a table, of sorts. 629 * these functions are for dealing with a list as a table, of sorts.
630 * An idea of the "current element" is kept and used by all the functions 630 * An idea of the "current element" is kept and used by all the functions
631 * between Lst_Open() and Lst_Close(). 631 * between Lst_Open() and Lst_Close().
632 * 632 *
633 * The sequential functions access the list in a slightly different way. 633 * The sequential functions access the list in a slightly different way.
634 * CurPtr points to their idea of the current node in the list and they 634 * CurPtr points to their idea of the current node in the list and they
635 * access the list based on it. 635 * access the list based on it.
636 */ 636 */
637 637
638/* Open a list for sequential access. A list can still be searched, etc., 638/* Open a list for sequential access. A list can still be searched, etc.,
639 * without confusing these functions. */ 639 * without confusing these functions. */
640ReturnStatus 
641Lst_Open(Lst list) 
642{ 
643 if (!LstIsValid(list)) { 
644 return FAILURE; 
645 } 
646 Lst_OpenS(list); 
647 return SUCCESS; 
648} 
649 
650/* Open a list for sequential access. A list can still be searched, etc., 
651 * without confusing these functions. */ 
652void 640void
653Lst_OpenS(Lst list) 641Lst_OpenS(Lst list)
654{ 642{
655 assert(LstIsValid(list)); 643 assert(LstIsValid(list));
656 644
657 /* XXX: This assertion fails for NetBSD's "build.sh -j1 tools", somewhere 645 /* XXX: This assertion fails for NetBSD's "build.sh -j1 tools", somewhere
658 * between "dependall ===> compat" and "dependall ===> binstall". 646 * between "dependall ===> compat" and "dependall ===> binstall".
659 * Building without the "-j1" succeeds though. */ 647 * Building without the "-j1" succeeds though. */
660 if (DEBUG(LINT) && list->isOpen) 648 if (DEBUG(LINT) && list->isOpen)
661 Parse_Error(PARSE_WARNING, "Internal inconsistency: list opened twice"); 649 Parse_Error(PARSE_WARNING, "Internal inconsistency: list opened twice");
662 650
663 list->isOpen = TRUE; 651 list->isOpen = TRUE;
664 list->lastAccess = LstIsEmpty(list) ? Head : Unknown; 652 list->lastAccess = LstIsEmpty(list) ? Head : Unknown;
665 list->curr = NULL; 653 list->curr = NULL;
666} 654}
667 655
668/* Return the next node for the given list, or NULL if the end has been 656/* Return the next node for the given list, or NULL if the end has been
669 * reached. */ 657 * reached. */
670LstNode 658LstNode
671Lst_NextS(Lst list) 659Lst_NextS(Lst list)
672{ 660{
673 LstNode node; 661 LstNode node;
674 662
675 assert(LstIsValid(list)); 663 assert(LstIsValid(list));
676 assert(list->isOpen); 664 assert(list->isOpen);
677 665
678 list->prev = list->curr; 666 list->prev = list->curr;
679 667
680 if (list->curr == NULL) { 668 if (list->curr == NULL) {
681 if (list->lastAccess == Unknown) { 669 if (list->lastAccess == Unknown) {
682 /* 670 /*
683 * If we're just starting out, lastAccess will be Unknown. 671 * If we're just starting out, lastAccess will be Unknown.
684 * Then we want to start this thing off in the right 672 * Then we want to start this thing off in the right
685 * direction -- at the start with lastAccess being Middle. 673 * direction -- at the start with lastAccess being Middle.
686 */ 674 */
687 list->curr = node = list->first; 675 list->curr = node = list->first;
688 list->lastAccess = Middle; 676 list->lastAccess = Middle;
689 } else { 677 } else {
690 node = NULL; 678 node = NULL;
691 list->lastAccess = Tail; 679 list->lastAccess = Tail;
692 } 680 }
693 } else { 681 } else {
694 node = list->curr->next; 682 node = list->curr->next;
695 list->curr = node; 683 list->curr = node;
696 684
697 if (node == list->first || node == NULL) { 685 if (node == list->first || node == NULL) {
698 /* 686 /*
699 * If back at the front, then we've hit the end... 687 * If back at the front, then we've hit the end...
700 */ 688 */
701 list->lastAccess = Tail; 689 list->lastAccess = Tail;
702 } else { 690 } else {
703 /* 691 /*
704 * Reset to Middle if gone past first. 692 * Reset to Middle if gone past first.
705 */ 693 */
706 list->lastAccess = Middle; 694 list->lastAccess = Middle;
707 } 695 }
708 } 696 }
709 697
710 return node; 698 return node;
711} 699}
712 700
713/* Close a list which was opened for sequential access. */ 701/* Close a list which was opened for sequential access. */
714void 702void
715Lst_CloseS(Lst list) 703Lst_CloseS(Lst list)
716{ 704{
717 assert(LstIsValid(list)); 705 assert(LstIsValid(list));
718 assert(list->isOpen); 706 assert(list->isOpen);
719 707
720 list->isOpen = FALSE; 708 list->isOpen = FALSE;
721 list->lastAccess = Unknown; 709 list->lastAccess = Unknown;
722} 710}
723 711
724 712
725/* 713/*
726 * for using the list as a queue 714 * for using the list as a queue
727 */ 715 */
728 716
729/* Add the datum to the tail of the given list. */ 717/* Add the datum to the tail of the given list. */
730void 718void
731Lst_EnqueueS(Lst list, void *datum) 719Lst_EnqueueS(Lst list, void *datum)
732{ 720{
733 Lst_AppendS(list, datum); 721 Lst_AppendS(list, datum);
734} 722}
735 723
736/* Remove and return the datum at the head of the given list. */ 724/* Remove and return the datum at the head of the given list. */
737void * 725void *
738Lst_DequeueS(Lst list) 726Lst_DequeueS(Lst list)
739{ 727{
740 void *datum; 728 void *datum;
741 729
742 assert(LstIsValid(list)); 730 assert(LstIsValid(list));
743 assert(!LstIsEmpty(list)); 731 assert(!LstIsEmpty(list));
744 732
745 datum = list->first->datum; 733 datum = list->first->datum;
746 Lst_RemoveS(list, list->first); 734 Lst_RemoveS(list, list->first);
747 assert(datum != NULL); 735 assert(datum != NULL);
748 return datum; 736 return datum;
749} 737}

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

--- src/usr.bin/make/lst.h 2020/08/26 23:00:47 1.45
+++ src/usr.bin/make/lst.h 2020/08/27 06:28:44 1.46
@@ -1,189 +1,188 @@ @@ -1,189 +1,188 @@
1/* $NetBSD: lst.h,v 1.45 2020/08/26 23:00:47 rillig Exp $ */ 1/* $NetBSD: lst.h,v 1.46 2020/08/27 06:28:44 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 int LstFindProc(const void *, const void *); 95typedef int 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_CopyS(Lst, LstCopyProc); 104Lst Lst_CopyS(Lst, LstCopyProc);
105/* Destroy an old one */ 105/* Destroy an old one */
106void Lst_FreeS(Lst); 106void Lst_FreeS(Lst);
107void Lst_DestroyS(Lst, LstFreeProc); 107void Lst_DestroyS(Lst, LstFreeProc);
108/* True if list is empty */ 108/* True if list is empty */
109Boolean Lst_IsEmpty(Lst); 109Boolean Lst_IsEmpty(Lst);
110Boolean Lst_IsEmptyS(Lst); 110Boolean Lst_IsEmptyS(Lst);
111 111
112/* 112/*
113 * Functions to modify a list 113 * Functions to modify a list
114 */ 114 */
115/* Insert an element before another */ 115/* Insert an element before another */
116void Lst_InsertBeforeS(Lst, LstNode, void *); 116void Lst_InsertBeforeS(Lst, LstNode, void *);
117/* Place an element at the front of a lst. */ 117/* Place an element at the front of a lst. */
118void Lst_PrependS(Lst, void *); 118void Lst_PrependS(Lst, void *);
119/* Place an element at the end of a lst. */ 119/* Place an element at the end of a lst. */
120void Lst_AppendS(Lst, void *); 120void Lst_AppendS(Lst, void *);
121/* Remove an element */ 121/* Remove an element */
122void Lst_RemoveS(Lst, LstNode); 122void Lst_RemoveS(Lst, LstNode);
123/* Replace a node with a new value */ 123/* Replace a node with a new value */
124void LstNode_SetS(LstNode, void *); 124void LstNode_SetS(LstNode, void *);
125void LstNode_SetNullS(LstNode); 125void LstNode_SetNullS(LstNode);
126 126
127void Lst_PrependAllS(Lst, Lst); 127void Lst_PrependAllS(Lst, Lst);
128void Lst_AppendAllS(Lst, Lst); 128void Lst_AppendAllS(Lst, Lst);
129void Lst_MoveAllS(Lst, Lst); 129void Lst_MoveAllS(Lst, Lst);
130 130
131/* 131/*
132 * Node-specific functions 132 * Node-specific functions
133 */ 133 */
134/* Return first element in list */ 134/* Return first element in list */
135LstNode Lst_First(Lst); 135LstNode Lst_First(Lst);
136LstNode Lst_FirstS(Lst); 136LstNode Lst_FirstS(Lst);
137/* Return last element in list */ 137/* Return last element in list */
138LstNode Lst_Last(Lst); 138LstNode Lst_Last(Lst);
139LstNode Lst_LastS(Lst); 139LstNode Lst_LastS(Lst);
140/* Return successor to given element */ 140/* Return successor to given element */
141LstNode Lst_Succ(LstNode); 141LstNode Lst_Succ(LstNode);
142LstNode Lst_SuccS(LstNode); 142LstNode Lst_SuccS(LstNode);
143/* Return predecessor to given element */ 143/* Return predecessor to given element */
144LstNode Lst_PrevS(LstNode); 144LstNode Lst_PrevS(LstNode);
145/* Get datum from LstNode */ 145/* Get datum from LstNode */
146void *Lst_DatumS(LstNode); 146void *Lst_DatumS(LstNode);
147 147
148/* 148/*
149 * Functions for entire lists 149 * Functions for entire lists
150 */ 150 */
151/* Find an element in a list */ 151/* Find an element in a list */
152LstNode Lst_Find(Lst, LstFindProc, const void *); 152LstNode Lst_Find(Lst, LstFindProc, const void *);
153LstNode Lst_FindS(Lst, LstFindProc, const void *); 153LstNode Lst_FindS(Lst, LstFindProc, const void *);
154/* Find an element starting from somewhere */ 154/* Find an element starting from somewhere */
155LstNode Lst_FindFrom(Lst, LstNode, LstFindProc, const void *); 155LstNode Lst_FindFrom(Lst, LstNode, LstFindProc, const void *);
156LstNode Lst_FindFromS(Lst, LstNode, LstFindProc, const void *); 156LstNode Lst_FindFromS(Lst, LstNode, LstFindProc, const void *);
157/* 157/*
158 * See if the given datum is on the list. Returns the LstNode containing 158 * See if the given datum is on the list. Returns the LstNode containing
159 * the datum 159 * the datum
160 */ 160 */
161LstNode Lst_MemberS(Lst, void *); 161LstNode Lst_MemberS(Lst, void *);
162/* Apply a function to all elements of a lst */ 162/* Apply a function to all elements of a lst */
163int Lst_ForEach(Lst, LstActionProc, void *); 163int Lst_ForEach(Lst, LstActionProc, void *);
164int Lst_ForEachS(Lst, LstActionProc, void *); 164int Lst_ForEachS(Lst, LstActionProc, void *);
165/* Apply a function to all elements of a lst starting from a certain point. */ 165/* Apply a function to all elements of a lst starting from a certain point. */
166int Lst_ForEachFrom(Lst, LstNode, LstActionProc, void *); 166int Lst_ForEachFrom(Lst, LstNode, LstActionProc, void *);
167int Lst_ForEachFromS(Lst, LstNode, LstActionProc, void *); 167int Lst_ForEachFromS(Lst, LstNode, LstActionProc, void *);
168/* 168/*
169 * these functions are for dealing with a list as a table, of sorts. 169 * these functions are for dealing with a list as a table, of sorts.
170 * An idea of the "current element" is kept and used by all the functions 170 * An idea of the "current element" is kept and used by all the functions
171 * between Lst_Open() and Lst_Close(). 171 * between Lst_Open() and Lst_Close().
172 */ 172 */
173/* Open the list */ 173/* Open the list */
174ReturnStatus Lst_Open(Lst); 
175void Lst_OpenS(Lst); 174void Lst_OpenS(Lst);
176/* Next element please, or NULL */ 175/* Next element please, or NULL */
177LstNode Lst_NextS(Lst); 176LstNode Lst_NextS(Lst);
178/* Finish table access */ 177/* Finish table access */
179void Lst_CloseS(Lst); 178void Lst_CloseS(Lst);
180 179
181/* 180/*
182 * for using the list as a queue 181 * for using the list as a queue
183 */ 182 */
184/* Place an element at tail of queue */ 183/* Place an element at tail of queue */
185void Lst_EnqueueS(Lst, void *); 184void Lst_EnqueueS(Lst, void *);
186/* Remove an element from head of queue */ 185/* Remove an element from head of queue */
187void *Lst_DequeueS(Lst); 186void *Lst_DequeueS(Lst);
188 187
189#endif /* MAKE_LST_H */ 188#endif /* MAKE_LST_H */