Tue Sep 1 21:11:31 2020 UTC ()
make(1): rename Hash_Table fields

Back in the 1980s it made sense to have the type information encoded in
the variable names.  At the time when make was imported into the NetBSD
tree (1993-03-21), the functions did indeed not have prototypes, they
only had return types.  The void type was already invented at that time.
Since the compiler could not verify the types of function parameters, it
made perfect sense to have each variable tell whether it was a pointer
or not.

Since ISO C90 this is no longer necessary since the compiler checks
this.  The variable names can now focus on the application level and
their high-level meaning, expressing the relationship to other
variables instead of encoding redundant type information.


(rillig)
diff -r1.129 -r1.130 src/usr.bin/make/dir.c
diff -r1.28 -r1.29 src/usr.bin/make/hash.c
diff -r1.20 -r1.21 src/usr.bin/make/hash.h

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

--- src/usr.bin/make/dir.c 2020/09/01 20:17:18 1.129
+++ src/usr.bin/make/dir.c 2020/09/01 21:11:31 1.130
@@ -1,1325 +1,1325 @@ @@ -1,1325 +1,1325 @@
1/* $NetBSD: dir.c,v 1.129 2020/09/01 20:17:18 rillig Exp $ */ 1/* $NetBSD: dir.c,v 1.130 2020/09/01 21:11:31 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.129 2020/09/01 20:17:18 rillig Exp $"; 73static char rcsid[] = "$NetBSD: dir.c,v 1.130 2020/09/01 21:11:31 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.129 2020/09/01 20:17:18 rillig Exp $"); 80__RCSID("$NetBSD: dir.c,v 1.130 2020/09/01 21:11:31 rillig Exp $");
81#endif 81#endif
82#endif /* not lint */ 82#endif /* not lint */
83#endif 83#endif
84 84
85/*- 85/*-
86 * dir.c -- 86 * dir.c --
87 * Directory searching using wildcards and/or normal names... 87 * Directory searching using wildcards and/or normal names...
88 * Used both for source wildcarding in the Makefile and for finding 88 * Used both for source wildcarding in the Makefile and for finding
89 * implicit sources. 89 * implicit sources.
90 * 90 *
91 * The interface for this module is: 91 * The interface for this module is:
92 * Dir_Init Initialize the module. 92 * Dir_Init Initialize the module.
93 * 93 *
94 * Dir_InitCur Set the cur Path. 94 * Dir_InitCur Set the cur Path.
95 * 95 *
96 * Dir_InitDot Set the dot Path. 96 * Dir_InitDot Set the dot Path.
97 * 97 *
98 * Dir_End Cleanup the module. 98 * Dir_End Cleanup the module.
99 * 99 *
100 * Dir_SetPATH Set ${.PATH} to reflect state of dirSearchPath. 100 * Dir_SetPATH Set ${.PATH} to reflect state of dirSearchPath.
101 * 101 *
102 * Dir_HasWildcards Returns TRUE if the name given it needs to 102 * Dir_HasWildcards Returns TRUE if the name given it needs to
103 * be wildcard-expanded. 103 * be wildcard-expanded.
104 * 104 *
105 * Dir_Expand Given a pattern and a path, return a Lst of names 105 * Dir_Expand Given a pattern and a path, return a Lst of names
106 * which match the pattern on the search path. 106 * which match the pattern on the search path.
107 * 107 *
108 * Dir_FindFile Searches for a file on a given search path. 108 * Dir_FindFile Searches for a file on a given search path.
109 * If it exists, the entire path is returned. 109 * If it exists, the entire path is returned.
110 * Otherwise NULL is returned. 110 * Otherwise NULL is returned.
111 * 111 *
112 * Dir_FindHereOrAbove Search for a path in the current directory and 112 * Dir_FindHereOrAbove Search for a path in the current directory and
113 * then all the directories above it in turn until 113 * then all the directories above it in turn until
114 * the path is found or we reach the root ("/"). 114 * the path is found or we reach the root ("/").
115 * 115 *
116 * Dir_MTime Return the modification time of a node. The file 116 * Dir_MTime Return the modification time of a node. The file
117 * is searched for along the default search path. 117 * is searched for along the default search path.
118 * The path and mtime fields of the node are filled 118 * The path and mtime fields of the node are filled
119 * in. 119 * in.
120 * 120 *
121 * Dir_AddDir Add a directory to a search path. 121 * Dir_AddDir Add a directory to a search path.
122 * 122 *
123 * Dir_MakeFlags Given a search path and a command flag, create 123 * Dir_MakeFlags Given a search path and a command flag, create
124 * a string with each of the directories in the path 124 * a string with each of the directories in the path
125 * preceded by the command flag and all of them 125 * preceded by the command flag and all of them
126 * separated by a space. 126 * separated by a space.
127 * 127 *
128 * Dir_Destroy Destroy an element of a search path. Frees up all 128 * Dir_Destroy Destroy an element of a search path. Frees up all
129 * things that can be freed for the element as long 129 * things that can be freed for the element as long
130 * as the element is no longer referenced by any other 130 * as the element is no longer referenced by any other
131 * search path. 131 * search path.
132 * Dir_ClearPath Resets a search path to the empty list. 132 * Dir_ClearPath Resets a search path to the empty list.
133 * 133 *
134 * For debugging: 134 * For debugging:
135 * Dir_PrintDirectories Print stats about the directory cache. 135 * Dir_PrintDirectories Print stats about the directory cache.
136 */ 136 */
137 137
138#include <sys/types.h> 138#include <sys/types.h>
139#include <sys/stat.h> 139#include <sys/stat.h>
140 140
141#include <dirent.h> 141#include <dirent.h>
142#include <errno.h> 142#include <errno.h>
143#include <stdio.h> 143#include <stdio.h>
144 144
145#include "make.h" 145#include "make.h"
146#include "dir.h" 146#include "dir.h"
147#include "job.h" 147#include "job.h"
148 148
149 149
150#define DIR_DEBUG0(fmt) \ 150#define DIR_DEBUG0(fmt) \
151 if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt) 151 if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt)
152 152
153#define DIR_DEBUG1(fmt, arg1) \ 153#define DIR_DEBUG1(fmt, arg1) \
154 if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1) 154 if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1)
155 155
156#define DIR_DEBUG2(fmt, arg1, arg2) \ 156#define DIR_DEBUG2(fmt, arg1, arg2) \
157 if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1, arg2) 157 if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1, arg2)
158 158
159 159
160/* 160/*
161 * A search path consists of a Lst of Path structures. A Path structure 161 * A search path consists of a Lst of Path structures. A Path structure
162 * has in it the name of the directory and a hash table of all the files 162 * has in it the name of the directory and a hash table of all the files
163 * in the directory. This is used to cut down on the number of system 163 * in the directory. This is used to cut down on the number of system
164 * calls necessary to find implicit dependents and their like. Since 164 * calls necessary to find implicit dependents and their like. Since
165 * these searches are made before any actions are taken, we need not 165 * these searches are made before any actions are taken, we need not
166 * worry about the directory changing due to creation commands. If this 166 * worry about the directory changing due to creation commands. If this
167 * hampers the style of some makefiles, they must be changed. 167 * hampers the style of some makefiles, they must be changed.
168 * 168 *
169 * A list of all previously-read directories is kept in the 169 * A list of all previously-read directories is kept in the
170 * openDirectories Lst. This list is checked first before a directory 170 * openDirectories Lst. This list is checked first before a directory
171 * is opened. 171 * is opened.
172 * 172 *
173 * The need for the caching of whole directories is brought about by 173 * The need for the caching of whole directories is brought about by
174 * the multi-level transformation code in suff.c, which tends to search 174 * the multi-level transformation code in suff.c, which tends to search
175 * for far more files than regular make does. In the initial 175 * for far more files than regular make does. In the initial
176 * implementation, the amount of time spent performing "stat" calls was 176 * implementation, the amount of time spent performing "stat" calls was
177 * truly astronomical. The problem with hashing at the start is, 177 * truly astronomical. The problem with hashing at the start is,
178 * of course, that pmake doesn't then detect changes to these directories 178 * of course, that pmake doesn't then detect changes to these directories
179 * during the course of the make. Three possibilities suggest themselves: 179 * during the course of the make. Three possibilities suggest themselves:
180 * 180 *
181 * 1) just use stat to test for a file's existence. As mentioned 181 * 1) just use stat to test for a file's existence. As mentioned
182 * above, this is very inefficient due to the number of checks 182 * above, this is very inefficient due to the number of checks
183 * engendered by the multi-level transformation code. 183 * engendered by the multi-level transformation code.
184 * 2) use readdir() and company to search the directories, keeping 184 * 2) use readdir() and company to search the directories, keeping
185 * them open between checks. I have tried this and while it 185 * them open between checks. I have tried this and while it
186 * didn't slow down the process too much, it could severely 186 * didn't slow down the process too much, it could severely
187 * affect the amount of parallelism available as each directory 187 * affect the amount of parallelism available as each directory
188 * open would take another file descriptor out of play for 188 * open would take another file descriptor out of play for
189 * handling I/O for another job. Given that it is only recently 189 * handling I/O for another job. Given that it is only recently
190 * that UNIX OS's have taken to allowing more than 20 or 32 190 * that UNIX OS's have taken to allowing more than 20 or 32
191 * file descriptors for a process, this doesn't seem acceptable 191 * file descriptors for a process, this doesn't seem acceptable
192 * to me. 192 * to me.
193 * 3) record the mtime of the directory in the Path structure and 193 * 3) record the mtime of the directory in the Path structure and
194 * verify the directory hasn't changed since the contents were 194 * verify the directory hasn't changed since the contents were
195 * hashed. This will catch the creation or deletion of files, 195 * hashed. This will catch the creation or deletion of files,
196 * but not the updating of files. However, since it is the 196 * but not the updating of files. However, since it is the
197 * creation and deletion that is the problem, this could be 197 * creation and deletion that is the problem, this could be
198 * a good thing to do. Unfortunately, if the directory (say ".") 198 * a good thing to do. Unfortunately, if the directory (say ".")
199 * were fairly large and changed fairly frequently, the constant 199 * were fairly large and changed fairly frequently, the constant
200 * rehashing could seriously degrade performance. It might be 200 * rehashing could seriously degrade performance. It might be
201 * good in such cases to keep track of the number of rehashes 201 * good in such cases to keep track of the number of rehashes
202 * and if the number goes over a (small) limit, resort to using 202 * and if the number goes over a (small) limit, resort to using
203 * stat in its place. 203 * stat in its place.
204 * 204 *
205 * An additional thing to consider is that pmake is used primarily 205 * An additional thing to consider is that pmake is used primarily
206 * to create C programs and until recently pcc-based compilers refused 206 * to create C programs and until recently pcc-based compilers refused
207 * to allow you to specify where the resulting object file should be 207 * to allow you to specify where the resulting object file should be
208 * placed. This forced all objects to be created in the current 208 * placed. This forced all objects to be created in the current
209 * directory. This isn't meant as a full excuse, just an explanation of 209 * directory. This isn't meant as a full excuse, just an explanation of
210 * some of the reasons for the caching used here. 210 * some of the reasons for the caching used here.
211 * 211 *
212 * One more note: the location of a target's file is only performed 212 * One more note: the location of a target's file is only performed
213 * on the downward traversal of the graph and then only for terminal 213 * on the downward traversal of the graph and then only for terminal
214 * nodes in the graph. This could be construed as wrong in some cases, 214 * nodes in the graph. This could be construed as wrong in some cases,
215 * but prevents inadvertent modification of files when the "installed" 215 * but prevents inadvertent modification of files when the "installed"
216 * directory for a file is provided in the search path. 216 * directory for a file is provided in the search path.
217 * 217 *
218 * Another data structure maintained by this module is an mtime 218 * Another data structure maintained by this module is an mtime
219 * cache used when the searching of cached directories fails to find 219 * cache used when the searching of cached directories fails to find
220 * a file. In the past, Dir_FindFile would simply perform an access() 220 * a file. In the past, Dir_FindFile would simply perform an access()
221 * call in such a case to determine if the file could be found using 221 * call in such a case to determine if the file could be found using
222 * just the name given. When this hit, however, all that was gained 222 * just the name given. When this hit, however, all that was gained
223 * was the knowledge that the file existed. Given that an access() is 223 * was the knowledge that the file existed. Given that an access() is
224 * essentially a stat() without the copyout() call, and that the same 224 * essentially a stat() without the copyout() call, and that the same
225 * filesystem overhead would have to be incurred in Dir_MTime, it made 225 * filesystem overhead would have to be incurred in Dir_MTime, it made
226 * sense to replace the access() with a stat() and record the mtime 226 * sense to replace the access() with a stat() and record the mtime
227 * in a cache for when Dir_MTime was actually called. 227 * in a cache for when Dir_MTime was actually called.
228 */ 228 */
229 229
230Lst dirSearchPath; /* main search path */ 230Lst dirSearchPath; /* main search path */
231 231
232static Lst openDirectories; /* the list of all open directories */ 232static Lst openDirectories; /* the list of all open directories */
233 233
234/* 234/*
235 * Variables for gathering statistics on the efficiency of the hashing 235 * Variables for gathering statistics on the efficiency of the hashing
236 * mechanism. 236 * mechanism.
237 */ 237 */
238static int hits; /* Found in directory cache */ 238static int hits; /* Found in directory cache */
239static int misses; /* Sad, but not evil misses */ 239static int misses; /* Sad, but not evil misses */
240static int nearmisses; /* Found under search path */ 240static int nearmisses; /* Found under search path */
241static int bigmisses; /* Sought by itself */ 241static int bigmisses; /* Sought by itself */
242 242
243static Path *dot; /* contents of current directory */ 243static Path *dot; /* contents of current directory */
244static Path *cur; /* contents of current directory, if not dot */ 244static Path *cur; /* contents of current directory, if not dot */
245static Path *dotLast; /* a fake path entry indicating we need to 245static Path *dotLast; /* a fake path entry indicating we need to
246 * look for . last */ 246 * look for . last */
247 247
248/* Results of doing a last-resort stat in Dir_FindFile -- if we have to go to 248/* Results of doing a last-resort stat in Dir_FindFile -- if we have to go to
249 * the system to find the file, we might as well have its mtime on record. 249 * the system to find the file, we might as well have its mtime on record.
250 * 250 *
251 * XXX: If this is done way early, there's a chance other rules will have 251 * XXX: If this is done way early, there's a chance other rules will have
252 * already updated the file, in which case we'll update it again. Generally, 252 * already updated the file, in which case we'll update it again. Generally,
253 * there won't be two rules to update a single file, so this should be ok, 253 * there won't be two rules to update a single file, so this should be ok,
254 * but... */ 254 * but... */
255static Hash_Table mtimes; 255static Hash_Table mtimes;
256 256
257static Hash_Table lmtimes; /* same as mtimes but for lstat */ 257static Hash_Table lmtimes; /* same as mtimes but for lstat */
258 258
259static void DirExpandCurly(const char *, const char *, Lst, Lst); 259static void DirExpandCurly(const char *, const char *, Lst, Lst);
260static void DirExpandInt(const char *, Lst, Lst); 260static void DirExpandInt(const char *, Lst, Lst);
261static int DirPrintWord(void *, void *); 261static int DirPrintWord(void *, void *);
262static int DirPrintDir(void *, void *); 262static int DirPrintDir(void *, void *);
263static char *DirLookup(Path *, const char *, const char *, Boolean); 263static char *DirLookup(Path *, const char *, const char *, Boolean);
264static char *DirLookupSubdir(Path *, const char *); 264static char *DirLookupSubdir(Path *, const char *);
265static char *DirFindDot(Boolean, const char *, const char *); 265static char *DirFindDot(Boolean, const char *, const char *);
266static char *DirLookupAbs(Path *, const char *, const char *); 266static char *DirLookupAbs(Path *, const char *, const char *);
267 267
268 268
269/* 269/*
270 * We use stat(2) a lot, cache the results. 270 * We use stat(2) a lot, cache the results.
271 * mtime and mode are all we care about. 271 * mtime and mode are all we care about.
272 */ 272 */
273struct cache_st { 273struct cache_st {
274 time_t lmtime; /* lstat */ 274 time_t lmtime; /* lstat */
275 time_t mtime; /* stat */ 275 time_t mtime; /* stat */
276 mode_t mode; 276 mode_t mode;
277}; 277};
278 278
279/* minimize changes below */ 279/* minimize changes below */
280typedef enum { 280typedef enum {
281 CST_LSTAT = 0x01, /* call lstat(2) instead of stat(2) */ 281 CST_LSTAT = 0x01, /* call lstat(2) instead of stat(2) */
282 CST_UPDATE = 0x02 /* ignore existing cached entry */ 282 CST_UPDATE = 0x02 /* ignore existing cached entry */
283} CachedStatsFlags; 283} CachedStatsFlags;
284 284
285/* Returns 0 and the result of stat(2) or lstat(2) in *st, or -1 on error. 285/* Returns 0 and the result of stat(2) or lstat(2) in *st, or -1 on error.
286 * Only st->st_mode and st->st_mtime are filled. */ 286 * Only st->st_mode and st->st_mtime are filled. */
287static int 287static int
288cached_stats(Hash_Table *htp, const char *pathname, struct stat *st, 288cached_stats(Hash_Table *htp, const char *pathname, struct stat *st,
289 CachedStatsFlags flags) 289 CachedStatsFlags flags)
290{ 290{
291 Hash_Entry *entry; 291 Hash_Entry *entry;
292 struct cache_st *cst; 292 struct cache_st *cst;
293 int rc; 293 int rc;
294 294
295 if (!pathname || !pathname[0]) 295 if (!pathname || !pathname[0])
296 return -1; 296 return -1;
297 297
298 entry = Hash_FindEntry(htp, pathname); 298 entry = Hash_FindEntry(htp, pathname);
299 299
300 if (entry && !(flags & CST_UPDATE)) { 300 if (entry && !(flags & CST_UPDATE)) {
301 cst = entry->clientPtr; 301 cst = entry->value;
302 302
303 memset(st, 0, sizeof(*st)); 303 memset(st, 0, sizeof(*st));
304 st->st_mode = cst->mode; 304 st->st_mode = cst->mode;
305 st->st_mtime = (flags & CST_LSTAT) ? cst->lmtime : cst->mtime; 305 st->st_mtime = (flags & CST_LSTAT) ? cst->lmtime : cst->mtime;
306 if (st->st_mtime) { 306 if (st->st_mtime) {
307 DIR_DEBUG2("Using cached time %s for %s\n", 307 DIR_DEBUG2("Using cached time %s for %s\n",
308 Targ_FmtTime(st->st_mtime), pathname); 308 Targ_FmtTime(st->st_mtime), pathname);
309 return 0; 309 return 0;
310 } 310 }
311 } 311 }
312 312
313 rc = (flags & CST_LSTAT) ? lstat(pathname, st) : stat(pathname, st); 313 rc = (flags & CST_LSTAT) ? lstat(pathname, st) : stat(pathname, st);
314 if (rc == -1) 314 if (rc == -1)
315 return -1; 315 return -1;
316 316
317 if (st->st_mtime == 0) 317 if (st->st_mtime == 0)
318 st->st_mtime = 1; /* avoid confusion with missing file */ 318 st->st_mtime = 1; /* avoid confusion with missing file */
319 319
320 if (!entry) 320 if (!entry)
321 entry = Hash_CreateEntry(htp, pathname, NULL); 321 entry = Hash_CreateEntry(htp, pathname, NULL);
322 if (!entry->clientPtr) { 322 if (!entry->value) {
323 entry->clientPtr = bmake_malloc(sizeof(*cst)); 323 entry->value = bmake_malloc(sizeof(*cst));
324 memset(entry->clientPtr, 0, sizeof(*cst)); 324 memset(entry->value, 0, sizeof(*cst));
325 } 325 }
326 cst = entry->clientPtr; 326 cst = entry->value;
327 if (flags & CST_LSTAT) { 327 if (flags & CST_LSTAT) {
328 cst->lmtime = st->st_mtime; 328 cst->lmtime = st->st_mtime;
329 } else { 329 } else {
330 cst->mtime = st->st_mtime; 330 cst->mtime = st->st_mtime;
331 } 331 }
332 cst->mode = st->st_mode; 332 cst->mode = st->st_mode;
333 DIR_DEBUG2(" Caching %s for %s\n", 333 DIR_DEBUG2(" Caching %s for %s\n",
334 Targ_FmtTime(st->st_mtime), pathname); 334 Targ_FmtTime(st->st_mtime), pathname);
335 335
336 return 0; 336 return 0;
337} 337}
338 338
339int 339int
340cached_stat(const char *pathname, void *st) 340cached_stat(const char *pathname, void *st)
341{ 341{
342 return cached_stats(&mtimes, pathname, st, 0); 342 return cached_stats(&mtimes, pathname, st, 0);
343} 343}
344 344
345int 345int
346cached_lstat(const char *pathname, void *st) 346cached_lstat(const char *pathname, void *st)
347{ 347{
348 return cached_stats(&lmtimes, pathname, st, CST_LSTAT); 348 return cached_stats(&lmtimes, pathname, st, CST_LSTAT);
349} 349}
350 350
351/* Initialize things for this module. */ 351/* Initialize things for this module. */
352void 352void
353Dir_Init(void) 353Dir_Init(void)
354{ 354{
355 dirSearchPath = Lst_Init(); 355 dirSearchPath = Lst_Init();
356 openDirectories = Lst_Init(); 356 openDirectories = Lst_Init();
357 Hash_InitTable(&mtimes, 0); 357 Hash_InitTable(&mtimes, 0);
358 Hash_InitTable(&lmtimes, 0); 358 Hash_InitTable(&lmtimes, 0);
359} 359}
360 360
361void 361void
362Dir_InitDir(const char *cdname) 362Dir_InitDir(const char *cdname)
363{ 363{
364 Dir_InitCur(cdname); 364 Dir_InitCur(cdname);
365 365
366 dotLast = bmake_malloc(sizeof(Path)); 366 dotLast = bmake_malloc(sizeof(Path));
367 dotLast->refCount = 1; 367 dotLast->refCount = 1;
368 dotLast->hits = 0; 368 dotLast->hits = 0;
369 dotLast->name = bmake_strdup(".DOTLAST"); 369 dotLast->name = bmake_strdup(".DOTLAST");
370 Hash_InitTable(&dotLast->files, -1); 370 Hash_InitTable(&dotLast->files, -1);
371} 371}
372 372
373/* 373/*
374 * Called by Dir_InitDir and whenever .CURDIR is assigned to. 374 * Called by Dir_InitDir and whenever .CURDIR is assigned to.
375 */ 375 */
376void 376void
377Dir_InitCur(const char *cdname) 377Dir_InitCur(const char *cdname)
378{ 378{
379 Path *p; 379 Path *p;
380 380
381 if (cdname != NULL) { 381 if (cdname != NULL) {
382 /* 382 /*
383 * Our build directory is not the same as our source directory. 383 * Our build directory is not the same as our source directory.
384 * Keep this one around too. 384 * Keep this one around too.
385 */ 385 */
386 if ((p = Dir_AddDir(NULL, cdname))) { 386 if ((p = Dir_AddDir(NULL, cdname))) {
387 p->refCount += 1; 387 p->refCount += 1;
388 if (cur && cur != p) { 388 if (cur && cur != p) {
389 /* 389 /*
390 * We've been here before, cleanup. 390 * We've been here before, cleanup.
391 */ 391 */
392 cur->refCount -= 1; 392 cur->refCount -= 1;
393 Dir_Destroy(cur); 393 Dir_Destroy(cur);
394 } 394 }
395 cur = p; 395 cur = p;
396 } 396 }
397 } 397 }
398} 398}
399 399
400/* (Re)initialize "dot" (current/object directory) path hash. 400/* (Re)initialize "dot" (current/object directory) path hash.
401 * Some directories may be opened. */ 401 * Some directories may be opened. */
402void 402void
403Dir_InitDot(void) 403Dir_InitDot(void)
404{ 404{
405 if (dot != NULL) { 405 if (dot != NULL) {
406 LstNode ln; 406 LstNode ln;
407 407
408 /* Remove old entry from openDirectories, but do not destroy. */ 408 /* Remove old entry from openDirectories, but do not destroy. */
409 ln = Lst_FindDatum(openDirectories, dot); 409 ln = Lst_FindDatum(openDirectories, dot);
410 Lst_Remove(openDirectories, ln); 410 Lst_Remove(openDirectories, ln);
411 } 411 }
412 412
413 dot = Dir_AddDir(NULL, "."); 413 dot = Dir_AddDir(NULL, ".");
414 414
415 if (dot == NULL) { 415 if (dot == NULL) {
416 Error("Cannot open `.' (%s)", strerror(errno)); 416 Error("Cannot open `.' (%s)", strerror(errno));
417 exit(1); 417 exit(1);
418 } 418 }
419 419
420 /* 420 /*
421 * We always need to have dot around, so we increment its reference count 421 * We always need to have dot around, so we increment its reference count
422 * to make sure it's not destroyed. 422 * to make sure it's not destroyed.
423 */ 423 */
424 dot->refCount += 1; 424 dot->refCount += 1;
425 Dir_SetPATH(); /* initialize */ 425 Dir_SetPATH(); /* initialize */
426} 426}
427 427
428/* Clean up things for this module. */ 428/* Clean up things for this module. */
429void 429void
430Dir_End(void) 430Dir_End(void)
431{ 431{
432#ifdef CLEANUP 432#ifdef CLEANUP
433 if (cur) { 433 if (cur) {
434 cur->refCount -= 1; 434 cur->refCount -= 1;
435 Dir_Destroy(cur); 435 Dir_Destroy(cur);
436 } 436 }
437 dot->refCount -= 1; 437 dot->refCount -= 1;
438 dotLast->refCount -= 1; 438 dotLast->refCount -= 1;
439 Dir_Destroy(dotLast); 439 Dir_Destroy(dotLast);
440 Dir_Destroy(dot); 440 Dir_Destroy(dot);
441 Dir_ClearPath(dirSearchPath); 441 Dir_ClearPath(dirSearchPath);
442 Lst_Free(dirSearchPath); 442 Lst_Free(dirSearchPath);
443 Dir_ClearPath(openDirectories); 443 Dir_ClearPath(openDirectories);
444 Lst_Free(openDirectories); 444 Lst_Free(openDirectories);
445 Hash_DeleteTable(&mtimes); 445 Hash_DeleteTable(&mtimes);
446#endif 446#endif
447} 447}
448 448
449/* 449/*
450 * We want ${.PATH} to indicate the order in which we will actually 450 * We want ${.PATH} to indicate the order in which we will actually
451 * search, so we rebuild it after any .PATH: target. 451 * search, so we rebuild it after any .PATH: target.
452 * This is the simplest way to deal with the effect of .DOTLAST. 452 * This is the simplest way to deal with the effect of .DOTLAST.
453 */ 453 */
454void 454void
455Dir_SetPATH(void) 455Dir_SetPATH(void)
456{ 456{
457 LstNode ln; /* a list element */ 457 LstNode ln; /* a list element */
458 Path *p; 458 Path *p;
459 Boolean hasLastDot = FALSE; /* true if we should search dot last */ 459 Boolean hasLastDot = FALSE; /* true if we should search dot last */
460 460
461 Var_Delete(".PATH", VAR_GLOBAL); 461 Var_Delete(".PATH", VAR_GLOBAL);
462 462
463 Lst_Open(dirSearchPath); 463 Lst_Open(dirSearchPath);
464 if ((ln = Lst_First(dirSearchPath)) != NULL) { 464 if ((ln = Lst_First(dirSearchPath)) != NULL) {
465 p = LstNode_Datum(ln); 465 p = LstNode_Datum(ln);
466 if (p == dotLast) { 466 if (p == dotLast) {
467 hasLastDot = TRUE; 467 hasLastDot = TRUE;
468 Var_Append(".PATH", dotLast->name, VAR_GLOBAL); 468 Var_Append(".PATH", dotLast->name, VAR_GLOBAL);
469 } 469 }
470 } 470 }
471 471
472 if (!hasLastDot) { 472 if (!hasLastDot) {
473 if (dot) 473 if (dot)
474 Var_Append(".PATH", dot->name, VAR_GLOBAL); 474 Var_Append(".PATH", dot->name, VAR_GLOBAL);
475 if (cur) 475 if (cur)
476 Var_Append(".PATH", cur->name, VAR_GLOBAL); 476 Var_Append(".PATH", cur->name, VAR_GLOBAL);
477 } 477 }
478 478
479 while ((ln = Lst_Next(dirSearchPath)) != NULL) { 479 while ((ln = Lst_Next(dirSearchPath)) != NULL) {
480 p = LstNode_Datum(ln); 480 p = LstNode_Datum(ln);
481 if (p == dotLast) 481 if (p == dotLast)
482 continue; 482 continue;
483 if (p == dot && hasLastDot) 483 if (p == dot && hasLastDot)
484 continue; 484 continue;
485 Var_Append(".PATH", p->name, VAR_GLOBAL); 485 Var_Append(".PATH", p->name, VAR_GLOBAL);
486 } 486 }
487 487
488 if (hasLastDot) { 488 if (hasLastDot) {
489 if (dot) 489 if (dot)
490 Var_Append(".PATH", dot->name, VAR_GLOBAL); 490 Var_Append(".PATH", dot->name, VAR_GLOBAL);
491 if (cur) 491 if (cur)
492 Var_Append(".PATH", cur->name, VAR_GLOBAL); 492 Var_Append(".PATH", cur->name, VAR_GLOBAL);
493 } 493 }
494 Lst_Close(dirSearchPath); 494 Lst_Close(dirSearchPath);
495} 495}
496 496
497/* See if the Path structure describes the same directory as the 497/* See if the Path structure describes the same directory as the
498 * given one by comparing their names. Called from Dir_AddDir via 498 * given one by comparing their names. Called from Dir_AddDir via
499 * Lst_Find when searching the list of open directories. */ 499 * Lst_Find when searching the list of open directories. */
500static Boolean 500static Boolean
501DirFindName(const void *p, const void *desiredName) 501DirFindName(const void *p, const void *desiredName)
502{ 502{
503 return strcmp(((const Path *)p)->name, desiredName) == 0; 503 return strcmp(((const Path *)p)->name, desiredName) == 0;
504} 504}
505 505
506/* See if the given name has any wildcard characters in it. Be careful not to 506/* See if the given name has any wildcard characters in it. Be careful not to
507 * expand unmatching brackets or braces. 507 * expand unmatching brackets or braces.
508 * 508 *
509 * XXX: This code is not 100% correct ([^]] fails etc.). I really don't think 509 * XXX: This code is not 100% correct ([^]] fails etc.). I really don't think
510 * that make(1) should be expanding patterns, because then you have to set a 510 * that make(1) should be expanding patterns, because then you have to set a
511 * mechanism for escaping the expansion! 511 * mechanism for escaping the expansion!
512 * 512 *
513 * Input: 513 * Input:
514 * name name to check 514 * name name to check
515 * 515 *
516 * Results: 516 * Results:
517 * returns TRUE if the word should be expanded, FALSE otherwise 517 * returns TRUE if the word should be expanded, FALSE otherwise
518 */ 518 */
519Boolean 519Boolean
520Dir_HasWildcards(const char *name) 520Dir_HasWildcards(const char *name)
521{ 521{
522 const char *cp; 522 const char *cp;
523 Boolean wild = FALSE; 523 Boolean wild = FALSE;
524 int braces = 0, brackets = 0; 524 int braces = 0, brackets = 0;
525 525
526 for (cp = name; *cp; cp++) { 526 for (cp = name; *cp; cp++) {
527 switch (*cp) { 527 switch (*cp) {
528 case '{': 528 case '{':
529 braces++; 529 braces++;
530 wild = TRUE; 530 wild = TRUE;
531 break; 531 break;
532 case '}': 532 case '}':
533 braces--; 533 braces--;
534 break; 534 break;
535 case '[': 535 case '[':
536 brackets++; 536 brackets++;
537 wild = TRUE; 537 wild = TRUE;
538 break; 538 break;
539 case ']': 539 case ']':
540 brackets--; 540 brackets--;
541 break; 541 break;
542 case '?': 542 case '?':
543 case '*': 543 case '*':
544 wild = TRUE; 544 wild = TRUE;
545 break; 545 break;
546 default: 546 default:
547 break; 547 break;
548 } 548 }
549 } 549 }
550 return wild && brackets == 0 && braces == 0; 550 return wild && brackets == 0 && braces == 0;
551} 551}
552 552
553/*- 553/*-
554 *----------------------------------------------------------------------- 554 *-----------------------------------------------------------------------
555 * DirMatchFiles -- 555 * DirMatchFiles --
556 * Given a pattern and a Path structure, see if any files 556 * Given a pattern and a Path structure, see if any files
557 * match the pattern and add their names to the 'expansions' list if 557 * match the pattern and add their names to the 'expansions' list if
558 * any do. This is incomplete -- it doesn't take care of patterns like 558 * any do. This is incomplete -- it doesn't take care of patterns like
559 * src / *src / *.c properly (just *.c on any of the directories), but it 559 * src / *src / *.c properly (just *.c on any of the directories), but it
560 * will do for now. 560 * will do for now.
561 * 561 *
562 * Input: 562 * Input:
563 * pattern Pattern to look for 563 * pattern Pattern to look for
564 * p Directory to search 564 * p Directory to search
565 * expansion Place to store the results 565 * expansion Place to store the results
566 * 566 *
567 * Side Effects: 567 * Side Effects:
568 * File names are added to the expansions lst. The directory will be 568 * File names are added to the expansions lst. The directory will be
569 * fully hashed when this is done. 569 * fully hashed when this is done.
570 *----------------------------------------------------------------------- 570 *-----------------------------------------------------------------------
571 */ 571 */
572static void 572static void
573DirMatchFiles(const char *pattern, Path *p, Lst expansions) 573DirMatchFiles(const char *pattern, Path *p, Lst expansions)
574{ 574{
575 Hash_Search search; /* Index into the directory's table */ 575 Hash_Search search; /* Index into the directory's table */
576 Hash_Entry *entry; /* Current entry in the table */ 576 Hash_Entry *entry; /* Current entry in the table */
577 Boolean isDot; /* TRUE if the directory being searched is . */ 577 Boolean isDot; /* TRUE if the directory being searched is . */
578 578
579 isDot = (*p->name == '.' && p->name[1] == '\0'); 579 isDot = (*p->name == '.' && p->name[1] == '\0');
580 580
581 for (entry = Hash_EnumFirst(&p->files, &search); 581 for (entry = Hash_EnumFirst(&p->files, &search);
582 entry != NULL; 582 entry != NULL;
583 entry = Hash_EnumNext(&search)) 583 entry = Hash_EnumNext(&search))
584 { 584 {
585 /* 585 /*
586 * See if the file matches the given pattern. Note we follow the UNIX 586 * See if the file matches the given pattern. Note we follow the UNIX
587 * convention that dot files will only be found if the pattern 587 * convention that dot files will only be found if the pattern
588 * begins with a dot (note also that as a side effect of the hashing 588 * begins with a dot (note also that as a side effect of the hashing
589 * scheme, .* won't match . or .. since they aren't hashed). 589 * scheme, .* won't match . or .. since they aren't hashed).
590 */ 590 */
591 if (Str_Match(entry->name, pattern) && 591 if (Str_Match(entry->name, pattern) &&
592 ((entry->name[0] != '.') || 592 ((entry->name[0] != '.') ||
593 (pattern[0] == '.'))) 593 (pattern[0] == '.')))
594 { 594 {
595 Lst_Append(expansions, 595 Lst_Append(expansions,
596 (isDot ? bmake_strdup(entry->name) : 596 (isDot ? bmake_strdup(entry->name) :
597 str_concat3(p->name, "/", entry->name))); 597 str_concat3(p->name, "/", entry->name)));
598 } 598 }
599 } 599 }
600} 600}
601 601
602/* Find the next closing brace in the string, taking nested braces into 602/* Find the next closing brace in the string, taking nested braces into
603 * account. */ 603 * account. */
604static const char * 604static const char *
605closing_brace(const char *p) 605closing_brace(const char *p)
606{ 606{
607 int nest = 0; 607 int nest = 0;
608 while (*p != '\0') { 608 while (*p != '\0') {
609 if (*p == '}' && nest == 0) 609 if (*p == '}' && nest == 0)
610 break; 610 break;
611 if (*p == '{') 611 if (*p == '{')
612 nest++; 612 nest++;
613 if (*p == '}') 613 if (*p == '}')
614 nest--; 614 nest--;
615 p++; 615 p++;
616 } 616 }
617 return p; 617 return p;
618} 618}
619 619
620/* Find the next closing brace or comma in the string, taking nested braces 620/* Find the next closing brace or comma in the string, taking nested braces
621 * into account. */ 621 * into account. */
622static const char * 622static const char *
623separator_comma(const char *p) 623separator_comma(const char *p)
624{ 624{
625 int nest = 0; 625 int nest = 0;
626 while (*p != '\0') { 626 while (*p != '\0') {
627 if ((*p == '}' || *p == ',') && nest == 0) 627 if ((*p == '}' || *p == ',') && nest == 0)
628 break; 628 break;
629 if (*p == '{') 629 if (*p == '{')
630 nest++; 630 nest++;
631 if (*p == '}') 631 if (*p == '}')
632 nest--; 632 nest--;
633 p++; 633 p++;
634 } 634 }
635 return p; 635 return p;
636} 636}
637 637
638static Boolean 638static Boolean
639contains_wildcard(const char *p) 639contains_wildcard(const char *p)
640{ 640{
641 for (; *p != '\0'; p++) { 641 for (; *p != '\0'; p++) {
642 switch (*p) { 642 switch (*p) {
643 case '*': 643 case '*':
644 case '?': 644 case '?':
645 case '{': 645 case '{':
646 case '[': 646 case '[':
647 return TRUE; 647 return TRUE;
648 } 648 }
649 } 649 }
650 return FALSE; 650 return FALSE;
651} 651}
652 652
653static char * 653static char *
654concat3(const char *a, size_t a_len, const char *b, size_t b_len, 654concat3(const char *a, size_t a_len, const char *b, size_t b_len,
655 const char *c, size_t c_len) 655 const char *c, size_t c_len)
656{ 656{
657 size_t s_len = a_len + b_len + c_len; 657 size_t s_len = a_len + b_len + c_len;
658 char *s = bmake_malloc(s_len + 1); 658 char *s = bmake_malloc(s_len + 1);
659 memcpy(s, a, a_len); 659 memcpy(s, a, a_len);
660 memcpy(s + a_len, b, b_len); 660 memcpy(s + a_len, b, b_len);
661 memcpy(s + a_len + b_len, c, c_len); 661 memcpy(s + a_len + b_len, c, c_len);
662 s[s_len] = '\0'; 662 s[s_len] = '\0';
663 return s; 663 return s;
664} 664}
665 665
666/*- 666/*-
667 *----------------------------------------------------------------------- 667 *-----------------------------------------------------------------------
668 * DirExpandCurly -- 668 * DirExpandCurly --
669 * Expand curly braces like the C shell. Does this recursively. 669 * Expand curly braces like the C shell. Does this recursively.
670 * Note the special case: if after the piece of the curly brace is 670 * Note the special case: if after the piece of the curly brace is
671 * done there are no wildcard characters in the result, the result is 671 * done there are no wildcard characters in the result, the result is
672 * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE. 672 * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE.
673 * 673 *
674 * Input: 674 * Input:
675 * word Entire word to expand 675 * word Entire word to expand
676 * brace First curly brace in it 676 * brace First curly brace in it
677 * path Search path to use 677 * path Search path to use
678 * expansions Place to store the expansions 678 * expansions Place to store the expansions
679 * 679 *
680 * Results: 680 * Results:
681 * None. 681 * None.
682 * 682 *
683 * Side Effects: 683 * Side Effects:
684 * The given list is filled with the expansions... 684 * The given list is filled with the expansions...
685 * 685 *
686 *----------------------------------------------------------------------- 686 *-----------------------------------------------------------------------
687 */ 687 */
688static void 688static void
689DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions) 689DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions)
690{ 690{
691 const char *prefix, *middle, *piece, *middle_end, *suffix; 691 const char *prefix, *middle, *piece, *middle_end, *suffix;
692 size_t prefix_len, suffix_len; 692 size_t prefix_len, suffix_len;
693 693
694 /* Split the word into prefix '{' middle '}' suffix. */ 694 /* Split the word into prefix '{' middle '}' suffix. */
695 695
696 middle = brace + 1; 696 middle = brace + 1;
697 middle_end = closing_brace(middle); 697 middle_end = closing_brace(middle);
698 if (*middle_end == '\0') { 698 if (*middle_end == '\0') {
699 Error("Unterminated {} clause \"%s\"", middle); 699 Error("Unterminated {} clause \"%s\"", middle);
700 return; 700 return;
701 } 701 }
702 702
703 prefix = word; 703 prefix = word;
704 prefix_len = (size_t)(brace - prefix); 704 prefix_len = (size_t)(brace - prefix);
705 suffix = middle_end + 1; 705 suffix = middle_end + 1;
706 suffix_len = strlen(suffix); 706 suffix_len = strlen(suffix);
707 707
708 /* Split the middle into pieces, separated by commas. */ 708 /* Split the middle into pieces, separated by commas. */
709 709
710 piece = middle; 710 piece = middle;
711 while (piece < middle_end + 1) { 711 while (piece < middle_end + 1) {
712 const char *piece_end = separator_comma(piece); 712 const char *piece_end = separator_comma(piece);
713 size_t piece_len = (size_t)(piece_end - piece); 713 size_t piece_len = (size_t)(piece_end - piece);
714 714
715 char *file = concat3(prefix, prefix_len, piece, piece_len, 715 char *file = concat3(prefix, prefix_len, piece, piece_len,
716 suffix, suffix_len); 716 suffix, suffix_len);
717 717
718 if (contains_wildcard(file)) { 718 if (contains_wildcard(file)) {
719 Dir_Expand(file, path, expansions); 719 Dir_Expand(file, path, expansions);
720 free(file); 720 free(file);
721 } else { 721 } else {
722 Lst_Append(expansions, file); 722 Lst_Append(expansions, file);
723 } 723 }
724 724
725 piece = piece_end + 1; /* skip over the comma or closing brace */ 725 piece = piece_end + 1; /* skip over the comma or closing brace */
726 } 726 }
727} 727}
728 728
729 729
730/*- 730/*-
731 *----------------------------------------------------------------------- 731 *-----------------------------------------------------------------------
732 * DirExpandInt -- 732 * DirExpandInt --
733 * Internal expand routine. Passes through the directories in the 733 * Internal expand routine. Passes through the directories in the
734 * path one by one, calling DirMatchFiles for each. NOTE: This still 734 * path one by one, calling DirMatchFiles for each. NOTE: This still
735 * doesn't handle patterns in directories... 735 * doesn't handle patterns in directories...
736 * 736 *
737 * Input: 737 * Input:
738 * word Word to expand 738 * word Word to expand
739 * path Path on which to look 739 * path Path on which to look
740 * expansions Place to store the result 740 * expansions Place to store the result
741 * 741 *
742 * Results: 742 * Results:
743 * None. 743 * None.
744 * 744 *
745 * Side Effects: 745 * Side Effects:
746 * Things are added to the expansions list. 746 * Things are added to the expansions list.
747 * 747 *
748 *----------------------------------------------------------------------- 748 *-----------------------------------------------------------------------
749 */ 749 */
750static void 750static void
751DirExpandInt(const char *word, Lst path, Lst expansions) 751DirExpandInt(const char *word, Lst path, Lst expansions)
752{ 752{
753 LstNode ln; /* Current node */ 753 LstNode ln; /* Current node */
754 754
755 Lst_Open(path); 755 Lst_Open(path);
756 while ((ln = Lst_Next(path)) != NULL) { 756 while ((ln = Lst_Next(path)) != NULL) {
757 Path *p = LstNode_Datum(ln); 757 Path *p = LstNode_Datum(ln);
758 DirMatchFiles(word, p, expansions); 758 DirMatchFiles(word, p, expansions);
759 } 759 }
760 Lst_Close(path); 760 Lst_Close(path);
761} 761}
762 762
763/* Print a word in the list of expansions. 763/* Print a word in the list of expansions.
764 * Callback for Dir_Expand when DEBUG(DIR), via Lst_ForEach. */ 764 * Callback for Dir_Expand when DEBUG(DIR), via Lst_ForEach. */
765static int 765static int
766DirPrintWord(void *word, void *dummy MAKE_ATTR_UNUSED) 766DirPrintWord(void *word, void *dummy MAKE_ATTR_UNUSED)
767{ 767{
768 fprintf(debug_file, "%s ", (char *)word); 768 fprintf(debug_file, "%s ", (char *)word);
769 769
770 return 0; 770 return 0;
771} 771}
772 772
773/*- 773/*-
774 *----------------------------------------------------------------------- 774 *-----------------------------------------------------------------------
775 * Dir_Expand -- 775 * Dir_Expand --
776 * Expand the given word into a list of words by globbing it looking 776 * Expand the given word into a list of words by globbing it looking
777 * in the directories on the given search path. 777 * in the directories on the given search path.
778 * 778 *
779 * Input: 779 * Input:
780 * word the word to expand 780 * word the word to expand
781 * path the list of directories in which to find the 781 * path the list of directories in which to find the
782 * resulting files 782 * resulting files
783 * expansions the list on which to place the results 783 * expansions the list on which to place the results
784 * 784 *
785 * Results: 785 * Results:
786 * A list of words consisting of the files which exist along the search 786 * A list of words consisting of the files which exist along the search
787 * path matching the given pattern. 787 * path matching the given pattern.
788 * 788 *
789 * Side Effects: 789 * Side Effects:
790 * Directories may be opened. Who knows? 790 * Directories may be opened. Who knows?
791 * Undefined behavior if the word is really in read-only memory. 791 * Undefined behavior if the word is really in read-only memory.
792 *----------------------------------------------------------------------- 792 *-----------------------------------------------------------------------
793 */ 793 */
794void 794void
795Dir_Expand(const char *word, Lst path, Lst expansions) 795Dir_Expand(const char *word, Lst path, Lst expansions)
796{ 796{
797 const char *cp; 797 const char *cp;
798 798
799 assert(path != NULL); 799 assert(path != NULL);
800 assert(expansions != NULL); 800 assert(expansions != NULL);
801 801
802 DIR_DEBUG1("Expanding \"%s\"... ", word); 802 DIR_DEBUG1("Expanding \"%s\"... ", word);
803 803
804 cp = strchr(word, '{'); 804 cp = strchr(word, '{');
805 if (cp) { 805 if (cp) {
806 DirExpandCurly(word, cp, path, expansions); 806 DirExpandCurly(word, cp, path, expansions);
807 } else { 807 } else {
808 cp = strchr(word, '/'); 808 cp = strchr(word, '/');
809 if (cp) { 809 if (cp) {
810 /* 810 /*
811 * The thing has a directory component -- find the first wildcard 811 * The thing has a directory component -- find the first wildcard
812 * in the string. 812 * in the string.
813 */ 813 */
814 for (cp = word; *cp; cp++) { 814 for (cp = word; *cp; cp++) {
815 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') { 815 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') {
816 break; 816 break;
817 } 817 }
818 } 818 }
819 if (*cp == '{') { 819 if (*cp == '{') {
820 /* 820 /*
821 * This one will be fun. 821 * This one will be fun.
822 */ 822 */
823 DirExpandCurly(word, cp, path, expansions); 823 DirExpandCurly(word, cp, path, expansions);
824 return; 824 return;
825 } else if (*cp != '\0') { 825 } else if (*cp != '\0') {
826 /* 826 /*
827 * Back up to the start of the component 827 * Back up to the start of the component
828 */ 828 */
829 while (cp > word && *cp != '/') { 829 while (cp > word && *cp != '/') {
830 cp--; 830 cp--;
831 } 831 }
832 if (cp != word) { 832 if (cp != word) {
833 char sc; 833 char sc;
834 char *dirpath; 834 char *dirpath;
835 /* 835 /*
836 * If the glob isn't in the first component, try and find 836 * If the glob isn't in the first component, try and find
837 * all the components up to the one with a wildcard. 837 * all the components up to the one with a wildcard.
838 */ 838 */
839 sc = cp[1]; 839 sc = cp[1];
840 ((char *)UNCONST(cp))[1] = '\0'; 840 ((char *)UNCONST(cp))[1] = '\0';
841 dirpath = Dir_FindFile(word, path); 841 dirpath = Dir_FindFile(word, path);
842 ((char *)UNCONST(cp))[1] = sc; 842 ((char *)UNCONST(cp))[1] = sc;
843 /* 843 /*
844 * dirpath is null if can't find the leading component 844 * dirpath is null if can't find the leading component
845 * XXX: Dir_FindFile won't find internal components. 845 * XXX: Dir_FindFile won't find internal components.
846 * i.e. if the path contains ../Etc/Object and we're 846 * i.e. if the path contains ../Etc/Object and we're
847 * looking for Etc, it won't be found. Ah well. 847 * looking for Etc, it won't be found. Ah well.
848 * Probably not important. 848 * Probably not important.
849 */ 849 */
850 if (dirpath != NULL) { 850 if (dirpath != NULL) {
851 char *dp = &dirpath[strlen(dirpath) - 1]; 851 char *dp = &dirpath[strlen(dirpath) - 1];
852 if (*dp == '/') 852 if (*dp == '/')
853 *dp = '\0'; 853 *dp = '\0';
854 path = Lst_Init(); 854 path = Lst_Init();
855 (void)Dir_AddDir(path, dirpath); 855 (void)Dir_AddDir(path, dirpath);
856 DirExpandInt(cp + 1, path, expansions); 856 DirExpandInt(cp + 1, path, expansions);
857 Lst_Free(path); 857 Lst_Free(path);
858 } 858 }
859 } else { 859 } else {
860 /* 860 /*
861 * Start the search from the local directory 861 * Start the search from the local directory
862 */ 862 */
863 DirExpandInt(word, path, expansions); 863 DirExpandInt(word, path, expansions);
864 } 864 }
865 } else { 865 } else {
866 /* 866 /*
867 * Return the file -- this should never happen. 867 * Return the file -- this should never happen.
868 */ 868 */
869 DirExpandInt(word, path, expansions); 869 DirExpandInt(word, path, expansions);
870 } 870 }
871 } else { 871 } else {
872 /* 872 /*
873 * First the files in dot 873 * First the files in dot
874 */ 874 */
875 DirMatchFiles(word, dot, expansions); 875 DirMatchFiles(word, dot, expansions);
876 876
877 /* 877 /*
878 * Then the files in every other directory on the path. 878 * Then the files in every other directory on the path.
879 */ 879 */
880 DirExpandInt(word, path, expansions); 880 DirExpandInt(word, path, expansions);
881 } 881 }
882 } 882 }
883 if (DEBUG(DIR)) { 883 if (DEBUG(DIR)) {
884 Lst_ForEach(expansions, DirPrintWord, NULL); 884 Lst_ForEach(expansions, DirPrintWord, NULL);
885 fprintf(debug_file, "\n"); 885 fprintf(debug_file, "\n");
886 } 886 }
887} 887}
888 888
889/*- 889/*-
890 *----------------------------------------------------------------------- 890 *-----------------------------------------------------------------------
891 * DirLookup -- 891 * DirLookup --
892 * Find if the file with the given name exists in the given path. 892 * Find if the file with the given name exists in the given path.
893 * 893 *
894 * Results: 894 * Results:
895 * The path to the file or NULL. This path is guaranteed to be in a 895 * The path to the file or NULL. This path is guaranteed to be in a
896 * different part of memory than name and so may be safely free'd. 896 * different part of memory than name and so may be safely free'd.
897 * 897 *
898 * Side Effects: 898 * Side Effects:
899 * None. 899 * None.
900 *----------------------------------------------------------------------- 900 *-----------------------------------------------------------------------
901 */ 901 */
902static char * 902static char *
903DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp, 903DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp,
904 Boolean hasSlash MAKE_ATTR_UNUSED) 904 Boolean hasSlash MAKE_ATTR_UNUSED)
905{ 905{
906 char *file; /* the current filename to check */ 906 char *file; /* the current filename to check */
907 907
908 DIR_DEBUG1(" %s ...\n", p->name); 908 DIR_DEBUG1(" %s ...\n", p->name);
909 909
910 if (Hash_FindEntry(&p->files, cp) == NULL) 910 if (Hash_FindEntry(&p->files, cp) == NULL)
911 return NULL; 911 return NULL;
912 912
913 file = str_concat3(p->name, "/", cp); 913 file = str_concat3(p->name, "/", cp);
914 DIR_DEBUG1(" returning %s\n", file); 914 DIR_DEBUG1(" returning %s\n", file);
915 p->hits += 1; 915 p->hits += 1;
916 hits += 1; 916 hits += 1;
917 return file; 917 return file;
918} 918}
919 919
920 920
921/*- 921/*-
922 *----------------------------------------------------------------------- 922 *-----------------------------------------------------------------------
923 * DirLookupSubdir -- 923 * DirLookupSubdir --
924 * Find if the file with the given name exists in the given path. 924 * Find if the file with the given name exists in the given path.
925 * 925 *
926 * Results: 926 * Results:
927 * The path to the file or NULL. This path is guaranteed to be in a 927 * The path to the file or NULL. This path is guaranteed to be in a
928 * different part of memory than name and so may be safely free'd. 928 * different part of memory than name and so may be safely free'd.
929 * 929 *
930 * Side Effects: 930 * Side Effects:
931 * If the file is found, it is added in the modification times hash 931 * If the file is found, it is added in the modification times hash
932 * table. 932 * table.
933 *----------------------------------------------------------------------- 933 *-----------------------------------------------------------------------
934 */ 934 */
935static char * 935static char *
936DirLookupSubdir(Path *p, const char *name) 936DirLookupSubdir(Path *p, const char *name)
937{ 937{
938 struct stat stb; /* Buffer for stat, if necessary */ 938 struct stat stb; /* Buffer for stat, if necessary */
939 char *file; /* the current filename to check */ 939 char *file; /* the current filename to check */
940 940
941 if (p != dot) { 941 if (p != dot) {
942 file = str_concat3(p->name, "/", name); 942 file = str_concat3(p->name, "/", name);
943 } else { 943 } else {
944 /* 944 /*
945 * Checking in dot -- DON'T put a leading ./ on the thing. 945 * Checking in dot -- DON'T put a leading ./ on the thing.
946 */ 946 */
947 file = bmake_strdup(name); 947 file = bmake_strdup(name);
948 } 948 }
949 949
950 DIR_DEBUG1("checking %s ...\n", file); 950 DIR_DEBUG1("checking %s ...\n", file);
951 951
952 if (cached_stat(file, &stb) == 0) { 952 if (cached_stat(file, &stb) == 0) {
953 nearmisses += 1; 953 nearmisses += 1;
954 return file; 954 return file;
955 } 955 }
956 free(file); 956 free(file);
957 return NULL; 957 return NULL;
958} 958}
959 959
960/*- 960/*-
961 *----------------------------------------------------------------------- 961 *-----------------------------------------------------------------------
962 * DirLookupAbs -- 962 * DirLookupAbs --
963 * Find if the file with the given name exists in the given path. 963 * Find if the file with the given name exists in the given path.
964 * 964 *
965 * Results: 965 * Results:
966 * The path to the file, the empty string or NULL. If the file is 966 * The path to the file, the empty string or NULL. If the file is
967 * the empty string, the search should be terminated. 967 * the empty string, the search should be terminated.
968 * This path is guaranteed to be in a different part of memory 968 * This path is guaranteed to be in a different part of memory
969 * than name and so may be safely free'd. 969 * than name and so may be safely free'd.
970 * 970 *
971 * Side Effects: 971 * Side Effects:
972 * None. 972 * None.
973 *----------------------------------------------------------------------- 973 *-----------------------------------------------------------------------
974 */ 974 */
975static char * 975static char *
976DirLookupAbs(Path *p, const char *name, const char *cp) 976DirLookupAbs(Path *p, const char *name, const char *cp)
977{ 977{
978 char *p1; /* pointer into p->name */ 978 char *p1; /* pointer into p->name */
979 const char *p2; /* pointer into name */ 979 const char *p2; /* pointer into name */
980 980
981 DIR_DEBUG1(" %s ...\n", p->name); 981 DIR_DEBUG1(" %s ...\n", p->name);
982 982
983 /* 983 /*
984 * If the file has a leading path component and that component 984 * If the file has a leading path component and that component
985 * exactly matches the entire name of the current search 985 * exactly matches the entire name of the current search
986 * directory, we can attempt another cache lookup. And if we don't 986 * directory, we can attempt another cache lookup. And if we don't
987 * have a hit, we can safely assume the file does not exist at all. 987 * have a hit, we can safely assume the file does not exist at all.
988 */ 988 */
989 for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) { 989 for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
990 continue; 990 continue;
991 } 991 }
992 if (*p1 != '\0' || p2 != cp - 1) { 992 if (*p1 != '\0' || p2 != cp - 1) {
993 return NULL; 993 return NULL;
994 } 994 }
995 995
996 if (Hash_FindEntry(&p->files, cp) == NULL) { 996 if (Hash_FindEntry(&p->files, cp) == NULL) {
997 DIR_DEBUG0(" must be here but isn't -- returning\n"); 997 DIR_DEBUG0(" must be here but isn't -- returning\n");
998 /* Return empty string: terminates search */ 998 /* Return empty string: terminates search */
999 return bmake_strdup(""); 999 return bmake_strdup("");
1000 } 1000 }
1001 1001
1002 p->hits += 1; 1002 p->hits += 1;
1003 hits += 1; 1003 hits += 1;
1004 DIR_DEBUG1(" returning %s\n", name); 1004 DIR_DEBUG1(" returning %s\n", name);
1005 return bmake_strdup(name); 1005 return bmake_strdup(name);
1006} 1006}
1007 1007
1008/*- 1008/*-
1009 *----------------------------------------------------------------------- 1009 *-----------------------------------------------------------------------
1010 * DirFindDot -- 1010 * DirFindDot --
1011 * Find the file given on "." or curdir 1011 * Find the file given on "." or curdir
1012 * 1012 *
1013 * Results: 1013 * Results:
1014 * The path to the file or NULL. This path is guaranteed to be in a 1014 * The path to the file or NULL. This path is guaranteed to be in a
1015 * different part of memory than name and so may be safely free'd. 1015 * different part of memory than name and so may be safely free'd.
1016 * 1016 *
1017 * Side Effects: 1017 * Side Effects:
1018 * Hit counts change 1018 * Hit counts change
1019 *----------------------------------------------------------------------- 1019 *-----------------------------------------------------------------------
1020 */ 1020 */
1021static char * 1021static char *
1022DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp) 1022DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp)
1023{ 1023{
1024 1024
1025 if (Hash_FindEntry(&dot->files, cp) != NULL) { 1025 if (Hash_FindEntry(&dot->files, cp) != NULL) {
1026 DIR_DEBUG0(" in '.'\n"); 1026 DIR_DEBUG0(" in '.'\n");
1027 hits += 1; 1027 hits += 1;
1028 dot->hits += 1; 1028 dot->hits += 1;
1029 return bmake_strdup(name); 1029 return bmake_strdup(name);
1030 } 1030 }
1031 if (cur && Hash_FindEntry(&cur->files, cp) != NULL) { 1031 if (cur && Hash_FindEntry(&cur->files, cp) != NULL) {
1032 DIR_DEBUG1(" in ${.CURDIR} = %s\n", cur->name); 1032 DIR_DEBUG1(" in ${.CURDIR} = %s\n", cur->name);
1033 hits += 1; 1033 hits += 1;
1034 cur->hits += 1; 1034 cur->hits += 1;
1035 return str_concat3(cur->name, "/", cp); 1035 return str_concat3(cur->name, "/", cp);
1036 } 1036 }
1037 1037
1038 return NULL; 1038 return NULL;
1039} 1039}
1040 1040
1041/*- 1041/*-
1042 *----------------------------------------------------------------------- 1042 *-----------------------------------------------------------------------
1043 * Dir_FindFile -- 1043 * Dir_FindFile --
1044 * Find the file with the given name along the given search path. 1044 * Find the file with the given name along the given search path.
1045 * 1045 *
1046 * Input: 1046 * Input:
1047 * name the file to find 1047 * name the file to find
1048 * path the Lst of directories to search 1048 * path the Lst of directories to search
1049 * 1049 *
1050 * Results: 1050 * Results:
1051 * The path to the file or NULL. This path is guaranteed to be in a 1051 * The path to the file or NULL. This path is guaranteed to be in a
1052 * different part of memory than name and so may be safely free'd. 1052 * different part of memory than name and so may be safely free'd.
1053 * 1053 *
1054 * Side Effects: 1054 * Side Effects:
1055 * If the file is found in a directory which is not on the path 1055 * If the file is found in a directory which is not on the path
1056 * already (either 'name' is absolute or it is a relative path 1056 * already (either 'name' is absolute or it is a relative path
1057 * [ dir1/.../dirn/file ] which exists below one of the directories 1057 * [ dir1/.../dirn/file ] which exists below one of the directories
1058 * already on the search path), its directory is added to the end 1058 * already on the search path), its directory is added to the end
1059 * of the path on the assumption that there will be more files in 1059 * of the path on the assumption that there will be more files in
1060 * that directory later on. Sometimes this is true. Sometimes not. 1060 * that directory later on. Sometimes this is true. Sometimes not.
1061 *----------------------------------------------------------------------- 1061 *-----------------------------------------------------------------------
1062 */ 1062 */
1063char * 1063char *
1064Dir_FindFile(const char *name, Lst path) 1064Dir_FindFile(const char *name, Lst path)
1065{ 1065{
1066 LstNode ln; /* a list element */ 1066 LstNode ln; /* a list element */
1067 char *file; /* the current filename to check */ 1067 char *file; /* the current filename to check */
1068 Path *p; /* current path member */ 1068 Path *p; /* current path member */
1069 const char *cp; /* Terminal name of file */ 1069 const char *cp; /* Terminal name of file */
1070 Boolean hasLastDot = FALSE; /* true we should search dot last */ 1070 Boolean hasLastDot = FALSE; /* true we should search dot last */
1071 Boolean hasSlash; /* true if 'name' contains a / */ 1071 Boolean hasSlash; /* true if 'name' contains a / */
1072 struct stat stb; /* Buffer for stat, if necessary */ 1072 struct stat stb; /* Buffer for stat, if necessary */
1073 const char *trailing_dot = "."; 1073 const char *trailing_dot = ".";
1074 1074
1075 /* 1075 /*
1076 * Find the final component of the name and note whether it has a 1076 * Find the final component of the name and note whether it has a
1077 * slash in it (the name, I mean) 1077 * slash in it (the name, I mean)
1078 */ 1078 */
1079 cp = strrchr(name, '/'); 1079 cp = strrchr(name, '/');
1080 if (cp) { 1080 if (cp) {
1081 hasSlash = TRUE; 1081 hasSlash = TRUE;
1082 cp += 1; 1082 cp += 1;
1083 } else { 1083 } else {
1084 hasSlash = FALSE; 1084 hasSlash = FALSE;
1085 cp = name; 1085 cp = name;
1086 } 1086 }
1087 1087
1088 DIR_DEBUG1("Searching for %s ...", name); 1088 DIR_DEBUG1("Searching for %s ...", name);
1089 1089
1090 if (path == NULL) { 1090 if (path == NULL) {
1091 DIR_DEBUG0("couldn't open path, file not found\n"); 1091 DIR_DEBUG0("couldn't open path, file not found\n");
1092 misses += 1; 1092 misses += 1;
1093 return NULL; 1093 return NULL;
1094 } 1094 }
1095 1095
1096 Lst_Open(path); 1096 Lst_Open(path);
1097 if ((ln = Lst_First(path)) != NULL) { 1097 if ((ln = Lst_First(path)) != NULL) {
1098 p = LstNode_Datum(ln); 1098 p = LstNode_Datum(ln);
1099 if (p == dotLast) { 1099 if (p == dotLast) {
1100 hasLastDot = TRUE; 1100 hasLastDot = TRUE;
1101 DIR_DEBUG0("[dot last]..."); 1101 DIR_DEBUG0("[dot last]...");
1102 } 1102 }
1103 } 1103 }
1104 DIR_DEBUG0("\n"); 1104 DIR_DEBUG0("\n");
1105 1105
1106 /* 1106 /*
1107 * If there's no leading directory components or if the leading 1107 * If there's no leading directory components or if the leading
1108 * directory component is exactly `./', consult the cached contents 1108 * directory component is exactly `./', consult the cached contents
1109 * of each of the directories on the search path. 1109 * of each of the directories on the search path.
1110 */ 1110 */
1111 if (!hasSlash || (cp - name == 2 && *name == '.')) { 1111 if (!hasSlash || (cp - name == 2 && *name == '.')) {
1112 /* 1112 /*
1113 * We look through all the directories on the path seeking one which 1113 * We look through all the directories on the path seeking one which
1114 * contains the final component of the given name. If such a beast 1114 * contains the final component of the given name. If such a beast
1115 * is found, we concatenate the directory name and the final 1115 * is found, we concatenate the directory name and the final
1116 * component and return the resulting string. If we don't find any 1116 * component and return the resulting string. If we don't find any
1117 * such thing, we go on to phase two... 1117 * such thing, we go on to phase two...
1118 * 1118 *
1119 * No matter what, we always look for the file in the current 1119 * No matter what, we always look for the file in the current
1120 * directory before anywhere else (unless we found the magic 1120 * directory before anywhere else (unless we found the magic
1121 * DOTLAST path, in which case we search it last) and we *do not* 1121 * DOTLAST path, in which case we search it last) and we *do not*
1122 * add the ./ to it if it exists. 1122 * add the ./ to it if it exists.
1123 * This is so there are no conflicts between what the user 1123 * This is so there are no conflicts between what the user
1124 * specifies (fish.c) and what pmake finds (./fish.c). 1124 * specifies (fish.c) and what pmake finds (./fish.c).
1125 */ 1125 */
1126 if (!hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) { 1126 if (!hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) {
1127 Lst_Close(path); 1127 Lst_Close(path);
1128 return file; 1128 return file;
1129 } 1129 }
1130 1130
1131 while ((ln = Lst_Next(path)) != NULL) { 1131 while ((ln = Lst_Next(path)) != NULL) {
1132 p = LstNode_Datum(ln); 1132 p = LstNode_Datum(ln);
1133 if (p == dotLast) 1133 if (p == dotLast)
1134 continue; 1134 continue;
1135 if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) { 1135 if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) {
1136 Lst_Close(path); 1136 Lst_Close(path);
1137 return file; 1137 return file;
1138 } 1138 }
1139 } 1139 }
1140 1140
1141 if (hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) { 1141 if (hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) {
1142 Lst_Close(path); 1142 Lst_Close(path);
1143 return file; 1143 return file;
1144 } 1144 }
1145 } 1145 }
1146 Lst_Close(path); 1146 Lst_Close(path);
1147 1147
1148 /* 1148 /*
1149 * We didn't find the file on any directory in the search path. 1149 * We didn't find the file on any directory in the search path.
1150 * If the name doesn't contain a slash, that means it doesn't exist. 1150 * If the name doesn't contain a slash, that means it doesn't exist.
1151 * If it *does* contain a slash, however, there is still hope: it 1151 * If it *does* contain a slash, however, there is still hope: it
1152 * could be in a subdirectory of one of the members of the search 1152 * could be in a subdirectory of one of the members of the search
1153 * path. (eg. /usr/include and sys/types.h. The above search would 1153 * path. (eg. /usr/include and sys/types.h. The above search would
1154 * fail to turn up types.h in /usr/include, but it *is* in 1154 * fail to turn up types.h in /usr/include, but it *is* in
1155 * /usr/include/sys/types.h). 1155 * /usr/include/sys/types.h).
1156 * [ This no longer applies: If we find such a beast, we assume there 1156 * [ This no longer applies: If we find such a beast, we assume there
1157 * will be more (what else can we assume?) and add all but the last 1157 * will be more (what else can we assume?) and add all but the last
1158 * component of the resulting name onto the search path (at the 1158 * component of the resulting name onto the search path (at the
1159 * end).] 1159 * end).]
1160 * This phase is only performed if the file is *not* absolute. 1160 * This phase is only performed if the file is *not* absolute.
1161 */ 1161 */
1162 if (!hasSlash) { 1162 if (!hasSlash) {
1163 DIR_DEBUG0(" failed.\n"); 1163 DIR_DEBUG0(" failed.\n");
1164 misses += 1; 1164 misses += 1;
1165 return NULL; 1165 return NULL;
1166 } 1166 }
1167 1167
1168 if (*cp == '\0') { 1168 if (*cp == '\0') {
1169 /* we were given a trailing "/" */ 1169 /* we were given a trailing "/" */
1170 cp = trailing_dot; 1170 cp = trailing_dot;
1171 } 1171 }
1172 1172
1173 if (name[0] != '/') { 1173 if (name[0] != '/') {
1174 Boolean checkedDot = FALSE; 1174 Boolean checkedDot = FALSE;
1175 1175
1176 DIR_DEBUG0(" Trying subdirectories...\n"); 1176 DIR_DEBUG0(" Trying subdirectories...\n");
1177 1177
1178 if (!hasLastDot) { 1178 if (!hasLastDot) {
1179 if (dot) { 1179 if (dot) {
1180 checkedDot = TRUE; 1180 checkedDot = TRUE;
1181 if ((file = DirLookupSubdir(dot, name)) != NULL) 1181 if ((file = DirLookupSubdir(dot, name)) != NULL)
1182 return file; 1182 return file;
1183 } 1183 }
1184 if (cur && (file = DirLookupSubdir(cur, name)) != NULL) 1184 if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
1185 return file; 1185 return file;
1186 } 1186 }
1187 1187
1188 Lst_Open(path); 1188 Lst_Open(path);
1189 while ((ln = Lst_Next(path)) != NULL) { 1189 while ((ln = Lst_Next(path)) != NULL) {
1190 p = LstNode_Datum(ln); 1190 p = LstNode_Datum(ln);
1191 if (p == dotLast) 1191 if (p == dotLast)
1192 continue; 1192 continue;
1193 if (p == dot) { 1193 if (p == dot) {
1194 if (checkedDot) 1194 if (checkedDot)
1195 continue; 1195 continue;
1196 checkedDot = TRUE; 1196 checkedDot = TRUE;
1197 } 1197 }
1198 if ((file = DirLookupSubdir(p, name)) != NULL) { 1198 if ((file = DirLookupSubdir(p, name)) != NULL) {
1199 Lst_Close(path); 1199 Lst_Close(path);
1200 return file; 1200 return file;
1201 } 1201 }
1202 } 1202 }
1203 Lst_Close(path); 1203 Lst_Close(path);
1204 1204
1205 if (hasLastDot) { 1205 if (hasLastDot) {
1206 if (dot && !checkedDot) { 1206 if (dot && !checkedDot) {
1207 checkedDot = TRUE; 1207 checkedDot = TRUE;
1208 if ((file = DirLookupSubdir(dot, name)) != NULL) 1208 if ((file = DirLookupSubdir(dot, name)) != NULL)
1209 return file; 1209 return file;
1210 } 1210 }
1211 if (cur && (file = DirLookupSubdir(cur, name)) != NULL) 1211 if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
1212 return file; 1212 return file;
1213 } 1213 }
1214 1214
1215 if (checkedDot) { 1215 if (checkedDot) {
1216 /* 1216 /*
1217 * Already checked by the given name, since . was in the path, 1217 * Already checked by the given name, since . was in the path,
1218 * so no point in proceeding... 1218 * so no point in proceeding...
1219 */ 1219 */
1220 DIR_DEBUG0(" Checked . already, returning NULL\n"); 1220 DIR_DEBUG0(" Checked . already, returning NULL\n");
1221 return NULL; 1221 return NULL;
1222 } 1222 }
1223 1223
1224 } else { /* name[0] == '/' */ 1224 } else { /* name[0] == '/' */
1225 1225
1226 /* 1226 /*
1227 * For absolute names, compare directory path prefix against the 1227 * For absolute names, compare directory path prefix against the
1228 * the directory path of each member on the search path for an exact 1228 * the directory path of each member on the search path for an exact
1229 * match. If we have an exact match on any member of the search path, 1229 * match. If we have an exact match on any member of the search path,
1230 * use the cached contents of that member to lookup the final file 1230 * use the cached contents of that member to lookup the final file
1231 * component. If that lookup fails we can safely assume that the 1231 * component. If that lookup fails we can safely assume that the
1232 * file does not exist at all. This is signified by DirLookupAbs() 1232 * file does not exist at all. This is signified by DirLookupAbs()
1233 * returning an empty string. 1233 * returning an empty string.
1234 */ 1234 */
1235 DIR_DEBUG0(" Trying exact path matches...\n"); 1235 DIR_DEBUG0(" Trying exact path matches...\n");
1236 1236
1237 if (!hasLastDot && cur && 1237 if (!hasLastDot && cur &&
1238 ((file = DirLookupAbs(cur, name, cp)) != NULL)) { 1238 ((file = DirLookupAbs(cur, name, cp)) != NULL)) {
1239 if (file[0] == '\0') { 1239 if (file[0] == '\0') {
1240 free(file); 1240 free(file);
1241 return NULL; 1241 return NULL;
1242 } 1242 }
1243 return file; 1243 return file;
1244 } 1244 }
1245 1245
1246 Lst_Open(path); 1246 Lst_Open(path);
1247 while ((ln = Lst_Next(path)) != NULL) { 1247 while ((ln = Lst_Next(path)) != NULL) {
1248 p = LstNode_Datum(ln); 1248 p = LstNode_Datum(ln);
1249 if (p == dotLast) 1249 if (p == dotLast)
1250 continue; 1250 continue;
1251 if ((file = DirLookupAbs(p, name, cp)) != NULL) { 1251 if ((file = DirLookupAbs(p, name, cp)) != NULL) {
1252 Lst_Close(path); 1252 Lst_Close(path);
1253 if (file[0] == '\0') { 1253 if (file[0] == '\0') {
1254 free(file); 1254 free(file);
1255 return NULL; 1255 return NULL;
1256 } 1256 }
1257 return file; 1257 return file;
1258 } 1258 }
1259 } 1259 }
1260 Lst_Close(path); 1260 Lst_Close(path);
1261 1261
1262 if (hasLastDot && cur && 1262 if (hasLastDot && cur &&
1263 ((file = DirLookupAbs(cur, name, cp)) != NULL)) { 1263 ((file = DirLookupAbs(cur, name, cp)) != NULL)) {
1264 if (file[0] == '\0') { 1264 if (file[0] == '\0') {
1265 free(file); 1265 free(file);
1266 return NULL; 1266 return NULL;
1267 } 1267 }
1268 return file; 1268 return file;
1269 } 1269 }
1270 } 1270 }
1271 1271
1272 /* 1272 /*
1273 * Didn't find it that way, either. Sigh. Phase 3. Add its directory 1273 * Didn't find it that way, either. Sigh. Phase 3. Add its directory
1274 * onto the search path in any case, just in case, then look for the 1274 * onto the search path in any case, just in case, then look for the
1275 * thing in the hash table. If we find it, grand. We return a new 1275 * thing in the hash table. If we find it, grand. We return a new
1276 * copy of the name. Otherwise we sadly return a NULL pointer. Sigh. 1276 * copy of the name. Otherwise we sadly return a NULL pointer. Sigh.
1277 * Note that if the directory holding the file doesn't exist, this will 1277 * Note that if the directory holding the file doesn't exist, this will
1278 * do an extra search of the final directory on the path. Unless something 1278 * do an extra search of the final directory on the path. Unless something
1279 * weird happens, this search won't succeed and life will be groovy. 1279 * weird happens, this search won't succeed and life will be groovy.
1280 * 1280 *
1281 * Sigh. We cannot add the directory onto the search path because 1281 * Sigh. We cannot add the directory onto the search path because
1282 * of this amusing case: 1282 * of this amusing case:
1283 * $(INSTALLDIR)/$(FILE): $(FILE) 1283 * $(INSTALLDIR)/$(FILE): $(FILE)
1284 * 1284 *
1285 * $(FILE) exists in $(INSTALLDIR) but not in the current one. 1285 * $(FILE) exists in $(INSTALLDIR) but not in the current one.
1286 * When searching for $(FILE), we will find it in $(INSTALLDIR) 1286 * When searching for $(FILE), we will find it in $(INSTALLDIR)
1287 * b/c we added it here. This is not good... 1287 * b/c we added it here. This is not good...
1288 */ 1288 */
1289#ifdef notdef 1289#ifdef notdef
1290 if (cp == traling_dot) { 1290 if (cp == traling_dot) {
1291 cp = strrchr(name, '/'); 1291 cp = strrchr(name, '/');
1292 cp += 1; 1292 cp += 1;
1293 } 1293 }
1294 cp[-1] = '\0'; 1294 cp[-1] = '\0';
1295 (void)Dir_AddDir(path, name); 1295 (void)Dir_AddDir(path, name);
1296 cp[-1] = '/'; 1296 cp[-1] = '/';
1297 1297
1298 bigmisses += 1; 1298 bigmisses += 1;
1299 ln = Lst_Last(path); 1299 ln = Lst_Last(path);
1300 if (ln == NULL) { 1300 if (ln == NULL) {
1301 return NULL; 1301 return NULL;
1302 } else { 1302 } else {
1303 p = LstNode_Datum(ln); 1303 p = LstNode_Datum(ln);
1304 } 1304 }
1305 1305
1306 if (Hash_FindEntry(&p->files, cp) != NULL) { 1306 if (Hash_FindEntry(&p->files, cp) != NULL) {
1307 return bmake_strdup(name); 1307 return bmake_strdup(name);
1308 } else { 1308 } else {
1309 return NULL; 1309 return NULL;
1310 } 1310 }
1311#else /* !notdef */ 1311#else /* !notdef */
1312 DIR_DEBUG1(" Looking for \"%s\" ...\n", name); 1312 DIR_DEBUG1(" Looking for \"%s\" ...\n", name);
1313 1313
1314 bigmisses += 1; 1314 bigmisses += 1;
1315 if (cached_stat(name, &stb) == 0) { 1315 if (cached_stat(name, &stb) == 0) {
1316 return bmake_strdup(name); 1316 return bmake_strdup(name);
1317 } 1317 }
1318 1318
1319 DIR_DEBUG0(" failed. Returning NULL\n"); 1319 DIR_DEBUG0(" failed. Returning NULL\n");
1320 return NULL; 1320 return NULL;
1321#endif /* notdef */ 1321#endif /* notdef */
1322} 1322}
1323 1323
1324 1324
1325/*- 1325/*-

cvs diff -r1.28 -r1.29 src/usr.bin/make/hash.c (switch to unified diff)

--- src/usr.bin/make/hash.c 2020/08/28 20:16:19 1.28
+++ src/usr.bin/make/hash.c 2020/09/01 21:11:31 1.29
@@ -1,404 +1,404 @@ @@ -1,404 +1,404 @@
1/* $NetBSD: hash.c,v 1.28 2020/08/28 20:16:19 rillig Exp $ */ 1/* $NetBSD: hash.c,v 1.29 2020/09/01 21:11:31 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: hash.c,v 1.28 2020/08/28 20:16:19 rillig Exp $"; 73static char rcsid[] = "$NetBSD: hash.c,v 1.29 2020/09/01 21:11:31 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[] = "@(#)hash.c 8.1 (Berkeley) 6/6/93"; 78static char sccsid[] = "@(#)hash.c 8.1 (Berkeley) 6/6/93";
79#else 79#else
80__RCSID("$NetBSD: hash.c,v 1.28 2020/08/28 20:16:19 rillig Exp $"); 80__RCSID("$NetBSD: hash.c,v 1.29 2020/09/01 21:11:31 rillig Exp $");
81#endif 81#endif
82#endif /* not lint */ 82#endif /* not lint */
83#endif 83#endif
84 84
85/* hash.c -- 85/* hash.c --
86 * 86 *
87 * This module contains routines to manipulate a hash table. 87 * This module contains routines to manipulate a hash table.
88 * See hash.h for a definition of the structure of the hash 88 * See hash.h for a definition of the structure of the hash
89 * table. Hash tables grow automatically as the amount of 89 * table. Hash tables grow automatically as the amount of
90 * information increases. 90 * information increases.
91 */ 91 */
92#include "make.h" 92#include "make.h"
93 93
94/* 94/*
95 * Forward references to local procedures that are used before they're 95 * Forward references to local procedures that are used before they're
96 * defined: 96 * defined:
97 */ 97 */
98 98
99static void RebuildTable(Hash_Table *); 99static void RebuildTable(Hash_Table *);
100 100
101/* 101/*
102 * The following defines the ratio of # entries to # buckets 102 * The following defines the ratio of # entries to # buckets
103 * at which we rebuild the table to make it larger. 103 * at which we rebuild the table to make it larger.
104 */ 104 */
105 105
106#define rebuildLimit 3 106#define rebuildLimit 3
107 107
108/* The hash function(s) */ 108/* The hash function(s) */
109 109
110#ifndef HASH 110#ifndef HASH
111/* The default: this one matches Gosling's emacs */ 111/* The default: this one matches Gosling's emacs */
112#define HASH(h, key, p) do { \ 112#define HASH(h, key, p) do { \
113 for (h = 0, p = key; *p;) \ 113 for (h = 0, p = key; *p;) \
114 h = (h << 5) - h + *p++; \ 114 h = (h << 5) - h + *p++; \
115 } while (0) 115 } while (0)
116 116
117#endif 117#endif
118 118
119/* Sets up the hash table. 119/* Sets up the hash table.
120 * 120 *
121 * Input: 121 * Input:
122 * t Structure to to hold the table. 122 * t Structure to to hold the table.
123 * numBuckets How many buckets to create for starters. This 123 * numBuckets How many buckets to create for starters. This
124 * number is rounded up to a power of two. If 124 * number is rounded up to a power of two. If
125 * <= 0, a reasonable default is chosen. The 125 * <= 0, a reasonable default is chosen. The
126 * table will grow in size later as needed. 126 * table will grow in size later as needed.
127 */ 127 */
128void 128void
129Hash_InitTable(Hash_Table *t, int numBuckets) 129Hash_InitTable(Hash_Table *t, int numBuckets)
130{ 130{
131 int i; 131 int i;
132 struct Hash_Entry **hp; 132 struct Hash_Entry **hp;
133 133
134 /* 134 /*
135 * Round up the size to a power of two. 135 * Round up the size to a power of two.
136 */ 136 */
137 if (numBuckets <= 0) 137 if (numBuckets <= 0)
138 i = 16; 138 i = 16;
139 else { 139 else {
140 for (i = 2; i < numBuckets; i <<= 1) 140 for (i = 2; i < numBuckets; i <<= 1)
141 continue; 141 continue;
142 } 142 }
143 t->numEntries = 0; 143 t->numEntries = 0;
144 t->maxchain = 0; 144 t->maxchain = 0;
145 t->size = i; 145 t->bucketsSize = i;
146 t->mask = i - 1; 146 t->bucketsMask = i - 1;
147 t->bucketPtr = hp = bmake_malloc(sizeof(*hp) * i); 147 t->buckets = hp = bmake_malloc(sizeof(*hp) * i);
148 while (--i >= 0) 148 while (--i >= 0)
149 *hp++ = NULL; 149 *hp++ = NULL;
150} 150}
151 151
152/* Removes everything from the hash table and frees up the memory space it 152/* Removes everything from the hash table and frees up the memory space it
153 * occupied (except for the space in the Hash_Table structure). */ 153 * occupied (except for the space in the Hash_Table structure). */
154void 154void
155Hash_DeleteTable(Hash_Table *t) 155Hash_DeleteTable(Hash_Table *t)
156{ 156{
157 struct Hash_Entry **hp, *h, *nexth = NULL; 157 struct Hash_Entry **hp, *h, *nexth = NULL;
158 int i; 158 int i;
159 159
160 for (hp = t->bucketPtr, i = t->size; --i >= 0;) { 160 for (hp = t->buckets, i = t->bucketsSize; --i >= 0;) {
161 for (h = *hp++; h != NULL; h = nexth) { 161 for (h = *hp++; h != NULL; h = nexth) {
162 nexth = h->next; 162 nexth = h->next;
163 free(h); 163 free(h);
164 } 164 }
165 } 165 }
166 free(t->bucketPtr); 166 free(t->buckets);
167 167
168 /* 168 /*
169 * Set up the hash table to cause memory faults on any future access 169 * Set up the hash table to cause memory faults on any future access
170 * attempts until re-initialization. 170 * attempts until re-initialization.
171 */ 171 */
172 t->bucketPtr = NULL; 172 t->buckets = NULL;
173} 173}
174 174
175/* Searches the hash table for an entry corresponding to the key. 175/* Searches the hash table for an entry corresponding to the key.
176 * 176 *
177 * Input: 177 * Input:
178 * t Hash table to search. 178 * t Hash table to search.
179 * key A hash key. 179 * key A hash key.
180 * 180 *
181 * Results: 181 * Results:
182 * Returns a pointer to the entry for key, or NULL if the table contains 182 * Returns a pointer to the entry for key, or NULL if the table contains
183 * no entry for the key. 183 * no entry for the key.
184 */ 184 */
185Hash_Entry * 185Hash_Entry *
186Hash_FindEntry(Hash_Table *t, const char *key) 186Hash_FindEntry(Hash_Table *t, const char *key)
187{ 187{
188 Hash_Entry *e; 188 Hash_Entry *e;
189 unsigned h; 189 unsigned h;
190 const char *p; 190 const char *p;
191 int chainlen; 191 int chainlen;
192 192
193 if (t == NULL || t->bucketPtr == NULL) { 193 if (t == NULL || t->buckets == NULL) {
194 return NULL; 194 return NULL;
195 } 195 }
196 HASH(h, key, p); 196 HASH(h, key, p);
197 p = key; 197 p = key;
198 chainlen = 0; 198 chainlen = 0;
199#ifdef DEBUG_HASH_LOOKUP 199#ifdef DEBUG_HASH_LOOKUP
200 if (DEBUG(HASH)) 200 if (DEBUG(HASH))
201 fprintf(debug_file, "%s: %p h=%x key=%s\n", __func__, 201 fprintf(debug_file, "%s: %p h=%x key=%s\n", __func__,
202 t, h, key); 202 t, h, key);
203#endif 203#endif
204 for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) { 204 for (e = t->buckets[h & t->bucketsMask]; e != NULL; e = e->next) {
205 chainlen++; 205 chainlen++;
206 if (e->namehash == h && strcmp(e->name, p) == 0) 206 if (e->namehash == h && strcmp(e->name, p) == 0)
207 break; 207 break;
208 } 208 }
209 if (chainlen > t->maxchain) 209 if (chainlen > t->maxchain)
210 t->maxchain = chainlen; 210 t->maxchain = chainlen;
211 return e; 211 return e;
212} 212}
213 213
214/* Searches the hash table for an entry corresponding to the key. 214/* Searches the hash table for an entry corresponding to the key.
215 * If no entry is found, then one is created. 215 * If no entry is found, then one is created.
216 * 216 *
217 * Input: 217 * Input:
218 * t Hash table to search. 218 * t Hash table to search.
219 * key A hash key. 219 * key A hash key.
220 * newPtr Filled with TRUE if new entry created, 220 * newPtr Filled with TRUE if new entry created,
221 * FALSE otherwise. 221 * FALSE otherwise.
222 */ 222 */
223Hash_Entry * 223Hash_Entry *
224Hash_CreateEntry(Hash_Table *t, const char *key, Boolean *newPtr) 224Hash_CreateEntry(Hash_Table *t, const char *key, Boolean *newPtr)
225{ 225{
226 Hash_Entry *e; 226 Hash_Entry *e;
227 unsigned h; 227 unsigned h;
228 const char *p; 228 const char *p;
229 int keylen; 229 int keylen;
230 int chainlen; 230 int chainlen;
231 struct Hash_Entry **hp; 231 struct Hash_Entry **hp;
232 232
233 /* 233 /*
234 * Hash the key. As a side effect, save the length (strlen) of the 234 * Hash the key. As a side effect, save the length (strlen) of the
235 * key in case we need to create the entry. 235 * key in case we need to create the entry.
236 */ 236 */
237 HASH(h, key, p); 237 HASH(h, key, p);
238 keylen = p - key; 238 keylen = p - key;
239 p = key; 239 p = key;
240 chainlen = 0; 240 chainlen = 0;
241#ifdef DEBUG_HASH_LOOKUP 241#ifdef DEBUG_HASH_LOOKUP
242 if (DEBUG(HASH)) 242 if (DEBUG(HASH))
243 fprintf(debug_file, "%s: %p h=%x key=%s\n", __func__, 243 fprintf(debug_file, "%s: %p h=%x key=%s\n", __func__,
244 t, h, key); 244 t, h, key);
245#endif 245#endif
246 for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) { 246 for (e = t->buckets[h & t->bucketsMask]; e != NULL; e = e->next) {
247 chainlen++; 247 chainlen++;
248 if (e->namehash == h && strcmp(e->name, p) == 0) { 248 if (e->namehash == h && strcmp(e->name, p) == 0) {
249 if (newPtr != NULL) 249 if (newPtr != NULL)
250 *newPtr = FALSE; 250 *newPtr = FALSE;
251 break; 251 break;
252 } 252 }
253 } 253 }
254 if (chainlen > t->maxchain) 254 if (chainlen > t->maxchain)
255 t->maxchain = chainlen; 255 t->maxchain = chainlen;
256 if (e) 256 if (e)
257 return e; 257 return e;
258 258
259 /* 259 /*
260 * The desired entry isn't there. Before allocating a new entry, 260 * The desired entry isn't there. Before allocating a new entry,
261 * expand the table if necessary (and this changes the resulting 261 * expand the table if necessary (and this changes the resulting
262 * bucket chain). 262 * bucket chain).
263 */ 263 */
264 if (t->numEntries >= rebuildLimit * t->size) 264 if (t->numEntries >= rebuildLimit * t->bucketsSize)
265 RebuildTable(t); 265 RebuildTable(t);
266 e = bmake_malloc(sizeof(*e) + keylen); 266 e = bmake_malloc(sizeof(*e) + keylen);
267 hp = &t->bucketPtr[h & t->mask]; 267 hp = &t->buckets[h & t->bucketsMask];
268 e->next = *hp; 268 e->next = *hp;
269 *hp = e; 269 *hp = e;
270 Hash_SetValue(e, NULL); 270 Hash_SetValue(e, NULL);
271 e->namehash = h; 271 e->namehash = h;
272 (void)strcpy(e->name, p); 272 (void)strcpy(e->name, p);
273 t->numEntries++; 273 t->numEntries++;
274 274
275 if (newPtr != NULL) 275 if (newPtr != NULL)
276 *newPtr = TRUE; 276 *newPtr = TRUE;
277 return e; 277 return e;
278} 278}
279 279
280/* Delete the given hash table entry and free memory associated with it. */ 280/* Delete the given hash table entry and free memory associated with it. */
281void 281void
282Hash_DeleteEntry(Hash_Table *t, Hash_Entry *e) 282Hash_DeleteEntry(Hash_Table *t, Hash_Entry *e)
283{ 283{
284 Hash_Entry **hp, *p; 284 Hash_Entry **hp, *p;
285 285
286 if (e == NULL) 286 if (e == NULL)
287 return; 287 return;
288 for (hp = &t->bucketPtr[e->namehash & t->mask]; 288 for (hp = &t->buckets[e->namehash & t->bucketsMask];
289 (p = *hp) != NULL; hp = &p->next) { 289 (p = *hp) != NULL; hp = &p->next) {
290 if (p == e) { 290 if (p == e) {
291 *hp = p->next; 291 *hp = p->next;
292 free(p); 292 free(p);
293 t->numEntries--; 293 t->numEntries--;
294 return; 294 return;
295 } 295 }
296 } 296 }
297 (void)write(2, "bad call to Hash_DeleteEntry\n", 29); 297 (void)write(2, "bad call to Hash_DeleteEntry\n", 29);
298 abort(); 298 abort();
299} 299}
300 300
301/* Sets things up for enumerating all entries in the hash table. 301/* Sets things up for enumerating all entries in the hash table.
302 * 302 *
303 * Input: 303 * Input:
304 * t Table to be searched. 304 * t Table to be searched.
305 * searchPtr Area in which to keep state about search. 305 * searchPtr Area in which to keep state about search.
306 * 306 *
307 * Results: 307 * Results:
308 * The return value is the address of the first entry in 308 * The return value is the address of the first entry in
309 * the hash table, or NULL if the table is empty. 309 * the hash table, or NULL if the table is empty.
310 */ 310 */
311Hash_Entry * 311Hash_Entry *
312Hash_EnumFirst(Hash_Table *t, Hash_Search *searchPtr) 312Hash_EnumFirst(Hash_Table *t, Hash_Search *searchPtr)
313{ 313{
314 searchPtr->tablePtr = t; 314 searchPtr->table = t;
315 searchPtr->nextIndex = 0; 315 searchPtr->nextBucket = 0;
316 searchPtr->hashEntryPtr = NULL; 316 searchPtr->entry = NULL;
317 return Hash_EnumNext(searchPtr); 317 return Hash_EnumNext(searchPtr);
318} 318}
319 319
320/* Returns the next entry in the hash table, or NULL if the end of the table 320/* Returns the next entry in the hash table, or NULL if the end of the table
321 * is reached. 321 * is reached.
322 * 322 *
323 * Input: 323 * Input:
324 * searchPtr Area used to keep state about search. 324 * searchPtr Area used to keep state about search.
325 */ 325 */
326Hash_Entry * 326Hash_Entry *
327Hash_EnumNext(Hash_Search *searchPtr) 327Hash_EnumNext(Hash_Search *searchPtr)
328{ 328{
329 Hash_Entry *e; 329 Hash_Entry *e;
330 Hash_Table *t = searchPtr->tablePtr; 330 Hash_Table *t = searchPtr->table;
331 331
332 /* 332 /*
333 * The hashEntryPtr field points to the most recently returned 333 * The entry field points to the most recently returned
334 * entry, or is nil if we are starting up. If not nil, we have 334 * entry, or is NULL if we are starting up. If not NULL, we have
335 * to start at the next one in the chain. 335 * to start at the next one in the chain.
336 */ 336 */
337 e = searchPtr->hashEntryPtr; 337 e = searchPtr->entry;
338 if (e != NULL) 338 if (e != NULL)
339 e = e->next; 339 e = e->next;
340 /* 340 /*
341 * If the chain ran out, or if we are starting up, we need to 341 * If the chain ran out, or if we are starting up, we need to
342 * find the next nonempty chain. 342 * find the next nonempty chain.
343 */ 343 */
344 while (e == NULL) { 344 while (e == NULL) {
345 if (searchPtr->nextIndex >= t->size) 345 if (searchPtr->nextBucket >= t->bucketsSize)
346 return NULL; 346 return NULL;
347 e = t->bucketPtr[searchPtr->nextIndex++]; 347 e = t->buckets[searchPtr->nextBucket++];
348 } 348 }
349 searchPtr->hashEntryPtr = e; 349 searchPtr->entry = e;
350 return e; 350 return e;
351} 351}
352 352
353/* Makes a new hash table that is larger than the old one. The entire hash 353/* Makes a new hash table that is larger than the old one. The entire hash
354 * table is moved, so any bucket numbers from the old table become invalid. */ 354 * table is moved, so any bucket numbers from the old table become invalid. */
355static void 355static void
356RebuildTable(Hash_Table *t) 356RebuildTable(Hash_Table *t)
357{ 357{
358 Hash_Entry *e, *next = NULL, **hp, **xp; 358 Hash_Entry *e, *next = NULL, **hp, **xp;
359 int i, mask; 359 int i, mask;
360 Hash_Entry **oldhp; 360 Hash_Entry **oldhp;
361 int oldsize; 361 int oldsize;
362 362
363 oldhp = t->bucketPtr; 363 oldhp = t->buckets;
364 oldsize = i = t->size; 364 oldsize = i = t->bucketsSize;
365 i <<= 1; 365 i <<= 1;
366 t->size = i; 366 t->bucketsSize = i;
367 t->mask = mask = i - 1; 367 t->bucketsMask = mask = i - 1;
368 t->bucketPtr = hp = bmake_malloc(sizeof(*hp) * i); 368 t->buckets = hp = bmake_malloc(sizeof(*hp) * i);
369 while (--i >= 0) 369 while (--i >= 0)
370 *hp++ = NULL; 370 *hp++ = NULL;
371 for (hp = oldhp, i = oldsize; --i >= 0;) { 371 for (hp = oldhp, i = oldsize; --i >= 0;) {
372 for (e = *hp++; e != NULL; e = next) { 372 for (e = *hp++; e != NULL; e = next) {
373 next = e->next; 373 next = e->next;
374 xp = &t->bucketPtr[e->namehash & mask]; 374 xp = &t->buckets[e->namehash & mask];
375 e->next = *xp; 375 e->next = *xp;
376 *xp = e; 376 *xp = e;
377 } 377 }
378 } 378 }
379 free(oldhp); 379 free(oldhp);
380 if (DEBUG(HASH)) 380 if (DEBUG(HASH))
381 fprintf(debug_file, "%s: %p size=%d entries=%d maxchain=%d\n", 381 fprintf(debug_file, "%s: %p size=%d entries=%d maxchain=%d\n",
382 __func__, t, t->size, t->numEntries, t->maxchain); 382 __func__, t, t->bucketsSize, t->numEntries, t->maxchain);
383 t->maxchain = 0; 383 t->maxchain = 0;
384} 384}
385 385
386void 386void
387Hash_ForEach(Hash_Table *t, void (*action)(void *, void *), void *data) 387Hash_ForEach(Hash_Table *t, void (*action)(void *, void *), void *data)
388{ 388{
389 Hash_Search search; 389 Hash_Search search;
390 Hash_Entry *e; 390 Hash_Entry *e;
391 391
392 for (e = Hash_EnumFirst(t, &search); 392 for (e = Hash_EnumFirst(t, &search);
393 e != NULL; 393 e != NULL;
394 e = Hash_EnumNext(&search)) 394 e = Hash_EnumNext(&search))
395 action(Hash_GetValue(e), data); 395 action(Hash_GetValue(e), data);
396} 396}
397 397
398void 398void
399Hash_DebugStats(Hash_Table *t, const char *name) 399Hash_DebugStats(Hash_Table *t, const char *name)
400{ 400{
401 if (DEBUG(HASH)) 401 if (DEBUG(HASH))
402 fprintf(debug_file, "Hash_Table %s: size=%d numEntries=%d maxchain=%d\n", 402 fprintf(debug_file, "Hash_Table %s: size=%d numEntries=%d maxchain=%d\n",
403 name, t->size, t->numEntries, t->maxchain); 403 name, t->bucketsSize, t->numEntries, t->maxchain);
404} 404}

