1 1.297 rillig /* $NetBSD: dir.c,v 1.297 2025/06/12 18:51:05 rillig Exp $ */ 2 1.8 christos 3 1.1 cgd /* 4 1.1 cgd * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 5 1.37 agc * All rights reserved. 6 1.37 agc * 7 1.37 agc * This code is derived from software contributed to Berkeley by 8 1.37 agc * Adam de Boor. 9 1.37 agc * 10 1.37 agc * Redistribution and use in source and binary forms, with or without 11 1.37 agc * modification, are permitted provided that the following conditions 12 1.37 agc * are met: 13 1.37 agc * 1. Redistributions of source code must retain the above copyright 14 1.37 agc * notice, this list of conditions and the following disclaimer. 15 1.37 agc * 2. Redistributions in binary form must reproduce the above copyright 16 1.37 agc * notice, this list of conditions and the following disclaimer in the 17 1.37 agc * documentation and/or other materials provided with the distribution. 18 1.37 agc * 3. Neither the name of the University nor the names of its contributors 19 1.37 agc * may be used to endorse or promote products derived from this software 20 1.37 agc * without specific prior written permission. 21 1.37 agc * 22 1.37 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.37 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.37 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.37 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.37 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.37 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.37 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.37 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.37 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.37 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.37 agc * SUCH DAMAGE. 33 1.37 agc */ 34 1.37 agc 35 1.37 agc /* 36 1.1 cgd * Copyright (c) 1988, 1989 by Adam de Boor 37 1.1 cgd * Copyright (c) 1989 by Berkeley Softworks 38 1.1 cgd * All rights reserved. 39 1.1 cgd * 40 1.1 cgd * This code is derived from software contributed to Berkeley by 41 1.1 cgd * Adam de Boor. 42 1.1 cgd * 43 1.1 cgd * Redistribution and use in source and binary forms, with or without 44 1.1 cgd * modification, are permitted provided that the following conditions 45 1.1 cgd * are met: 46 1.1 cgd * 1. Redistributions of source code must retain the above copyright 47 1.1 cgd * notice, this list of conditions and the following disclaimer. 48 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 49 1.1 cgd * notice, this list of conditions and the following disclaimer in the 50 1.1 cgd * documentation and/or other materials provided with the distribution. 51 1.1 cgd * 3. All advertising materials mentioning features or use of this software 52 1.1 cgd * must display the following acknowledgement: 53 1.1 cgd * This product includes software developed by the University of 54 1.1 cgd * California, Berkeley and its contributors. 55 1.1 cgd * 4. Neither the name of the University nor the names of its contributors 56 1.1 cgd * may be used to endorse or promote products derived from this software 57 1.1 cgd * without specific prior written permission. 58 1.1 cgd * 59 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 1.1 cgd * SUCH DAMAGE. 70 1.1 cgd */ 71 1.1 cgd 72 1.254 rillig /* 73 1.254 rillig * Directory searching using wildcards and/or normal names. 74 1.191 rillig * Used both for source wildcarding in the makefile and for finding 75 1.191 rillig * implicit sources. 76 1.1 cgd * 77 1.1 cgd * The interface for this module is: 78 1.149 rillig * Dir_Init Initialize the module. 79 1.1 cgd * 80 1.149 rillig * Dir_InitCur Set the cur CachedDir. 81 1.35 sjg * 82 1.149 rillig * Dir_InitDot Set the dot CachedDir. 83 1.35 sjg * 84 1.163 rillig * Dir_End Clean up the module. 85 1.6 jtc * 86 1.283 rillig * Dir_SetPATH Set ${.PATH} to reflect the state of dirSearchPath. 87 1.35 sjg * 88 1.149 rillig * Dir_HasWildcards 89 1.271 rillig * Returns true if the name given it needs to 90 1.149 rillig * be wildcard-expanded. 91 1.1 cgd * 92 1.256 rillig * SearchPath_Expand 93 1.256 rillig * Expand a filename pattern to find all matching files 94 1.256 rillig * from the search path. 95 1.1 cgd * 96 1.149 rillig * Dir_FindFile Searches for a file on a given search path. 97 1.283 rillig * If it exists, returns the entire path, otherwise NULL. 98 1.1 cgd * 99 1.149 rillig * Dir_FindHereOrAbove 100 1.283 rillig * Search for a path in the current directory and then 101 1.283 rillig * all the directories above it in turn, until the path 102 1.283 rillig * is found or the root directory ("/") is reached. 103 1.76 rillig * 104 1.201 rillig * Dir_UpdateMTime 105 1.201 rillig * Update the modification time and path of a node with 106 1.201 rillig * data from the file corresponding to the node. 107 1.1 cgd * 108 1.260 rillig * SearchPath_Add Add a directory to a search path. 109 1.1 cgd * 110 1.224 rillig * SearchPath_ToFlags 111 1.224 rillig * Given a search path and a command flag, create 112 1.149 rillig * a string with each of the directories in the path 113 1.149 rillig * preceded by the command flag and all of them 114 1.149 rillig * separated by a space. 115 1.1 cgd * 116 1.224 rillig * SearchPath_Clear 117 1.224 rillig * Resets a search path to the empty list. 118 1.1 cgd * 119 1.1 cgd * For debugging: 120 1.191 rillig * Dir_PrintDirectories 121 1.191 rillig * Print stats about the directory cache. 122 1.1 cgd */ 123 1.1 cgd 124 1.1 cgd #include <sys/types.h> 125 1.34 wiz #include <sys/stat.h> 126 1.34 wiz 127 1.5 cgd #include <dirent.h> 128 1.34 wiz #include <errno.h> 129 1.34 wiz 130 1.1 cgd #include "make.h" 131 1.5 cgd #include "dir.h" 132 1.67 christos #include "job.h" 133 1.1 cgd 134 1.142 rillig /* "@(#)dir.c 8.2 (Berkeley) 1/2/94" */ 135 1.297 rillig MAKE_RCSID("$NetBSD: dir.c,v 1.297 2025/06/12 18:51:05 rillig Exp $"); 136 1.92 rillig 137 1.254 rillig /* 138 1.254 rillig * A search path is a list of CachedDir structures. A CachedDir has in it the 139 1.191 rillig * name of the directory and the names of all the files in the directory. 140 1.191 rillig * This is used to cut down on the number of system calls necessary to find 141 1.191 rillig * implicit dependents and their like. Since these searches are made before 142 1.191 rillig * any actions are taken, we need not worry about the directory changing due 143 1.191 rillig * to creation commands. If this hampers the style of some makefiles, they 144 1.191 rillig * must be changed. 145 1.191 rillig * 146 1.191 rillig * All previously-read directories are kept in openDirs, which is checked 147 1.191 rillig * first before a directory is opened. 148 1.191 rillig * 149 1.283 rillig * This cache is used by the multi-level transformation code in suff.c, which 150 1.283 rillig * tends to search for far more files than in regular explicit targets. After 151 1.283 rillig * a directory has been cached, any later changes to that directory are not 152 1.283 rillig * reflected in the cache. To keep the cache up to date, there are several 153 1.283 rillig * ideas: 154 1.191 rillig * 155 1.191 rillig * 1) just use stat to test for a file's existence. As mentioned above, 156 1.283 rillig * this is very inefficient due to the number of checks performed by 157 1.191 rillig * the multi-level transformation code. 158 1.191 rillig * 159 1.283 rillig * 2) use readdir() to search the directories, keeping them open between 160 1.283 rillig * checks. Around 1993 or earlier, this didn't slow down the process too 161 1.283 rillig * much, but it consumed one file descriptor per open directory, which 162 1.283 rillig * was critical on the then-current operating systems, as many limited 163 1.283 rillig * the number of open file descriptors to 20 or 32. 164 1.191 rillig * 165 1.191 rillig * 3) record the mtime of the directory in the CachedDir structure and 166 1.191 rillig * verify the directory hasn't changed since the contents were cached. 167 1.191 rillig * This will catch the creation or deletion of files, but not the 168 1.191 rillig * updating of files. However, since it is the creation and deletion 169 1.191 rillig * that is the problem, this could be a good thing to do. Unfortunately, 170 1.191 rillig * if the directory (say ".") were fairly large and changed fairly 171 1.191 rillig * frequently, the constant reloading could seriously degrade 172 1.191 rillig * performance. It might be good in such cases to keep track of the 173 1.191 rillig * number of reloadings and if the number goes over a (small) limit, 174 1.191 rillig * resort to using stat in its place. 175 1.191 rillig * 176 1.283 rillig * An additional thing to consider is that make is used primarily to create 177 1.283 rillig * C programs and until recently (as of 1993 or earlier), pcc-based compilers 178 1.283 rillig * didn't have an option to specify where the resulting object file should be 179 1.205 rillig * placed. This forced all objects to be created in the current directory. 180 1.205 rillig * This isn't meant as a full excuse, just an explanation of some of the 181 1.205 rillig * reasons for the caching used here. 182 1.191 rillig * 183 1.191 rillig * One more note: the location of a target's file is only performed on the 184 1.191 rillig * downward traversal of the graph and then only for terminal nodes in the 185 1.191 rillig * graph. This could be construed as wrong in some cases, but prevents 186 1.191 rillig * inadvertent modification of files when the "installed" directory for a 187 1.191 rillig * file is provided in the search path. 188 1.191 rillig * 189 1.191 rillig * Another data structure maintained by this module is an mtime cache used 190 1.191 rillig * when the searching of cached directories fails to find a file. In the past, 191 1.191 rillig * Dir_FindFile would simply perform an access() call in such a case to 192 1.191 rillig * determine if the file could be found using just the name given. When this 193 1.191 rillig * hit, however, all that was gained was the knowledge that the file existed. 194 1.191 rillig * Given that an access() is essentially a stat() without the copyout() call, 195 1.191 rillig * and that the same filesystem overhead would have to be incurred in 196 1.191 rillig * Dir_MTime, it made sense to replace the access() with a stat() and record 197 1.201 rillig * the mtime in a cache for when Dir_UpdateMTime was actually called. 198 1.1 cgd */ 199 1.1 cgd 200 1.144 rillig 201 1.229 rillig /* A cache for the filenames in a directory. */ 202 1.229 rillig struct CachedDir { 203 1.229 rillig /* 204 1.283 rillig * Name of the directory, either absolute or relative to the current 205 1.229 rillig * directory. The name is not normalized in any way, that is, "." 206 1.229 rillig * and "./." are different. 207 1.229 rillig * 208 1.229 rillig * Not sure what happens when .CURDIR is assigned a new value; see 209 1.272 rillig * Parse_Var. 210 1.229 rillig */ 211 1.229 rillig char *name; 212 1.229 rillig 213 1.229 rillig /* 214 1.233 rillig * The number of SearchPaths that refer to this directory. 215 1.233 rillig * Plus the number of global variables that refer to this directory. 216 1.234 rillig * References from openDirs do not count though. 217 1.229 rillig */ 218 1.229 rillig int refCount; 219 1.229 rillig 220 1.229 rillig /* The number of times a file in this directory has been found. */ 221 1.229 rillig int hits; 222 1.229 rillig 223 1.243 rillig /* The names of the directory entries. */ 224 1.229 rillig HashSet files; 225 1.229 rillig }; 226 1.229 rillig 227 1.232 rillig typedef List CachedDirList; 228 1.232 rillig typedef ListNode CachedDirListNode; 229 1.232 rillig 230 1.158 rillig /* A list of cached directories, with fast lookup by directory name. */ 231 1.158 rillig typedef struct OpenDirs { 232 1.227 rillig CachedDirList list; 233 1.212 rillig HashTable /* of CachedDirListNode */ table; 234 1.158 rillig } OpenDirs; 235 1.158 rillig 236 1.232 rillig 237 1.264 rillig SearchPath dirSearchPath = { LST_INIT }; /* main search path */ 238 1.232 rillig 239 1.232 rillig static OpenDirs openDirs; /* all cached directories */ 240 1.232 rillig 241 1.232 rillig /* 242 1.232 rillig * Variables for gathering statistics on the efficiency of the caching 243 1.232 rillig * mechanism. 244 1.232 rillig */ 245 1.232 rillig static int hits; /* Found in directory cache */ 246 1.232 rillig static int misses; /* Sad, but not evil misses */ 247 1.232 rillig static int nearmisses; /* Found under search path */ 248 1.232 rillig static int bigmisses; /* Sought by itself */ 249 1.232 rillig 250 1.244 rillig /* The cached contents of ".", the relative current directory. */ 251 1.244 rillig static CachedDir *dot = NULL; 252 1.244 rillig /* The cached contents of the absolute current directory. */ 253 1.244 rillig static CachedDir *cur = NULL; 254 1.240 rillig /* A fake path entry indicating we need to look for '.' last. */ 255 1.240 rillig static CachedDir *dotLast = NULL; 256 1.232 rillig 257 1.254 rillig /* 258 1.254 rillig * Results of doing a last-resort stat in Dir_FindFile -- if we have to go to 259 1.232 rillig * the system to find the file, we might as well have its mtime on record. 260 1.232 rillig * 261 1.232 rillig * XXX: If this is done way early, there's a chance other rules will have 262 1.232 rillig * already updated the file, in which case we'll update it again. Generally, 263 1.283 rillig * there won't be two rules to update a single file, so this should be ok. 264 1.254 rillig */ 265 1.232 rillig static HashTable mtimes; 266 1.232 rillig 267 1.232 rillig static HashTable lmtimes; /* same as mtimes but for lstat */ 268 1.232 rillig 269 1.232 rillig 270 1.238 rillig static void OpenDirs_Remove(OpenDirs *, const char *); 271 1.232 rillig 272 1.232 rillig 273 1.233 rillig static CachedDir * 274 1.233 rillig CachedDir_New(const char *name) 275 1.233 rillig { 276 1.233 rillig CachedDir *dir = bmake_malloc(sizeof *dir); 277 1.233 rillig 278 1.233 rillig dir->name = bmake_strdup(name); 279 1.233 rillig dir->refCount = 0; 280 1.233 rillig dir->hits = 0; 281 1.233 rillig HashSet_Init(&dir->files); 282 1.233 rillig 283 1.241 rillig #ifdef DEBUG_REFCNT 284 1.241 rillig DEBUG2(DIR, "CachedDir %p new for \"%s\"\n", dir, dir->name); 285 1.241 rillig #endif 286 1.241 rillig 287 1.233 rillig return dir; 288 1.233 rillig } 289 1.233 rillig 290 1.233 rillig static CachedDir * 291 1.233 rillig CachedDir_Ref(CachedDir *dir) 292 1.233 rillig { 293 1.233 rillig dir->refCount++; 294 1.241 rillig 295 1.241 rillig #ifdef DEBUG_REFCNT 296 1.241 rillig DEBUG3(DIR, "CachedDir %p ++ %d for \"%s\"\n", 297 1.241 rillig dir, dir->refCount, dir->name); 298 1.241 rillig #endif 299 1.241 rillig 300 1.233 rillig return dir; 301 1.233 rillig } 302 1.233 rillig 303 1.238 rillig static void 304 1.241 rillig CachedDir_Unref(CachedDir *dir) 305 1.238 rillig { 306 1.241 rillig dir->refCount--; 307 1.241 rillig 308 1.241 rillig #ifdef DEBUG_REFCNT 309 1.241 rillig DEBUG3(DIR, "CachedDir %p -- %d for \"%s\"\n", 310 1.241 rillig dir, dir->refCount, dir->name); 311 1.241 rillig #endif 312 1.241 rillig 313 1.241 rillig if (dir->refCount > 0) 314 1.241 rillig return; 315 1.241 rillig 316 1.241 rillig #ifdef DEBUG_REFCNT 317 1.241 rillig DEBUG2(DIR, "CachedDir %p free for \"%s\"\n", dir, dir->name); 318 1.241 rillig #endif 319 1.238 rillig 320 1.238 rillig OpenDirs_Remove(&openDirs, dir->name); 321 1.238 rillig 322 1.238 rillig free(dir->name); 323 1.238 rillig HashSet_Done(&dir->files); 324 1.238 rillig free(dir); 325 1.238 rillig } 326 1.238 rillig 327 1.283 rillig /* Update the value of 'var', updating the reference counts. */ 328 1.240 rillig static void 329 1.240 rillig CachedDir_Assign(CachedDir **var, CachedDir *dir) 330 1.240 rillig { 331 1.240 rillig CachedDir *prev; 332 1.240 rillig 333 1.240 rillig prev = *var; 334 1.240 rillig *var = dir; 335 1.240 rillig if (dir != NULL) 336 1.240 rillig CachedDir_Ref(dir); 337 1.240 rillig if (prev != NULL) 338 1.241 rillig CachedDir_Unref(prev); 339 1.240 rillig } 340 1.240 rillig 341 1.158 rillig static void 342 1.158 rillig OpenDirs_Init(OpenDirs *odirs) 343 1.158 rillig { 344 1.227 rillig Lst_Init(&odirs->list); 345 1.212 rillig HashTable_Init(&odirs->table); 346 1.158 rillig } 347 1.158 rillig 348 1.175 rillig #ifdef CLEANUP 349 1.175 rillig static void 350 1.158 rillig OpenDirs_Done(OpenDirs *odirs) 351 1.158 rillig { 352 1.227 rillig CachedDirListNode *ln = odirs->list.first; 353 1.250 rillig DEBUG1(DIR, "OpenDirs_Done: %u entries to remove\n", 354 1.236 rillig odirs->table.numEntries); 355 1.212 rillig while (ln != NULL) { 356 1.212 rillig CachedDirListNode *next = ln->next; 357 1.212 rillig CachedDir *dir = ln->datum; 358 1.250 rillig DEBUG2(DIR, "OpenDirs_Done: refCount %d for \"%s\"\n", 359 1.236 rillig dir->refCount, dir->name); 360 1.241 rillig CachedDir_Unref(dir); /* removes the dir from odirs->list */ 361 1.212 rillig ln = next; 362 1.212 rillig } 363 1.227 rillig Lst_Done(&odirs->list); 364 1.212 rillig HashTable_Done(&odirs->table); 365 1.158 rillig } 366 1.175 rillig #endif 367 1.158 rillig 368 1.158 rillig static CachedDir * 369 1.158 rillig OpenDirs_Find(OpenDirs *odirs, const char *name) 370 1.158 rillig { 371 1.212 rillig CachedDirListNode *ln = HashTable_FindValue(&odirs->table, name); 372 1.212 rillig return ln != NULL ? ln->datum : NULL; 373 1.158 rillig } 374 1.158 rillig 375 1.158 rillig static void 376 1.158 rillig OpenDirs_Add(OpenDirs *odirs, CachedDir *cdir) 377 1.158 rillig { 378 1.212 rillig if (HashTable_FindEntry(&odirs->table, cdir->name) != NULL) 379 1.212 rillig return; 380 1.227 rillig Lst_Append(&odirs->list, cdir); 381 1.227 rillig HashTable_Set(&odirs->table, cdir->name, odirs->list.last); 382 1.158 rillig } 383 1.158 rillig 384 1.158 rillig static void 385 1.158 rillig OpenDirs_Remove(OpenDirs *odirs, const char *name) 386 1.158 rillig { 387 1.212 rillig HashEntry *he = HashTable_FindEntry(&odirs->table, name); 388 1.212 rillig CachedDirListNode *ln; 389 1.212 rillig if (he == NULL) 390 1.212 rillig return; 391 1.212 rillig ln = HashEntry_Get(he); 392 1.212 rillig HashTable_DeleteEntry(&odirs->table, he); 393 1.227 rillig Lst_Remove(&odirs->list, ln); 394 1.158 rillig } 395 1.158 rillig 396 1.254 rillig /* 397 1.254 rillig * Returns 0 and the result of stat(2) or lstat(2) in *out_cst, 398 1.254 rillig * or -1 on error. 399 1.254 rillig */ 400 1.68 sjg static int 401 1.208 rillig cached_stats(const char *pathname, struct cached_stat *out_cst, 402 1.275 rillig bool useLstat, bool forceRefresh) 403 1.68 sjg { 404 1.275 rillig HashTable *tbl = useLstat ? &lmtimes : &mtimes; 405 1.212 rillig struct stat sys_st; 406 1.212 rillig struct cached_stat *cst; 407 1.212 rillig int rc; 408 1.68 sjg 409 1.212 rillig if (pathname == NULL || pathname[0] == '\0') 410 1.212 rillig return -1; /* This can happen in meta mode. */ 411 1.68 sjg 412 1.212 rillig cst = HashTable_FindValue(tbl, pathname); 413 1.275 rillig if (cst != NULL && !forceRefresh) { 414 1.212 rillig *out_cst = *cst; 415 1.250 rillig DEBUG2(DIR, "Using cached time %s for %s\n", 416 1.250 rillig Targ_FmtTime(cst->cst_mtime), pathname); 417 1.212 rillig return 0; 418 1.212 rillig } 419 1.212 rillig 420 1.275 rillig rc = (useLstat ? lstat : stat)(pathname, &sys_st); 421 1.212 rillig if (rc == -1) 422 1.212 rillig return -1; /* don't cache negative lookups */ 423 1.212 rillig 424 1.212 rillig if (sys_st.st_mtime == 0) 425 1.212 rillig sys_st.st_mtime = 1; /* avoid confusion with missing file */ 426 1.208 rillig 427 1.212 rillig if (cst == NULL) { 428 1.212 rillig cst = bmake_malloc(sizeof *cst); 429 1.212 rillig HashTable_Set(tbl, pathname, cst); 430 1.212 rillig } 431 1.208 rillig 432 1.212 rillig cst->cst_mtime = sys_st.st_mtime; 433 1.212 rillig cst->cst_mode = sys_st.st_mode; 434 1.208 rillig 435 1.212 rillig *out_cst = *cst; 436 1.250 rillig DEBUG2(DIR, " Caching %s for %s\n", 437 1.250 rillig Targ_FmtTime(sys_st.st_mtime), pathname); 438 1.68 sjg 439 1.212 rillig return 0; 440 1.68 sjg } 441 1.68 sjg 442 1.68 sjg int 443 1.208 rillig cached_stat(const char *pathname, struct cached_stat *cst) 444 1.68 sjg { 445 1.275 rillig return cached_stats(pathname, cst, false, false); 446 1.68 sjg } 447 1.68 sjg 448 1.68 sjg int 449 1.208 rillig cached_lstat(const char *pathname, struct cached_stat *cst) 450 1.68 sjg { 451 1.275 rillig return cached_stats(pathname, cst, true, false); 452 1.68 sjg } 453 1.68 sjg 454 1.163 rillig /* Initialize the directories module. */ 455 1.1 cgd void 456 1.97 rillig Dir_Init(void) 457 1.97 rillig { 458 1.212 rillig OpenDirs_Init(&openDirs); 459 1.212 rillig HashTable_Init(&mtimes); 460 1.212 rillig HashTable_Init(&lmtimes); 461 1.240 rillig CachedDir_Assign(&dotLast, CachedDir_New(".DOTLAST")); 462 1.35 sjg } 463 1.35 sjg 464 1.285 rillig /* Called by Dir_InitDir and whenever .CURDIR is assigned to. */ 465 1.35 sjg void 466 1.260 rillig Dir_InitCur(const char *newCurdir) 467 1.35 sjg { 468 1.212 rillig CachedDir *dir; 469 1.203 rillig 470 1.260 rillig if (newCurdir == NULL) 471 1.212 rillig return; 472 1.203 rillig 473 1.17 gwr /* 474 1.283 rillig * The build directory is not the same as the source directory. 475 1.212 rillig * Keep this one around too. 476 1.17 gwr */ 477 1.260 rillig dir = SearchPath_Add(NULL, newCurdir); 478 1.212 rillig if (dir == NULL) 479 1.212 rillig return; 480 1.212 rillig 481 1.241 rillig CachedDir_Assign(&cur, dir); 482 1.28 tv } 483 1.28 tv 484 1.254 rillig /* 485 1.283 rillig * (Re)initialize "dot" (the current/object directory). 486 1.254 rillig * Some directories may be cached. 487 1.254 rillig */ 488 1.28 tv void 489 1.34 wiz Dir_InitDot(void) 490 1.28 tv { 491 1.241 rillig CachedDir *dir; 492 1.28 tv 493 1.260 rillig dir = SearchPath_Add(NULL, "."); 494 1.241 rillig if (dir == NULL) { 495 1.297 rillig Error("Cannot open \".\": %s", strerror(errno)); 496 1.253 rillig exit(2); /* Not 1 so -q can distinguish error */ 497 1.212 rillig } 498 1.28 tv 499 1.241 rillig CachedDir_Assign(&dot, dir); 500 1.241 rillig 501 1.213 rillig Dir_SetPATH(); /* initialize */ 502 1.1 cgd } 503 1.1 cgd 504 1.292 rillig #ifdef CLEANUP 505 1.292 rillig static void 506 1.292 rillig FreeCachedTable(HashTable *tbl) 507 1.292 rillig { 508 1.292 rillig HashIter hi; 509 1.292 rillig HashIter_Init(&hi, tbl); 510 1.294 rillig while (HashIter_Next(&hi)) 511 1.292 rillig free(hi.entry->value); 512 1.292 rillig HashTable_Done(tbl); 513 1.292 rillig } 514 1.292 rillig 515 1.163 rillig /* Clean up the directories module. */ 516 1.6 jtc void 517 1.34 wiz Dir_End(void) 518 1.6 jtc { 519 1.241 rillig CachedDir_Assign(&cur, NULL); 520 1.241 rillig CachedDir_Assign(&dot, NULL); 521 1.240 rillig CachedDir_Assign(&dotLast, NULL); 522 1.228 rillig SearchPath_Clear(&dirSearchPath); 523 1.212 rillig OpenDirs_Done(&openDirs); 524 1.292 rillig FreeCachedTable(&mtimes); 525 1.292 rillig FreeCachedTable(&lmtimes); 526 1.295 rillig } 527 1.24 mycroft #endif 528 1.6 jtc 529 1.35 sjg /* 530 1.35 sjg * We want ${.PATH} to indicate the order in which we will actually 531 1.35 sjg * search, so we rebuild it after any .PATH: target. 532 1.35 sjg * This is the simplest way to deal with the effect of .DOTLAST. 533 1.35 sjg */ 534 1.35 sjg void 535 1.45 christos Dir_SetPATH(void) 536 1.35 sjg { 537 1.212 rillig CachedDirListNode *ln; 538 1.271 rillig bool seenDotLast = false; /* true if we should search '.' last */ 539 1.35 sjg 540 1.269 rillig Global_Delete(".PATH"); 541 1.76 rillig 542 1.264 rillig if ((ln = dirSearchPath.dirs.first) != NULL) { 543 1.212 rillig CachedDir *dir = ln->datum; 544 1.212 rillig if (dir == dotLast) { 545 1.271 rillig seenDotLast = true; 546 1.267 rillig Global_Append(".PATH", dotLast->name); 547 1.212 rillig } 548 1.35 sjg } 549 1.35 sjg 550 1.247 rillig if (!seenDotLast) { 551 1.222 rillig if (dot != NULL) 552 1.267 rillig Global_Append(".PATH", dot->name); 553 1.222 rillig if (cur != NULL) 554 1.267 rillig Global_Append(".PATH", cur->name); 555 1.212 rillig } 556 1.35 sjg 557 1.264 rillig for (ln = dirSearchPath.dirs.first; ln != NULL; ln = ln->next) { 558 1.212 rillig CachedDir *dir = ln->datum; 559 1.212 rillig if (dir == dotLast) 560 1.212 rillig continue; 561 1.247 rillig if (dir == dot && seenDotLast) 562 1.212 rillig continue; 563 1.267 rillig Global_Append(".PATH", dir->name); 564 1.212 rillig } 565 1.35 sjg 566 1.247 rillig if (seenDotLast) { 567 1.222 rillig if (dot != NULL) 568 1.267 rillig Global_Append(".PATH", dot->name); 569 1.222 rillig if (cur != NULL) 570 1.267 rillig Global_Append(".PATH", cur->name); 571 1.212 rillig } 572 1.35 sjg } 573 1.35 sjg 574 1.280 sjg 575 1.280 sjg void 576 1.280 sjg Dir_SetSYSPATH(void) 577 1.280 sjg { 578 1.280 sjg CachedDirListNode *ln; 579 1.287 sjg SearchPath *path = Lst_IsEmpty(&sysIncPath->dirs) 580 1.287 sjg ? defSysIncPath : sysIncPath; 581 1.291 rillig 582 1.280 sjg Var_ReadOnly(".SYSPATH", false); 583 1.280 sjg Global_Delete(".SYSPATH"); 584 1.287 sjg for (ln = path->dirs.first; ln != NULL; ln = ln->next) { 585 1.280 sjg CachedDir *dir = ln->datum; 586 1.280 sjg Global_Append(".SYSPATH", dir->name); 587 1.280 sjg } 588 1.280 sjg Var_ReadOnly(".SYSPATH", true); 589 1.280 sjg } 590 1.280 sjg 591 1.254 rillig /* 592 1.254 rillig * See if the given name has any wildcard characters in it and all braces and 593 1.186 rillig * brackets are properly balanced. 594 1.124 rillig * 595 1.124 rillig * XXX: This code is not 100% correct ([^]] fails etc.). I really don't think 596 1.124 rillig * that make(1) should be expanding patterns, because then you have to set a 597 1.124 rillig * mechanism for escaping the expansion! 598 1.1 cgd */ 599 1.271 rillig bool 600 1.128 rillig Dir_HasWildcards(const char *name) 601 1.1 cgd { 602 1.212 rillig const char *p; 603 1.271 rillig bool wild = false; 604 1.212 rillig int braces = 0, brackets = 0; 605 1.212 rillig 606 1.212 rillig for (p = name; *p != '\0'; p++) { 607 1.212 rillig switch (*p) { 608 1.212 rillig case '{': 609 1.212 rillig braces++; 610 1.271 rillig wild = true; 611 1.212 rillig break; 612 1.212 rillig case '}': 613 1.212 rillig braces--; 614 1.212 rillig break; 615 1.212 rillig case '[': 616 1.212 rillig brackets++; 617 1.271 rillig wild = true; 618 1.212 rillig break; 619 1.212 rillig case ']': 620 1.212 rillig brackets--; 621 1.212 rillig break; 622 1.212 rillig case '?': 623 1.212 rillig case '*': 624 1.271 rillig wild = true; 625 1.212 rillig break; 626 1.212 rillig default: 627 1.212 rillig break; 628 1.212 rillig } 629 1.1 cgd } 630 1.212 rillig return wild && brackets == 0 && braces == 0; 631 1.1 cgd } 632 1.1 cgd 633 1.254 rillig /* 634 1.283 rillig * See if any files as seen from 'dir' match 'pattern', and add their names 635 1.283 rillig * to 'expansions' if they do. 636 1.181 rillig * 637 1.283 rillig * Wildcards are only expanded in the final path component, but not in 638 1.283 rillig * directories like src/lib*c/file*.c. To expand these wildcards, 639 1.261 rillig * delegate the work to the shell, using the '!=' variable assignment 640 1.261 rillig * operator, the ':sh' variable modifier or the ':!...!' variable modifier, 641 1.261 rillig * such as in ${:!echo src/lib*c/file*.c!}. 642 1.1 cgd */ 643 1.98 rillig static void 644 1.144 rillig DirMatchFiles(const char *pattern, CachedDir *dir, StringList *expansions) 645 1.1 cgd { 646 1.212 rillig const char *dirName = dir->name; 647 1.271 rillig bool isDot = dirName[0] == '.' && dirName[1] == '\0'; 648 1.212 rillig HashIter hi; 649 1.12 christos 650 1.1 cgd /* 651 1.212 rillig * XXX: Iterating over all hash entries is inefficient. If the 652 1.212 rillig * pattern is a plain string without any wildcards, a direct lookup 653 1.212 rillig * is faster. 654 1.1 cgd */ 655 1.181 rillig 656 1.212 rillig HashIter_InitSet(&hi, &dir->files); 657 1.294 rillig while (HashIter_Next(&hi)) { 658 1.212 rillig const char *base = hi.entry->key; 659 1.282 rillig StrMatchResult res = Str_Match(base, pattern); 660 1.282 rillig /* TODO: handle errors from res.error */ 661 1.212 rillig 662 1.282 rillig if (!res.matched) 663 1.212 rillig continue; 664 1.212 rillig 665 1.212 rillig /* 666 1.212 rillig * Follow the UNIX convention that dot files are only found 667 1.212 rillig * if the pattern begins with a dot. The pattern '.*' does 668 1.212 rillig * not match '.' or '..' since these are not included in the 669 1.212 rillig * directory cache. 670 1.212 rillig * 671 1.212 rillig * This means that the pattern '[a-z.]*' does not find 672 1.261 rillig * '.file', which is consistent with NetBSD sh, NetBSD ksh, 673 1.261 rillig * bash, dash, csh and probably many other shells as well. 674 1.212 rillig */ 675 1.212 rillig if (base[0] == '.' && pattern[0] != '.') 676 1.212 rillig continue; 677 1.212 rillig 678 1.212 rillig { 679 1.212 rillig char *fullName = isDot 680 1.276 rillig ? bmake_strdup(base) 681 1.276 rillig : str_concat3(dirName, "/", base); 682 1.212 rillig Lst_Append(expansions, fullName); 683 1.212 rillig } 684 1.1 cgd } 685 1.1 cgd } 686 1.1 cgd 687 1.285 rillig /* Find the next closing brace in 'p', taking nested braces into account. */ 688 1.80 rillig static const char * 689 1.80 rillig closing_brace(const char *p) 690 1.80 rillig { 691 1.284 rillig int depth = 0; 692 1.212 rillig while (*p != '\0') { 693 1.284 rillig if (*p == '}' && depth == 0) 694 1.212 rillig break; 695 1.212 rillig if (*p == '{') 696 1.284 rillig depth++; 697 1.212 rillig if (*p == '}') 698 1.284 rillig depth--; 699 1.212 rillig p++; 700 1.212 rillig } 701 1.212 rillig return p; 702 1.80 rillig } 703 1.80 rillig 704 1.254 rillig /* 705 1.254 rillig * Find the next closing brace or comma in the string, taking nested braces 706 1.254 rillig * into account. 707 1.254 rillig */ 708 1.80 rillig static const char * 709 1.80 rillig separator_comma(const char *p) 710 1.80 rillig { 711 1.284 rillig int depth = 0; 712 1.212 rillig while (*p != '\0') { 713 1.284 rillig if ((*p == '}' || *p == ',') && depth == 0) 714 1.212 rillig break; 715 1.212 rillig if (*p == '{') 716 1.284 rillig depth++; 717 1.212 rillig if (*p == '}') 718 1.284 rillig depth--; 719 1.212 rillig p++; 720 1.212 rillig } 721 1.212 rillig return p; 722 1.80 rillig } 723 1.80 rillig 724 1.271 rillig static bool 725 1.80 rillig contains_wildcard(const char *p) 726 1.80 rillig { 727 1.212 rillig for (; *p != '\0'; p++) { 728 1.212 rillig switch (*p) { 729 1.212 rillig case '*': 730 1.212 rillig case '?': 731 1.212 rillig case '{': 732 1.212 rillig case '[': 733 1.271 rillig return true; 734 1.212 rillig } 735 1.80 rillig } 736 1.271 rillig return false; 737 1.80 rillig } 738 1.80 rillig 739 1.80 rillig static char * 740 1.80 rillig concat3(const char *a, size_t a_len, const char *b, size_t b_len, 741 1.80 rillig const char *c, size_t c_len) 742 1.80 rillig { 743 1.212 rillig size_t s_len = a_len + b_len + c_len; 744 1.212 rillig char *s = bmake_malloc(s_len + 1); 745 1.212 rillig memcpy(s, a, a_len); 746 1.212 rillig memcpy(s + a_len, b, b_len); 747 1.212 rillig memcpy(s + a_len + b_len, c, c_len); 748 1.212 rillig s[s_len] = '\0'; 749 1.212 rillig return s; 750 1.80 rillig } 751 1.80 rillig 752 1.254 rillig /* 753 1.254 rillig * Expand curly braces like the C shell. Brace expansion by itself is purely 754 1.181 rillig * textual, the expansions are not looked up in the file system. But if an 755 1.181 rillig * expanded word contains wildcard characters, it is expanded further, 756 1.181 rillig * matching only the actually existing files. 757 1.181 rillig * 758 1.181 rillig * Example: "{a{b,c}}" expands to "ab" and "ac". 759 1.181 rillig * Example: "{a}" expands to "a". 760 1.181 rillig * Example: "{a,*.c}" expands to "a" and all "*.c" files that exist. 761 1.1 cgd * 762 1.34 wiz * Input: 763 1.34 wiz * word Entire word to expand 764 1.34 wiz * brace First curly brace in it 765 1.34 wiz * path Search path to use 766 1.34 wiz * expansions Place to store the expansions 767 1.1 cgd */ 768 1.1 cgd static void 769 1.144 rillig DirExpandCurly(const char *word, const char *brace, SearchPath *path, 770 1.144 rillig StringList *expansions) 771 1.1 cgd { 772 1.212 rillig const char *prefix, *middle, *piece, *middle_end, *suffix; 773 1.212 rillig size_t prefix_len, suffix_len; 774 1.212 rillig 775 1.285 rillig /* Split the word into prefix, '{', middle, '}' and suffix. */ 776 1.212 rillig 777 1.212 rillig middle = brace + 1; 778 1.212 rillig middle_end = closing_brace(middle); 779 1.212 rillig if (*middle_end == '\0') { 780 1.212 rillig Error("Unterminated {} clause \"%s\"", middle); 781 1.212 rillig return; 782 1.212 rillig } 783 1.212 rillig 784 1.212 rillig prefix = word; 785 1.212 rillig prefix_len = (size_t)(brace - prefix); 786 1.212 rillig suffix = middle_end + 1; 787 1.212 rillig suffix_len = strlen(suffix); 788 1.212 rillig 789 1.212 rillig /* Split the middle into pieces, separated by commas. */ 790 1.212 rillig 791 1.212 rillig piece = middle; 792 1.212 rillig while (piece < middle_end + 1) { 793 1.212 rillig const char *piece_end = separator_comma(piece); 794 1.212 rillig size_t piece_len = (size_t)(piece_end - piece); 795 1.90 rillig 796 1.212 rillig char *file = concat3(prefix, prefix_len, piece, piece_len, 797 1.276 rillig suffix, suffix_len); 798 1.1 cgd 799 1.212 rillig if (contains_wildcard(file)) { 800 1.256 rillig SearchPath_Expand(path, file, expansions); 801 1.212 rillig free(file); 802 1.212 rillig } else { 803 1.212 rillig Lst_Append(expansions, file); 804 1.212 rillig } 805 1.78 rillig 806 1.213 rillig /* skip over the comma or closing brace */ 807 1.213 rillig piece = piece_end + 1; 808 1.1 cgd } 809 1.1 cgd } 810 1.1 cgd 811 1.1 cgd 812 1.283 rillig /* Expand 'pattern' in each of the directories from 'path'. */ 813 1.1 cgd static void 814 1.281 rillig DirExpandPath(const char *pattern, SearchPath *path, StringList *expansions) 815 1.1 cgd { 816 1.286 rillig CachedDirListNode *ln; 817 1.264 rillig for (ln = path->dirs.first; ln != NULL; ln = ln->next) { 818 1.212 rillig CachedDir *dir = ln->datum; 819 1.281 rillig DirMatchFiles(pattern, dir, expansions); 820 1.212 rillig } 821 1.1 cgd } 822 1.1 cgd 823 1.146 rillig static void 824 1.184 rillig PrintExpansions(StringList *expansions) 825 1.1 cgd { 826 1.212 rillig const char *sep = ""; 827 1.212 rillig StringListNode *ln; 828 1.212 rillig for (ln = expansions->first; ln != NULL; ln = ln->next) { 829 1.212 rillig const char *word = ln->datum; 830 1.212 rillig debug_printf("%s%s", sep, word); 831 1.212 rillig sep = " "; 832 1.212 rillig } 833 1.212 rillig debug_printf("\n"); 834 1.1 cgd } 835 1.1 cgd 836 1.254 rillig /* 837 1.259 rillig * The wildcard isn't in the first component. 838 1.259 rillig * Find all the components up to the one with the wildcard. 839 1.259 rillig */ 840 1.259 rillig static void 841 1.259 rillig SearchPath_ExpandMiddle(SearchPath *path, const char *pattern, 842 1.259 rillig const char *wildcardComponent, StringList *expansions) 843 1.259 rillig { 844 1.259 rillig char *prefix, *dirpath, *end; 845 1.259 rillig SearchPath *partPath; 846 1.259 rillig 847 1.259 rillig prefix = bmake_strsedup(pattern, wildcardComponent + 1); 848 1.259 rillig /* 849 1.259 rillig * XXX: Only the first match of the prefix in the path is 850 1.259 rillig * taken, any others are ignored. The expectation may be 851 1.259 rillig * that the pattern is expanded in the whole path. 852 1.259 rillig */ 853 1.259 rillig dirpath = Dir_FindFile(prefix, path); 854 1.259 rillig free(prefix); 855 1.259 rillig 856 1.259 rillig /* 857 1.259 rillig * dirpath is null if can't find the leading component 858 1.259 rillig * 859 1.259 rillig * XXX: Dir_FindFile won't find internal components. i.e. if the 860 1.259 rillig * path contains ../Etc/Object and we're looking for Etc, it won't 861 1.259 rillig * be found. Ah well. Probably not important. 862 1.259 rillig * 863 1.283 rillig * TODO: Check whether the above comment is still true. 864 1.259 rillig */ 865 1.259 rillig if (dirpath == NULL) 866 1.259 rillig return; 867 1.259 rillig 868 1.259 rillig end = &dirpath[strlen(dirpath) - 1]; 869 1.259 rillig /* XXX: What about multiple trailing slashes? */ 870 1.259 rillig if (*end == '/') 871 1.259 rillig *end = '\0'; 872 1.259 rillig 873 1.259 rillig partPath = SearchPath_New(); 874 1.260 rillig (void)SearchPath_Add(partPath, dirpath); 875 1.259 rillig DirExpandPath(wildcardComponent + 1, partPath, expansions); 876 1.259 rillig SearchPath_Free(partPath); 877 1.293 rillig free(dirpath); 878 1.259 rillig } 879 1.259 rillig 880 1.259 rillig /* 881 1.257 rillig * Expand the given pattern into a list of existing filenames by globbing it, 882 1.257 rillig * looking in each directory from the search path. 883 1.1 cgd * 884 1.34 wiz * Input: 885 1.180 rillig * path the directories in which to find the files 886 1.257 rillig * pattern the pattern to expand 887 1.34 wiz * expansions the list on which to place the results 888 1.1 cgd */ 889 1.1 cgd void 890 1.257 rillig SearchPath_Expand(SearchPath *path, const char *pattern, StringList *expansions) 891 1.1 cgd { 892 1.258 rillig const char *brace, *slash, *wildcard, *wildcardComponent; 893 1.1 cgd 894 1.216 rillig assert(path != NULL); 895 1.216 rillig assert(expansions != NULL); 896 1.112 rillig 897 1.257 rillig DEBUG1(DIR, "Expanding \"%s\"... ", pattern); 898 1.12 christos 899 1.258 rillig brace = strchr(pattern, '{'); 900 1.258 rillig if (brace != NULL) { 901 1.258 rillig DirExpandCurly(pattern, brace, path, expansions); 902 1.216 rillig goto done; 903 1.216 rillig } 904 1.216 rillig 905 1.258 rillig slash = strchr(pattern, '/'); 906 1.258 rillig if (slash == NULL) { 907 1.257 rillig DirMatchFiles(pattern, dot, expansions); 908 1.257 rillig DirExpandPath(pattern, path, expansions); 909 1.216 rillig goto done; 910 1.216 rillig } 911 1.215 rillig 912 1.257 rillig /* At this point, the pattern has a directory component. */ 913 1.215 rillig 914 1.257 rillig /* Find the first wildcard in the pattern. */ 915 1.258 rillig for (wildcard = pattern; *wildcard != '\0'; wildcard++) 916 1.258 rillig if (*wildcard == '?' || *wildcard == '[' || *wildcard == '*') 917 1.216 rillig break; 918 1.215 rillig 919 1.258 rillig if (*wildcard == '\0') { 920 1.216 rillig /* 921 1.216 rillig * No directory component and no wildcard at all -- this 922 1.216 rillig * should never happen as in such a simple case there is no 923 1.216 rillig * need to expand anything. 924 1.216 rillig */ 925 1.257 rillig DirExpandPath(pattern, path, expansions); 926 1.216 rillig goto done; 927 1.216 rillig } 928 1.216 rillig 929 1.216 rillig /* Back up to the start of the component containing the wildcard. */ 930 1.216 rillig /* XXX: This handles '///' and '/' differently. */ 931 1.258 rillig wildcardComponent = wildcard; 932 1.258 rillig while (wildcardComponent > pattern && *wildcardComponent != '/') 933 1.258 rillig wildcardComponent--; 934 1.215 rillig 935 1.258 rillig if (wildcardComponent == pattern) { 936 1.216 rillig /* The first component contains the wildcard. */ 937 1.216 rillig /* Start the search from the local directory */ 938 1.257 rillig DirExpandPath(pattern, path, expansions); 939 1.259 rillig } else { 940 1.259 rillig SearchPath_ExpandMiddle(path, pattern, wildcardComponent, 941 1.259 rillig expansions); 942 1.1 cgd } 943 1.215 rillig 944 1.215 rillig done: 945 1.216 rillig if (DEBUG(DIR)) 946 1.216 rillig PrintExpansions(expansions); 947 1.1 cgd } 948 1.1 cgd 949 1.254 rillig /* 950 1.283 rillig * Find if 'base' exists in 'dir'. 951 1.254 rillig * Return the freshly allocated path to the file, or NULL. 952 1.254 rillig */ 953 1.18 christos static char * 954 1.177 rillig DirLookup(CachedDir *dir, const char *base) 955 1.18 christos { 956 1.283 rillig char *file; 957 1.18 christos 958 1.250 rillig DEBUG1(DIR, " %s ...\n", dir->name); 959 1.32 pk 960 1.212 rillig if (!HashSet_Contains(&dir->files, base)) 961 1.212 rillig return NULL; 962 1.32 pk 963 1.212 rillig file = str_concat3(dir->name, "/", base); 964 1.250 rillig DEBUG1(DIR, " returning %s\n", file); 965 1.212 rillig dir->hits++; 966 1.212 rillig hits++; 967 1.212 rillig return file; 968 1.18 christos } 969 1.18 christos 970 1.18 christos 971 1.254 rillig /* 972 1.283 rillig * Find if 'name' exists in 'dir'. 973 1.254 rillig * Return the freshly allocated path to the file, or NULL. 974 1.254 rillig */ 975 1.18 christos static char * 976 1.143 rillig DirLookupSubdir(CachedDir *dir, const char *name) 977 1.18 christos { 978 1.212 rillig struct cached_stat cst; 979 1.276 rillig char *file = dir == dot 980 1.276 rillig ? bmake_strdup(name) 981 1.276 rillig : str_concat3(dir->name, "/", name); 982 1.18 christos 983 1.250 rillig DEBUG1(DIR, "checking %s ...\n", file); 984 1.18 christos 985 1.212 rillig if (cached_stat(file, &cst) == 0) { 986 1.212 rillig nearmisses++; 987 1.212 rillig return file; 988 1.212 rillig } 989 1.212 rillig free(file); 990 1.212 rillig return NULL; 991 1.18 christos } 992 1.18 christos 993 1.254 rillig /* 994 1.283 rillig * Find if 'name' (which has basename 'base') exists in 'dir'. 995 1.283 rillig * Return the freshly allocated path to the file, an empty string, or NULL. 996 1.283 rillig * Returning an empty string means that the search should be terminated. 997 1.32 pk */ 998 1.32 pk static char * 999 1.283 rillig DirLookupAbs(CachedDir *dir, const char *name, const char *base) 1000 1.32 pk { 1001 1.212 rillig const char *dnp; /* pointer into dir->name */ 1002 1.212 rillig const char *np; /* pointer into name */ 1003 1.32 pk 1004 1.250 rillig DEBUG1(DIR, " %s ...\n", dir->name); 1005 1.32 pk 1006 1.212 rillig /* 1007 1.212 rillig * If the file has a leading path component and that component 1008 1.212 rillig * exactly matches the entire name of the current search 1009 1.212 rillig * directory, we can attempt another cache lookup. And if we don't 1010 1.212 rillig * have a hit, we can safely assume the file does not exist at all. 1011 1.212 rillig */ 1012 1.212 rillig for (dnp = dir->name, np = name; 1013 1.212 rillig *dnp != '\0' && *dnp == *np; dnp++, np++) 1014 1.212 rillig continue; 1015 1.283 rillig if (*dnp != '\0' || np != base - 1) 1016 1.212 rillig return NULL; 1017 1.32 pk 1018 1.283 rillig if (!HashSet_Contains(&dir->files, base)) { 1019 1.250 rillig DEBUG0(DIR, " must be here but isn't -- returning\n"); 1020 1.212 rillig return bmake_strdup(""); /* to terminate the search */ 1021 1.212 rillig } 1022 1.32 pk 1023 1.212 rillig dir->hits++; 1024 1.212 rillig hits++; 1025 1.250 rillig DEBUG1(DIR, " returning %s\n", name); 1026 1.212 rillig return bmake_strdup(name); 1027 1.32 pk } 1028 1.32 pk 1029 1.254 rillig /* 1030 1.279 rillig * Find the given file in "." or curdir. 1031 1.254 rillig * Return the freshly allocated path to the file, or NULL. 1032 1.254 rillig */ 1033 1.21 thorpej static char * 1034 1.178 rillig DirFindDot(const char *name, const char *base) 1035 1.21 thorpej { 1036 1.21 thorpej 1037 1.212 rillig if (HashSet_Contains(&dot->files, base)) { 1038 1.250 rillig DEBUG0(DIR, " in '.'\n"); 1039 1.212 rillig hits++; 1040 1.212 rillig dot->hits++; 1041 1.212 rillig return bmake_strdup(name); 1042 1.212 rillig } 1043 1.188 rillig 1044 1.212 rillig if (cur != NULL && HashSet_Contains(&cur->files, base)) { 1045 1.250 rillig DEBUG1(DIR, " in ${.CURDIR} = %s\n", cur->name); 1046 1.212 rillig hits++; 1047 1.212 rillig cur->hits++; 1048 1.212 rillig return str_concat3(cur->name, "/", base); 1049 1.212 rillig } 1050 1.21 thorpej 1051 1.212 rillig return NULL; 1052 1.21 thorpej } 1053 1.21 thorpej 1054 1.271 rillig static bool 1055 1.271 rillig FindFileRelative(SearchPath *path, bool seenDotLast, 1056 1.263 rillig const char *name, char **out_file) 1057 1.263 rillig { 1058 1.286 rillig CachedDirListNode *ln; 1059 1.271 rillig bool checkedDot = false; 1060 1.263 rillig char *file; 1061 1.263 rillig 1062 1.263 rillig DEBUG0(DIR, " Trying subdirectories...\n"); 1063 1.263 rillig 1064 1.263 rillig if (!seenDotLast) { 1065 1.263 rillig if (dot != NULL) { 1066 1.271 rillig checkedDot = true; 1067 1.263 rillig if ((file = DirLookupSubdir(dot, name)) != NULL) 1068 1.283 rillig goto done; 1069 1.263 rillig } 1070 1.263 rillig if (cur != NULL && 1071 1.263 rillig (file = DirLookupSubdir(cur, name)) != NULL) 1072 1.283 rillig goto done; 1073 1.263 rillig } 1074 1.263 rillig 1075 1.264 rillig for (ln = path->dirs.first; ln != NULL; ln = ln->next) { 1076 1.263 rillig CachedDir *dir = ln->datum; 1077 1.263 rillig if (dir == dotLast) 1078 1.263 rillig continue; 1079 1.263 rillig if (dir == dot) { 1080 1.263 rillig if (checkedDot) 1081 1.263 rillig continue; 1082 1.271 rillig checkedDot = true; 1083 1.263 rillig } 1084 1.263 rillig if ((file = DirLookupSubdir(dir, name)) != NULL) 1085 1.283 rillig goto done; 1086 1.263 rillig } 1087 1.263 rillig 1088 1.263 rillig if (seenDotLast) { 1089 1.263 rillig if (dot != NULL && !checkedDot) { 1090 1.271 rillig checkedDot = true; 1091 1.263 rillig if ((file = DirLookupSubdir(dot, name)) != NULL) 1092 1.283 rillig goto done; 1093 1.263 rillig } 1094 1.263 rillig if (cur != NULL && 1095 1.263 rillig (file = DirLookupSubdir(cur, name)) != NULL) 1096 1.283 rillig goto done; 1097 1.263 rillig } 1098 1.263 rillig 1099 1.263 rillig if (checkedDot) { 1100 1.263 rillig /* 1101 1.263 rillig * Already checked by the given name, since . was in 1102 1.263 rillig * the path, so no point in proceeding. 1103 1.263 rillig */ 1104 1.263 rillig DEBUG0(DIR, " Checked . already, returning NULL\n"); 1105 1.263 rillig file = NULL; 1106 1.283 rillig goto done; 1107 1.263 rillig } 1108 1.263 rillig 1109 1.271 rillig return false; 1110 1.263 rillig 1111 1.283 rillig done: 1112 1.263 rillig *out_file = file; 1113 1.271 rillig return true; 1114 1.263 rillig } 1115 1.263 rillig 1116 1.271 rillig static bool 1117 1.273 rillig FindFileAbsolute(SearchPath *path, bool seenDotLast, 1118 1.273 rillig const char *name, const char *base, char **out_file) 1119 1.263 rillig { 1120 1.263 rillig char *file; 1121 1.286 rillig CachedDirListNode *ln; 1122 1.263 rillig 1123 1.263 rillig DEBUG0(DIR, " Trying exact path matches...\n"); 1124 1.263 rillig 1125 1.263 rillig if (!seenDotLast && cur != NULL && 1126 1.263 rillig ((file = DirLookupAbs(cur, name, base)) != NULL)) 1127 1.263 rillig goto found; 1128 1.263 rillig 1129 1.264 rillig for (ln = path->dirs.first; ln != NULL; ln = ln->next) { 1130 1.263 rillig CachedDir *dir = ln->datum; 1131 1.263 rillig if (dir == dotLast) 1132 1.263 rillig continue; 1133 1.263 rillig if ((file = DirLookupAbs(dir, name, base)) != NULL) 1134 1.263 rillig goto found; 1135 1.263 rillig } 1136 1.263 rillig 1137 1.263 rillig if (seenDotLast && cur != NULL && 1138 1.263 rillig ((file = DirLookupAbs(cur, name, base)) != NULL)) 1139 1.263 rillig goto found; 1140 1.263 rillig 1141 1.271 rillig return false; 1142 1.263 rillig 1143 1.263 rillig found: 1144 1.263 rillig if (file[0] == '\0') { 1145 1.263 rillig free(file); 1146 1.263 rillig file = NULL; 1147 1.263 rillig } 1148 1.263 rillig *out_file = file; 1149 1.271 rillig return true; 1150 1.263 rillig } 1151 1.263 rillig 1152 1.254 rillig /* 1153 1.254 rillig * Find the file with the given name along the given search path. 1154 1.179 rillig * 1155 1.34 wiz * Input: 1156 1.34 wiz * name the file to find 1157 1.179 rillig * path the directories to search, or NULL 1158 1.288 sjg * isinclude if true, do not search .CURDIR at all 1159 1.34 wiz * 1160 1.1 cgd * Results: 1161 1.179 rillig * The freshly allocated path to the file, or NULL. 1162 1.1 cgd */ 1163 1.288 sjg static char * 1164 1.288 sjg FindFile(const char *name, SearchPath *path, bool isinclude) 1165 1.1 cgd { 1166 1.212 rillig char *file; /* the current filename to check */ 1167 1.288 sjg bool seenDotLast = isinclude; /* true if we should search dot last */ 1168 1.283 rillig struct cached_stat cst; 1169 1.212 rillig const char *trailing_dot = "."; 1170 1.252 rillig const char *base = str_basename(name); 1171 1.12 christos 1172 1.250 rillig DEBUG1(DIR, "Searching for %s ...", name); 1173 1.12 christos 1174 1.212 rillig if (path == NULL) { 1175 1.250 rillig DEBUG0(DIR, "couldn't open path, file not found\n"); 1176 1.212 rillig misses++; 1177 1.212 rillig return NULL; 1178 1.212 rillig } 1179 1.12 christos 1180 1.288 sjg if (!seenDotLast && path->dirs.first != NULL) { 1181 1.264 rillig CachedDir *dir = path->dirs.first->datum; 1182 1.212 rillig if (dir == dotLast) { 1183 1.271 rillig seenDotLast = true; 1184 1.250 rillig DEBUG0(DIR, "[dot last]..."); 1185 1.212 rillig } 1186 1.21 thorpej } 1187 1.250 rillig DEBUG0(DIR, "\n"); 1188 1.18 christos 1189 1.85 rillig /* 1190 1.212 rillig * If there's no leading directory components or if the leading 1191 1.212 rillig * directory component is exactly `./', consult the cached contents 1192 1.212 rillig * of each of the directories on the search path. 1193 1.85 rillig */ 1194 1.252 rillig if (base == name || (base - name == 2 && *name == '.')) { 1195 1.286 rillig CachedDirListNode *ln; 1196 1.217 rillig 1197 1.212 rillig /* 1198 1.283 rillig * Look through all the directories on the path seeking one 1199 1.212 rillig * which contains the final component of the given name. If 1200 1.283 rillig * such a file is found, return its pathname. 1201 1.283 rillig * If there is no such file, go on to phase two. 1202 1.212 rillig * 1203 1.283 rillig * No matter what, always look for the file in the current 1204 1.283 rillig * directory before anywhere else (unless the path contains 1205 1.283 rillig * the magic '.DOTLAST', in which case search it last). 1206 1.212 rillig * This is so there are no conflicts between what the user 1207 1.283 rillig * specifies (fish.c) and what make finds (./fish.c). 1208 1.212 rillig */ 1209 1.245 rillig if (!seenDotLast && (file = DirFindDot(name, base)) != NULL) 1210 1.212 rillig return file; 1211 1.212 rillig 1212 1.264 rillig for (ln = path->dirs.first; ln != NULL; ln = ln->next) { 1213 1.212 rillig CachedDir *dir = ln->datum; 1214 1.212 rillig if (dir == dotLast) 1215 1.212 rillig continue; 1216 1.212 rillig if ((file = DirLookup(dir, base)) != NULL) 1217 1.212 rillig return file; 1218 1.212 rillig } 1219 1.32 pk 1220 1.290 sjg if (seenDotLast && (file = DirFindDot(name, base)) != NULL) 1221 1.212 rillig return file; 1222 1.212 rillig } 1223 1.212 rillig 1224 1.252 rillig if (base == name) { 1225 1.250 rillig DEBUG0(DIR, " failed.\n"); 1226 1.212 rillig misses++; 1227 1.212 rillig return NULL; 1228 1.85 rillig } 1229 1.21 thorpej 1230 1.283 rillig if (*base == '\0') 1231 1.283 rillig base = trailing_dot; /* we were given a trailing "/" */ 1232 1.212 rillig 1233 1.212 rillig if (name[0] != '/') { 1234 1.263 rillig if (FindFileRelative(path, seenDotLast, name, &file)) 1235 1.212 rillig return file; 1236 1.263 rillig } else { 1237 1.263 rillig if (FindFileAbsolute(path, seenDotLast, name, base, &file)) 1238 1.212 rillig return file; 1239 1.32 pk } 1240 1.32 pk 1241 1.32 pk /* 1242 1.283 rillig * We cannot add the directory onto the search path because 1243 1.212 rillig * of this amusing case: 1244 1.212 rillig * $(INSTALLDIR)/$(FILE): $(FILE) 1245 1.212 rillig * 1246 1.212 rillig * $(FILE) exists in $(INSTALLDIR) but not in the current one. 1247 1.212 rillig * When searching for $(FILE), we will find it in $(INSTALLDIR) 1248 1.212 rillig * b/c we added it here. This is not good... 1249 1.32 pk */ 1250 1.283 rillig 1251 1.250 rillig DEBUG1(DIR, " Looking for \"%s\" ...\n", name); 1252 1.32 pk 1253 1.212 rillig bigmisses++; 1254 1.283 rillig if (cached_stat(name, &cst) == 0) 1255 1.212 rillig return bmake_strdup(name); 1256 1.12 christos 1257 1.250 rillig DEBUG0(DIR, " failed. Returning NULL\n"); 1258 1.57 dsl return NULL; 1259 1.1 cgd } 1260 1.1 cgd 1261 1.288 sjg /* 1262 1.288 sjg * Find the file with the given name along the given search path. 1263 1.288 sjg * 1264 1.288 sjg * Input: 1265 1.288 sjg * name the file to find 1266 1.288 sjg * path the directories to search, or NULL 1267 1.288 sjg * 1268 1.288 sjg * Results: 1269 1.288 sjg * The freshly allocated path to the file, or NULL. 1270 1.288 sjg */ 1271 1.288 sjg char * 1272 1.288 sjg Dir_FindFile(const char *name, SearchPath *path) 1273 1.288 sjg { 1274 1.288 sjg return FindFile(name, path, false); 1275 1.288 sjg } 1276 1.288 sjg 1277 1.288 sjg /* 1278 1.288 sjg * Find the include file with the given name along the given search path. 1279 1.288 sjg * 1280 1.288 sjg * Input: 1281 1.288 sjg * name the file to find 1282 1.288 sjg * path the directories to search, or NULL 1283 1.288 sjg * 1284 1.288 sjg * Results: 1285 1.288 sjg * The freshly allocated path to the file, or NULL. 1286 1.288 sjg */ 1287 1.288 sjg char * 1288 1.288 sjg Dir_FindInclude(const char *name, SearchPath *path) 1289 1.288 sjg { 1290 1.288 sjg return FindFile(name, path, true); 1291 1.288 sjg } 1292 1.288 sjg 1293 1.40 chuck 1294 1.254 rillig /* 1295 1.283 rillig * Search for 'needle' starting at the directory 'here' and then working our 1296 1.283 rillig * way up towards the root directory. Return the allocated path, or NULL. 1297 1.40 chuck */ 1298 1.161 rillig char * 1299 1.283 rillig Dir_FindHereOrAbove(const char *here, const char *needle) 1300 1.85 rillig { 1301 1.212 rillig struct cached_stat cst; 1302 1.212 rillig char *dirbase, *dirbase_end; 1303 1.212 rillig char *try, *try_end; 1304 1.212 rillig 1305 1.212 rillig dirbase = bmake_strdup(here); 1306 1.212 rillig dirbase_end = dirbase + strlen(dirbase); 1307 1.212 rillig 1308 1.212 rillig for (;;) { 1309 1.283 rillig try = str_concat3(dirbase, "/", needle); 1310 1.212 rillig if (cached_stat(try, &cst) != -1) { 1311 1.212 rillig if ((cst.cst_mode & S_IFMT) != S_IFDIR) { 1312 1.283 rillig /* 1313 1.283 rillig * Chop off the filename, to return a 1314 1.283 rillig * directory. 1315 1.283 rillig */ 1316 1.212 rillig try_end = try + strlen(try); 1317 1.212 rillig while (try_end > try && *try_end != '/') 1318 1.212 rillig try_end--; 1319 1.212 rillig if (try_end > try) 1320 1.212 rillig *try_end = '\0'; /* chop! */ 1321 1.212 rillig } 1322 1.212 rillig 1323 1.212 rillig free(dirbase); 1324 1.212 rillig return try; 1325 1.212 rillig } 1326 1.212 rillig free(try); 1327 1.85 rillig 1328 1.212 rillig if (dirbase_end == dirbase) 1329 1.212 rillig break; /* failed! */ 1330 1.40 chuck 1331 1.283 rillig /* Truncate dirbase from the end to move up a dir. */ 1332 1.212 rillig while (dirbase_end > dirbase && *dirbase_end != '/') 1333 1.212 rillig dirbase_end--; 1334 1.212 rillig *dirbase_end = '\0'; /* chop! */ 1335 1.85 rillig } 1336 1.40 chuck 1337 1.212 rillig free(dirbase); 1338 1.212 rillig return NULL; 1339 1.40 chuck } 1340 1.40 chuck 1341 1.220 rillig /* 1342 1.220 rillig * This is an implied source, and it may have moved, 1343 1.220 rillig * see if we can find it via the current .PATH 1344 1.220 rillig */ 1345 1.220 rillig static char * 1346 1.220 rillig ResolveMovedDepends(GNode *gn) 1347 1.220 rillig { 1348 1.221 rillig char *fullName; 1349 1.220 rillig 1350 1.252 rillig const char *base = str_basename(gn->name); 1351 1.252 rillig if (base == gn->name) 1352 1.221 rillig return NULL; 1353 1.220 rillig 1354 1.221 rillig fullName = Dir_FindFile(base, Suff_FindPath(gn)); 1355 1.221 rillig if (fullName == NULL) 1356 1.221 rillig return NULL; 1357 1.220 rillig 1358 1.221 rillig /* 1359 1.221 rillig * Put the found file in gn->path so that we give that to the compiler. 1360 1.221 rillig */ 1361 1.221 rillig /* 1362 1.221 rillig * XXX: Better just reset gn->path to NULL; updating it is already done 1363 1.221 rillig * by Dir_UpdateMTime. 1364 1.221 rillig */ 1365 1.221 rillig gn->path = bmake_strdup(fullName); 1366 1.221 rillig if (!Job_RunTarget(".STALE", gn->fname)) 1367 1.221 rillig fprintf(stdout, /* XXX: Why stdout? */ 1368 1.296 rillig "%s: %s:%u: ignoring stale %s for %s, found %s\n", 1369 1.276 rillig progname, gn->fname, gn->lineno, 1370 1.276 rillig makeDependfile, gn->name, fullName); 1371 1.220 rillig 1372 1.221 rillig return fullName; 1373 1.220 rillig } 1374 1.220 rillig 1375 1.219 rillig static char * 1376 1.219 rillig ResolveFullName(GNode *gn) 1377 1.1 cgd { 1378 1.221 rillig char *fullName; 1379 1.201 rillig 1380 1.221 rillig fullName = gn->path; 1381 1.221 rillig if (fullName == NULL && !(gn->type & OP_NOPATH)) { 1382 1.76 rillig 1383 1.221 rillig fullName = Dir_FindFile(gn->name, Suff_FindPath(gn)); 1384 1.220 rillig 1385 1.274 rillig if (fullName == NULL && gn->flags.fromDepend && 1386 1.223 rillig !Lst_IsEmpty(&gn->implicitParents)) 1387 1.221 rillig fullName = ResolveMovedDepends(gn); 1388 1.220 rillig 1389 1.250 rillig DEBUG2(DIR, "Found '%s' as '%s'\n", 1390 1.255 rillig gn->name, fullName != NULL ? fullName : "(not found)"); 1391 1.221 rillig } 1392 1.12 christos 1393 1.221 rillig if (fullName == NULL) 1394 1.221 rillig fullName = bmake_strdup(gn->name); 1395 1.1 cgd 1396 1.221 rillig /* XXX: Is every piece of memory freed as it should? */ 1397 1.219 rillig 1398 1.221 rillig return fullName; 1399 1.219 rillig } 1400 1.219 rillig 1401 1.254 rillig /* 1402 1.283 rillig * Search 'gn' along 'dirSearchPath' and store its modification time in 1403 1.283 rillig * 'gn->mtime'. If no file is found, store 0 instead. 1404 1.219 rillig * 1405 1.283 rillig * The found file is stored in 'gn->path', unless the node already had a path. 1406 1.254 rillig */ 1407 1.219 rillig void 1408 1.275 rillig Dir_UpdateMTime(GNode *gn, bool forceRefresh) 1409 1.219 rillig { 1410 1.221 rillig char *fullName; 1411 1.221 rillig struct cached_stat cst; 1412 1.221 rillig 1413 1.221 rillig if (gn->type & OP_ARCHV) { 1414 1.221 rillig Arch_UpdateMTime(gn); 1415 1.221 rillig return; 1416 1.221 rillig } 1417 1.219 rillig 1418 1.221 rillig if (gn->type & OP_PHONY) { 1419 1.221 rillig gn->mtime = 0; 1420 1.221 rillig return; 1421 1.221 rillig } 1422 1.219 rillig 1423 1.221 rillig fullName = ResolveFullName(gn); 1424 1.219 rillig 1425 1.275 rillig if (cached_stats(fullName, &cst, false, forceRefresh) < 0) { 1426 1.221 rillig if (gn->type & OP_MEMBER) { 1427 1.221 rillig if (fullName != gn->path) 1428 1.221 rillig free(fullName); 1429 1.221 rillig Arch_UpdateMemberMTime(gn); 1430 1.221 rillig return; 1431 1.221 rillig } 1432 1.219 rillig 1433 1.221 rillig cst.cst_mtime = 0; 1434 1.1 cgd } 1435 1.198 rillig 1436 1.221 rillig if (fullName != NULL && gn->path == NULL) 1437 1.221 rillig gn->path = fullName; 1438 1.221 rillig /* XXX: else free(fullName)? */ 1439 1.12 christos 1440 1.221 rillig gn->mtime = cst.cst_mtime; 1441 1.1 cgd } 1442 1.1 cgd 1443 1.235 rillig /* 1444 1.242 rillig * Read the directory and add it to the cache in openDirs. 1445 1.242 rillig * If a path is given, add the directory to that path as well. 1446 1.235 rillig */ 1447 1.235 rillig static CachedDir * 1448 1.235 rillig CacheNewDir(const char *name, SearchPath *path) 1449 1.235 rillig { 1450 1.235 rillig CachedDir *dir = NULL; 1451 1.235 rillig DIR *d; 1452 1.235 rillig struct dirent *dp; 1453 1.235 rillig 1454 1.235 rillig if ((d = opendir(name)) == NULL) { 1455 1.250 rillig DEBUG1(DIR, "Caching %s ... not found\n", name); 1456 1.235 rillig return dir; 1457 1.235 rillig } 1458 1.235 rillig 1459 1.250 rillig DEBUG1(DIR, "Caching %s ...\n", name); 1460 1.235 rillig 1461 1.235 rillig dir = CachedDir_New(name); 1462 1.235 rillig 1463 1.235 rillig while ((dp = readdir(d)) != NULL) { 1464 1.235 rillig 1465 1.235 rillig #if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ 1466 1.235 rillig /* 1467 1.235 rillig * The sun directory library doesn't check for a 0 inode 1468 1.235 rillig * (0-inode slots just take up space), so we have to do 1469 1.235 rillig * it ourselves. 1470 1.235 rillig */ 1471 1.235 rillig if (dp->d_fileno == 0) 1472 1.235 rillig continue; 1473 1.235 rillig #endif /* sun && d_ino */ 1474 1.235 rillig 1475 1.235 rillig (void)HashSet_Add(&dir->files, dp->d_name); 1476 1.235 rillig } 1477 1.235 rillig (void)closedir(d); 1478 1.235 rillig 1479 1.235 rillig OpenDirs_Add(&openDirs, dir); 1480 1.235 rillig if (path != NULL) 1481 1.264 rillig Lst_Append(&path->dirs, CachedDir_Ref(dir)); 1482 1.235 rillig 1483 1.250 rillig DEBUG1(DIR, "Caching %s done\n", name); 1484 1.235 rillig return dir; 1485 1.235 rillig } 1486 1.235 rillig 1487 1.254 rillig /* 1488 1.283 rillig * Read the list of filenames in the directory 'name' and store the result 1489 1.283 rillig * in 'openDirs'. 1490 1.150 rillig * 1491 1.283 rillig * If a search path is given, append the directory to that path. 1492 1.1 cgd * 1493 1.34 wiz * Input: 1494 1.150 rillig * path The path to which the directory should be 1495 1.283 rillig * added, or NULL to only add the directory to openDirs. 1496 1.150 rillig * name The name of the directory to add. 1497 1.150 rillig * The name is not normalized in any way. 1498 1.242 rillig * Output: 1499 1.242 rillig * result If no path is given and the directory exists, the 1500 1.242 rillig * returned CachedDir has a reference count of 0. It 1501 1.242 rillig * must either be assigned to a variable using 1502 1.242 rillig * CachedDir_Assign or be appended to a SearchPath using 1503 1.242 rillig * Lst_Append and CachedDir_Ref. 1504 1.1 cgd */ 1505 1.143 rillig CachedDir * 1506 1.260 rillig SearchPath_Add(SearchPath *path, const char *name) 1507 1.1 cgd { 1508 1.212 rillig 1509 1.212 rillig if (path != NULL && strcmp(name, ".DOTLAST") == 0) { 1510 1.286 rillig CachedDirListNode *ln; 1511 1.212 rillig 1512 1.212 rillig /* XXX: Linear search gets slow with thousands of entries. */ 1513 1.264 rillig for (ln = path->dirs.first; ln != NULL; ln = ln->next) { 1514 1.212 rillig CachedDir *pathDir = ln->datum; 1515 1.212 rillig if (strcmp(pathDir->name, name) == 0) 1516 1.212 rillig return pathDir; 1517 1.212 rillig } 1518 1.173 rillig 1519 1.264 rillig Lst_Prepend(&path->dirs, CachedDir_Ref(dotLast)); 1520 1.173 rillig } 1521 1.120 rillig 1522 1.235 rillig if (path != NULL) { 1523 1.242 rillig /* XXX: Why is OpenDirs only checked if path != NULL? */ 1524 1.235 rillig CachedDir *dir = OpenDirs_Find(&openDirs, name); 1525 1.235 rillig if (dir != NULL) { 1526 1.264 rillig if (Lst_FindDatum(&path->dirs, dir) == NULL) 1527 1.264 rillig Lst_Append(&path->dirs, CachedDir_Ref(dir)); 1528 1.235 rillig return dir; 1529 1.235 rillig } 1530 1.1 cgd } 1531 1.120 rillig 1532 1.235 rillig return CacheNewDir(name, path); 1533 1.1 cgd } 1534 1.1 cgd 1535 1.254 rillig /* 1536 1.254 rillig * Return a copy of dirSearchPath, incrementing the reference counts for 1537 1.254 rillig * the contained directories. 1538 1.254 rillig */ 1539 1.187 rillig SearchPath * 1540 1.187 rillig Dir_CopyDirSearchPath(void) 1541 1.1 cgd { 1542 1.225 rillig SearchPath *path = SearchPath_New(); 1543 1.286 rillig CachedDirListNode *ln; 1544 1.264 rillig for (ln = dirSearchPath.dirs.first; ln != NULL; ln = ln->next) { 1545 1.212 rillig CachedDir *dir = ln->datum; 1546 1.264 rillig Lst_Append(&path->dirs, CachedDir_Ref(dir)); 1547 1.212 rillig } 1548 1.212 rillig return path; 1549 1.1 cgd } 1550 1.1 cgd 1551 1.251 rillig /* 1552 1.251 rillig * Make a string by taking all the directories in the given search path and 1553 1.251 rillig * preceding them by the given flag. Used by the suffix module to create 1554 1.283 rillig * variables for compilers based on suffix search paths. Note that there is no 1555 1.283 rillig * space between the given flag and each directory. 1556 1.1 cgd */ 1557 1.1 cgd char * 1558 1.260 rillig SearchPath_ToFlags(SearchPath *path, const char *flag) 1559 1.1 cgd { 1560 1.212 rillig Buffer buf; 1561 1.286 rillig CachedDirListNode *ln; 1562 1.12 christos 1563 1.212 rillig Buf_Init(&buf); 1564 1.12 christos 1565 1.212 rillig if (path != NULL) { 1566 1.264 rillig for (ln = path->dirs.first; ln != NULL; ln = ln->next) { 1567 1.212 rillig CachedDir *dir = ln->datum; 1568 1.212 rillig Buf_AddStr(&buf, " "); 1569 1.212 rillig Buf_AddStr(&buf, flag); 1570 1.212 rillig Buf_AddStr(&buf, dir->name); 1571 1.212 rillig } 1572 1.1 cgd } 1573 1.12 christos 1574 1.265 rillig return Buf_DoneData(&buf); 1575 1.1 cgd } 1576 1.1 cgd 1577 1.225 rillig /* Free the search path and all directories mentioned in it. */ 1578 1.225 rillig void 1579 1.225 rillig SearchPath_Free(SearchPath *path) 1580 1.225 rillig { 1581 1.286 rillig CachedDirListNode *ln; 1582 1.225 rillig 1583 1.264 rillig for (ln = path->dirs.first; ln != NULL; ln = ln->next) { 1584 1.225 rillig CachedDir *dir = ln->datum; 1585 1.241 rillig CachedDir_Unref(dir); 1586 1.225 rillig } 1587 1.264 rillig Lst_Done(&path->dirs); 1588 1.264 rillig free(path); 1589 1.225 rillig } 1590 1.225 rillig 1591 1.254 rillig /* 1592 1.254 rillig * Clear out all elements from the given search path. 1593 1.254 rillig * The path is set to the empty list but is not destroyed. 1594 1.254 rillig */ 1595 1.1 cgd void 1596 1.224 rillig SearchPath_Clear(SearchPath *path) 1597 1.1 cgd { 1598 1.264 rillig while (!Lst_IsEmpty(&path->dirs)) { 1599 1.264 rillig CachedDir *dir = Lst_Dequeue(&path->dirs); 1600 1.241 rillig CachedDir_Unref(dir); 1601 1.212 rillig } 1602 1.1 cgd } 1603 1.12 christos 1604 1.1 cgd 1605 1.254 rillig /* 1606 1.254 rillig * Concatenate two paths, adding the second to the end of the first, 1607 1.254 rillig * skipping duplicates. 1608 1.254 rillig */ 1609 1.1 cgd void 1610 1.224 rillig SearchPath_AddAll(SearchPath *dst, SearchPath *src) 1611 1.1 cgd { 1612 1.286 rillig CachedDirListNode *ln; 1613 1.1 cgd 1614 1.264 rillig for (ln = src->dirs.first; ln != NULL; ln = ln->next) { 1615 1.212 rillig CachedDir *dir = ln->datum; 1616 1.264 rillig if (Lst_FindDatum(&dst->dirs, dir) == NULL) 1617 1.264 rillig Lst_Append(&dst->dirs, CachedDir_Ref(dir)); 1618 1.1 cgd } 1619 1.1 cgd } 1620 1.1 cgd 1621 1.105 rillig static int 1622 1.105 rillig percentage(int num, int den) 1623 1.105 rillig { 1624 1.212 rillig return den != 0 ? num * 100 / den : 0; 1625 1.105 rillig } 1626 1.105 rillig 1627 1.5 cgd void 1628 1.34 wiz Dir_PrintDirectories(void) 1629 1.1 cgd { 1630 1.212 rillig CachedDirListNode *ln; 1631 1.12 christos 1632 1.212 rillig debug_printf("#*** Directory Cache:\n"); 1633 1.212 rillig debug_printf( 1634 1.212 rillig "# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n", 1635 1.212 rillig hits, misses, nearmisses, bigmisses, 1636 1.212 rillig percentage(hits, hits + bigmisses + nearmisses)); 1637 1.248 rillig debug_printf("# refs hits directory\n"); 1638 1.212 rillig 1639 1.227 rillig for (ln = openDirs.list.first; ln != NULL; ln = ln->next) { 1640 1.212 rillig CachedDir *dir = ln->datum; 1641 1.248 rillig debug_printf("# %4d %4d %s\n", 1642 1.248 rillig dir->refCount, dir->hits, dir->name); 1643 1.212 rillig } 1644 1.1 cgd } 1645 1.1 cgd 1646 1.5 cgd void 1647 1.270 rillig SearchPath_Print(const SearchPath *path) 1648 1.1 cgd { 1649 1.286 rillig CachedDirListNode *ln; 1650 1.249 rillig 1651 1.264 rillig for (ln = path->dirs.first; ln != NULL; ln = ln->next) { 1652 1.249 rillig const CachedDir *dir = ln->datum; 1653 1.212 rillig debug_printf("%s ", dir->name); 1654 1.212 rillig } 1655 1.1 cgd } 1656