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