version 1.49, 2007/09/16 12:09:36 |
version 1.50, 2007/09/16 12:19:15 |
|
|
#include "timestamp.h" |
#include "timestamp.h" |
|
|
|
|
typedef struct Path_ { |
struct PathEntry { |
int refCount; /* Number of paths with this directory */ |
int refCount; /* Number of paths with this directory */ |
#ifdef DEBUG_DIRECTORY_CACHE |
#ifdef DEBUG_DIRECTORY_CACHE |
int hits; /* the number of times a file in this |
int hits; /* the number of times a file in this |
|
|
#endif |
#endif |
struct ohash files; /* Hash table of files in directory */ |
struct ohash files; /* Hash table of files in directory */ |
char name[1]; /* Name of directory */ |
char name[1]; /* Name of directory */ |
} Path; |
}; |
|
|
/* A search path consists of a Lst of Path structures. A Path structure |
/* A search path consists of a Lst of PathEntry structures. A PathEntry |
* has in it the name of the directory and a hash table of all the files |
* structure has in it the name of the directory and a hash table of all |
* in the directory. This is used to cut down on the number of system |
* the files in the directory. This is used to cut down on the number of |
* calls necessary to find implicit dependents and their like. Since |
* system calls necessary to find implicit dependents and their like. |
* these searches are made before any actions are taken, we need not |
* Since these searches are made before any actions are taken, we need not |
* worry about the directory changing due to creation commands. If this |
* worry about the directory changing due to creation commands. If this |
* hampers the style of some makefiles, they must be changed. |
* hampers the style of some makefiles, they must be changed. |
* |
* |
|
|
* that UNIX OS's have taken to allowing more than 20 or 32 |
* that UNIX OS's have taken to allowing more than 20 or 32 |
* file descriptors for a process, this doesn't seem acceptable |
* file descriptors for a process, this doesn't seem acceptable |
* to me. |
* to me. |
* 3) record the mtime of the directory in the Path structure and |
* 3) record the mtime of the directory in the PathEntry structure and |
* verify the directory hasn't changed since the contents were |
* verify the directory hasn't changed since the contents were |
* hashed. This will catch the creation or deletion of files, |
* hashed. This will catch the creation or deletion of files, |
* but not the updating of files. However, since it is the |
* but not the updating of files. However, since it is the |
|
|
bigmisses; /* Sought by itself */ |
bigmisses; /* Sought by itself */ |
#endif |
#endif |
|
|
Path *dot; /* contents of current directory */ |
struct PathEntry *dot; /* contents of current directory */ |
|
|
struct file_stamp { |
struct file_stamp { |
TIMESTAMP mtime; /* time stamp... */ |
TIMESTAMP mtime; /* time stamp... */ |
|
|
|
|
/* There are three distinct hash structures: |
/* There are three distinct hash structures: |
* - to collate files's last modification times (global mtimes) |
* - to collate files's last modification times (global mtimes) |
* - to collate file names (in each Path structure) |
* - to collate file names (in each PathEntry structure) |
* - to collate known directories (global openDirectories). */ |
* - to collate known directories (global openDirectories). */ |
static struct ohash_info stamp_info = { |
static struct ohash_info stamp_info = { |
offsetof(struct file_stamp, name), NULL, hash_alloc, hash_free, |
offsetof(struct file_stamp, name), NULL, hash_alloc, hash_free, |
|
|
0, NULL, hash_alloc, hash_free, element_alloc }; |
0, NULL, hash_alloc, hash_free, element_alloc }; |
|
|
static struct ohash_info dir_info = { |
static struct ohash_info dir_info = { |
offsetof(Path, name), NULL, hash_alloc, hash_free, element_alloc }; |
offsetof(struct PathEntry, name), NULL, |
|
hash_alloc, hash_free, element_alloc }; |
|
|
/* add_file(path, name): add a file name to a path hash structure. */ |
/* add_file(path, name): add a file name to a path hash structure. */ |
static void add_file(Path *, const char *); |
static void add_file(struct PathEntry *, const char *); |
/* n = find_file_hashi(p, name, end, hv): retrieve name in a path hash |
/* n = find_file_hashi(p, name, end, hv): retrieve name in a path hash |
* structure. */ |
* structure. */ |
static char *find_file_hashi(Path *, const char *, const char *, uint32_t); |
static char *find_file_hashi(struct PathEntry *, const char *, const char *, |
|
uint32_t); |
|
|
/* stamp = find_stampi(name, end): look for (name, end) in the global |
/* stamp = find_stampi(name, end): look for (name, end) in the global |
* cache. */ |
* cache. */ |
|
|
|
|
/* p = DirReaddiri(name, end): read an actual directory, caching results |
/* p = DirReaddiri(name, end): read an actual directory, caching results |
* as we go. */ |
* as we go. */ |
static Path *DirReaddiri(const char *, const char *); |
static struct PathEntry *DirReaddiri(const char *, const char *); |
/* Debugging: show a dir name in a path. */ |
/* Debugging: show a dir name in a path. */ |
static void DirPrintDir(void *); |
static void DirPrintDir(void *); |
|
|
|
|
} |
} |
|
|
static void |
static void |
add_file(Path *p, const char *file) |
add_file(struct PathEntry *p, const char *file) |
{ |
{ |
unsigned int slot; |
unsigned int slot; |
const char *end = NULL; |
const char *end = NULL; |
|
|
} |
} |
|
|
static char * |
static char * |
find_file_hashi(Path *p, const char *file, const char *efile, uint32_t hv) |
find_file_hashi(struct PathEntry *p, const char *file, const char *efile, |
|
uint32_t hv) |
{ |
{ |
struct ohash *h = &p->files; |
struct ohash *h = &p->files; |
|
|
|
|
void |
void |
Dir_End(void) |
Dir_End(void) |
{ |
{ |
struct Path *p; |
struct PathEntry *p; |
unsigned int i; |
unsigned int i; |
|
|
dot->refCount--; |
dot->refCount--; |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* Dir_MatchFilesi -- |
* Dir_MatchFilesi -- |
* Given a pattern and a Path structure, see if any files |
* Given a pattern and a PathEntry structure, see if any files |
* match the pattern and add their names to the 'expansions' list if |
* 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 |
* 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 |
* src / *src / *.c properly (just *.c on any of the directories), but it |
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
Dir_MatchFilesi(const char *word, const char *eword, Path *p, Lst expansions) |
Dir_MatchFilesi(const char *word, const char *eword, struct PathEntry *p, |
|
Lst expansions) |
{ |
{ |
unsigned int search; /* Index into the directory's table */ |
unsigned int search; /* Index into the directory's table */ |
const char *entry; /* Current entry in the table */ |
const char *entry; /* Current entry in the table */ |
|
|
Dir_FindFileComplexi(const char *name, const char *ename, Lst path, |
Dir_FindFileComplexi(const char *name, const char *ename, Lst path, |
bool checkCurdirFirst) |
bool checkCurdirFirst) |
{ |
{ |
Path *p; /* current path member */ |
struct PathEntry *p; /* current path member */ |
char *p1; /* pointer into p->name */ |
char *p1; /* pointer into p->name */ |
const char *p2; /* pointer into name */ |
const char *p2; /* pointer into name */ |
LstNode ln; /* a list element */ |
LstNode ln; /* a list element */ |
|
|
* If found, we concatenate the directory name and the |
* If found, we concatenate the directory name and the |
* final component and return the resulting string. */ |
* final component and return the resulting string. */ |
for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) { |
for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) { |
p = (Path *)Lst_Datum(ln); |
p = (struct PathEntry *)Lst_Datum(ln); |
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("%s...", p->name); |
printf("%s...", p->name); |
if (find_file_hashi(p, cp, ename, hv) != NULL) { |
if (find_file_hashi(p, cp, ename, hv) != NULL) { |
|
|
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("failed. Trying subdirectories..."); |
printf("failed. Trying subdirectories..."); |
for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) { |
for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) { |
p = (Path *)Lst_Datum(ln); |
p = (struct PathEntry *)Lst_Datum(ln); |
if (p != dot) |
if (p != dot) |
file = Str_concati(p->name, |
file = Str_concati(p->name, |
strchr(p->name, '\0'), name, ename, '/'); |
strchr(p->name, '\0'), name, ename, '/'); |
|
|
} |
} |
|
|
/* Read a directory, either from the disk, or from the cache. */ |
/* Read a directory, either from the disk, or from the cache. */ |
static Path * |
static struct PathEntry * |
DirReaddiri(const char *name, const char *ename) |
DirReaddiri(const char *name, const char *ename) |
{ |
{ |
Path *p; |
struct PathEntry *p; |
DIR *d; |
DIR *d; |
struct dirent *dp; |
struct dirent *dp; |
unsigned int slot; |
unsigned int slot; |
|
|
void |
void |
Dir_AddDiri(Lst path, const char *name, const char *ename) |
Dir_AddDiri(Lst path, const char *name, const char *ename) |
{ |
{ |
Path *p; |
struct PathEntry *p; |
|
|
p = DirReaddiri(name, ename); |
p = DirReaddiri(name, ename); |
if (p == NULL) |
if (p == NULL) |
|
|
* Ups the reference count for the directory. |
* Ups the reference count for the directory. |
* |
* |
* Results: |
* Results: |
* Returns the Path it was given. |
* Returns the PathEntry it was given. |
* |
* |
* Side Effects: |
* Side Effects: |
* The refCount of the path is incremented. |
* The refCount of the path is incremented. |
|
|
void * |
void * |
Dir_CopyDir(void *p) |
Dir_CopyDir(void *p) |
{ |
{ |
((Path *)p)->refCount++; |
((struct PathEntry *)p)->refCount++; |
return p; |
return p; |
} |
} |
|
|
|
|
|
|
for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) { |
for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) { |
Buf_AddString(&buf, flag); |
Buf_AddString(&buf, flag); |
Buf_AddString(&buf, ((Path *)Lst_Datum(ln))->name); |
Buf_AddString(&buf, ((struct PathEntry *)Lst_Datum(ln))->name); |
Buf_AddSpace(&buf); |
Buf_AddSpace(&buf); |
} |
} |
|
|
|
|
* |
* |
* Side Effects: |
* Side Effects: |
* If no other path references this directory (refCount == 0), |
* If no other path references this directory (refCount == 0), |
* the Path and all its data are freed. |
* the PathEntry and all its data are freed. |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
Dir_Destroy(void *pp) |
Dir_Destroy(void *pp) |
{ |
{ |
Path *p = (Path *)pp; |
struct PathEntry *p = (struct PathEntry *)pp; |
|
|
if (--p->refCount == 0) { |
if (--p->refCount == 0) { |
ohash_remove(&openDirectories, |
ohash_remove(&openDirectories, |
|
|
Dir_Concat(Lst path1, Lst path2) |
Dir_Concat(Lst path1, Lst path2) |
{ |
{ |
LstNode ln; |
LstNode ln; |
Path *p; |
struct PathEntry *p; |
|
|
for (ln = Lst_First(path2); ln != NULL; ln = Lst_Adv(ln)) { |
for (ln = Lst_First(path2); ln != NULL; ln = Lst_Adv(ln)) { |
p = (Path *)Lst_Datum(ln); |
p = (struct PathEntry *)Lst_Datum(ln); |
if (Lst_AddNew(path1, p)) |
if (Lst_AddNew(path1, p)) |
p->refCount++; |
p->refCount++; |
} |
} |
|
|
void |
void |
Dir_PrintDirectories(void) |
Dir_PrintDirectories(void) |
{ |
{ |
Path *p; |
struct PathEntry *p; |
unsigned int i; |
unsigned int i; |
|
|
printf("#*** Directory Cache:\n"); |
printf("#*** Directory Cache:\n"); |
|
|
static void |
static void |
DirPrintDir(void *p) |
DirPrintDir(void *p) |
{ |
{ |
printf("%s ", ((Path *)p)->name); |
printf("%s ", ((struct PathEntry *)p)->name); |
} |
} |
|
|
void |
void |