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