Deleted Added
full compact
dir.c (138232) dir.c (138264)
1/*
2 * Copyright (c) 1988, 1989, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1988, 1989 by Adam de Boor
5 * Copyright (c) 1989 by Berkeley Softworks
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Adam de Boor.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)dir.c 8.2 (Berkeley) 1/2/94
40 */
41
42#include <sys/cdefs.h>
1/*
2 * Copyright (c) 1988, 1989, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1988, 1989 by Adam de Boor
5 * Copyright (c) 1989 by Berkeley Softworks
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Adam de Boor.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)dir.c 8.2 (Berkeley) 1/2/94
40 */
41
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: head/usr.bin/make/dir.c 138232 2004-11-30 17:46:29Z harti $");
43__FBSDID("$FreeBSD: head/usr.bin/make/dir.c 138264 2004-12-01 10:29:20Z harti $");
44
45/*-
46 * dir.c --
47 * Directory searching using wildcards and/or normal names...
48 * Used both for source wildcarding in the Makefile and for finding
49 * implicit sources.
50 *
51 * The interface for this module is:
52 * Dir_Init Initialize the module.
53 *
54 * Dir_End Cleanup the module.
55 *
56 * Dir_HasWildcards Returns TRUE if the name given it needs to
57 * be wildcard-expanded.
58 *
59 * Dir_Expand Given a pattern and a path, return a Lst of names
60 * which match the pattern on the search path.
61 *
62 * Dir_FindFile Searches for a file on a given search path.
63 * If it exists, the entire path is returned.
64 * Otherwise NULL is returned.
65 *
66 * Dir_MTime Return the modification time of a node. The file
67 * is searched for along the default search path.
68 * The path and mtime fields of the node are filled
69 * in.
70 *
71 * Dir_AddDir Add a directory to a search path.
72 *
73 * Dir_MakeFlags Given a search path and a command flag, create
74 * a string with each of the directories in the path
75 * preceded by the command flag and all of them
76 * separated by a space.
77 *
78 * Dir_Destroy Destroy an element of a search path. Frees up all
79 * things that can be freed for the element as long
80 * as the element is no longer referenced by any other
81 * search path.
82 * Dir_ClearPath Resets a search path to the empty list.
83 *
84 * For debugging:
85 * Dir_PrintDirectories Print stats about the directory cache.
86 */
87
88#include <stdio.h>
89#include <sys/types.h>
90#include <sys/stat.h>
91#include <dirent.h>
92#include <err.h>
93#include "make.h"
94#include "hash.h"
95#include "dir.h"
96
97/*
98 * A search path consists of a Lst of Path structures. A Path structure
99 * has in it the name of the directory and a hash table of all the files
100 * in the directory. This is used to cut down on the number of system
101 * calls necessary to find implicit dependents and their like. Since
102 * these searches are made before any actions are taken, we need not
103 * worry about the directory changing due to creation commands. If this
104 * hampers the style of some makefiles, they must be changed.
105 *
106 * A list of all previously-read directories is kept in the
107 * openDirectories Lst. This list is checked first before a directory
108 * is opened.
109 *
110 * The need for the caching of whole directories is brought about by
111 * the multi-level transformation code in suff.c, which tends to search
112 * for far more files than regular make does. In the initial
113 * implementation, the amount of time spent performing "stat" calls was
114 * truly astronomical. The problem with hashing at the start is,
115 * of course, that pmake doesn't then detect changes to these directories
116 * during the course of the make. Three possibilities suggest themselves:
117 *
118 * 1) just use stat to test for a file's existence. As mentioned
119 * above, this is very inefficient due to the number of checks
120 * engendered by the multi-level transformation code.
121 * 2) use readdir() and company to search the directories, keeping
122 * them open between checks. I have tried this and while it
123 * didn't slow down the process too much, it could severely
124 * affect the amount of parallelism available as each directory
125 * open would take another file descriptor out of play for
126 * handling I/O for another job. Given that it is only recently
127 * that UNIX OS's have taken to allowing more than 20 or 32
128 * file descriptors for a process, this doesn't seem acceptable
129 * to me.
130 * 3) record the mtime of the directory in the Path structure and
131 * verify the directory hasn't changed since the contents were
132 * hashed. This will catch the creation or deletion of files,
133 * but not the updating of files. However, since it is the
134 * creation and deletion that is the problem, this could be
135 * a good thing to do. Unfortunately, if the directory (say ".")
136 * were fairly large and changed fairly frequently, the constant
137 * rehashing could seriously degrade performance. It might be
138 * good in such cases to keep track of the number of rehashes
139 * and if the number goes over a (small) limit, resort to using
140 * stat in its place.
141 *
142 * An additional thing to consider is that pmake is used primarily
143 * to create C programs and until recently pcc-based compilers refused
144 * to allow you to specify where the resulting object file should be
145 * placed. This forced all objects to be created in the current
146 * directory. This isn't meant as a full excuse, just an explanation of
147 * some of the reasons for the caching used here.
148 *
149 * One more note: the location of a target's file is only performed
150 * on the downward traversal of the graph and then only for terminal
151 * nodes in the graph. This could be construed as wrong in some cases,
152 * but prevents inadvertent modification of files when the "installed"
153 * directory for a file is provided in the search path.
154 *
155 * Another data structure maintained by this module is an mtime
156 * cache used when the searching of cached directories fails to find
157 * a file. In the past, Dir_FindFile would simply perform an access()
158 * call in such a case to determine if the file could be found using
159 * just the name given. When this hit, however, all that was gained
160 * was the knowledge that the file existed. Given that an access() is
161 * essentially a stat() without the copyout() call, and that the same
162 * filesystem overhead would have to be incurred in Dir_MTime, it made
163 * sense to replace the access() with a stat() and record the mtime
164 * in a cache for when Dir_MTime was actually called.
165 */
166
167Lst dirSearchPath; /* main search path */
168
169static Lst openDirectories; /* the list of all open directories */
170
171/*
172 * Variables for gathering statistics on the efficiency of the hashing
173 * mechanism.
174 */
175static int hits, /* Found in directory cache */
176 misses, /* Sad, but not evil misses */
177 nearmisses, /* Found under search path */
178 bigmisses; /* Sought by itself */
179
180static Path *dot; /* contents of current directory */
181static Hash_Table mtimes; /* Results of doing a last-resort stat in
182 * Dir_FindFile -- if we have to go to the
183 * system to find the file, we might as well
184 * have its mtime on record. XXX: If this is done
185 * way early, there's a chance other rules will
186 * have already updated the file, in which case
187 * we'll update it again. Generally, there won't
188 * be two rules to update a single file, so this
189 * should be ok, but... */
190
191
192static int DirFindName(void *, void *);
193static int DirMatchFiles(char *, Path *, Lst);
194static void DirExpandCurly(char *, char *, Lst, Lst);
195static void DirExpandInt(char *, Lst, Lst);
196static int DirPrintWord(void *, void *);
197static int DirPrintDir(void *, void *);
198
199/*-
200 *-----------------------------------------------------------------------
201 * Dir_Init --
202 * initialize things for this module
203 *
204 * Results:
205 * none
206 *
207 * Side Effects:
208 * none
209 *-----------------------------------------------------------------------
210 */
211void
212Dir_Init(void)
213{
214
215 dirSearchPath = Lst_Init(FALSE);
216 openDirectories = Lst_Init(FALSE);
217 Hash_InitTable(&mtimes, 0);
218}
219
220/*-
221 *-----------------------------------------------------------------------
222 * Dir_InitDot --
223 * initialize the "." directory
224 *
225 * Results:
226 * none
227 *
228 * Side Effects:
229 * some directories may be opened.
230 *-----------------------------------------------------------------------
231 */
232void
233Dir_InitDot(void)
234{
235 LstNode ln;
236
237 Dir_AddDir(openDirectories, ".");
238 if ((ln = Lst_Last(openDirectories)) == NULL)
239 err(1, "cannot open current directory");
240 dot = Lst_Datum(ln);
241
242 /*
243 * We always need to have dot around, so we increment its reference count
244 * to make sure it's not destroyed.
245 */
246 dot->refCount += 1;
247}
248
249/*-
250 *-----------------------------------------------------------------------
251 * Dir_End --
252 * cleanup things for this module
253 *
254 * Results:
255 * none
256 *
257 * Side Effects:
258 * none
259 *-----------------------------------------------------------------------
260 */
261void
262Dir_End(void)
263{
264
265 dot->refCount -= 1;
44
45/*-
46 * dir.c --
47 * Directory searching using wildcards and/or normal names...
48 * Used both for source wildcarding in the Makefile and for finding
49 * implicit sources.
50 *
51 * The interface for this module is:
52 * Dir_Init Initialize the module.
53 *
54 * Dir_End Cleanup the module.
55 *
56 * Dir_HasWildcards Returns TRUE if the name given it needs to
57 * be wildcard-expanded.
58 *
59 * Dir_Expand Given a pattern and a path, return a Lst of names
60 * which match the pattern on the search path.
61 *
62 * Dir_FindFile Searches for a file on a given search path.
63 * If it exists, the entire path is returned.
64 * Otherwise NULL is returned.
65 *
66 * Dir_MTime Return the modification time of a node. The file
67 * is searched for along the default search path.
68 * The path and mtime fields of the node are filled
69 * in.
70 *
71 * Dir_AddDir Add a directory to a search path.
72 *
73 * Dir_MakeFlags Given a search path and a command flag, create
74 * a string with each of the directories in the path
75 * preceded by the command flag and all of them
76 * separated by a space.
77 *
78 * Dir_Destroy Destroy an element of a search path. Frees up all
79 * things that can be freed for the element as long
80 * as the element is no longer referenced by any other
81 * search path.
82 * Dir_ClearPath Resets a search path to the empty list.
83 *
84 * For debugging:
85 * Dir_PrintDirectories Print stats about the directory cache.
86 */
87
88#include <stdio.h>
89#include <sys/types.h>
90#include <sys/stat.h>
91#include <dirent.h>
92#include <err.h>
93#include "make.h"
94#include "hash.h"
95#include "dir.h"
96
97/*
98 * A search path consists of a Lst of Path structures. A Path structure
99 * has in it the name of the directory and a hash table of all the files
100 * in the directory. This is used to cut down on the number of system
101 * calls necessary to find implicit dependents and their like. Since
102 * these searches are made before any actions are taken, we need not
103 * worry about the directory changing due to creation commands. If this
104 * hampers the style of some makefiles, they must be changed.
105 *
106 * A list of all previously-read directories is kept in the
107 * openDirectories Lst. This list is checked first before a directory
108 * is opened.
109 *
110 * The need for the caching of whole directories is brought about by
111 * the multi-level transformation code in suff.c, which tends to search
112 * for far more files than regular make does. In the initial
113 * implementation, the amount of time spent performing "stat" calls was
114 * truly astronomical. The problem with hashing at the start is,
115 * of course, that pmake doesn't then detect changes to these directories
116 * during the course of the make. Three possibilities suggest themselves:
117 *
118 * 1) just use stat to test for a file's existence. As mentioned
119 * above, this is very inefficient due to the number of checks
120 * engendered by the multi-level transformation code.
121 * 2) use readdir() and company to search the directories, keeping
122 * them open between checks. I have tried this and while it
123 * didn't slow down the process too much, it could severely
124 * affect the amount of parallelism available as each directory
125 * open would take another file descriptor out of play for
126 * handling I/O for another job. Given that it is only recently
127 * that UNIX OS's have taken to allowing more than 20 or 32
128 * file descriptors for a process, this doesn't seem acceptable
129 * to me.
130 * 3) record the mtime of the directory in the Path structure and
131 * verify the directory hasn't changed since the contents were
132 * hashed. This will catch the creation or deletion of files,
133 * but not the updating of files. However, since it is the
134 * creation and deletion that is the problem, this could be
135 * a good thing to do. Unfortunately, if the directory (say ".")
136 * were fairly large and changed fairly frequently, the constant
137 * rehashing could seriously degrade performance. It might be
138 * good in such cases to keep track of the number of rehashes
139 * and if the number goes over a (small) limit, resort to using
140 * stat in its place.
141 *
142 * An additional thing to consider is that pmake is used primarily
143 * to create C programs and until recently pcc-based compilers refused
144 * to allow you to specify where the resulting object file should be
145 * placed. This forced all objects to be created in the current
146 * directory. This isn't meant as a full excuse, just an explanation of
147 * some of the reasons for the caching used here.
148 *
149 * One more note: the location of a target's file is only performed
150 * on the downward traversal of the graph and then only for terminal
151 * nodes in the graph. This could be construed as wrong in some cases,
152 * but prevents inadvertent modification of files when the "installed"
153 * directory for a file is provided in the search path.
154 *
155 * Another data structure maintained by this module is an mtime
156 * cache used when the searching of cached directories fails to find
157 * a file. In the past, Dir_FindFile would simply perform an access()
158 * call in such a case to determine if the file could be found using
159 * just the name given. When this hit, however, all that was gained
160 * was the knowledge that the file existed. Given that an access() is
161 * essentially a stat() without the copyout() call, and that the same
162 * filesystem overhead would have to be incurred in Dir_MTime, it made
163 * sense to replace the access() with a stat() and record the mtime
164 * in a cache for when Dir_MTime was actually called.
165 */
166
167Lst dirSearchPath; /* main search path */
168
169static Lst openDirectories; /* the list of all open directories */
170
171/*
172 * Variables for gathering statistics on the efficiency of the hashing
173 * mechanism.
174 */
175static int hits, /* Found in directory cache */
176 misses, /* Sad, but not evil misses */
177 nearmisses, /* Found under search path */
178 bigmisses; /* Sought by itself */
179
180static Path *dot; /* contents of current directory */
181static Hash_Table mtimes; /* Results of doing a last-resort stat in
182 * Dir_FindFile -- if we have to go to the
183 * system to find the file, we might as well
184 * have its mtime on record. XXX: If this is done
185 * way early, there's a chance other rules will
186 * have already updated the file, in which case
187 * we'll update it again. Generally, there won't
188 * be two rules to update a single file, so this
189 * should be ok, but... */
190
191
192static int DirFindName(void *, void *);
193static int DirMatchFiles(char *, Path *, Lst);
194static void DirExpandCurly(char *, char *, Lst, Lst);
195static void DirExpandInt(char *, Lst, Lst);
196static int DirPrintWord(void *, void *);
197static int DirPrintDir(void *, void *);
198
199/*-
200 *-----------------------------------------------------------------------
201 * Dir_Init --
202 * initialize things for this module
203 *
204 * Results:
205 * none
206 *
207 * Side Effects:
208 * none
209 *-----------------------------------------------------------------------
210 */
211void
212Dir_Init(void)
213{
214
215 dirSearchPath = Lst_Init(FALSE);
216 openDirectories = Lst_Init(FALSE);
217 Hash_InitTable(&mtimes, 0);
218}
219
220/*-
221 *-----------------------------------------------------------------------
222 * Dir_InitDot --
223 * initialize the "." directory
224 *
225 * Results:
226 * none
227 *
228 * Side Effects:
229 * some directories may be opened.
230 *-----------------------------------------------------------------------
231 */
232void
233Dir_InitDot(void)
234{
235 LstNode ln;
236
237 Dir_AddDir(openDirectories, ".");
238 if ((ln = Lst_Last(openDirectories)) == NULL)
239 err(1, "cannot open current directory");
240 dot = Lst_Datum(ln);
241
242 /*
243 * We always need to have dot around, so we increment its reference count
244 * to make sure it's not destroyed.
245 */
246 dot->refCount += 1;
247}
248
249/*-
250 *-----------------------------------------------------------------------
251 * Dir_End --
252 * cleanup things for this module
253 *
254 * Results:
255 * none
256 *
257 * Side Effects:
258 * none
259 *-----------------------------------------------------------------------
260 */
261void
262Dir_End(void)
263{
264
265 dot->refCount -= 1;
266 Dir_Destroy((void *) dot);
266 Dir_Destroy(dot);
267 Dir_ClearPath(dirSearchPath);
268 Lst_Destroy(dirSearchPath, NOFREE);
269 Dir_ClearPath(openDirectories);
270 Lst_Destroy(openDirectories, NOFREE);
271 Hash_DeleteTable(&mtimes);
272}
273
274/*-
275 *-----------------------------------------------------------------------
276 * DirFindName --
277 * See if the Path structure describes the same directory as the
278 * given one by comparing their names. Called from Dir_AddDir via
279 * Lst_Find when searching the list of open directories.
280 *
281 * Results:
282 * 0 if it is the same. Non-zero otherwise
283 *
284 * Side Effects:
285 * None
286 *-----------------------------------------------------------------------
287 */
288static int
289DirFindName(void *p, void *dname)
290{
267 Dir_ClearPath(dirSearchPath);
268 Lst_Destroy(dirSearchPath, NOFREE);
269 Dir_ClearPath(openDirectories);
270 Lst_Destroy(openDirectories, NOFREE);
271 Hash_DeleteTable(&mtimes);
272}
273
274/*-
275 *-----------------------------------------------------------------------
276 * DirFindName --
277 * See if the Path structure describes the same directory as the
278 * given one by comparing their names. Called from Dir_AddDir via
279 * Lst_Find when searching the list of open directories.
280 *
281 * Results:
282 * 0 if it is the same. Non-zero otherwise
283 *
284 * Side Effects:
285 * None
286 *-----------------------------------------------------------------------
287 */
288static int
289DirFindName(void *p, void *dname)
290{
291
291 return (strcmp(((Path *)p)->name, (char *)dname));
292}
293
294/*-
295 *-----------------------------------------------------------------------
296 * Dir_HasWildcards --
297 * See if the given name has any wildcard characters in it.
298 *
299 * Results:
300 * returns TRUE if the word should be expanded, FALSE otherwise
301 *
302 * Side Effects:
303 * none
304 *-----------------------------------------------------------------------
305 */
306Boolean
307Dir_HasWildcards(char *name)
308{
309 char *cp;
310 int wild = 0, brace = 0, bracket = 0;
311
312 for (cp = name; *cp; cp++) {
313 switch (*cp) {
314 case '{':
315 brace++;
316 wild = 1;
317 break;
318 case '}':
319 brace--;
320 break;
321 case '[':
322 bracket++;
323 wild = 1;
324 break;
325 case ']':
326 bracket--;
327 break;
328 case '?':
329 case '*':
330 wild = 1;
331 break;
332 default:
333 break;
334 }
335 }
336 return (wild && bracket == 0 && brace == 0);
337}
338
339/*-
340 *-----------------------------------------------------------------------
341 * DirMatchFiles --
342 * Given a pattern and a Path structure, see if any files
343 * match the pattern and add their names to the 'expansions' list if
344 * any do. This is incomplete -- it doesn't take care of patterns like
345 * src / *src / *.c properly (just *.c on any of the directories), but it
346 * will do for now.
347 *
348 * Results:
349 * Always returns 0
350 *
351 * Side Effects:
352 * File names are added to the expansions lst. The directory will be
353 * fully hashed when this is done.
354 *-----------------------------------------------------------------------
355 */
356static int
357DirMatchFiles(char *pattern, Path *p, Lst expansions)
358{
359 Hash_Search search; /* Index into the directory's table */
360 Hash_Entry *entry; /* Current entry in the table */
361 Boolean isDot; /* TRUE if the directory being searched is . */
362
363 isDot = (*p->name == '.' && p->name[1] == '\0');
364
365 for (entry = Hash_EnumFirst(&p->files, &search);
292 return (strcmp(((Path *)p)->name, (char *)dname));
293}
294
295/*-
296 *-----------------------------------------------------------------------
297 * Dir_HasWildcards --
298 * See if the given name has any wildcard characters in it.
299 *
300 * Results:
301 * returns TRUE if the word should be expanded, FALSE otherwise
302 *
303 * Side Effects:
304 * none
305 *-----------------------------------------------------------------------
306 */
307Boolean
308Dir_HasWildcards(char *name)
309{
310 char *cp;
311 int wild = 0, brace = 0, bracket = 0;
312
313 for (cp = name; *cp; cp++) {
314 switch (*cp) {
315 case '{':
316 brace++;
317 wild = 1;
318 break;
319 case '}':
320 brace--;
321 break;
322 case '[':
323 bracket++;
324 wild = 1;
325 break;
326 case ']':
327 bracket--;
328 break;
329 case '?':
330 case '*':
331 wild = 1;
332 break;
333 default:
334 break;
335 }
336 }
337 return (wild && bracket == 0 && brace == 0);
338}
339
340/*-
341 *-----------------------------------------------------------------------
342 * DirMatchFiles --
343 * Given a pattern and a Path structure, see if any files
344 * match the pattern and add their names to the 'expansions' list if
345 * any do. This is incomplete -- it doesn't take care of patterns like
346 * src / *src / *.c properly (just *.c on any of the directories), but it
347 * will do for now.
348 *
349 * Results:
350 * Always returns 0
351 *
352 * Side Effects:
353 * File names are added to the expansions lst. The directory will be
354 * fully hashed when this is done.
355 *-----------------------------------------------------------------------
356 */
357static int
358DirMatchFiles(char *pattern, Path *p, Lst expansions)
359{
360 Hash_Search search; /* Index into the directory's table */
361 Hash_Entry *entry; /* Current entry in the table */
362 Boolean isDot; /* TRUE if the directory being searched is . */
363
364 isDot = (*p->name == '.' && p->name[1] == '\0');
365
366 for (entry = Hash_EnumFirst(&p->files, &search);
366 entry != (Hash_Entry *)NULL;
367 entry != NULL;
367 entry = Hash_EnumNext(&search))
368 {
369 /*
370 * See if the file matches the given pattern. Note we follow the UNIX
371 * convention that dot files will only be found if the pattern
372 * begins with a dot (note also that as a side effect of the hashing
373 * scheme, .* won't match . or .. since they aren't hashed).
374 */
375 if (Str_Match(entry->name, pattern) &&
376 ((entry->name[0] != '.') ||
377 (pattern[0] == '.')))
378 {
379 Lst_AtEnd(expansions,
380 (isDot ? estrdup(entry->name) :
381 str_concat(p->name, entry->name,
382 STR_ADDSLASH)));
383 }
384 }
385 return (0);
386}
387
388/*-
389 *-----------------------------------------------------------------------
390 * DirExpandCurly --
391 * Expand curly braces like the C shell. Does this recursively.
392 * Note the special case: if after the piece of the curly brace is
393 * done there are no wildcard characters in the result, the result is
394 * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE. The
395 * given arguments are the entire word to expand, the first curly
396 * brace in the word, the search path, and the list to store the
397 * expansions in.
398 *
399 * Results:
400 * None.
401 *
402 * Side Effects:
403 * The given list is filled with the expansions...
404 *
405 *-----------------------------------------------------------------------
406 */
407static void
408DirExpandCurly(char *word, char *brace, Lst path, Lst expansions)
409{
410 char *end; /* Character after the closing brace */
411 char *cp; /* Current position in brace clause */
412 char *start; /* Start of current piece of brace clause */
413 int bracelevel; /* Number of braces we've seen. If we see a
414 * right brace when this is 0, we've hit the
415 * end of the clause. */
416 char *file; /* Current expansion */
417 int otherLen; /* The length of the other pieces of the
418 * expansion (chars before and after the
419 * clause in 'word') */
420 char *cp2; /* Pointer for checking for wildcards in
421 * expansion before calling Dir_Expand */
422
423 start = brace + 1;
424
425 /*
426 * Find the end of the brace clause first, being wary of nested brace
427 * clauses.
428 */
429 for (end = start, bracelevel = 0; *end != '\0'; end++) {
430 if (*end == '{') {
431 bracelevel++;
432 } else if ((*end == '}') && (bracelevel-- == 0)) {
433 break;
434 }
435 }
436 if (*end == '\0') {
437 Error("Unterminated {} clause \"%s\"", start);
438 return;
439 } else {
440 end++;
441 }
442 otherLen = brace - word + strlen(end);
443
444 for (cp = start; cp < end; cp++) {
445 /*
446 * Find the end of this piece of the clause.
447 */
448 bracelevel = 0;
449 while (*cp != ',') {
450 if (*cp == '{') {
451 bracelevel++;
452 } else if ((*cp == '}') && (bracelevel-- <= 0)) {
453 break;
454 }
455 cp++;
456 }
457 /*
458 * Allocate room for the combination and install the three pieces.
459 */
460 file = emalloc(otherLen + cp - start + 1);
461 if (brace != word) {
462 strncpy(file, word, brace - word);
463 }
464 if (cp != start) {
465 strncpy(&file[brace - word], start, cp - start);
466 }
467 strcpy(&file[(brace - word) + (cp - start)], end);
468
469 /*
470 * See if the result has any wildcards in it. If we find one, call
471 * Dir_Expand right away, telling it to place the result on our list
472 * of expansions.
473 */
474 for (cp2 = file; *cp2 != '\0'; cp2++) {
475 switch(*cp2) {
476 case '*':
477 case '?':
478 case '{':
479 case '[':
480 Dir_Expand(file, path, expansions);
481 goto next;
482 default:
483 break;
484 }
485 }
486 if (*cp2 == '\0') {
487 /*
488 * Hit the end w/o finding any wildcards, so stick the expansion
489 * on the end of the list.
490 */
491 Lst_AtEnd(expansions, file);
492 } else {
493 next:
494 free(file);
495 }
496 start = cp+1;
497 }
498}
499
500
501/*-
502 *-----------------------------------------------------------------------
503 * DirExpandInt --
504 * Internal expand routine. Passes through the directories in the
505 * path one by one, calling DirMatchFiles for each. NOTE: This still
506 * doesn't handle patterns in directories... Works given a word to
507 * expand, a path to look in, and a list to store expansions in.
508 *
509 * Results:
510 * None.
511 *
512 * Side Effects:
513 * Things are added to the expansions list.
514 *
515 *-----------------------------------------------------------------------
516 */
517static void
518DirExpandInt(char *word, Lst path, Lst expansions)
519{
520 LstNode ln; /* Current node */
521 Path *p; /* Directory in the node */
522
523 if (Lst_Open(path) == SUCCESS) {
524 while ((ln = Lst_Next(path)) != NULL) {
368 entry = Hash_EnumNext(&search))
369 {
370 /*
371 * See if the file matches the given pattern. Note we follow the UNIX
372 * convention that dot files will only be found if the pattern
373 * begins with a dot (note also that as a side effect of the hashing
374 * scheme, .* won't match . or .. since they aren't hashed).
375 */
376 if (Str_Match(entry->name, pattern) &&
377 ((entry->name[0] != '.') ||
378 (pattern[0] == '.')))
379 {
380 Lst_AtEnd(expansions,
381 (isDot ? estrdup(entry->name) :
382 str_concat(p->name, entry->name,
383 STR_ADDSLASH)));
384 }
385 }
386 return (0);
387}
388
389/*-
390 *-----------------------------------------------------------------------
391 * DirExpandCurly --
392 * Expand curly braces like the C shell. Does this recursively.
393 * Note the special case: if after the piece of the curly brace is
394 * done there are no wildcard characters in the result, the result is
395 * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE. The
396 * given arguments are the entire word to expand, the first curly
397 * brace in the word, the search path, and the list to store the
398 * expansions in.
399 *
400 * Results:
401 * None.
402 *
403 * Side Effects:
404 * The given list is filled with the expansions...
405 *
406 *-----------------------------------------------------------------------
407 */
408static void
409DirExpandCurly(char *word, char *brace, Lst path, Lst expansions)
410{
411 char *end; /* Character after the closing brace */
412 char *cp; /* Current position in brace clause */
413 char *start; /* Start of current piece of brace clause */
414 int bracelevel; /* Number of braces we've seen. If we see a
415 * right brace when this is 0, we've hit the
416 * end of the clause. */
417 char *file; /* Current expansion */
418 int otherLen; /* The length of the other pieces of the
419 * expansion (chars before and after the
420 * clause in 'word') */
421 char *cp2; /* Pointer for checking for wildcards in
422 * expansion before calling Dir_Expand */
423
424 start = brace + 1;
425
426 /*
427 * Find the end of the brace clause first, being wary of nested brace
428 * clauses.
429 */
430 for (end = start, bracelevel = 0; *end != '\0'; end++) {
431 if (*end == '{') {
432 bracelevel++;
433 } else if ((*end == '}') && (bracelevel-- == 0)) {
434 break;
435 }
436 }
437 if (*end == '\0') {
438 Error("Unterminated {} clause \"%s\"", start);
439 return;
440 } else {
441 end++;
442 }
443 otherLen = brace - word + strlen(end);
444
445 for (cp = start; cp < end; cp++) {
446 /*
447 * Find the end of this piece of the clause.
448 */
449 bracelevel = 0;
450 while (*cp != ',') {
451 if (*cp == '{') {
452 bracelevel++;
453 } else if ((*cp == '}') && (bracelevel-- <= 0)) {
454 break;
455 }
456 cp++;
457 }
458 /*
459 * Allocate room for the combination and install the three pieces.
460 */
461 file = emalloc(otherLen + cp - start + 1);
462 if (brace != word) {
463 strncpy(file, word, brace - word);
464 }
465 if (cp != start) {
466 strncpy(&file[brace - word], start, cp - start);
467 }
468 strcpy(&file[(brace - word) + (cp - start)], end);
469
470 /*
471 * See if the result has any wildcards in it. If we find one, call
472 * Dir_Expand right away, telling it to place the result on our list
473 * of expansions.
474 */
475 for (cp2 = file; *cp2 != '\0'; cp2++) {
476 switch(*cp2) {
477 case '*':
478 case '?':
479 case '{':
480 case '[':
481 Dir_Expand(file, path, expansions);
482 goto next;
483 default:
484 break;
485 }
486 }
487 if (*cp2 == '\0') {
488 /*
489 * Hit the end w/o finding any wildcards, so stick the expansion
490 * on the end of the list.
491 */
492 Lst_AtEnd(expansions, file);
493 } else {
494 next:
495 free(file);
496 }
497 start = cp+1;
498 }
499}
500
501
502/*-
503 *-----------------------------------------------------------------------
504 * DirExpandInt --
505 * Internal expand routine. Passes through the directories in the
506 * path one by one, calling DirMatchFiles for each. NOTE: This still
507 * doesn't handle patterns in directories... Works given a word to
508 * expand, a path to look in, and a list to store expansions in.
509 *
510 * Results:
511 * None.
512 *
513 * Side Effects:
514 * Things are added to the expansions list.
515 *
516 *-----------------------------------------------------------------------
517 */
518static void
519DirExpandInt(char *word, Lst path, Lst expansions)
520{
521 LstNode ln; /* Current node */
522 Path *p; /* Directory in the node */
523
524 if (Lst_Open(path) == SUCCESS) {
525 while ((ln = Lst_Next(path)) != NULL) {
525 p = (Path *)Lst_Datum(ln);
526 p = Lst_Datum(ln);
526 DirMatchFiles(word, p, expansions);
527 }
528 Lst_Close(path);
529 }
530}
531
532/*-
533 *-----------------------------------------------------------------------
534 * DirPrintWord --
535 * Print a word in the list of expansions. Callback for Dir_Expand
536 * when DEBUG(DIR), via Lst_ForEach.
537 *
538 * Results:
539 * === 0
540 *
541 * Side Effects:
542 * The passed word is printed, followed by a space.
543 *
544 *-----------------------------------------------------------------------
545 */
546static int
547DirPrintWord(void *word, void *dummy __unused)
548{
549
550 DEBUGF(DIR, ("%s ", (char *)word));
551
552 return (0);
553}
554
555/*-
556 *-----------------------------------------------------------------------
557 * Dir_Expand --
558 * Expand the given word into a list of words by globbing it looking
559 * in the directories on the given search path.
560 *
561 * Results:
562 * A list of words consisting of the files which exist along the search
563 * path matching the given pattern is placed in expansions.
564 *
565 * Side Effects:
566 * Directories may be opened. Who knows?
567 *-----------------------------------------------------------------------
568 */
569void
570Dir_Expand(char *word, Lst path, Lst expansions)
571{
572 char *cp;
573
574 DEBUGF(DIR, ("expanding \"%s\"...", word));
575
576 cp = strchr(word, '{');
577 if (cp) {
578 DirExpandCurly(word, cp, path, expansions);
579 } else {
580 cp = strchr(word, '/');
581 if (cp) {
582 /*
583 * The thing has a directory component -- find the first wildcard
584 * in the string.
585 */
586 for (cp = word; *cp; cp++) {
587 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') {
588 break;
589 }
590 }
591 if (*cp == '{') {
592 /*
593 * This one will be fun.
594 */
595 DirExpandCurly(word, cp, path, expansions);
596 return;
597 } else if (*cp != '\0') {
598 /*
599 * Back up to the start of the component
600 */
601 char *dirpath;
602
603 while (cp > word && *cp != '/') {
604 cp--;
605 }
606 if (cp != word) {
607 char sc;
608 /*
609 * If the glob isn't in the first component, try and find
610 * all the components up to the one with a wildcard.
611 */
612 sc = cp[1];
613 cp[1] = '\0';
614 dirpath = Dir_FindFile(word, path);
615 cp[1] = sc;
616 /*
617 * dirpath is null if can't find the leading component
618 * XXX: Dir_FindFile won't find internal components.
619 * i.e. if the path contains ../Etc/Object and we're
620 * looking for Etc, it won't be found. Ah well.
621 * Probably not important.
622 */
527 DirMatchFiles(word, p, expansions);
528 }
529 Lst_Close(path);
530 }
531}
532
533/*-
534 *-----------------------------------------------------------------------
535 * DirPrintWord --
536 * Print a word in the list of expansions. Callback for Dir_Expand
537 * when DEBUG(DIR), via Lst_ForEach.
538 *
539 * Results:
540 * === 0
541 *
542 * Side Effects:
543 * The passed word is printed, followed by a space.
544 *
545 *-----------------------------------------------------------------------
546 */
547static int
548DirPrintWord(void *word, void *dummy __unused)
549{
550
551 DEBUGF(DIR, ("%s ", (char *)word));
552
553 return (0);
554}
555
556/*-
557 *-----------------------------------------------------------------------
558 * Dir_Expand --
559 * Expand the given word into a list of words by globbing it looking
560 * in the directories on the given search path.
561 *
562 * Results:
563 * A list of words consisting of the files which exist along the search
564 * path matching the given pattern is placed in expansions.
565 *
566 * Side Effects:
567 * Directories may be opened. Who knows?
568 *-----------------------------------------------------------------------
569 */
570void
571Dir_Expand(char *word, Lst path, Lst expansions)
572{
573 char *cp;
574
575 DEBUGF(DIR, ("expanding \"%s\"...", word));
576
577 cp = strchr(word, '{');
578 if (cp) {
579 DirExpandCurly(word, cp, path, expansions);
580 } else {
581 cp = strchr(word, '/');
582 if (cp) {
583 /*
584 * The thing has a directory component -- find the first wildcard
585 * in the string.
586 */
587 for (cp = word; *cp; cp++) {
588 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') {
589 break;
590 }
591 }
592 if (*cp == '{') {
593 /*
594 * This one will be fun.
595 */
596 DirExpandCurly(word, cp, path, expansions);
597 return;
598 } else if (*cp != '\0') {
599 /*
600 * Back up to the start of the component
601 */
602 char *dirpath;
603
604 while (cp > word && *cp != '/') {
605 cp--;
606 }
607 if (cp != word) {
608 char sc;
609 /*
610 * If the glob isn't in the first component, try and find
611 * all the components up to the one with a wildcard.
612 */
613 sc = cp[1];
614 cp[1] = '\0';
615 dirpath = Dir_FindFile(word, path);
616 cp[1] = sc;
617 /*
618 * dirpath is null if can't find the leading component
619 * XXX: Dir_FindFile won't find internal components.
620 * i.e. if the path contains ../Etc/Object and we're
621 * looking for Etc, it won't be found. Ah well.
622 * Probably not important.
623 */
623 if (dirpath != (char *)NULL) {
624 if (dirpath != NULL) {
624 char *dp = &dirpath[strlen(dirpath) - 1];
625 if (*dp == '/')
626 *dp = '\0';
627 path = Lst_Init(FALSE);
628 Dir_AddDir(path, dirpath);
629 DirExpandInt(cp+1, path, expansions);
630 Lst_Destroy(path, NOFREE);
631 }
632 } else {
633 /*
634 * Start the search from the local directory
635 */
636 DirExpandInt(word, path, expansions);
637 }
638 } else {
639 /*
640 * Return the file -- this should never happen.
641 */
642 DirExpandInt(word, path, expansions);
643 }
644 } else {
645 /*
646 * First the files in dot
647 */
648 DirMatchFiles(word, dot, expansions);
649
650 /*
651 * Then the files in every other directory on the path.
652 */
653 DirExpandInt(word, path, expansions);
654 }
655 }
656 if (DEBUG(DIR)) {
625 char *dp = &dirpath[strlen(dirpath) - 1];
626 if (*dp == '/')
627 *dp = '\0';
628 path = Lst_Init(FALSE);
629 Dir_AddDir(path, dirpath);
630 DirExpandInt(cp+1, path, expansions);
631 Lst_Destroy(path, NOFREE);
632 }
633 } else {
634 /*
635 * Start the search from the local directory
636 */
637 DirExpandInt(word, path, expansions);
638 }
639 } else {
640 /*
641 * Return the file -- this should never happen.
642 */
643 DirExpandInt(word, path, expansions);
644 }
645 } else {
646 /*
647 * First the files in dot
648 */
649 DirMatchFiles(word, dot, expansions);
650
651 /*
652 * Then the files in every other directory on the path.
653 */
654 DirExpandInt(word, path, expansions);
655 }
656 }
657 if (DEBUG(DIR)) {
657 Lst_ForEach(expansions, DirPrintWord, (void *) 0);
658 Lst_ForEach(expansions, DirPrintWord, (void *)NULL);
658 DEBUGF(DIR, ("\n"));
659 }
660}
661
662/*-
663 *-----------------------------------------------------------------------
664 * Dir_FindFile --
665 * Find the file with the given name along the given search path.
666 *
667 * Results:
668 * The path to the file or NULL. This path is guaranteed to be in a
669 * different part of memory than name and so may be safely free'd.
670 *
671 * Side Effects:
672 * If the file is found in a directory which is not on the path
673 * already (either 'name' is absolute or it is a relative path
674 * [ dir1/.../dirn/file ] which exists below one of the directories
675 * already on the search path), its directory is added to the end
676 * of the path on the assumption that there will be more files in
677 * that directory later on. Sometimes this is true. Sometimes not.
678 *-----------------------------------------------------------------------
679 */
680char *
681Dir_FindFile(char *name, Lst path)
682{
683 char *p1; /* pointer into p->name */
684 char *p2; /* pointer into name */
685 LstNode ln; /* a list element */
686 char *file; /* the current filename to check */
687 Path *p; /* current path member */
688 char *cp; /* final component of the name */
689 Boolean hasSlash; /* true if 'name' contains a / */
690 struct stat stb; /* Buffer for stat, if necessary */
691 Hash_Entry *entry; /* Entry for mtimes table */
692
693 /*
694 * Find the final component of the name and note whether it has a
695 * slash in it (the name, I mean)
696 */
697 cp = strrchr(name, '/');
698 if (cp) {
699 hasSlash = TRUE;
700 cp += 1;
701 } else {
702 hasSlash = FALSE;
703 cp = name;
704 }
705
706 DEBUGF(DIR, ("Searching for %s...", name));
707 /*
708 * No matter what, we always look for the file in the current directory
709 * before anywhere else and we *do not* add the ./ to it if it exists.
710 * This is so there are no conflicts between what the user specifies
711 * (fish.c) and what pmake finds (./fish.c).
712 */
713 if ((!hasSlash || (cp - name == 2 && *name == '.')) &&
659 DEBUGF(DIR, ("\n"));
660 }
661}
662
663/*-
664 *-----------------------------------------------------------------------
665 * Dir_FindFile --
666 * Find the file with the given name along the given search path.
667 *
668 * Results:
669 * The path to the file or NULL. This path is guaranteed to be in a
670 * different part of memory than name and so may be safely free'd.
671 *
672 * Side Effects:
673 * If the file is found in a directory which is not on the path
674 * already (either 'name' is absolute or it is a relative path
675 * [ dir1/.../dirn/file ] which exists below one of the directories
676 * already on the search path), its directory is added to the end
677 * of the path on the assumption that there will be more files in
678 * that directory later on. Sometimes this is true. Sometimes not.
679 *-----------------------------------------------------------------------
680 */
681char *
682Dir_FindFile(char *name, Lst path)
683{
684 char *p1; /* pointer into p->name */
685 char *p2; /* pointer into name */
686 LstNode ln; /* a list element */
687 char *file; /* the current filename to check */
688 Path *p; /* current path member */
689 char *cp; /* final component of the name */
690 Boolean hasSlash; /* true if 'name' contains a / */
691 struct stat stb; /* Buffer for stat, if necessary */
692 Hash_Entry *entry; /* Entry for mtimes table */
693
694 /*
695 * Find the final component of the name and note whether it has a
696 * slash in it (the name, I mean)
697 */
698 cp = strrchr(name, '/');
699 if (cp) {
700 hasSlash = TRUE;
701 cp += 1;
702 } else {
703 hasSlash = FALSE;
704 cp = name;
705 }
706
707 DEBUGF(DIR, ("Searching for %s...", name));
708 /*
709 * No matter what, we always look for the file in the current directory
710 * before anywhere else and we *do not* add the ./ to it if it exists.
711 * This is so there are no conflicts between what the user specifies
712 * (fish.c) and what pmake finds (./fish.c).
713 */
714 if ((!hasSlash || (cp - name == 2 && *name == '.')) &&
714 (Hash_FindEntry(&dot->files, cp) != (Hash_Entry *)NULL)) {
715 (Hash_FindEntry(&dot->files, cp) != NULL)) {
715 DEBUGF(DIR, ("in '.'\n"));
716 hits += 1;
717 dot->hits += 1;
718 return (estrdup(name));
719 }
720
721 if (Lst_Open(path) == FAILURE) {
722 DEBUGF(DIR, ("couldn't open path, file not found\n"));
723 misses += 1;
716 DEBUGF(DIR, ("in '.'\n"));
717 hits += 1;
718 dot->hits += 1;
719 return (estrdup(name));
720 }
721
722 if (Lst_Open(path) == FAILURE) {
723 DEBUGF(DIR, ("couldn't open path, file not found\n"));
724 misses += 1;
724 return ((char *)NULL);
725 return (NULL);
725 }
726
727 /*
728 * We look through all the directories on the path seeking one which
729 * contains the final component of the given name and whose final
730 * component(s) match the name's initial component(s). If such a beast
731 * is found, we concatenate the directory name and the final component
732 * and return the resulting string. If we don't find any such thing,
733 * we go on to phase two...
734 */
735 while ((ln = Lst_Next(path)) != NULL) {
726 }
727
728 /*
729 * We look through all the directories on the path seeking one which
730 * contains the final component of the given name and whose final
731 * component(s) match the name's initial component(s). If such a beast
732 * is found, we concatenate the directory name and the final component
733 * and return the resulting string. If we don't find any such thing,
734 * we go on to phase two...
735 */
736 while ((ln = Lst_Next(path)) != NULL) {
736 p = (Path *)Lst_Datum (ln);
737 p = Lst_Datum (ln);
737 DEBUGF(DIR, ("%s...", p->name));
738 DEBUGF(DIR, ("%s...", p->name));
738 if (Hash_FindEntry(&p->files, cp) != (Hash_Entry *)NULL) {
739 if (Hash_FindEntry(&p->files, cp) != NULL) {
739 DEBUGF(DIR, ("here..."));
740 if (hasSlash) {
741 /*
742 * If the name had a slash, its initial components and p's
743 * final components must match. This is false if a mismatch
744 * is encountered before all of the initial components
745 * have been checked (p2 > name at the end of the loop), or
746 * we matched only part of one of the components of p
747 * along with all the rest of them (*p1 != '/').
748 */
749 p1 = p->name + strlen(p->name) - 1;
750 p2 = cp - 2;
751 while (p2 >= name && p1 >= p->name && *p1 == *p2) {
752 p1 -= 1; p2 -= 1;
753 }
754 if (p2 >= name || (p1 >= p->name && *p1 != '/')) {
755 DEBUGF(DIR, ("component mismatch -- continuing..."));
756 continue;
757 }
758 }
759 file = str_concat(p->name, cp, STR_ADDSLASH);
760 DEBUGF(DIR, ("returning %s\n", file));
761 Lst_Close(path);
762 p->hits += 1;
763 hits += 1;
764 return (file);
765 } else if (hasSlash) {
766 /*
767 * If the file has a leading path component and that component
768 * exactly matches the entire name of the current search
769 * directory, we assume the file doesn't exist and return NULL.
770 */
771 for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
772 continue;
773 }
774 if (*p1 == '\0' && p2 == cp - 1) {
775 Lst_Close(path);
776 if (*cp == '\0' || ISDOT(cp) || ISDOTDOT(cp)) {
777 DEBUGF(DIR, ("returning %s\n", name));
778 return (estrdup(name));
779 } else {
780 DEBUGF(DIR, ("must be here but isn't -- returning NULL\n"));
740 DEBUGF(DIR, ("here..."));
741 if (hasSlash) {
742 /*
743 * If the name had a slash, its initial components and p's
744 * final components must match. This is false if a mismatch
745 * is encountered before all of the initial components
746 * have been checked (p2 > name at the end of the loop), or
747 * we matched only part of one of the components of p
748 * along with all the rest of them (*p1 != '/').
749 */
750 p1 = p->name + strlen(p->name) - 1;
751 p2 = cp - 2;
752 while (p2 >= name && p1 >= p->name && *p1 == *p2) {
753 p1 -= 1; p2 -= 1;
754 }
755 if (p2 >= name || (p1 >= p->name && *p1 != '/')) {
756 DEBUGF(DIR, ("component mismatch -- continuing..."));
757 continue;
758 }
759 }
760 file = str_concat(p->name, cp, STR_ADDSLASH);
761 DEBUGF(DIR, ("returning %s\n", file));
762 Lst_Close(path);
763 p->hits += 1;
764 hits += 1;
765 return (file);
766 } else if (hasSlash) {
767 /*
768 * If the file has a leading path component and that component
769 * exactly matches the entire name of the current search
770 * directory, we assume the file doesn't exist and return NULL.
771 */
772 for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
773 continue;
774 }
775 if (*p1 == '\0' && p2 == cp - 1) {
776 Lst_Close(path);
777 if (*cp == '\0' || ISDOT(cp) || ISDOTDOT(cp)) {
778 DEBUGF(DIR, ("returning %s\n", name));
779 return (estrdup(name));
780 } else {
781 DEBUGF(DIR, ("must be here but isn't -- returning NULL\n"));
781 return ((char *)NULL);
782 return (NULL);
782 }
783 }
784 }
785 }
786
787 /*
788 * We didn't find the file on any existing members of the directory.
789 * If the name doesn't contain a slash, that means it doesn't exist.
790 * If it *does* contain a slash, however, there is still hope: it
791 * could be in a subdirectory of one of the members of the search
792 * path. (eg. /usr/include and sys/types.h. The above search would
793 * fail to turn up types.h in /usr/include, but it *is* in
794 * /usr/include/sys/types.h) If we find such a beast, we assume there
795 * will be more (what else can we assume?) and add all but the last
796 * component of the resulting name onto the search path (at the
797 * end). This phase is only performed if the file is *not* absolute.
798 */
799 if (!hasSlash) {
800 DEBUGF(DIR, ("failed.\n"));
801 misses += 1;
783 }
784 }
785 }
786 }
787
788 /*
789 * We didn't find the file on any existing members of the directory.
790 * If the name doesn't contain a slash, that means it doesn't exist.
791 * If it *does* contain a slash, however, there is still hope: it
792 * could be in a subdirectory of one of the members of the search
793 * path. (eg. /usr/include and sys/types.h. The above search would
794 * fail to turn up types.h in /usr/include, but it *is* in
795 * /usr/include/sys/types.h) If we find such a beast, we assume there
796 * will be more (what else can we assume?) and add all but the last
797 * component of the resulting name onto the search path (at the
798 * end). This phase is only performed if the file is *not* absolute.
799 */
800 if (!hasSlash) {
801 DEBUGF(DIR, ("failed.\n"));
802 misses += 1;
802 return ((char *)NULL);
803 return (NULL);
803 }
804
805 if (*name != '/') {
806 Boolean checkedDot = FALSE;
807
808 DEBUGF(DIR, ("failed. Trying subdirectories..."));
804 }
805
806 if (*name != '/') {
807 Boolean checkedDot = FALSE;
808
809 DEBUGF(DIR, ("failed. Trying subdirectories..."));
809 Lst_Open(path);
810 Lst_Open(path);
810 while ((ln = Lst_Next(path)) != NULL) {
811 while ((ln = Lst_Next(path)) != NULL) {
811 p = (Path *)Lst_Datum(ln);
812 p = Lst_Datum(ln);
812 if (p != dot) {
813 file = str_concat(p->name, name, STR_ADDSLASH);
814 } else {
815 /*
816 * Checking in dot -- DON'T put a leading ./ on the thing.
817 */
818 file = estrdup(name);
819 checkedDot = TRUE;
820 }
821 DEBUGF(DIR, ("checking %s...", file));
822
823 if (stat(file, &stb) == 0) {
824 DEBUGF(DIR, ("got it.\n"));
825
826 Lst_Close(path);
827
828 /*
829 * We've found another directory to search. We know there's
830 * a slash in 'file' because we put one there. We nuke it after
831 * finding it and call Dir_AddDir to add this new directory
832 * onto the existing search path. Once that's done, we restore
833 * the slash and triumphantly return the file name, knowing
834 * that should a file in this directory every be referenced
835 * again in such a manner, we will find it without having to do
836 * numerous numbers of access calls. Hurrah!
837 */
838 cp = strrchr(file, '/');
839 *cp = '\0';
840 Dir_AddDir(path, file);
841 *cp = '/';
842
843 /*
844 * Save the modification time so if it's needed, we don't have
845 * to fetch it again.
846 */
847 DEBUGF(DIR, ("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), file));
813 if (p != dot) {
814 file = str_concat(p->name, name, STR_ADDSLASH);
815 } else {
816 /*
817 * Checking in dot -- DON'T put a leading ./ on the thing.
818 */
819 file = estrdup(name);
820 checkedDot = TRUE;
821 }
822 DEBUGF(DIR, ("checking %s...", file));
823
824 if (stat(file, &stb) == 0) {
825 DEBUGF(DIR, ("got it.\n"));
826
827 Lst_Close(path);
828
829 /*
830 * We've found another directory to search. We know there's
831 * a slash in 'file' because we put one there. We nuke it after
832 * finding it and call Dir_AddDir to add this new directory
833 * onto the existing search path. Once that's done, we restore
834 * the slash and triumphantly return the file name, knowing
835 * that should a file in this directory every be referenced
836 * again in such a manner, we will find it without having to do
837 * numerous numbers of access calls. Hurrah!
838 */
839 cp = strrchr(file, '/');
840 *cp = '\0';
841 Dir_AddDir(path, file);
842 *cp = '/';
843
844 /*
845 * Save the modification time so if it's needed, we don't have
846 * to fetch it again.
847 */
848 DEBUGF(DIR, ("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), file));
848 entry = Hash_CreateEntry(&mtimes, (char *)file,
849 (Boolean *)NULL);
850 Hash_SetValue(entry, (long)stb.st_mtime);
849 entry = Hash_CreateEntry(&mtimes, file, (Boolean *)NULL);
850 Hash_SetValue(entry, (void *)(long)stb.st_mtime);
851 nearmisses += 1;
852 return (file);
853 } else {
854 free(file);
855 }
856 }
857
858 DEBUGF(DIR, ("failed. "));
859 Lst_Close(path);
860
861 if (checkedDot) {
862 /*
863 * Already checked by the given name, since . was in the path,
864 * so no point in proceeding...
865 */
866 DEBUGF(DIR, ("Checked . already, returning NULL\n"));
867 return (NULL);
868 }
869 }
870
871 /*
872 * Didn't find it that way, either. Sigh. Phase 3. Add its directory
873 * onto the search path in any case, just in case, then look for the
874 * thing in the hash table. If we find it, grand. We return a new
875 * copy of the name. Otherwise we sadly return a NULL pointer. Sigh.
876 * Note that if the directory holding the file doesn't exist, this will
877 * do an extra search of the final directory on the path. Unless something
878 * weird happens, this search won't succeed and life will be groovy.
879 *
880 * Sigh. We cannot add the directory onto the search path because
881 * of this amusing case:
882 * $(INSTALLDIR)/$(FILE): $(FILE)
883 *
884 * $(FILE) exists in $(INSTALLDIR) but not in the current one.
885 * When searching for $(FILE), we will find it in $(INSTALLDIR)
886 * b/c we added it here. This is not good...
887 */
888#ifdef notdef
889 cp[-1] = '\0';
890 Dir_AddDir(path, name);
891 cp[-1] = '/';
892
893 bigmisses += 1;
894 ln = Lst_Last(path);
895 if (ln == NULL) {
851 nearmisses += 1;
852 return (file);
853 } else {
854 free(file);
855 }
856 }
857
858 DEBUGF(DIR, ("failed. "));
859 Lst_Close(path);
860
861 if (checkedDot) {
862 /*
863 * Already checked by the given name, since . was in the path,
864 * so no point in proceeding...
865 */
866 DEBUGF(DIR, ("Checked . already, returning NULL\n"));
867 return (NULL);
868 }
869 }
870
871 /*
872 * Didn't find it that way, either. Sigh. Phase 3. Add its directory
873 * onto the search path in any case, just in case, then look for the
874 * thing in the hash table. If we find it, grand. We return a new
875 * copy of the name. Otherwise we sadly return a NULL pointer. Sigh.
876 * Note that if the directory holding the file doesn't exist, this will
877 * do an extra search of the final directory on the path. Unless something
878 * weird happens, this search won't succeed and life will be groovy.
879 *
880 * Sigh. We cannot add the directory onto the search path because
881 * of this amusing case:
882 * $(INSTALLDIR)/$(FILE): $(FILE)
883 *
884 * $(FILE) exists in $(INSTALLDIR) but not in the current one.
885 * When searching for $(FILE), we will find it in $(INSTALLDIR)
886 * b/c we added it here. This is not good...
887 */
888#ifdef notdef
889 cp[-1] = '\0';
890 Dir_AddDir(path, name);
891 cp[-1] = '/';
892
893 bigmisses += 1;
894 ln = Lst_Last(path);
895 if (ln == NULL) {
896 return ((char *)NULL);
896 return (NULL);
897 } else {
897 } else {
898 p = (Path *)Lst_Datum (ln);
898 p = Lst_Datum(ln);
899 }
900
899 }
900
901 if (Hash_FindEntry(&p->files, cp) != (Hash_Entry *)NULL) {
901 if (Hash_FindEntry(&p->files, cp) != NULL) {
902 return (estrdup(name));
903 } else {
902 return (estrdup(name));
903 } else {
904 return ((char *)NULL);
904 return (NULL);
905 }
906#else /* !notdef */
907 DEBUGF(DIR, ("Looking for \"%s\"...", name));
908
909 bigmisses += 1;
910 entry = Hash_FindEntry(&mtimes, name);
905 }
906#else /* !notdef */
907 DEBUGF(DIR, ("Looking for \"%s\"...", name));
908
909 bigmisses += 1;
910 entry = Hash_FindEntry(&mtimes, name);
911 if (entry != (Hash_Entry *)NULL) {
911 if (entry != NULL) {
912 DEBUGF(DIR, ("got it (in mtime cache)\n"));
913 return (estrdup(name));
914 } else if (stat (name, &stb) == 0) {
915 entry = Hash_CreateEntry(&mtimes, name, (Boolean *)NULL);
916 DEBUGF(DIR, ("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), name));
912 DEBUGF(DIR, ("got it (in mtime cache)\n"));
913 return (estrdup(name));
914 } else if (stat (name, &stb) == 0) {
915 entry = Hash_CreateEntry(&mtimes, name, (Boolean *)NULL);
916 DEBUGF(DIR, ("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), name));
917 Hash_SetValue(entry, (long)stb.st_mtime);
917 Hash_SetValue(entry, (void *)(long)stb.st_mtime);
918 return (estrdup(name));
919 } else {
920 DEBUGF(DIR, ("failed. Returning NULL\n"));
918 return (estrdup(name));
919 } else {
920 DEBUGF(DIR, ("failed. Returning NULL\n"));
921 return ((char *)NULL);
921 return (NULL);
922 }
923#endif /* notdef */
924}
925
926/*-
927 *-----------------------------------------------------------------------
928 * Dir_MTime --
929 * Find the modification time of the file described by gn along the
930 * search path dirSearchPath.
931 *
932 * Results:
933 * The modification time or 0 if it doesn't exist
934 *
935 * Side Effects:
936 * The modification time is placed in the node's mtime slot.
937 * If the node didn't have a path entry before, and Dir_FindFile
938 * found one for it, the full name is placed in the path slot.
939 *-----------------------------------------------------------------------
940 */
941int
942Dir_MTime(GNode *gn)
943{
944 char *fullName; /* the full pathname of name */
945 struct stat stb; /* buffer for finding the mod time */
946 Hash_Entry *entry;
947
948 if (gn->type & OP_ARCHV) {
949 return (Arch_MTime(gn));
922 }
923#endif /* notdef */
924}
925
926/*-
927 *-----------------------------------------------------------------------
928 * Dir_MTime --
929 * Find the modification time of the file described by gn along the
930 * search path dirSearchPath.
931 *
932 * Results:
933 * The modification time or 0 if it doesn't exist
934 *
935 * Side Effects:
936 * The modification time is placed in the node's mtime slot.
937 * If the node didn't have a path entry before, and Dir_FindFile
938 * found one for it, the full name is placed in the path slot.
939 *-----------------------------------------------------------------------
940 */
941int
942Dir_MTime(GNode *gn)
943{
944 char *fullName; /* the full pathname of name */
945 struct stat stb; /* buffer for finding the mod time */
946 Hash_Entry *entry;
947
948 if (gn->type & OP_ARCHV) {
949 return (Arch_MTime(gn));
950 } else if (gn->path == (char *)NULL) {
950 } else if (gn->path == NULL) {
951 fullName = Dir_FindFile(gn->name, dirSearchPath);
952 } else {
953 fullName = gn->path;
954 }
955
951 fullName = Dir_FindFile(gn->name, dirSearchPath);
952 } else {
953 fullName = gn->path;
954 }
955
956 if (fullName == (char *)NULL) {
956 if (fullName == NULL) {
957 fullName = estrdup(gn->name);
958 }
959
960 entry = Hash_FindEntry(&mtimes, fullName);
957 fullName = estrdup(gn->name);
958 }
959
960 entry = Hash_FindEntry(&mtimes, fullName);
961 if (entry != (Hash_Entry *)NULL) {
961 if (entry != NULL) {
962 /*
963 * Only do this once -- the second time folks are checking to
964 * see if the file was actually updated, so we need to actually go
965 * to the filesystem.
966 */
967 DEBUGF(DIR, ("Using cached time %s for %s\n",
968 Targ_FmtTime((time_t)(long)Hash_GetValue(entry)), fullName));
969 stb.st_mtime = (time_t)(long)Hash_GetValue(entry);
970 Hash_DeleteEntry(&mtimes, entry);
971 } else if (stat(fullName, &stb) < 0) {
972 if (gn->type & OP_MEMBER) {
973 if (fullName != gn->path)
974 free(fullName);
975 return (Arch_MemMTime(gn));
976 } else {
977 stb.st_mtime = 0;
978 }
979 }
980 if (fullName && gn->path == (char *)NULL) {
981 gn->path = fullName;
982 }
983
984 gn->mtime = stb.st_mtime;
985 return (gn->mtime);
986}
987
988/*-
989 *-----------------------------------------------------------------------
990 * Dir_AddDir --
991 * Add the given name to the end of the given path. The order of
992 * the arguments is backwards so ParseDoDependency can do a
993 * Lst_ForEach of its list of paths...
994 *
995 * Results:
996 * none
997 *
998 * Side Effects:
999 * A structure is added to the list and the directory is
1000 * read and hashed.
1001 *-----------------------------------------------------------------------
1002 */
1003void
1004Dir_AddDir(Lst path, char *name)
1005{
1006 LstNode ln; /* node in case Path structure is found */
1007 Path *p; /* pointer to new Path structure */
1008 DIR *d; /* for reading directory */
1009 struct dirent *dp; /* entry in directory */
1010
962 /*
963 * Only do this once -- the second time folks are checking to
964 * see if the file was actually updated, so we need to actually go
965 * to the filesystem.
966 */
967 DEBUGF(DIR, ("Using cached time %s for %s\n",
968 Targ_FmtTime((time_t)(long)Hash_GetValue(entry)), fullName));
969 stb.st_mtime = (time_t)(long)Hash_GetValue(entry);
970 Hash_DeleteEntry(&mtimes, entry);
971 } else if (stat(fullName, &stb) < 0) {
972 if (gn->type & OP_MEMBER) {
973 if (fullName != gn->path)
974 free(fullName);
975 return (Arch_MemMTime(gn));
976 } else {
977 stb.st_mtime = 0;
978 }
979 }
980 if (fullName && gn->path == (char *)NULL) {
981 gn->path = fullName;
982 }
983
984 gn->mtime = stb.st_mtime;
985 return (gn->mtime);
986}
987
988/*-
989 *-----------------------------------------------------------------------
990 * Dir_AddDir --
991 * Add the given name to the end of the given path. The order of
992 * the arguments is backwards so ParseDoDependency can do a
993 * Lst_ForEach of its list of paths...
994 *
995 * Results:
996 * none
997 *
998 * Side Effects:
999 * A structure is added to the list and the directory is
1000 * read and hashed.
1001 *-----------------------------------------------------------------------
1002 */
1003void
1004Dir_AddDir(Lst path, char *name)
1005{
1006 LstNode ln; /* node in case Path structure is found */
1007 Path *p; /* pointer to new Path structure */
1008 DIR *d; /* for reading directory */
1009 struct dirent *dp; /* entry in directory */
1010
1011 ln = Lst_Find(openDirectories, (void *)name, DirFindName);
1011 ln = Lst_Find(openDirectories, name, DirFindName);
1012 if (ln != NULL) {
1012 if (ln != NULL) {
1013 p = (Path *)Lst_Datum(ln);
1014 if (Lst_Member(path, (void *)p) == NULL) {
1013 p = Lst_Datum(ln);
1014 if (Lst_Member(path, p) == NULL) {
1015 p->refCount += 1;
1015 p->refCount += 1;
1016 Lst_AtEnd(path, (void *)p);
1016 Lst_AtEnd(path, p);
1017 }
1018 } else {
1019 DEBUGF(DIR, ("Caching %s...", name));
1020
1021 if ((d = opendir(name)) != (DIR *)NULL) {
1017 }
1018 } else {
1019 DEBUGF(DIR, ("Caching %s...", name));
1020
1021 if ((d = opendir(name)) != (DIR *)NULL) {
1022 p = (Path *) emalloc(sizeof(Path));
1022 p = emalloc(sizeof(Path));
1023 p->name = estrdup(name);
1024 p->hits = 0;
1025 p->refCount = 1;
1026 Hash_InitTable(&p->files, -1);
1027
1023 p->name = estrdup(name);
1024 p->hits = 0;
1025 p->refCount = 1;
1026 Hash_InitTable(&p->files, -1);
1027
1028 while ((dp = readdir(d)) != (struct dirent *)NULL) {
1028 while ((dp = readdir(d)) != NULL) {
1029#if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */
1030 /*
1031 * The sun directory library doesn't check for a 0 inode
1032 * (0-inode slots just take up space), so we have to do
1033 * it ourselves.
1034 */
1035 if (dp->d_fileno == 0) {
1036 continue;
1037 }
1038#endif /* sun && d_ino */
1039
1040 /* Skip the '.' and '..' entries by checking for them
1041 * specifically instead of assuming readdir() reuturns them in
1042 * that order when first going through a directory. This is
1043 * needed for XFS over NFS filesystems since SGI does not
1044 * guarantee that these are the first two entries returned
1045 * from readdir().
1046 */
1047 if (ISDOT(dp->d_name) || ISDOTDOT(dp->d_name))
1048 continue;
1049
1050 Hash_CreateEntry(&p->files, dp->d_name, (Boolean *)NULL);
1051 }
1052 closedir(d);
1029#if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */
1030 /*
1031 * The sun directory library doesn't check for a 0 inode
1032 * (0-inode slots just take up space), so we have to do
1033 * it ourselves.
1034 */
1035 if (dp->d_fileno == 0) {
1036 continue;
1037 }
1038#endif /* sun && d_ino */
1039
1040 /* Skip the '.' and '..' entries by checking for them
1041 * specifically instead of assuming readdir() reuturns them in
1042 * that order when first going through a directory. This is
1043 * needed for XFS over NFS filesystems since SGI does not
1044 * guarantee that these are the first two entries returned
1045 * from readdir().
1046 */
1047 if (ISDOT(dp->d_name) || ISDOTDOT(dp->d_name))
1048 continue;
1049
1050 Hash_CreateEntry(&p->files, dp->d_name, (Boolean *)NULL);
1051 }
1052 closedir(d);
1053 Lst_AtEnd(openDirectories, (void *)p);
1053 Lst_AtEnd(openDirectories, p);
1054 if (path != openDirectories)
1054 if (path != openDirectories)
1055 Lst_AtEnd(path, (void *)p);
1055 Lst_AtEnd(path, p);
1056 }
1057 DEBUGF(DIR, ("done\n"));
1058 }
1059}
1060
1061/*-
1062 *-----------------------------------------------------------------------
1063 * Dir_CopyDir --
1064 * Callback function for duplicating a search path via Lst_Duplicate.
1065 * Ups the reference count for the directory.
1066 *
1067 * Results:
1068 * Returns the Path it was given.
1069 *
1070 * Side Effects:
1071 * The refCount of the path is incremented.
1072 *
1073 *-----------------------------------------------------------------------
1074 */
1075void *
1076Dir_CopyDir(void *p)
1077{
1078
1079 ((Path *)p)->refCount += 1;
1080
1056 }
1057 DEBUGF(DIR, ("done\n"));
1058 }
1059}
1060
1061/*-
1062 *-----------------------------------------------------------------------
1063 * Dir_CopyDir --
1064 * Callback function for duplicating a search path via Lst_Duplicate.
1065 * Ups the reference count for the directory.
1066 *
1067 * Results:
1068 * Returns the Path it was given.
1069 *
1070 * Side Effects:
1071 * The refCount of the path is incremented.
1072 *
1073 *-----------------------------------------------------------------------
1074 */
1075void *
1076Dir_CopyDir(void *p)
1077{
1078
1079 ((Path *)p)->refCount += 1;
1080
1081 return ((void *)p);
1081 return (p);
1082}
1083
1084/*-
1085 *-----------------------------------------------------------------------
1086 * Dir_MakeFlags --
1087 * Make a string by taking all the directories in the given search
1088 * path and preceding them by the given flag. Used by the suffix
1089 * module to create variables for compilers based on suffix search
1090 * paths.
1091 *
1092 * Results:
1093 * The string mentioned above. Note that there is no space between
1094 * the given flag and each directory. The empty string is returned if
1095 * Things don't go well.
1096 *
1097 * Side Effects:
1098 * None
1099 *-----------------------------------------------------------------------
1100 */
1101char *
1102Dir_MakeFlags(char *flag, Lst path)
1103{
1104 char *str; /* the string which will be returned */
1105 char *tstr; /* the current directory preceded by 'flag' */
1106 LstNode ln; /* the node of the current directory */
1107 Path *p; /* the structure describing the current directory */
1108
1109 str = estrdup("");
1110
1111 if (Lst_Open(path) == SUCCESS) {
1112 while ((ln = Lst_Next(path)) != NULL) {
1082}
1083
1084/*-
1085 *-----------------------------------------------------------------------
1086 * Dir_MakeFlags --
1087 * Make a string by taking all the directories in the given search
1088 * path and preceding them by the given flag. Used by the suffix
1089 * module to create variables for compilers based on suffix search
1090 * paths.
1091 *
1092 * Results:
1093 * The string mentioned above. Note that there is no space between
1094 * the given flag and each directory. The empty string is returned if
1095 * Things don't go well.
1096 *
1097 * Side Effects:
1098 * None
1099 *-----------------------------------------------------------------------
1100 */
1101char *
1102Dir_MakeFlags(char *flag, Lst path)
1103{
1104 char *str; /* the string which will be returned */
1105 char *tstr; /* the current directory preceded by 'flag' */
1106 LstNode ln; /* the node of the current directory */
1107 Path *p; /* the structure describing the current directory */
1108
1109 str = estrdup("");
1110
1111 if (Lst_Open(path) == SUCCESS) {
1112 while ((ln = Lst_Next(path)) != NULL) {
1113 p = (Path *)Lst_Datum(ln);
1113 p = Lst_Datum(ln);
1114 tstr = str_concat(flag, p->name, 0);
1115 str = str_concat(str, tstr, STR_ADDSPACE | STR_DOFREE);
1116 }
1117 Lst_Close(path);
1118 }
1119
1120 return (str);
1121}
1122
1123/*-
1124 *-----------------------------------------------------------------------
1125 * Dir_Destroy --
1126 * Nuke a directory descriptor, if possible. Callback procedure
1127 * for the suffixes module when destroying a search path.
1128 *
1129 * Results:
1130 * None.
1131 *
1132 * Side Effects:
1133 * If no other path references this directory (refCount == 0),
1134 * the Path and all its data are freed.
1135 *
1136 *-----------------------------------------------------------------------
1137 */
1138void
1139Dir_Destroy(void *pp)
1140{
1114 tstr = str_concat(flag, p->name, 0);
1115 str = str_concat(str, tstr, STR_ADDSPACE | STR_DOFREE);
1116 }
1117 Lst_Close(path);
1118 }
1119
1120 return (str);
1121}
1122
1123/*-
1124 *-----------------------------------------------------------------------
1125 * Dir_Destroy --
1126 * Nuke a directory descriptor, if possible. Callback procedure
1127 * for the suffixes module when destroying a search path.
1128 *
1129 * Results:
1130 * None.
1131 *
1132 * Side Effects:
1133 * If no other path references this directory (refCount == 0),
1134 * the Path and all its data are freed.
1135 *
1136 *-----------------------------------------------------------------------
1137 */
1138void
1139Dir_Destroy(void *pp)
1140{
1141 Path *p = (Path *)pp;
1141 Path *p = pp;
1142
1142 p->refCount -= 1;
1143
1144 if (p->refCount == 0) {
1145 LstNode ln;
1146
1143 p->refCount -= 1;
1144
1145 if (p->refCount == 0) {
1146 LstNode ln;
1147
1147 ln = Lst_Member(openDirectories, (void *)p);
1148 ln = Lst_Member(openDirectories, p);
1148 Lst_Remove(openDirectories, ln);
1149
1150 Hash_DeleteTable(&p->files);
1151 free(p->name);
1152 free(p);
1153 }
1154}
1155
1156/*-
1157 *-----------------------------------------------------------------------
1158 * Dir_ClearPath --
1159 * Clear out all elements of the given search path. This is different
1160 * from destroying the list, notice.
1161 *
1162 * Results:
1163 * None.
1164 *
1165 * Side Effects:
1166 * The path is set to the empty list.
1167 *
1168 *-----------------------------------------------------------------------
1169 */
1170void
1171Dir_ClearPath(Lst path)
1172{
1173 Path *p;
1174
1175 while (!Lst_IsEmpty(path)) {
1149 Lst_Remove(openDirectories, ln);
1150
1151 Hash_DeleteTable(&p->files);
1152 free(p->name);
1153 free(p);
1154 }
1155}
1156
1157/*-
1158 *-----------------------------------------------------------------------
1159 * Dir_ClearPath --
1160 * Clear out all elements of the given search path. This is different
1161 * from destroying the list, notice.
1162 *
1163 * Results:
1164 * None.
1165 *
1166 * Side Effects:
1167 * The path is set to the empty list.
1168 *
1169 *-----------------------------------------------------------------------
1170 */
1171void
1172Dir_ClearPath(Lst path)
1173{
1174 Path *p;
1175
1176 while (!Lst_IsEmpty(path)) {
1176 p = (Path *)Lst_DeQueue(path);
1177 Dir_Destroy((void *) p);
1177 p = Lst_DeQueue(path);
1178 Dir_Destroy(p);
1178 }
1179}
1180
1181
1182/*-
1183 *-----------------------------------------------------------------------
1184 * Dir_Concat --
1185 * Concatenate two paths, adding the second to the end of the first.
1186 * Makes sure to avoid duplicates.
1187 *
1188 * Results:
1189 * None
1190 *
1191 * Side Effects:
1192 * Reference counts for added dirs are upped.
1193 *
1194 *-----------------------------------------------------------------------
1195 */
1196void
1197Dir_Concat(Lst path1, Lst path2)
1198{
1199 LstNode ln;
1200 Path *p;
1201
1202 for (ln = Lst_First(path2); ln != NULL; ln = Lst_Succ(ln)) {
1179 }
1180}
1181
1182
1183/*-
1184 *-----------------------------------------------------------------------
1185 * Dir_Concat --
1186 * Concatenate two paths, adding the second to the end of the first.
1187 * Makes sure to avoid duplicates.
1188 *
1189 * Results:
1190 * None
1191 *
1192 * Side Effects:
1193 * Reference counts for added dirs are upped.
1194 *
1195 *-----------------------------------------------------------------------
1196 */
1197void
1198Dir_Concat(Lst path1, Lst path2)
1199{
1200 LstNode ln;
1201 Path *p;
1202
1203 for (ln = Lst_First(path2); ln != NULL; ln = Lst_Succ(ln)) {
1203 p = (Path *)Lst_Datum(ln);
1204 if (Lst_Member(path1, (void *)p) == NULL) {
1204 p = Lst_Datum(ln);
1205 if (Lst_Member(path1, p) == NULL) {
1205 p->refCount += 1;
1206 p->refCount += 1;
1206 Lst_AtEnd(path1, (void *)p);
1207 Lst_AtEnd(path1, p);
1207 }
1208 }
1209}
1210
1211/********** DEBUG INFO **********/
1212void
1213Dir_PrintDirectories(void)
1214{
1215 LstNode ln;
1216 Path *p;
1217
1218 printf("#*** Directory Cache:\n");
1219 printf("# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n",
1220 hits, misses, nearmisses, bigmisses,
1221 (hits + bigmisses + nearmisses ?
1222 hits * 100 / (hits + bigmisses + nearmisses) : 0));
1223 printf("# %-20s referenced\thits\n", "directory");
1224 if (Lst_Open(openDirectories) == SUCCESS) {
1225 while ((ln = Lst_Next(openDirectories)) != NULL) {
1208 }
1209 }
1210}
1211
1212/********** DEBUG INFO **********/
1213void
1214Dir_PrintDirectories(void)
1215{
1216 LstNode ln;
1217 Path *p;
1218
1219 printf("#*** Directory Cache:\n");
1220 printf("# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n",
1221 hits, misses, nearmisses, bigmisses,
1222 (hits + bigmisses + nearmisses ?
1223 hits * 100 / (hits + bigmisses + nearmisses) : 0));
1224 printf("# %-20s referenced\thits\n", "directory");
1225 if (Lst_Open(openDirectories) == SUCCESS) {
1226 while ((ln = Lst_Next(openDirectories)) != NULL) {
1226 p = (Path *)Lst_Datum(ln);
1227 p = Lst_Datum(ln);
1227 printf("# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits);
1228 }
1229 Lst_Close(openDirectories);
1230 }
1231}
1232
1233static int
1234DirPrintDir(void *p, void *dummy __unused)
1235{
1236
1237 printf("%s ", ((Path *)p)->name);
1238
1239 return (0);
1240}
1241
1242void
1243Dir_PrintPath(Lst path)
1244{
1245
1228 printf("# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits);
1229 }
1230 Lst_Close(openDirectories);
1231 }
1232}
1233
1234static int
1235DirPrintDir(void *p, void *dummy __unused)
1236{
1237
1238 printf("%s ", ((Path *)p)->name);
1239
1240 return (0);
1241}
1242
1243void
1244Dir_PrintPath(Lst path)
1245{
1246
1246 Lst_ForEach(path, DirPrintDir, (void *)0);
1247 Lst_ForEach(path, DirPrintDir, (void *)NULL);
1247}
1248}