cvs diff -r1.20 -r1.21 src/usr.bin/make/hash.h (switch to unified diff)

--- src/usr.bin/make/hash.h 2020/09/01 21:00:15 1.20
+++ src/usr.bin/make/hash.h 2020/09/01 21:11:31 1.21
@@ -1,139 +1,131 @@ @@ -1,139 +1,131 @@
1/* $NetBSD: hash.h,v 1.20 2020/09/01 21:00:15 rillig Exp $ */ 1/* $NetBSD: hash.h,v 1.21 2020/09/01 21:11:31 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 * 5 *
6 * This code is derived from software contributed to Berkeley by 6 * This code is derived from software contributed to Berkeley by
7 * Adam de Boor. 7 * Adam de Boor.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the 15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution. 16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors 17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software 18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission. 19 * without specific prior written permission.
20 * 20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE. 31 * SUCH DAMAGE.
32 * 32 *
33 * from: @(#)hash.h 8.1 (Berkeley) 6/6/93 33 * from: @(#)hash.h 8.1 (Berkeley) 6/6/93
34 */ 34 */
35 35
36/* 36/*
37 * Copyright (c) 1988, 1989 by Adam de Boor 37 * Copyright (c) 1988, 1989 by Adam de Boor
38 * Copyright (c) 1989 by Berkeley Softworks 38 * Copyright (c) 1989 by Berkeley Softworks
39 * All rights reserved. 39 * All rights reserved.
40 * 40 *
41 * This code is derived from software contributed to Berkeley by 41 * This code is derived from software contributed to Berkeley by
42 * Adam de Boor. 42 * Adam de Boor.
43 * 43 *
44 * Redistribution and use in source and binary forms, with or without 44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions 45 * modification, are permitted provided that the following conditions
46 * are met: 46 * are met:
47 * 1. Redistributions of source code must retain the above copyright 47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer. 48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright 49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the 50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution. 51 * documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software 52 * 3. All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement: 53 * must display the following acknowledgement:
54 * This product includes software developed by the University of 54 * This product includes software developed by the University of
55 * California, Berkeley and its contributors. 55 * California, Berkeley and its contributors.
56 * 4. Neither the name of the University nor the names of its contributors 56 * 4. Neither the name of the University nor the names of its contributors
57 * may be used to endorse or promote products derived from this software 57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission. 58 * without specific prior written permission.
59 * 59 *
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE. 70 * SUCH DAMAGE.
71 * 71 *
72 * from: @(#)hash.h 8.1 (Berkeley) 6/6/93 72 * from: @(#)hash.h 8.1 (Berkeley) 6/6/93
73 */ 73 */
74 74
75/* hash.h -- 75/* Hash tables with strings as keys and arbitrary pointers as values. */
76 * 
77 * This file contains definitions used by the hash module, 
78 * which maintains hash tables. 
79 */ 
80 76
81#ifndef MAKE_HASH_H 77#ifndef MAKE_HASH_H
82#define MAKE_HASH_H 78#define MAKE_HASH_H
83 79
84/* 80/* A single key-value entry in the hash table. */
85 * The following defines one entry in the hash table. 
86 */ 
87 
88typedef struct Hash_Entry { 81typedef struct Hash_Entry {
89 struct Hash_Entry *next; /* Used to link together all the 82 struct Hash_Entry *next; /* Used to link together all the entries
90 * entries associated with the same 83 * associated with the same bucket. */
91 * bucket. */ 84 void *value;
92 void *clientPtr; /* Arbitrary pointer */ 85 unsigned namehash; /* hash value of key */
93 unsigned namehash; /* hash value of key */ 86 char name[1]; /* key string, variable length */
94 char name[1]; /* key string, variable length */ 
95} Hash_Entry; 87} Hash_Entry;
96 88
 89/* The hash table containing the entries. */
