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