diff options
Diffstat (limited to 'dir.c')
-rw-r--r-- | dir.c | 1201 |
1 files changed, 505 insertions, 696 deletions
@@ -1,4 +1,4 @@ -/* $NetBSD: dir.c,v 1.135 2020/09/02 04:32:13 rillig Exp $ */ +/* $NetBSD: dir.c,v 1.193 2020/10/31 17:39:20 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -69,70 +69,58 @@ * SUCH DAMAGE. */ -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: dir.c,v 1.135 2020/09/02 04:32:13 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94"; -#else -__RCSID("$NetBSD: dir.c,v 1.135 2020/09/02 04:32:13 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * dir.c -- - * Directory searching using wildcards and/or normal names... - * Used both for source wildcarding in the Makefile and for finding - * implicit sources. +/* Directory searching using wildcards and/or normal names. + * Used both for source wildcarding in the makefile and for finding + * implicit sources. * * The interface for this module is: - * Dir_Init Initialize the module. + * Dir_Init Initialize the module. * - * Dir_InitCur Set the cur Path. + * Dir_InitCur Set the cur CachedDir. * - * Dir_InitDot Set the dot Path. + * Dir_InitDot Set the dot CachedDir. * - * Dir_End Cleanup the module. + * Dir_End Clean up the module. * - * Dir_SetPATH Set ${.PATH} to reflect state of dirSearchPath. + * Dir_SetPATH Set ${.PATH} to reflect state of dirSearchPath. * - * Dir_HasWildcards Returns TRUE if the name given it needs to - * be wildcard-expanded. + * Dir_HasWildcards + * Returns TRUE if the name given it needs to + * be wildcard-expanded. * - * Dir_Expand Given a pattern and a path, return a Lst of names - * which match the pattern on the search path. + * Dir_Expand Given a pattern and a path, return a Lst of names + * which match the pattern on the search path. * - * Dir_FindFile Searches for a file on a given search path. - * If it exists, the entire path is returned. - * Otherwise NULL is returned. + * Dir_FindFile Searches for a file on a given search path. + * If it exists, the entire path is returned. + * Otherwise NULL is returned. * - * Dir_FindHereOrAbove Search for a path in the current directory and - * then all the directories above it in turn until - * the path is found or we reach the root ("/"). + * Dir_FindHereOrAbove + * Search for a path in the current directory and + * then all the directories above it in turn until + * the path is found or we reach the root ("/"). * - * Dir_MTime Return the modification time of a node. The file - * is searched for along the default search path. - * The path and mtime fields of the node are filled - * in. + * Dir_MTime Return the modification time of a node. The file + * is searched for along the default search path. + * The path and mtime fields of the node are filled in. * - * Dir_AddDir Add a directory to a search path. + * Dir_AddDir Add a directory to a search path. * - * Dir_MakeFlags Given a search path and a command flag, create - * a string with each of the directories in the path - * preceded by the command flag and all of them - * separated by a space. + * Dir_MakeFlags Given a search path and a command flag, create + * a string with each of the directories in the path + * preceded by the command flag and all of them + * separated by a space. * - * Dir_Destroy Destroy an element of a search path. Frees up all - * things that can be freed for the element as long - * as the element is no longer referenced by any other - * search path. - * Dir_ClearPath Resets a search path to the empty list. + * Dir_Destroy Destroy an element of a search path. Frees up all + * things that can be freed for the element as long + * as the element is no longer referenced by any other + * search path. + * + * Dir_ClearPath Resets a search path to the empty list. * * For debugging: - * Dir_PrintDirectories Print stats about the directory cache. + * Dir_PrintDirectories + * Print stats about the directory cache. */ #include <sys/types.h> @@ -140,99 +128,155 @@ __RCSID("$NetBSD: dir.c,v 1.135 2020/09/02 04:32:13 rillig Exp $"); #include <dirent.h> #include <errno.h> -#include <stdio.h> #include "make.h" #include "dir.h" #include "job.h" +/* "@(#)dir.c 8.2 (Berkeley) 1/2/94" */ +MAKE_RCSID("$NetBSD: dir.c,v 1.193 2020/10/31 17:39:20 rillig Exp $"); + +#define DIR_DEBUG0(text) DEBUG0(DIR, text) +#define DIR_DEBUG1(fmt, arg1) DEBUG1(DIR, fmt, arg1) +#define DIR_DEBUG2(fmt, arg1, arg2) DEBUG2(DIR, fmt, arg1, arg2) + +/* A search path is a list of CachedDir structures. A CachedDir has in it the + * name of the directory and the names of all the files in the directory. + * This is used to cut down on the number of system calls necessary to find + * implicit dependents and their like. Since these searches are made before + * any actions are taken, we need not worry about the directory changing due + * to creation commands. If this hampers the style of some makefiles, they + * must be changed. + * + * All previously-read directories are kept in openDirs, which is checked + * first before a directory is opened. + * + * The need for the caching of whole directories is brought about by the + * multi-level transformation code in suff.c, which tends to search for far + * more files than regular make does. In the initial implementation, the + * amount of time spent performing "stat" calls was truly astronomical. + * The problem with caching at the start is, of course, that pmake doesn't + * then detect changes to these directories during the course of the make. + * Three possibilities suggest themselves: + * + * 1) just use stat to test for a file's existence. As mentioned above, + * this is very inefficient due to the number of checks engendered by + * the multi-level transformation code. + * + * 2) use readdir() and company to search the directories, keeping them + * open between checks. I have tried this and while it didn't slow down + * the process too much, it could severely affect the amount of + * parallelism available as each directory open would take another file + * descriptor out of play for handling I/O for another job. Given that + * it is only recently that UNIX OS's have taken to allowing more than + * 20 or 32 file descriptors for a process, this doesn't seem acceptable + * to me. + * + * 3) record the mtime of the directory in the CachedDir structure and + * verify the directory hasn't changed since the contents were cached. + * This will catch the creation or deletion of files, but not the + * updating of files. However, since it is the creation and deletion + * that is the problem, this could be a good thing to do. Unfortunately, + * if the directory (say ".") were fairly large and changed fairly + * frequently, the constant reloading could seriously degrade + * performance. It might be good in such cases to keep track of the + * number of reloadings and if the number goes over a (small) limit, + * resort to using stat in its place. + * + * An additional thing to consider is that pmake is used primarily to create + * C programs and until recently pcc-based compilers refused to allow you to + * specify where the resulting object file should be placed. This forced all + * objects to be created in the current directory. This isn't meant as a full + * excuse, just an explanation of some of the reasons for the caching used + * here. + * + * One more note: the location of a target's file is only performed on the + * downward traversal of the graph and then only for terminal nodes in the + * graph. This could be construed as wrong in some cases, but prevents + * inadvertent modification of files when the "installed" directory for a + * file is provided in the search path. + * + * Another data structure maintained by this module is an mtime cache used + * when the searching of cached directories fails to find a file. In the past, + * Dir_FindFile would simply perform an access() call in such a case to + * determine if the file could be found using just the name given. When this + * hit, however, all that was gained was the knowledge that the file existed. + * Given that an access() is essentially a stat() without the copyout() call, + * and that the same filesystem overhead would have to be incurred in + * Dir_MTime, it made sense to replace the access() with a stat() and record + * the mtime in a cache for when Dir_MTime was actually called. + */ -#define DIR_DEBUG0(fmt) \ - if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt) +typedef List CachedDirList; +typedef ListNode CachedDirListNode; -#define DIR_DEBUG1(fmt, arg1) \ - if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1) +typedef ListNode SearchPathNode; -#define DIR_DEBUG2(fmt, arg1, arg2) \ - if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1, arg2) +SearchPath *dirSearchPath; /* main search path */ +/* A list of cached directories, with fast lookup by directory name. */ +typedef struct OpenDirs { + CachedDirList *list; + HashTable /* of CachedDirListNode */ table; +} OpenDirs; -/* - * A search path consists of a Lst of Path structures. A Path structure - * has in it the name of the directory and a hash table of all the files - * in the directory. This is used to cut down on the number of system - * calls necessary to find implicit dependents and their like. Since - * these searches are made before any actions are taken, we need not - * worry about the directory changing due to creation commands. If this - * hampers the style of some makefiles, they must be changed. - * - * A list of all previously-read directories is kept in the - * openDirectories Lst. This list is checked first before a directory - * is opened. - * - * The need for the caching of whole directories is brought about by - * the multi-level transformation code in suff.c, which tends to search - * for far more files than regular make does. In the initial - * implementation, the amount of time spent performing "stat" calls was - * truly astronomical. The problem with hashing at the start is, - * of course, that pmake doesn't then detect changes to these directories - * during the course of the make. Three possibilities suggest themselves: - * - * 1) just use stat to test for a file's existence. As mentioned - * above, this is very inefficient due to the number of checks - * engendered by the multi-level transformation code. - * 2) use readdir() and company to search the directories, keeping - * them open between checks. I have tried this and while it - * didn't slow down the process too much, it could severely - * affect the amount of parallelism available as each directory - * open would take another file descriptor out of play for - * handling I/O for another job. Given that it is only recently - * that UNIX OS's have taken to allowing more than 20 or 32 - * file descriptors for a process, this doesn't seem acceptable - * to me. - * 3) record the mtime of the directory in the Path structure and - * verify the directory hasn't changed since the contents were - * hashed. This will catch the creation or deletion of files, - * but not the updating of files. However, since it is the - * creation and deletion that is the problem, this could be - * a good thing to do. Unfortunately, if the directory (say ".") - * were fairly large and changed fairly frequently, the constant - * rehashing could seriously degrade performance. It might be - * good in such cases to keep track of the number of rehashes - * and if the number goes over a (small) limit, resort to using - * stat in its place. - * - * An additional thing to consider is that pmake is used primarily - * to create C programs and until recently pcc-based compilers refused - * to allow you to specify where the resulting object file should be - * placed. This forced all objects to be created in the current - * directory. This isn't meant as a full excuse, just an explanation of - * some of the reasons for the caching used here. - * - * One more note: the location of a target's file is only performed - * on the downward traversal of the graph and then only for terminal - * nodes in the graph. This could be construed as wrong in some cases, - * but prevents inadvertent modification of files when the "installed" - * directory for a file is provided in the search path. - * - * Another data structure maintained by this module is an mtime - * cache used when the searching of cached directories fails to find - * a file. In the past, Dir_FindFile would simply perform an access() - * call in such a case to determine if the file could be found using - * just the name given. When this hit, however, all that was gained - * was the knowledge that the file existed. Given that an access() is - * essentially a stat() without the copyout() call, and that the same - * filesystem overhead would have to be incurred in Dir_MTime, it made - * sense to replace the access() with a stat() and record the mtime - * in a cache for when Dir_MTime was actually called. - */ +static void +OpenDirs_Init(OpenDirs *odirs) +{ + odirs->list = Lst_New(); + HashTable_Init(&odirs->table); +} + +#ifdef CLEANUP +static void +OpenDirs_Done(OpenDirs *odirs) +{ + CachedDirListNode *ln = odirs->list->first; + while (ln != NULL) { + CachedDirListNode *next = ln->next; + CachedDir *dir = ln->datum; + Dir_Destroy(dir); /* removes the dir from odirs->list */ + ln = next; + } + Lst_Free(odirs->list); + HashTable_Done(&odirs->table); +} +#endif + +static CachedDir * +OpenDirs_Find(OpenDirs *odirs, const char *name) +{ + CachedDirListNode *ln = HashTable_FindValue(&odirs->table, name); + return ln != NULL ? ln->datum : NULL; +} + +static void +OpenDirs_Add(OpenDirs *odirs, CachedDir *cdir) +{ + HashEntry *he = HashTable_FindEntry(&odirs->table, cdir->name); + if (he != NULL) + return; + he = HashTable_CreateEntry(&odirs->table, cdir->name, NULL); + Lst_Append(odirs->list, cdir); + HashEntry_Set(he, odirs->list->last); +} -Lst dirSearchPath; /* main search path */ +static void +OpenDirs_Remove(OpenDirs *odirs, const char *name) +{ + HashEntry *he = HashTable_FindEntry(&odirs->table, name); + CachedDirListNode *ln; + if (he == NULL) + return; + ln = HashEntry_Get(he); + HashTable_DeleteEntry(&odirs->table, he); + Lst_Remove(odirs->list, ln); +} -static Lst openDirectories; /* the list of all open directories */ +static OpenDirs openDirs; /* the list of all open directories */ /* - * Variables for gathering statistics on the efficiency of the hashing + * Variables for gathering statistics on the efficiency of the cashing * mechanism. */ static int hits; /* Found in directory cache */ @@ -240,9 +284,9 @@ static int misses; /* Sad, but not evil misses */ static int nearmisses; /* Found under search path */ static int bigmisses; /* Sought by itself */ -static Path *dot; /* contents of current directory */ -static Path *cur; /* contents of current directory, if not dot */ -static Path *dotLast; /* a fake path entry indicating we need to +static CachedDir *dot; /* contents of current directory */ +static CachedDir *cur; /* contents of current directory, if not dot */ +static CachedDir *dotLast; /* a fake path entry indicating we need to * look for . last */ /* Results of doing a last-resort stat in Dir_FindFile -- if we have to go to @@ -252,19 +296,9 @@ static Path *dotLast; /* a fake path entry indicating we need to * already updated the file, in which case we'll update it again. Generally, * there won't be two rules to update a single file, so this should be ok, * but... */ -static Hash_Table mtimes; - -static Hash_Table lmtimes; /* same as mtimes but for lstat */ - -static void DirExpandCurly(const char *, const char *, Lst, Lst); -static void DirExpandInt(const char *, Lst, Lst); -static int DirPrintWord(void *, void *); -static int DirPrintDir(void *, void *); -static char *DirLookup(Path *, const char *, const char *, Boolean); -static char *DirLookupSubdir(Path *, const char *); -static char *DirFindDot(Boolean, const char *, const char *); -static char *DirLookupAbs(Path *, const char *, const char *); +static HashTable mtimes; +static HashTable lmtimes; /* same as mtimes but for lstat */ /* * We use stat(2) a lot, cache the results. @@ -277,17 +311,17 @@ struct cache_st { }; /* minimize changes below */ -typedef enum { +typedef enum CachedStatsFlags { CST_LSTAT = 0x01, /* call lstat(2) instead of stat(2) */ CST_UPDATE = 0x02 /* ignore existing cached entry */ } CachedStatsFlags; /* Returns 0 and the result of stat(2) or lstat(2) in *mst, or -1 on error. */ static int -cached_stats(Hash_Table *htp, const char *pathname, struct make_stat *mst, +cached_stats(HashTable *htp, const char *pathname, struct make_stat *mst, CachedStatsFlags flags) { - Hash_Entry *entry; + HashEntry *entry; struct stat sys_st; struct cache_st *cst; int rc; @@ -295,10 +329,10 @@ cached_stats(Hash_Table *htp, const char *pathname, struct make_stat *mst, if (!pathname || !pathname[0]) return -1; - entry = Hash_FindEntry(htp, pathname); + entry = HashTable_FindEntry(htp, pathname); if (entry && !(flags & CST_UPDATE)) { - cst = Hash_GetValue(entry); + cst = HashEntry_Get(entry); mst->mst_mode = cst->mode; mst->mst_mtime = (flags & CST_LSTAT) ? cst->lmtime : cst->mtime; @@ -322,12 +356,12 @@ cached_stats(Hash_Table *htp, const char *pathname, struct make_stat *mst, mst->mst_mtime = sys_st.st_mtime; if (entry == NULL) - entry = Hash_CreateEntry(htp, pathname, NULL); - if (Hash_GetValue(entry) == NULL) { - Hash_SetValue(entry, bmake_malloc(sizeof(*cst))); - memset(Hash_GetValue(entry), 0, sizeof(*cst)); + entry = HashTable_CreateEntry(htp, pathname, NULL); + if (HashEntry_Get(entry) == NULL) { + HashEntry_Set(entry, bmake_malloc(sizeof(*cst))); + memset(HashEntry_Get(entry), 0, sizeof(*cst)); } - cst = Hash_GetValue(entry); + cst = HashEntry_Get(entry); if (flags & CST_LSTAT) { cst->lmtime = sys_st.st_mtime; } else { @@ -352,14 +386,14 @@ cached_lstat(const char *pathname, struct make_stat *st) return cached_stats(&lmtimes, pathname, st, CST_LSTAT); } -/* Initialize things for this module. */ +/* Initialize the directories module. */ void Dir_Init(void) { - dirSearchPath = Lst_Init(); - openDirectories = Lst_Init(); - Hash_InitTable(&mtimes, 0); - Hash_InitTable(&lmtimes, 0); + dirSearchPath = Lst_New(); + OpenDirs_Init(&openDirs); + HashTable_Init(&mtimes); + HashTable_Init(&lmtimes); } void @@ -367,11 +401,11 @@ Dir_InitDir(const char *cdname) { Dir_InitCur(cdname); - dotLast = bmake_malloc(sizeof(Path)); + dotLast = bmake_malloc(sizeof(CachedDir)); dotLast->refCount = 1; dotLast->hits = 0; dotLast->name = bmake_strdup(".DOTLAST"); - Hash_InitTable(&dotLast->files, -1); + HashTable_Init(&dotLast->files); } /* @@ -380,23 +414,23 @@ Dir_InitDir(const char *cdname) void Dir_InitCur(const char *cdname) { - Path *p; + CachedDir *dir; if (cdname != NULL) { /* * Our build directory is not the same as our source directory. * Keep this one around too. */ - if ((p = Dir_AddDir(NULL, cdname))) { - p->refCount += 1; - if (cur && cur != p) { + if ((dir = Dir_AddDir(NULL, cdname))) { + dir->refCount++; + if (cur && cur != dir) { /* - * We've been here before, cleanup. + * We've been here before, clean up. */ - cur->refCount -= 1; + cur->refCount--; Dir_Destroy(cur); } - cur = p; + cur = dir; } } } @@ -407,11 +441,8 @@ void Dir_InitDot(void) { if (dot != NULL) { - LstNode ln; - - /* Remove old entry from openDirectories, but do not destroy. */ - ln = Lst_FindDatum(openDirectories, dot); - Lst_Remove(openDirectories, ln); + /* Remove old entry from openDirs, but do not destroy. */ + OpenDirs_Remove(&openDirs, dot->name); } dot = Dir_AddDir(NULL, "."); @@ -425,28 +456,27 @@ Dir_InitDot(void) * We always need to have dot around, so we increment its reference count * to make sure it's not destroyed. */ - dot->refCount += 1; + dot->refCount++; Dir_SetPATH(); /* initialize */ } -/* Clean up things for this module. */ +/* Clean up the directories module. */ void Dir_End(void) { #ifdef CLEANUP if (cur) { - cur->refCount -= 1; + cur->refCount--; Dir_Destroy(cur); } - dot->refCount -= 1; - dotLast->refCount -= 1; + dot->refCount--; + dotLast->refCount--; Dir_Destroy(dotLast); Dir_Destroy(dot); Dir_ClearPath(dirSearchPath); Lst_Free(dirSearchPath); - Dir_ClearPath(openDirectories); - Lst_Free(openDirectories); - Hash_DeleteTable(&mtimes); + OpenDirs_Done(&openDirs); + HashTable_Done(&mtimes); #endif } @@ -458,16 +488,14 @@ Dir_End(void) void Dir_SetPATH(void) { - LstNode ln; /* a list element */ - Path *p; + CachedDirListNode *ln; Boolean hasLastDot = FALSE; /* true if we should search dot last */ Var_Delete(".PATH", VAR_GLOBAL); - Lst_Open(dirSearchPath); - if ((ln = Lst_First(dirSearchPath)) != NULL) { - p = LstNode_Datum(ln); - if (p == dotLast) { + if ((ln = dirSearchPath->first) != NULL) { + CachedDir *dir = ln->datum; + if (dir == dotLast) { hasLastDot = TRUE; Var_Append(".PATH", dotLast->name, VAR_GLOBAL); } @@ -480,13 +508,13 @@ Dir_SetPATH(void) Var_Append(".PATH", cur->name, VAR_GLOBAL); } - while ((ln = Lst_Next(dirSearchPath)) != NULL) { - p = LstNode_Datum(ln); - if (p == dotLast) + for (ln = dirSearchPath->first; ln != NULL; ln = ln->next) { + CachedDir *dir = ln->datum; + if (dir == dotLast) continue; - if (p == dot && hasLastDot) + if (dir == dot && hasLastDot) continue; - Var_Append(".PATH", p->name, VAR_GLOBAL); + Var_Append(".PATH", dir->name, VAR_GLOBAL); } if (hasLastDot) { @@ -495,40 +523,26 @@ Dir_SetPATH(void) if (cur) Var_Append(".PATH", cur->name, VAR_GLOBAL); } - Lst_Close(dirSearchPath); -} - -/* See if the Path structure describes the same directory as the - * given one by comparing their names. Called from Dir_AddDir via - * Lst_Find when searching the list of open directories. */ -static Boolean -DirFindName(const void *p, const void *desiredName) -{ - return strcmp(((const Path *)p)->name, desiredName) == 0; } -/* See if the given name has any wildcard characters in it. Be careful not to - * expand unmatching brackets or braces. +/* See if the given name has any wildcard characters in it and all braces and + * brackets are properly balanced. * * XXX: This code is not 100% correct ([^]] fails etc.). I really don't think * that make(1) should be expanding patterns, because then you have to set a * mechanism for escaping the expansion! * - * Input: - * name name to check - * - * Results: - * returns TRUE if the word should be expanded, FALSE otherwise + * Return TRUE if the word should be expanded, FALSE otherwise. */ Boolean Dir_HasWildcards(const char *name) { - const char *cp; + const char *p; Boolean wild = FALSE; int braces = 0, brackets = 0; - for (cp = name; *cp; cp++) { - switch (*cp) { + for (p = name; *p != '\0'; p++) { + switch (*p) { case '{': braces++; wild = TRUE; @@ -554,51 +568,49 @@ Dir_HasWildcards(const char *name) return wild && brackets == 0 && braces == 0; } -/*- - *----------------------------------------------------------------------- - * DirMatchFiles -- - * Given a pattern and a Path structure, see if any files - * match the pattern and add their names to the 'expansions' list if - * any do. This is incomplete -- it doesn't take care of patterns like - * src / *src / *.c properly (just *.c on any of the directories), but it - * will do for now. +/* See if any files match the pattern and add their names to the 'expansions' + * list if they do. + * + * This is incomplete -- wildcards are only expanded in the final path + * component, but not in directories like src/lib*c/file*.c, but it + * will do for now (now being 1993 until at least 2020). To expand these, + * use the ':sh' variable modifier such as in ${:!echo src/lib*c/file*.c!}. * * Input: * pattern Pattern to look for - * p Directory to search + * dir Directory to search * expansion Place to store the results - * - * Side Effects: - * File names are added to the expansions lst. The directory will be - * fully hashed when this is done. - *----------------------------------------------------------------------- */ static void -DirMatchFiles(const char *pattern, Path *p, Lst expansions) +DirMatchFiles(const char *pattern, CachedDir *dir, StringList *expansions) { - Hash_Search search; /* Index into the directory's table */ - Hash_Entry *entry; /* Current entry in the table */ - Boolean isDot; /* TRUE if the directory being searched is . */ + const char *dirName = dir->name; + Boolean isDot = dirName[0] == '.' && dirName[1] == '\0'; + HashIter hi; + + HashIter_Init(&hi, &dir->files); + while (HashIter_Next(&hi) != NULL) { + const char *base = hi.entry->key; - isDot = (*p->name == '.' && p->name[1] == '\0'); + if (!Str_Match(base, pattern)) + continue; - for (entry = Hash_EnumFirst(&p->files, &search); - entry != NULL; - entry = Hash_EnumNext(&search)) - { /* - * See if the file matches the given pattern. Note we follow the UNIX - * convention that dot files will only be found if the pattern - * begins with a dot (note also that as a side effect of the hashing - * scheme, .* won't match . or .. since they aren't hashed). + * Follow the UNIX convention that dot files are only found if the + * pattern begins with a dot. The pattern '.*' does not match '.' or + * '..' since these are not included in the directory cache. + * + * This means that the pattern '[a-z.]*' does not find '.file', which + * is consistent with bash, NetBSD sh and csh. */ - if (Str_Match(entry->name, pattern) && - ((entry->name[0] != '.') || - (pattern[0] == '.'))) + if (base[0] == '.' && pattern[0] != '.') + continue; + { - Lst_Append(expansions, - (isDot ? bmake_strdup(entry->name) : - str_concat3(p->name, "/", entry->name))); + char *fullName = isDot + ? bmake_strdup(base) + : str_concat3(dirName, "/", base); + Lst_Append(expansions, fullName); } } } @@ -667,30 +679,24 @@ concat3(const char *a, size_t a_len, const char *b, size_t b_len, return s; } -/*- - *----------------------------------------------------------------------- - * DirExpandCurly -- - * Expand curly braces like the C shell. Does this recursively. - * Note the special case: if after the piece of the curly brace is - * done there are no wildcard characters in the result, the result is - * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE. +/* Expand curly braces like the C shell. Brace expansion by itself is purely + * textual, the expansions are not looked up in the file system. But if an + * expanded word contains wildcard characters, it is expanded further, + * matching only the actually existing files. + * + * Example: "{a{b,c}}" expands to "ab" and "ac". + * Example: "{a}" expands to "a". + * Example: "{a,*.c}" expands to "a" and all "*.c" files that exist. * * Input: * word Entire word to expand * brace First curly brace in it * path Search path to use * expansions Place to store the expansions - * - * Results: - * None. - * - * Side Effects: - * The given list is filled with the expansions... - * - *----------------------------------------------------------------------- */ static void -DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions) +DirExpandCurly(const char *word, const char *brace, SearchPath *path, + StringList *expansions) { const char *prefix, *middle, *piece, *middle_end, *suffix; size_t prefix_len, suffix_len; @@ -731,72 +737,40 @@ DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions) } -/*- - *----------------------------------------------------------------------- - * DirExpandInt -- - * Internal expand routine. Passes through the directories in the - * path one by one, calling DirMatchFiles for each. NOTE: This still - * doesn't handle patterns in directories... - * - * Input: - * word Word to expand - * path Path on which to look - * expansions Place to store the result - * - * Results: - * None. - * - * Side Effects: - * Things are added to the expansions list. - * - *----------------------------------------------------------------------- - */ +/* Expand the word in each of the directories from the path. */ static void -DirExpandInt(const char *word, Lst path, Lst expansions) +DirExpandPath(const char *word, SearchPath *path, StringList *expansions) { - LstNode ln; /* Current node */ - - Lst_Open(path); - while ((ln = Lst_Next(path)) != NULL) { - Path *p = LstNode_Datum(ln); - DirMatchFiles(word, p, expansions); + SearchPathNode *ln; + for (ln = path->first; ln != NULL; ln = ln->next) { + CachedDir *dir = ln->datum; + DirMatchFiles(word, dir, expansions); } - Lst_Close(path); } -/* Print a word in the list of expansions. - * Callback for Dir_Expand when DEBUG(DIR), via Lst_ForEach. */ -static int -DirPrintWord(void *word, void *dummy MAKE_ATTR_UNUSED) +static void +PrintExpansions(StringList *expansions) { - fprintf(debug_file, "%s ", (char *)word); - - return 0; + const char *sep = ""; + StringListNode *ln; + for (ln = expansions->first; ln != NULL; ln = ln->next) { + const char *word = ln->datum; + debug_printf("%s%s", sep, word); + sep = " "; + } + debug_printf("\n"); } -/*- - *----------------------------------------------------------------------- - * Dir_Expand -- - * Expand the given word into a list of words by globbing it looking - * in the directories on the given search path. +/* Expand the given word into a list of words by globbing it, looking in the + * directories on the given search path. * * Input: * word the word to expand - * path the list of directories in which to find the - * resulting files + * path the directories in which to find the files * expansions the list on which to place the results - * - * Results: - * A list of words consisting of the files which exist along the search - * path matching the given pattern. - * - * Side Effects: - * Directories may be opened. Who knows? - * Undefined behavior if the word is really in read-only memory. - *----------------------------------------------------------------------- */ void -Dir_Expand(const char *word, Lst path, Lst expansions) +Dir_Expand(const char *word, SearchPath *path, StringList *expansions) { const char *cp; @@ -816,17 +790,12 @@ Dir_Expand(const char *word, Lst path, Lst expansions) * in the string. */ for (cp = word; *cp; cp++) { - if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') { + if (*cp == '?' || *cp == '[' || *cp == '*') { break; } } - if (*cp == '{') { - /* - * This one will be fun. - */ - DirExpandCurly(word, cp, path, expansions); - return; - } else if (*cp != '\0') { + + if (*cp != '\0') { /* * Back up to the start of the component */ @@ -834,16 +803,13 @@ Dir_Expand(const char *word, Lst path, Lst expansions) cp--; } if (cp != word) { - char sc; - char *dirpath; + char *prefix = bmake_strsedup(word, cp + 1); /* * If the glob isn't in the first component, try and find * all the components up to the one with a wildcard. */ - sc = cp[1]; - ((char *)UNCONST(cp))[1] = '\0'; - dirpath = Dir_FindFile(word, path); - ((char *)UNCONST(cp))[1] = sc; + char *dirpath = Dir_FindFile(prefix, path); + free(prefix); /* * dirpath is null if can't find the leading component * XXX: Dir_FindFile won't find internal components. @@ -855,22 +821,22 @@ Dir_Expand(const char *word, Lst path, Lst expansions) char *dp = &dirpath[strlen(dirpath) - 1]; if (*dp == '/') *dp = '\0'; - path = Lst_Init(); + path = Lst_New(); (void)Dir_AddDir(path, dirpath); - DirExpandInt(cp + 1, path, expansions); + DirExpandPath(cp + 1, path, expansions); Lst_Free(path); } } else { /* * Start the search from the local directory */ - DirExpandInt(word, path, expansions); + DirExpandPath(word, path, expansions); } } else { /* * Return the file -- this should never happen. */ - DirExpandInt(word, path, expansions); + DirExpandPath(word, path, expansions); } } else { /* @@ -881,108 +847,63 @@ Dir_Expand(const char *word, Lst path, Lst expansions) /* * Then the files in every other directory on the path. */ - DirExpandInt(word, path, expansions); + DirExpandPath(word, path, expansions); } } - if (DEBUG(DIR)) { - Lst_ForEach(expansions, DirPrintWord, NULL); - fprintf(debug_file, "\n"); - } + if (DEBUG(DIR)) + PrintExpansions(expansions); } -/*- - *----------------------------------------------------------------------- - * DirLookup -- - * Find if the file with the given name exists in the given path. - * - * Results: - * The path to the file or NULL. This path is guaranteed to be in a - * different part of memory than name and so may be safely free'd. - * - * Side Effects: - * None. - *----------------------------------------------------------------------- - */ +/* Find if the file with the given name exists in the given path. + * Return the freshly allocated path to the file, or NULL. */ static char * -DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp, - Boolean hasSlash MAKE_ATTR_UNUSED) +DirLookup(CachedDir *dir, const char *base) { char *file; /* the current filename to check */ - DIR_DEBUG1(" %s ...\n", p->name); + DIR_DEBUG1(" %s ...\n", dir->name); - if (Hash_FindEntry(&p->files, cp) == NULL) + if (HashTable_FindEntry(&dir->files, base) == NULL) return NULL; - file = str_concat3(p->name, "/", cp); + file = str_concat3(dir->name, "/", base); DIR_DEBUG1(" returning %s\n", file); - p->hits += 1; - hits += 1; + dir->hits++; + hits++; return file; } -/*- - *----------------------------------------------------------------------- - * DirLookupSubdir -- - * Find if the file with the given name exists in the given path. - * - * Results: - * The path to the file or NULL. This path is guaranteed to be in a - * different part of memory than name and so may be safely free'd. - * - * Side Effects: - * If the file is found, it is added in the modification times hash - * table. - *----------------------------------------------------------------------- - */ +/* Find if the file with the given name exists in the given directory. + * Return the freshly allocated path to the file, or NULL. */ static char * -DirLookupSubdir(Path *p, const char *name) +DirLookupSubdir(CachedDir *dir, const char *name) { struct make_stat mst; - char *file; /* the current filename to check */ - - if (p != dot) { - file = str_concat3(p->name, "/", name); - } else { - /* - * Checking in dot -- DON'T put a leading ./ on the thing. - */ - file = bmake_strdup(name); - } + char *file = dir == dot ? bmake_strdup(name) + : str_concat3(dir->name, "/", name); DIR_DEBUG1("checking %s ...\n", file); if (cached_stat(file, &mst) == 0) { - nearmisses += 1; + nearmisses++; return file; } free(file); return NULL; } -/*- - *----------------------------------------------------------------------- - * DirLookupAbs -- - * Find if the file with the given name exists in the given path. - * - * Results: - * The path to the file, the empty string or NULL. If the file is - * the empty string, the search should be terminated. - * This path is guaranteed to be in a different part of memory - * than name and so may be safely free'd. - * - * Side Effects: - * None. - *----------------------------------------------------------------------- +/* Find if the file with the given name exists in the given path. + * Return the freshly allocated path to the file, the empty string, or NULL. + * Returning the empty string means that the search should be terminated. */ static char * -DirLookupAbs(Path *p, const char *name, const char *cp) +DirLookupAbs(CachedDir *dir, const char *name, const char *cp) { - char *p1; /* pointer into p->name */ - const char *p2; /* pointer into name */ + const char *dnp; /* pointer into dir->name */ + const char *np; /* pointer into name */ - DIR_DEBUG1(" %s ...\n", p->name); + DIR_DEBUG1(" %s ...\n", dir->name); /* * If the file has a leading path component and that component @@ -990,88 +911,68 @@ DirLookupAbs(Path *p, const char *name, const char *cp) * directory, we can attempt another cache lookup. And if we don't * have a hit, we can safely assume the file does not exist at all. */ - for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) { + for (dnp = dir->name, np = name; *dnp != '\0' && *dnp == *np; dnp++, np++) continue; - } - if (*p1 != '\0' || p2 != cp - 1) { + if (*dnp != '\0' || np != cp - 1) return NULL; - } - if (Hash_FindEntry(&p->files, cp) == NULL) { + if (HashTable_FindEntry(&dir->files, cp) == NULL) { DIR_DEBUG0(" must be here but isn't -- returning\n"); - /* Return empty string: terminates search */ - return bmake_strdup(""); + return bmake_strdup(""); /* to terminate the search */ } - p->hits += 1; - hits += 1; + dir->hits++; + hits++; DIR_DEBUG1(" returning %s\n", name); return bmake_strdup(name); } -/*- - *----------------------------------------------------------------------- - * DirFindDot -- - * Find the file given on "." or curdir - * - * Results: - * The path to the file or NULL. This path is guaranteed to be in a - * different part of memory than name and so may be safely free'd. - * - * Side Effects: - * Hit counts change - *----------------------------------------------------------------------- - */ +/* Find the file given on "." or curdir. + * Return the freshly allocated path to the file, or NULL. */ static char * -DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp) +DirFindDot(const char *name, const char *base) { - if (Hash_FindEntry(&dot->files, cp) != NULL) { + if (HashTable_FindEntry(&dot->files, base) != NULL) { DIR_DEBUG0(" in '.'\n"); - hits += 1; - dot->hits += 1; + hits++; + dot->hits++; return bmake_strdup(name); } - if (cur && Hash_FindEntry(&cur->files, cp) != NULL) { + + if (cur != NULL && HashTable_FindEntry(&cur->files, base) != NULL) { DIR_DEBUG1(" in ${.CURDIR} = %s\n", cur->name); - hits += 1; - cur->hits += 1; - return str_concat3(cur->name, "/", cp); + hits++; + cur->hits++; + return str_concat3(cur->name, "/", base); } return NULL; } -/*- - *----------------------------------------------------------------------- - * Dir_FindFile -- - * Find the file with the given name along the given search path. +/* Find the file with the given name along the given search path. + * + * If the file is found in a directory that is not on the path + * already (either 'name' is absolute or it is a relative path + * [ dir1/.../dirn/file ] which exists below one of the directories + * already on the search path), its directory is added to the end + * of the path, on the assumption that there will be more files in + * that directory later on. Sometimes this is true. Sometimes not. * * Input: * name the file to find - * path the Lst of directories to search + * path the directories to search, or NULL * * Results: - * The path to the file or NULL. This path is guaranteed to be in a - * different part of memory than name and so may be safely free'd. - * - * Side Effects: - * If the file is found in a directory which is not on the path - * already (either 'name' is absolute or it is a relative path - * [ dir1/.../dirn/file ] which exists below one of the directories - * already on the search path), its directory is added to the end - * of the path on the assumption that there will be more files in - * that directory later on. Sometimes this is true. Sometimes not. - *----------------------------------------------------------------------- + * The freshly allocated path to the file, or NULL. */ char * -Dir_FindFile(const char *name, Lst path) +Dir_FindFile(const char *name, SearchPath *path) { - LstNode ln; /* a list element */ + SearchPathNode *ln; char *file; /* the current filename to check */ - Path *p; /* current path member */ - const char *cp; /* Terminal name of file */ - Boolean hasLastDot = FALSE; /* true we should search dot last */ + const char *base; /* Terminal name of file */ + Boolean hasLastDot = FALSE; /* true if we should search dot last */ Boolean hasSlash; /* true if 'name' contains a / */ struct make_stat mst; /* Buffer for stat, if necessary */ const char *trailing_dot = "."; @@ -1080,27 +981,26 @@ Dir_FindFile(const char *name, Lst path) * Find the final component of the name and note whether it has a * slash in it (the name, I mean) */ - cp = strrchr(name, '/'); - if (cp) { + base = strrchr(name, '/'); + if (base) { hasSlash = TRUE; - cp += 1; + base++; } else { hasSlash = FALSE; - cp = name; + base = name; } DIR_DEBUG1("Searching for %s ...", name); if (path == NULL) { DIR_DEBUG0("couldn't open path, file not found\n"); - misses += 1; + misses++; return NULL; } - Lst_Open(path); - if ((ln = Lst_First(path)) != NULL) { - p = LstNode_Datum(ln); - if (p == dotLast) { + if ((ln = path->first) != NULL) { + CachedDir *dir = ln->datum; + if (dir == dotLast) { hasLastDot = TRUE; DIR_DEBUG0("[dot last]..."); } @@ -1112,7 +1012,7 @@ Dir_FindFile(const char *name, Lst path) * directory component is exactly `./', consult the cached contents * of each of the directories on the search path. */ - if (!hasSlash || (cp - name == 2 && *name == '.')) { + if (!hasSlash || (base - name == 2 && *name == '.')) { /* * We look through all the directories on the path seeking one which * contains the final component of the given name. If such a beast @@ -1127,27 +1027,20 @@ Dir_FindFile(const char *name, Lst path) * This is so there are no conflicts between what the user * specifies (fish.c) and what pmake finds (./fish.c). */ - if (!hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) { - Lst_Close(path); + if (!hasLastDot && (file = DirFindDot(name, base)) != NULL) return file; - } - while ((ln = Lst_Next(path)) != NULL) { - p = LstNode_Datum(ln); - if (p == dotLast) + for (; ln != NULL; ln = ln->next) { + CachedDir *dir = ln->datum; + if (dir == dotLast) continue; - if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) { - Lst_Close(path); + if ((file = DirLookup(dir, base)) != NULL) return file; - } } - if (hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) { - Lst_Close(path); + if (hasLastDot && (file = DirFindDot(name, base)) != NULL) return file; - } } - Lst_Close(path); /* * We didn't find the file on any directory in the search path. @@ -1165,13 +1058,13 @@ Dir_FindFile(const char *name, Lst path) */ if (!hasSlash) { DIR_DEBUG0(" failed.\n"); - misses += 1; + misses++; return NULL; } - if (*cp == '\0') { + if (*base == '\0') { /* we were given a trailing "/" */ - cp = trailing_dot; + base = trailing_dot; } if (name[0] != '/') { @@ -1189,22 +1082,18 @@ Dir_FindFile(const char *name, Lst path) return file; } - Lst_Open(path); - while ((ln = Lst_Next(path)) != NULL) { - p = LstNode_Datum(ln); - if (p == dotLast) + for (ln = path->first; ln != NULL; ln = ln->next) { + CachedDir *dir = ln->datum; + if (dir == dotLast) continue; - if (p == dot) { + if (dir == dot) { if (checkedDot) continue; checkedDot = TRUE; } - if ((file = DirLookupSubdir(p, name)) != NULL) { - Lst_Close(path); + if ((file = DirLookupSubdir(dir, name)) != NULL) return file; - } } - Lst_Close(path); if (hasLastDot) { if (dot && !checkedDot) { @@ -1239,7 +1128,7 @@ Dir_FindFile(const char *name, Lst path) DIR_DEBUG0(" Trying exact path matches...\n"); if (!hasLastDot && cur && - ((file = DirLookupAbs(cur, name, cp)) != NULL)) { + ((file = DirLookupAbs(cur, name, base)) != NULL)) { if (file[0] == '\0') { free(file); return NULL; @@ -1247,13 +1136,11 @@ Dir_FindFile(const char *name, Lst path) return file; } - Lst_Open(path); - while ((ln = Lst_Next(path)) != NULL) { - p = LstNode_Datum(ln); - if (p == dotLast) + for (ln = path->first; ln != NULL; ln = ln->next) { + CachedDir *dir = ln->datum; + if (dir == dotLast) continue; - if ((file = DirLookupAbs(p, name, cp)) != NULL) { - Lst_Close(path); + if ((file = DirLookupAbs(dir, name, base)) != NULL) { if (file[0] == '\0') { free(file); return NULL; @@ -1261,10 +1148,9 @@ Dir_FindFile(const char *name, Lst path) return file; } } - Lst_Close(path); if (hasLastDot && cur && - ((file = DirLookupAbs(cur, name, cp)) != NULL)) { + ((file = DirLookupAbs(cur, name, base)) != NULL)) { if (file[0] == '\0') { free(file); return NULL; @@ -1291,23 +1177,23 @@ Dir_FindFile(const char *name, Lst path) * b/c we added it here. This is not good... */ #ifdef notdef - if (cp == traling_dot) { - cp = strrchr(name, '/'); - cp += 1; + if (base == trailing_dot) { + base = strrchr(name, '/'); + base++; } - cp[-1] = '\0'; + base[-1] = '\0'; (void)Dir_AddDir(path, name); - cp[-1] = '/'; + base[-1] = '/'; - bigmisses += 1; + bigmisses++; ln = Lst_Last(path); if (ln == NULL) { return NULL; } else { - p = LstNode_Datum(ln); + dir = LstNode_Datum(ln); } - if (Hash_FindEntry(&p->files, cp) != NULL) { + if (Hash_FindEntry(&dir->files, base) != NULL) { return bmake_strdup(name); } else { return NULL; @@ -1315,7 +1201,7 @@ Dir_FindFile(const char *name, Lst path) #else /* !notdef */ DIR_DEBUG1(" Looking for \"%s\" ...\n", name); - bigmisses += 1; + bigmisses++; if (cached_stat(name, &mst) == 0) { return bmake_strdup(name); } @@ -1326,43 +1212,32 @@ Dir_FindFile(const char *name, Lst path) } -/*- - *----------------------------------------------------------------------- - * Dir_FindHereOrAbove -- - * search for a path starting at a given directory and then working - * our way up towards the root. +/* Search for a path starting at a given directory and then working our way + * up towards the root. * * Input: * here starting directory - * search_path the path we are looking for - * result the result of a successful search is placed here - * result_len the length of the result buffer - * (typically MAXPATHLEN + 1) + * search_path the relative path we are looking for * * Results: - * 0 on failure, 1 on success [in which case the found path is put - * in the result buffer]. - * - * Side Effects: - *----------------------------------------------------------------------- + * The found path, or NULL. */ -Boolean -Dir_FindHereOrAbove(const char *here, const char *search_path, - char *result, int result_len) +char * +Dir_FindHereOrAbove(const char *here, const char *search_path) { struct make_stat mst; - char dirbase[MAXPATHLEN + 1], *dirbase_end; - char try[MAXPATHLEN + 1], *try_end; + char *dirbase, *dirbase_end; + char *try, *try_end; /* copy out our starting point */ - snprintf(dirbase, sizeof(dirbase), "%s", here); + dirbase = bmake_strdup(here); dirbase_end = dirbase + strlen(dirbase); /* loop until we determine a result */ - while (TRUE) { + for (;;) { /* try and stat(2) it ... */ - snprintf(try, sizeof(try), "%s/%s", dirbase, search_path); + try = str_concat3(dirbase, "/", search_path); if (cached_stat(try, &mst) != -1) { /* * success! if we found a file, chop off @@ -1376,9 +1251,10 @@ Dir_FindHereOrAbove(const char *here, const char *search_path, *try_end = '\0'; /* chop! */ } - snprintf(result, result_len, "%s", try); - return TRUE; + free(dirbase); + return try; } + free(try); /* * nope, we didn't find it. if we used up dirbase we've @@ -1393,10 +1269,10 @@ Dir_FindHereOrAbove(const char *here, const char *search_path, while (dirbase_end > dirbase && *dirbase_end != '/') dirbase_end--; *dirbase_end = '\0'; /* chop! */ + } - } /* while (TRUE) */ - - return FALSE; + free(dirbase); + return NULL; } /*- @@ -1417,7 +1293,7 @@ Dir_FindHereOrAbove(const char *here, const char *search_path, * found one for it, the full name is placed in the path slot. *----------------------------------------------------------------------- */ -int +time_t Dir_MTime(GNode *gn, Boolean recheck) { char *fullName; /* the full pathname of name */ @@ -1482,72 +1358,63 @@ Dir_MTime(GNode *gn, Boolean recheck) } } - if (fullName && gn->path == NULL) { + if (fullName != NULL && gn->path == NULL) gn->path = fullName; - } gn->mtime = mst.mst_mtime; return gn->mtime; } -/*- - *----------------------------------------------------------------------- - * Dir_AddDir -- - * Add the given name to the end of the given path. The order of - * the arguments is backwards so ParseDoDependency can do a - * Lst_ForEach of its list of paths... - * - * Input: - * path the path to which the directory should be - * added - * XXX: Why would this ever be NULL, and what does - * that mean? - * name the name of the directory to add +/* Read the list of filenames in the directory and store the result + * in openDirectories. * - * Results: - * none + * If a path is given, append the directory to that path. * - * Side Effects: - * A structure is added to the list and the directory is - * read and hashed. - *----------------------------------------------------------------------- + * Input: + * path The path to which the directory should be + * added, or NULL to only add the directory to + * openDirectories + * name The name of the directory to add. + * The name is not normalized in any way. */ -Path * -Dir_AddDir(Lst path, const char *name) +CachedDir * +Dir_AddDir(SearchPath *path, const char *name) { - LstNode ln = NULL; /* node in case Path structure is found */ - Path *p = NULL; /* pointer to new Path structure */ - DIR *d; /* for reading directory */ - struct dirent *dp; /* entry in directory */ + CachedDir *dir = NULL; /* the added directory */ + DIR *d; + struct dirent *dp; if (path != NULL && strcmp(name, ".DOTLAST") == 0) { - ln = Lst_Find(path, DirFindName, name); - if (ln != NULL) - return LstNode_Datum(ln); + SearchPathNode *ln; + + for (ln = path->first; ln != NULL; ln = ln->next) { + CachedDir *pathDir = ln->datum; + if (strcmp(pathDir->name, name) == 0) + return pathDir; + } dotLast->refCount++; Lst_Prepend(path, dotLast); } if (path != NULL) - ln = Lst_Find(openDirectories, DirFindName, name); - if (ln != NULL) { - p = LstNode_Datum(ln); - if (Lst_FindDatum(path, p) == NULL) { - p->refCount += 1; - Lst_Append(path, p); + dir = OpenDirs_Find(&openDirs, name); + if (dir != NULL) { + if (Lst_FindDatum(path, dir) == NULL) { + dir->refCount++; + Lst_Append(path, dir); } - return p; + return dir; } DIR_DEBUG1("Caching %s ...", name); if ((d = opendir(name)) != NULL) { - p = bmake_malloc(sizeof(Path)); - p->name = bmake_strdup(name); - p->hits = 0; - p->refCount = 1; - Hash_InitTable(&p->files, -1); + dir = bmake_malloc(sizeof(CachedDir)); + dir->name = bmake_strdup(name); + dir->hits = 0; + dir->refCount = 1; + HashTable_Init(&dir->files); while ((dp = readdir(d)) != NULL) { #if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ @@ -1560,33 +1427,30 @@ Dir_AddDir(Lst path, const char *name) continue; } #endif /* sun && d_ino */ - (void)Hash_CreateEntry(&p->files, dp->d_name, NULL); + (void)HashTable_CreateEntry(&dir->files, dp->d_name, NULL); } (void)closedir(d); - Lst_Append(openDirectories, p); + OpenDirs_Add(&openDirs, dir); if (path != NULL) - Lst_Append(path, p); + Lst_Append(path, dir); } DIR_DEBUG0("done\n"); - return p; + return dir; } -/*- - *----------------------------------------------------------------------- - * Dir_CopyDir -- - * Callback function for duplicating a search path via Lst_Copy. - * Ups the reference count for the directory. - * - * Results: - * Returns the Path it was given. - *----------------------------------------------------------------------- - */ -void * -Dir_CopyDir(void *p) +/* Return a copy of dirSearchPath, incrementing the reference counts for + * the contained directories. */ +SearchPath * +Dir_CopyDirSearchPath(void) { - ((Path *)p)->refCount += 1; - - return p; + SearchPath *path = Lst_New(); + SearchPathNode *ln; + for (ln = dirSearchPath->first; ln != NULL; ln = ln->next) { + CachedDir *dir = ln->datum; + dir->refCount++; + Lst_Append(path, dir); + } + return path; } /*- @@ -1611,119 +1475,70 @@ Dir_CopyDir(void *p) *----------------------------------------------------------------------- */ char * -Dir_MakeFlags(const char *flag, Lst path) +Dir_MakeFlags(const char *flag, SearchPath *path) { Buffer buf; - LstNode ln; /* the node of the current directory */ + SearchPathNode *ln; Buf_Init(&buf, 0); if (path != NULL) { - Lst_Open(path); - while ((ln = Lst_Next(path)) != NULL) { - Path *p = LstNode_Datum(ln); + for (ln = path->first; ln != NULL; ln = ln->next) { + CachedDir *dir = ln->datum; Buf_AddStr(&buf, " "); Buf_AddStr(&buf, flag); - Buf_AddStr(&buf, p->name); + Buf_AddStr(&buf, dir->name); } - Lst_Close(path); } return Buf_Destroy(&buf, FALSE); } -/*- - *----------------------------------------------------------------------- - * Dir_Destroy -- - * Nuke a directory descriptor, if possible. Callback procedure - * for the suffixes module when destroying a search path. +/* Nuke a directory descriptor, if possible. Callback procedure for the + * suffixes module when destroying a search path. * * Input: - * pp The directory descriptor to nuke - * - * Results: - * None. - * - * Side Effects: - * If no other path references this directory (refCount == 0), - * the Path and all its data are freed. - * - *----------------------------------------------------------------------- + * dirp The directory descriptor to nuke */ void -Dir_Destroy(void *pp) +Dir_Destroy(void *dirp) { - Path *p = (Path *)pp; - p->refCount -= 1; - - if (p->refCount == 0) { - LstNode ln; + CachedDir *dir = dirp; + dir->refCount--; - ln = Lst_FindDatum(openDirectories, p); - Lst_Remove(openDirectories, ln); + if (dir->refCount == 0) { + OpenDirs_Remove(&openDirs, dir->name); - Hash_DeleteTable(&p->files); - free(p->name); - free(p); + HashTable_Done(&dir->files); + free(dir->name); + free(dir); } } -/*- - *----------------------------------------------------------------------- - * Dir_ClearPath -- - * Clear out all elements of the given search path. This is different - * from destroying the list, notice. - * - * Input: - * path Path to clear - * - * Results: - * None. - * - * Side Effects: - * The path is set to the empty list. - * - *----------------------------------------------------------------------- - */ +/* Clear out all elements from the given search path. + * The path is set to the empty list but is not destroyed. */ void -Dir_ClearPath(Lst path) +Dir_ClearPath(SearchPath *path) { while (!Lst_IsEmpty(path)) { - Path *p = Lst_Dequeue(path); - Dir_Destroy(p); + CachedDir *dir = Lst_Dequeue(path); + Dir_Destroy(dir); } } -/*- - *----------------------------------------------------------------------- - * Dir_Concat -- - * Concatenate two paths, adding the second to the end of the first. - * Makes sure to avoid duplicates. - * - * Input: - * path1 Dest - * path2 Source - * - * Results: - * None - * - * Side Effects: - * Reference counts for added dirs are upped. - * - *----------------------------------------------------------------------- - */ +/* Concatenate two paths, adding the second to the end of the first, + * skipping duplicates. */ void -Dir_Concat(Lst path1, Lst path2) +Dir_Concat(SearchPath *dst, SearchPath *src) { - LstNode ln; - Path *p; - - for (ln = Lst_First(path2); ln != NULL; ln = LstNode_Next(ln)) { - p = LstNode_Datum(ln); - if (Lst_FindDatum(path1, p) == NULL) { - p->refCount += 1; - Lst_Append(path1, p); + SearchPathNode *ln; + + for (ln = src->first; ln != NULL; ln = ln->next) { + CachedDir *dir = ln->datum; + if (Lst_FindDatum(dst, dir) == NULL) { + dir->refCount++; + Lst_Append(dst, dir); } } } @@ -1738,33 +1553,27 @@ percentage(int num, int den) void Dir_PrintDirectories(void) { - LstNode ln; - - fprintf(debug_file, "#*** Directory Cache:\n"); - fprintf(debug_file, - "# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n", - hits, misses, nearmisses, bigmisses, - percentage(hits, hits + bigmisses + nearmisses)); - fprintf(debug_file, "# %-20s referenced\thits\n", "directory"); - - Lst_Open(openDirectories); - while ((ln = Lst_Next(openDirectories)) != NULL) { - Path *p = LstNode_Datum(ln); - fprintf(debug_file, "# %-20s %10d\t%4d\n", p->name, p->refCount, - p->hits); + CachedDirListNode *ln; + + debug_printf("#*** Directory Cache:\n"); + debug_printf("# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n", + hits, misses, nearmisses, bigmisses, + percentage(hits, hits + bigmisses + nearmisses)); + debug_printf("# %-20s referenced\thits\n", "directory"); + + for (ln = openDirs.list->first; ln != NULL; ln = ln->next) { + CachedDir *dir = ln->datum; + debug_printf("# %-20s %10d\t%4d\n", dir->name, dir->refCount, + dir->hits); } - Lst_Close(openDirectories); -} - -static int -DirPrintDir(void *p, void *dummy MAKE_ATTR_UNUSED) -{ - fprintf(debug_file, "%s ", ((Path *)p)->name); - return 0; } void -Dir_PrintPath(Lst path) +Dir_PrintPath(SearchPath *path) { - Lst_ForEach(path, DirPrintDir, NULL); + SearchPathNode *node; + for (node = path->first; node != NULL; node = node->next) { + const CachedDir *dir = node->datum; + debug_printf("%s ", dir->name); + } } |