| @@ -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 |
73 | static char rcsid[] = "$NetBSD: dir.c,v 1.129 2020/09/01 20:17:18 rillig Exp $"; | | 73 | static 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 |
78 | static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94"; | | 78 | static 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 | |
230 | Lst dirSearchPath; /* main search path */ | | 230 | Lst dirSearchPath; /* main search path */ |
231 | | | 231 | |
232 | static Lst openDirectories; /* the list of all open directories */ | | 232 | static 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 | */ |
238 | static int hits; /* Found in directory cache */ | | 238 | static int hits; /* Found in directory cache */ |
239 | static int misses; /* Sad, but not evil misses */ | | 239 | static int misses; /* Sad, but not evil misses */ |
240 | static int nearmisses; /* Found under search path */ | | 240 | static int nearmisses; /* Found under search path */ |
241 | static int bigmisses; /* Sought by itself */ | | 241 | static int bigmisses; /* Sought by itself */ |
242 | | | 242 | |
243 | static Path *dot; /* contents of current directory */ | | 243 | static Path *dot; /* contents of current directory */ |
244 | static Path *cur; /* contents of current directory, if not dot */ | | 244 | static Path *cur; /* contents of current directory, if not dot */ |
245 | static Path *dotLast; /* a fake path entry indicating we need to | | 245 | static 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... */ |
255 | static Hash_Table mtimes; | | 255 | static Hash_Table mtimes; |
256 | | | 256 | |
257 | static Hash_Table lmtimes; /* same as mtimes but for lstat */ | | 257 | static Hash_Table lmtimes; /* same as mtimes but for lstat */ |
258 | | | 258 | |
259 | static void DirExpandCurly(const char *, const char *, Lst, Lst); | | 259 | static void DirExpandCurly(const char *, const char *, Lst, Lst); |
260 | static void DirExpandInt(const char *, Lst, Lst); | | 260 | static void DirExpandInt(const char *, Lst, Lst); |
261 | static int DirPrintWord(void *, void *); | | 261 | static int DirPrintWord(void *, void *); |
262 | static int DirPrintDir(void *, void *); | | 262 | static int DirPrintDir(void *, void *); |
263 | static char *DirLookup(Path *, const char *, const char *, Boolean); | | 263 | static char *DirLookup(Path *, const char *, const char *, Boolean); |
264 | static char *DirLookupSubdir(Path *, const char *); | | 264 | static char *DirLookupSubdir(Path *, const char *); |
265 | static char *DirFindDot(Boolean, const char *, const char *); | | 265 | static char *DirFindDot(Boolean, const char *, const char *); |
266 | static char *DirLookupAbs(Path *, const char *, const char *); | | 266 | static 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 | */ |
273 | struct cache_st { | | 273 | struct 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 */ |
280 | typedef enum { | | 280 | typedef 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. */ |
287 | static int | | 287 | static int |
288 | cached_stats(Hash_Table *htp, const char *pathname, struct stat *st, | | 288 | cached_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 | |
339 | int | | 339 | int |
340 | cached_stat(const char *pathname, void *st) | | 340 | cached_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 | |
345 | int | | 345 | int |
346 | cached_lstat(const char *pathname, void *st) | | 346 | cached_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. */ |
352 | void | | 352 | void |
353 | Dir_Init(void) | | 353 | Dir_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 | |
361 | void | | 361 | void |
362 | Dir_InitDir(const char *cdname) | | 362 | Dir_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 | */ |
376 | void | | 376 | void |
377 | Dir_InitCur(const char *cdname) | | 377 | Dir_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. */ |
402 | void | | 402 | void |
403 | Dir_InitDot(void) | | 403 | Dir_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. */ |
429 | void | | 429 | void |
430 | Dir_End(void) | | 430 | Dir_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 | */ |
454 | void | | 454 | void |
455 | Dir_SetPATH(void) | | 455 | Dir_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. */ |
500 | static Boolean | | 500 | static Boolean |
501 | DirFindName(const void *p, const void *desiredName) | | 501 | DirFindName(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 | */ |
519 | Boolean | | 519 | Boolean |
520 | Dir_HasWildcards(const char *name) | | 520 | Dir_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 | */ |
572 | static void | | 572 | static void |
573 | DirMatchFiles(const char *pattern, Path *p, Lst expansions) | | 573 | DirMatchFiles(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. */ |
604 | static const char * | | 604 | static const char * |
605 | closing_brace(const char *p) | | 605 | closing_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. */ |
622 | static const char * | | 622 | static const char * |
623 | separator_comma(const char *p) | | 623 | separator_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 | |
638 | static Boolean | | 638 | static Boolean |
639 | contains_wildcard(const char *p) | | 639 | contains_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 | |
653 | static char * | | 653 | static char * |
654 | concat3(const char *a, size_t a_len, const char *b, size_t b_len, | | 654 | concat3(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 | */ |
688 | static void | | 688 | static void |
689 | DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions) | | 689 | DirExpandCurly(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 | */ |
750 | static void | | 750 | static void |
751 | DirExpandInt(const char *word, Lst path, Lst expansions) | | 751 | DirExpandInt(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. */ |
765 | static int | | 765 | static int |
766 | DirPrintWord(void *word, void *dummy MAKE_ATTR_UNUSED) | | 766 | DirPrintWord(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 | */ |
794 | void | | 794 | void |
795 | Dir_Expand(const char *word, Lst path, Lst expansions) | | 795 | Dir_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 | */ |
902 | static char * | | 902 | static char * |
903 | DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp, | | 903 | DirLookup(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 | */ |
935 | static char * | | 935 | static char * |
936 | DirLookupSubdir(Path *p, const char *name) | | 936 | DirLookupSubdir(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 | */ |
975 | static char * | | 975 | static char * |
976 | DirLookupAbs(Path *p, const char *name, const char *cp) | | 976 | DirLookupAbs(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 | */ |
1021 | static char * | | 1021 | static char * |
1022 | DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp) | | 1022 | DirFindDot(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 | */ |
1063 | char * | | 1063 | char * |
1064 | Dir_FindFile(const char *name, Lst path) | | 1064 | Dir_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 | /*- |