97typedef struct Hash_Table { 90typedef struct Hash_Table {
98 struct Hash_Entry **bucketPtr;/* Pointers to Hash_Entry, one 91 Hash_Entry **buckets; /* Pointers to Hash_Entry, one
99 * for each bucket in the table. */ 92 * for each bucket in the table. */
100 int size; /* Actual size of array. */ 93 int bucketsSize;
101 int numEntries; /* Number of entries in the table. */ 94 int numEntries; /* Number of entries in the table. */
102 int mask; /* Used to select bits for hashing. */ 95 int bucketsMask; /* Used to select the bucket for a hash. */
103 int maxchain; /* max length of chain detected */ 96 int maxchain; /* max length of chain detected */
104} Hash_Table; 97} Hash_Table;
105 98
106/* 99/*
107 * The following structure is used by the searching routines 100 * The following structure is used by the searching routines
108 * to record where we are in the search. 101 * to record where we are in the search.
109 */ 102 */
110 
111typedef struct Hash_Search { 103typedef struct Hash_Search {
112 Hash_Table *tablePtr; /* Table being searched. */ 104 Hash_Table *table; /* Table being searched. */
113 int nextIndex; /* Next bucket to check (after current). */ 105 int nextBucket; /* Next bucket to check (after current). */
114 Hash_Entry *hashEntryPtr; /* Next entry to check in current bucket. */ 106 Hash_Entry *entry; /* Next entry to check in current bucket. */
115} Hash_Search; 107} Hash_Search;
116 108
117static inline void * MAKE_ATTR_UNUSED 109static inline void * MAKE_ATTR_UNUSED
118Hash_GetValue(Hash_Entry *h) 110Hash_GetValue(Hash_Entry *h)
119{ 111{
120 return h->clientPtr; 112 return h->value;
121} 113}
122 114
123static inline void MAKE_ATTR_UNUSED 115static inline void MAKE_ATTR_UNUSED
124Hash_SetValue(Hash_Entry *h, void *datum) 116Hash_SetValue(Hash_Entry *h, void *datum)
125{ 117{
126 h->clientPtr = datum; 118 h->value = datum;
127} 119}
128 120
129void Hash_InitTable(Hash_Table *, int); 121void Hash_InitTable(Hash_Table *, int);
130void Hash_DeleteTable(Hash_Table *); 122void Hash_DeleteTable(Hash_Table *);
131Hash_Entry *Hash_FindEntry(Hash_Table *, const char *); 123Hash_Entry *Hash_FindEntry(Hash_Table *, const char *);
132Hash_Entry *Hash_CreateEntry(Hash_Table *, const char *, Boolean *); 124Hash_Entry *Hash_CreateEntry(Hash_Table *, const char *, Boolean *);
133void Hash_DeleteEntry(Hash_Table *, Hash_Entry *); 125void Hash_DeleteEntry(Hash_Table *, Hash_Entry *);
134Hash_Entry *Hash_EnumFirst(Hash_Table *, Hash_Search *); 126Hash_Entry *Hash_EnumFirst(Hash_Table *, Hash_Search *);
135Hash_Entry *Hash_EnumNext(Hash_Search *); 127Hash_Entry *Hash_EnumNext(Hash_Search *);
136void Hash_ForEach(Hash_Table *, void (*)(void *, void *), void *); 128void Hash_ForEach(Hash_Table *, void (*)(void *, void *), void *);
137void Hash_DebugStats(Hash_Table *, const char *); 129void Hash_DebugStats(Hash_Table *, const char *);
138 130
139#endif /* MAKE_HASH_H */ 131#endif /* MAKE_HASH_H */