Changeset 51 for trunk/src/kmk/dir.c


Ignore:
Timestamp:
Apr 7, 2003, 3:30:32 AM (22 years ago)
Author:
bird
Message:

kMk and porting to kLib.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/dir.c

    r46 r51  
    1818 * 3. All advertising materials mentioning features or use of this software
    1919 *    must display the following acknowledgement:
    20  *      This product includes software developed by the University of
    21  *      California, Berkeley and its contributors.
     20 *      This product includes software developed by the University of
     21 *      California, Berkeley and its contributors.
    2222 * 4. Neither the name of the University nor the names of its contributors
    2323 *    may be used to endorse or promote products derived from this software
     
    3939#ifndef lint
    4040#if 0
    41 static char sccsid[] = "@(#)dir.c       8.2 (Berkeley) 1/2/94";
     41static char sccsid[] = "@(#)dir.c       8.2 (Berkeley) 1/2/94";
    4242#else
    4343static const char rcsid[] =
    4444  "$FreeBSD: src/usr.bin/make/dir.c,v 1.10.2.1 2001/02/13 03:13:57 will Exp $";
    4545#endif
     46#define KLIBFILEDEF rcsid
    4647#endif /* not lint */
    4748
    4849/*-
    4950 * dir.c --
    50  *      Directory searching using wildcards and/or normal names...
    51  *      Used both for source wildcarding in the Makefile and for finding
    52  *      implicit sources.
     51 *      Directory searching using wildcards and/or normal names...
     52 *      Used both for source wildcarding in the Makefile and for finding
     53 *      implicit sources.
    5354 *
    5455 * The interface for this module is:
    55  *      Dir_Init            Initialize the module.
    56  *
    57  *      Dir_End             Cleanup the module.
    58  *
    59  *      Dir_HasWildcards    Returns TRUE if the name given it needs to
    60  *                          be wildcard-expanded.
    61  *
    62  *      Dir_Expand          Given a pattern and a path, return a Lst of names
    63  *                          which match the pattern on the search path.
    64  *
    65  *      Dir_FindFile        Searches for a file on a given search path.
    66  *                          If it exists, the entire path is returned.
    67  *                          Otherwise NULL is returned.
    68  *
    69  *      Dir_MTime           Return the modification time of a node. The file
    70  *                          is searched for along the default search path.
    71  *                          The path and mtime fields of the node are filled
    72  *                          in.
    73  *
    74  *      Dir_AddDir          Add a directory to a search path.
    75  *
    76  *      Dir_MakeFlags       Given a search path and a command flag, create
    77  *                          a string with each of the directories in the path
    78  *                          preceded by the command flag and all of them
    79  *                          separated by a space.
    80  *
    81  *      Dir_Destroy         Destroy an element of a search path. Frees up all
    82  *                          things that can be freed for the element as long
    83  *                          as the element is no longer referenced by any other
    84  *                          search path.
    85  *      Dir_ClearPath       Resets a search path to the empty list.
     56 *      Dir_Init            Initialize the module.
     57 *
     58 *      Dir_End             Cleanup the module.
     59 *
     60 *      Dir_HasWildcards    Returns TRUE if the name given it needs to
     61 *                          be wildcard-expanded.
     62 *
     63 *      Dir_Expand          Given a pattern and a path, return a Lst of names
     64 *                          which match the pattern on the search path.
     65 *
     66 *      Dir_FindFile        Searches for a file on a given search path.
     67 *                          If it exists, the entire path is returned.
     68 *                          Otherwise NULL is returned.
     69 *
     70 *      Dir_MTime           Return the modification time of a node. The file
     71 *                          is searched for along the default search path.
     72 *                          The path and mtime fields of the node are filled
     73 *                          in.
     74 *
     75 *      Dir_AddDir          Add a directory to a search path.
     76 *
     77 *      Dir_MakeFlags       Given a search path and a command flag, create
     78 *                          a string with each of the directories in the path
     79 *                          preceded by the command flag and all of them
     80 *                          separated by a space.
     81 *
     82 *      Dir_Destroy         Destroy an element of a search path. Frees up all
     83 *                          things that can be freed for the element as long
     84 *                          as the element is no longer referenced by any other
     85 *                          search path.
     86 *      Dir_ClearPath       Resets a search path to the empty list.
    8687 *
    8788 * For debugging:
    88  *      Dir_PrintDirectories    Print stats about the directory cache.
     89 *      Dir_PrintDirectories    Print stats about the directory cache.
    8990 */
    9091
     
    9899
    99100/*
    100  *      A search path consists of a Lst of Path structures. A Path structure
    101  *      has in it the name of the directory and a hash table of all the files
    102  *      in the directory. This is used to cut down on the number of system
    103  *      calls necessary to find implicit dependents and their like. Since
    104  *      these searches are made before any actions are taken, we need not
    105  *      worry about the directory changing due to creation commands. If this
    106  *      hampers the style of some makefiles, they must be changed.
    107  *
    108  *      A list of all previously-read directories is kept in the
    109  *      openDirectories Lst. This list is checked first before a directory
    110  *      is opened.
    111  *
    112  *      The need for the caching of whole directories is brought about by
    113  *      the multi-level transformation code in suff.c, which tends to search
    114  *      for far more files than regular make does. In the initial
    115  *      implementation, the amount of time spent performing "stat" calls was
    116  *      truly astronomical. The problem with hashing at the start is,
    117  *      of course, that pmake doesn't then detect changes to these directories
    118  *      during the course of the make. Three possibilities suggest themselves:
    119  *
    120  *          1) just use stat to test for a file's existence. As mentioned
    121  *             above, this is very inefficient due to the number of checks
    122  *             engendered by the multi-level transformation code.
    123  *          2) use readdir() and company to search the directories, keeping
    124  *             them open between checks. I have tried this and while it
    125  *             didn't slow down the process too much, it could severely
    126  *             affect the amount of parallelism available as each directory
    127  *             open would take another file descriptor out of play for
    128  *             handling I/O for another job. Given that it is only recently
    129  *             that UNIX OS's have taken to allowing more than 20 or 32
    130  *             file descriptors for a process, this doesn't seem acceptable
    131  *             to me.
    132  *          3) record the mtime of the directory in the Path structure and
    133  *             verify the directory hasn't changed since the contents were
    134  *             hashed. This will catch the creation or deletion of files,
    135  *             but not the updating of files. However, since it is the
    136  *             creation and deletion that is the problem, this could be
    137  *             a good thing to do. Unfortunately, if the directory (say ".")
    138  *             were fairly large and changed fairly frequently, the constant
    139  *             rehashing could seriously degrade performance. It might be
    140  *             good in such cases to keep track of the number of rehashes
    141  *             and if the number goes over a (small) limit, resort to using
    142  *             stat in its place.
    143  *
    144  *      An additional thing to consider is that pmake is used primarily
    145  *      to create C programs and until recently pcc-based compilers refused
    146  *      to allow you to specify where the resulting object file should be
    147  *      placed. This forced all objects to be created in the current
    148  *      directory. This isn't meant as a full excuse, just an explanation of
    149  *      some of the reasons for the caching used here.
    150  *
    151  *      One more note: the location of a target's file is only performed
    152  *      on the downward traversal of the graph and then only for terminal
    153  *      nodes in the graph. This could be construed as wrong in some cases,
    154  *      but prevents inadvertent modification of files when the "installed"
    155  *      directory for a file is provided in the search path.
    156  *
    157  *      Another data structure maintained by this module is an mtime
    158  *      cache used when the searching of cached directories fails to find
    159  *      a file. In the past, Dir_FindFile would simply perform an access()
    160  *      call in such a case to determine if the file could be found using
    161  *      just the name given. When this hit, however, all that was gained
    162  *      was the knowledge that the file existed. Given that an access() is
    163  *      essentially a stat() without the copyout() call, and that the same
    164  *      filesystem overhead would have to be incurred in Dir_MTime, it made
    165  *      sense to replace the access() with a stat() and record the mtime
    166  *      in a cache for when Dir_MTime was actually called.
    167  */
    168 
    169 Lst          dirSearchPath;     /* main search path */
    170 
    171 static Lst   openDirectories;   /* the list of all open directories */
     101 *      A search path consists of a Lst of Path structures. A Path structure
     102 *      has in it the name of the directory and a hash table of all the files
     103 *      in the directory. This is used to cut down on the number of system
     104 *      calls necessary to find implicit dependents and their like. Since
     105 *      these searches are made before any actions are taken, we need not
     106 *      worry about the directory changing due to creation commands. If this
     107 *      hampers the style of some makefiles, they must be changed.
     108 *
     109 *      A list of all previously-read directories is kept in the
     110 *      openDirectories Lst. This list is checked first before a directory
     111 *      is opened.
     112 *
     113 *      The need for the caching of whole directories is brought about by
     114 *      the multi-level transformation code in suff.c, which tends to search
     115 *      for far more files than regular make does. In the initial
     116 *      implementation, the amount of time spent performing "stat" calls was
     117 *      truly astronomical. The problem with hashing at the start is,
     118 *      of course, that pmake doesn't then detect changes to these directories
     119 *      during the course of the make. Three possibilities suggest themselves:
     120 *
     121 *          1) just use stat to test for a file's existence. As mentioned
     122 *             above, this is very inefficient due to the number of checks
     123 *             engendered by the multi-level transformation code.
     124 *          2) use readdir() and company to search the directories, keeping
     125 *             them open between checks. I have tried this and while it
     126 *             didn't slow down the process too much, it could severely
     127 *             affect the amount of parallelism available as each directory
     128 *             open would take another file descriptor out of play for
     129 *             handling I/O for another job. Given that it is only recently
     130 *             that UNIX OS's have taken to allowing more than 20 or 32
     131 *             file descriptors for a process, this doesn't seem acceptable
     132 *             to me.
     133 *          3) record the mtime of the directory in the Path structure and
     134 *             verify the directory hasn't changed since the contents were
     135 *             hashed. This will catch the creation or deletion of files,
     136 *             but not the updating of files. However, since it is the
     137 *             creation and deletion that is the problem, this could be
     138 *             a good thing to do. Unfortunately, if the directory (say ".")
     139 *             were fairly large and changed fairly frequently, the constant
     140 *             rehashing could seriously degrade performance. It might be
     141 *             good in such cases to keep track of the number of rehashes
     142 *             and if the number goes over a (small) limit, resort to using
     143 *             stat in its place.
     144 *
     145 *      An additional thing to consider is that pmake is used primarily
     146 *      to create C programs and until recently pcc-based compilers refused
     147 *      to allow you to specify where the resulting object file should be
     148 *      placed. This forced all objects to be created in the current
     149 *      directory. This isn't meant as a full excuse, just an explanation of
     150 *      some of the reasons for the caching used here.
     151 *
     152 *      One more note: the location of a target's file is only performed
     153 *      on the downward traversal of the graph and then only for terminal
     154 *      nodes in the graph. This could be construed as wrong in some cases,
     155 *      but prevents inadvertent modification of files when the "installed"
     156 *      directory for a file is provided in the search path.
     157 *
     158 *      Another data structure maintained by this module is an mtime
     159 *      cache used when the searching of cached directories fails to find
     160 *      a file. In the past, Dir_FindFile would simply perform an access()
     161 *      call in such a case to determine if the file could be found using
     162 *      just the name given. When this hit, however, all that was gained
     163 *      was the knowledge that the file existed. Given that an access() is
     164 *      essentially a stat() without the copyout() call, and that the same
     165 *      filesystem overhead would have to be incurred in Dir_MTime, it made
     166 *      sense to replace the access() with a stat() and record the mtime
     167 *      in a cache for when Dir_MTime was actually called.
     168 */
     169
     170Lst          dirSearchPath;     /* main search path */
     171
     172static Lst   openDirectories;   /* the list of all open directories */
    172173
    173174/*
     
    175176 * mechanism.
    176177 */
    177 static int    hits,           /* Found in directory cache */
    178               misses,         /* Sad, but not evil misses */
    179               nearmisses,     /* Found under search path */
    180               bigmisses;      /* Sought by itself */
    181 
    182 static Path       *dot;     /* contents of current directory */
     178static int    hits,           /* Found in directory cache */
     179              misses,         /* Sad, but not evil misses */
     180              nearmisses,     /* Found under search path */
     181              bigmisses;      /* Sought by itself */
     182
     183static Path       *dot;     /* contents of current directory */
    183184static Hash_Table mtimes;   /* Results of doing a last-resort stat in
    184                              * Dir_FindFile -- if we have to go to the
    185                              * system to find the file, we might as well
    186                              * have its mtime on record. XXX: If this is done
    187                              * way early, there's a chance other rules will
    188                              * have already updated the file, in which case
    189                              * we'll update it again. Generally, there won't
    190                              * be two rules to update a single file, so this
    191                              * should be ok, but... */
     185                             * Dir_FindFile -- if we have to go to the
     186                             * system to find the file, we might as well
     187                             * have its mtime on record. XXX: If this is done
     188                             * way early, there's a chance other rules will
     189                             * have already updated the file, in which case
     190                             * we'll update it again. Generally, there won't
     191                             * be two rules to update a single file, so this
     192                             * should be ok, but... */
    192193
    193194
     
    202203 *-----------------------------------------------------------------------
    203204 * Dir_Init --
    204  *      initialize things for this module
    205  *
    206  * Results:
    207  *      none
    208  *
    209  * Side Effects:
    210  *      some directories may be opened.
     205 *      initialize things for this module
     206 *
     207 * Results:
     208 *      none
     209 *
     210 * Side Effects:
     211 *      some directories may be opened.
    211212 *-----------------------------------------------------------------------
    212213 */
     
    227228    dot = (Path *) Lst_DeQueue (openDirectories);
    228229    if (dot == (Path *) NULL)
    229         err(1, "cannot open current directory");
     230        err(1, "cannot open current directory");
    230231
    231232    /*
     
    239240 *-----------------------------------------------------------------------
    240241 * Dir_End --
    241  *      cleanup things for this module
    242  *
    243  * Results:
    244  *      none
    245  *
    246  * Side Effects:
    247  *      none
     242 *      cleanup things for this module
     243 *
     244 * Results:
     245 *      none
     246 *
     247 * Side Effects:
     248 *      none
    248249 *-----------------------------------------------------------------------
    249250 */
     
    263264 *-----------------------------------------------------------------------
    264265 * DirFindName --
    265  *      See if the Path structure describes the same directory as the
    266  *      given one by comparing their names. Called from Dir_AddDir via
    267  *      Lst_Find when searching the list of open directories.
    268  *
    269  * Results:
    270  *      0 if it is the same. Non-zero otherwise
    271  *
    272  * Side Effects:
    273  *      None
     266 *      See if the Path structure describes the same directory as the
     267 *      given one by comparing their names. Called from Dir_AddDir via
     268 *      Lst_Find when searching the list of open directories.
     269 *
     270 * Results:
     271 *      0 if it is the same. Non-zero otherwise
     272 *
     273 * Side Effects:
     274 *      None
    274275 *-----------------------------------------------------------------------
    275276 */
    276277static int
    277278DirFindName (p, dname)
    278     ClientData    p;          /* Current name */
    279     ClientData    dname;      /* Desired name */
     279    ClientData    p;          /* Current name */
     280    ClientData    dname;      /* Desired name */
    280281{
    281282    return (strcmp (((Path *)p)->name, (char *) dname));
     
    285286 *-----------------------------------------------------------------------
    286287 * Dir_HasWildcards  --
    287  *      see if the given name has any wildcard characters in it
    288  *
    289  * Results:
    290  *      returns TRUE if the word should be expanded, FALSE otherwise
    291  *
    292  * Side Effects:
    293  *      none
     288 *      see if the given name has any wildcard characters in it
     289 *
     290 * Results:
     291 *      returns TRUE if the word should be expanded, FALSE otherwise
     292 *
     293 * Side Effects:
     294 *      none
    294295 *-----------------------------------------------------------------------
    295296 */
    296297Boolean
    297298Dir_HasWildcards (name)
    298     char          *name;        /* name to check */
     299    char          *name;        /* name to check */
    299300{
    300301    register char *cp;
    301302
    302303    for (cp = name; *cp; cp++) {
    303         switch(*cp) {
    304         case '{':
    305         case '[':
    306         case '?':
    307         case '*':
    308             return (TRUE);
    309         }
     304        switch(*cp) {
     305        case '{':
     306        case '[':
     307        case '?':
     308        case '*':
     309            return (TRUE);
     310        }
    310311    }
    311312    return (FALSE);
     
    315316 *-----------------------------------------------------------------------
    316317 * DirMatchFiles --
    317  *      Given a pattern and a Path structure, see if any files
    318  *      match the pattern and add their names to the 'expansions' list if
    319  *      any do. This is incomplete -- it doesn't take care of patterns like
    320  *      src / *src / *.c properly (just *.c on any of the directories), but it
    321  *      will do for now.
    322  *
    323  * Results:
    324  *      Always returns 0
    325  *
    326  * Side Effects:
    327  *      File names are added to the expansions lst. The directory will be
    328  *      fully hashed when this is done.
     318 *      Given a pattern and a Path structure, see if any files
     319 *      match the pattern and add their names to the 'expansions' list if
     320 *      any do. This is incomplete -- it doesn't take care of patterns like
     321 *      src / *src / *.c properly (just *.c on any of the directories), but it
     322 *      will do for now.
     323 *
     324 * Results:
     325 *      Always returns 0
     326 *
     327 * Side Effects:
     328 *      File names are added to the expansions lst. The directory will be
     329 *      fully hashed when this is done.
    329330 *-----------------------------------------------------------------------
    330331 */
    331332static int
    332333DirMatchFiles (pattern, p, expansions)
    333     char          *pattern;     /* Pattern to look for */
    334     Path          *p;           /* Directory to search */
    335     Lst           expansions;   /* Place to store the results */
    336 {
    337     Hash_Search   search;       /* Index into the directory's table */
    338     Hash_Entry    *entry;       /* Current entry in the table */
    339     Boolean       isDot;        /* TRUE if the directory being searched is . */
     334    char          *pattern;     /* Pattern to look for */
     335    Path          *p;           /* Directory to search */
     336    Lst           expansions;   /* Place to store the results */
     337{
     338    Hash_Search   search;       /* Index into the directory's table */
     339    Hash_Entry    *entry;       /* Current entry in the table */
     340    Boolean       isDot;        /* TRUE if the directory being searched is . */
    340341
    341342    isDot = (*p->name == '.' && p->name[1] == '\0');
    342343
    343344    for (entry = Hash_EnumFirst(&p->files, &search);
    344         entry != (Hash_Entry *)NULL;
    345         entry = Hash_EnumNext(&search))
     345        entry != (Hash_Entry *)NULL;
     346        entry = Hash_EnumNext(&search))
    346347    {
    347         /*
    348         * See if the file matches the given pattern. Note we follow the UNIX
    349         * convention that dot files will only be found if the pattern
    350         * begins with a dot (note also that as a side effect of the hashing
    351         * scheme, .* won't match . or .. since they aren't hashed).
    352         */
    353         if (Str_Match(entry->name, pattern) &&
    354             ((entry->name[0] != '.') ||
    355              (pattern[0] == '.')))
    356         {
    357             (void)Lst_AtEnd(expansions,
    358                             (isDot ? estrdup(entry->name) :
    359                              str_concat(p->name, entry->name,
    360                                         STR_ADDSLASH)));
    361         }
     348        /*
     349        * See if the file matches the given pattern. Note we follow the UNIX
     350        * convention that dot files will only be found if the pattern
     351        * begins with a dot (note also that as a side effect of the hashing
     352        * scheme, .* won't match . or .. since they aren't hashed).
     353        */
     354        if (Str_Match(entry->name, pattern) &&
     355            ((entry->name[0] != '.') ||
     356             (pattern[0] == '.')))
     357        {
     358            (void)Lst_AtEnd(expansions,
     359                            (isDot ? estrdup(entry->name) :
     360                             str_concat(p->name, entry->name,
     361                                        STR_ADDSLASH)));
     362        }
    362363    }
    363364    return (0);
     
    367368 *-----------------------------------------------------------------------
    368369 * DirExpandCurly --
    369  *      Expand curly braces like the C shell. Does this recursively.
    370  *      Note the special case: if after the piece of the curly brace is
    371  *      done there are no wildcard characters in the result, the result is
    372  *      placed on the list WITHOUT CHECKING FOR ITS EXISTENCE.
    373  *
    374  * Results:
    375  *      None.
    376  *
    377  * Side Effects:
    378  *      The given list is filled with the expansions...
     370 *      Expand curly braces like the C shell. Does this recursively.
     371 *      Note the special case: if after the piece of the curly brace is
     372 *      done there are no wildcard characters in the result, the result is
     373 *      placed on the list WITHOUT CHECKING FOR ITS EXISTENCE.
     374 *
     375 * Results:
     376 *      None.
     377 *
     378 * Side Effects:
     379 *      The given list is filled with the expansions...
    379380 *
    380381 *-----------------------------------------------------------------------
     
    382383static void
    383384DirExpandCurly(word, brace, path, expansions)
    384     char          *word;        /* Entire word to expand */
    385     char          *brace;       /* First curly brace in it */
    386     Lst           path;         /* Search path to use */
    387     Lst           expansions;   /* Place to store the expansions */
    388 {
    389     char          *end;         /* Character after the closing brace */
    390     char          *cp;          /* Current position in brace clause */
    391     char          *start;       /* Start of current piece of brace clause */
    392     int           bracelevel;   /* Number of braces we've seen. If we see a
    393                                 * right brace when this is 0, we've hit the
    394                                 * end of the clause. */
    395     char          *file;        /* Current expansion */
    396     int           otherLen;     /* The length of the other pieces of the
    397                                 * expansion (chars before and after the
    398                                 * clause in 'word') */
    399     char          *cp2;         /* Pointer for checking for wildcards in
    400                                 * expansion before calling Dir_Expand */
     385    char          *word;        /* Entire word to expand */
     386    char          *brace;       /* First curly brace in it */
     387    Lst           path;         /* Search path to use */
     388    Lst           expansions;   /* Place to store the expansions */
     389{
     390    char          *end;         /* Character after the closing brace */
     391    char          *cp;          /* Current position in brace clause */
     392    char          *start;       /* Start of current piece of brace clause */
     393    int           bracelevel;   /* Number of braces we've seen. If we see a
     394                                * right brace when this is 0, we've hit the
     395                                * end of the clause. */
     396    char          *file;        /* Current expansion */
     397    int           otherLen;     /* The length of the other pieces of the
     398                                * expansion (chars before and after the
     399                                * clause in 'word') */
     400    char          *cp2;         /* Pointer for checking for wildcards in
     401                                * expansion before calling Dir_Expand */
    401402
    402403    start = brace+1;
     
    407408     */
    408409    for (end = start, bracelevel = 0; *end != '\0'; end++) {
    409         if (*end == '{') {
    410             bracelevel++;
    411         } else if ((*end == '}') && (bracelevel-- == 0)) {
    412             break;
    413         }
     410        if (*end == '{') {
     411            bracelevel++;
     412        } else if ((*end == '}') && (bracelevel-- == 0)) {
     413            break;
     414        }
    414415    }
    415416    if (*end == '\0') {
    416         Error("Unterminated {} clause \"%s\"", start);
    417         return;
     417        Error("Unterminated {} clause \"%s\"", start);
     418        return;
    418419    } else {
    419         end++;
     420        end++;
    420421    }
    421422    otherLen = brace - word + strlen(end);
    422423
    423424    for (cp = start; cp < end; cp++) {
    424         /*
    425         * Find the end of this piece of the clause.
    426         */
    427         bracelevel = 0;
    428         while (*cp != ',') {
    429             if (*cp == '{') {
    430                 bracelevel++;
    431             } else if ((*cp == '}') && (bracelevel-- <= 0)) {
    432                 break;
    433             }
    434             cp++;
    435         }
    436         /*
    437         * Allocate room for the combination and install the three pieces.
    438         */
    439         file = emalloc(otherLen + cp - start + 1);
    440         if (brace != word) {
    441             strncpy(file, word, brace-word);
    442         }
    443         if (cp != start) {
    444             strncpy(&file[brace-word], start, cp-start);
    445         }
    446         strcpy(&file[(brace-word)+(cp-start)], end);
    447 
    448         /*
    449         * See if the result has any wildcards in it. If we find one, call
    450         * Dir_Expand right away, telling it to place the result on our list
    451         * of expansions.
    452         */
    453         for (cp2 = file; *cp2 != '\0'; cp2++) {
    454             switch(*cp2) {
    455             case '*':
    456             case '?':
    457             case '{':
    458             case '[':
    459                 Dir_Expand(file, path, expansions);
    460                 goto next;
    461             }
    462         }
    463         if (*cp2 == '\0') {
    464             /*
    465              * Hit the end w/o finding any wildcards, so stick the expansion
    466              * on the end of the list.
    467              */
    468             (void)Lst_AtEnd(expansions, file);
    469         } else {
    470         next:
    471             efree(file);
    472         }
    473         start = cp+1;
     425        /*
     426        * Find the end of this piece of the clause.
     427        */
     428        bracelevel = 0;
     429        while (*cp != ',') {
     430            if (*cp == '{') {
     431                bracelevel++;
     432            } else if ((*cp == '}') && (bracelevel-- <= 0)) {
     433                break;
     434            }
     435            cp++;
     436        }
     437        /*
     438        * Allocate room for the combination and install the three pieces.
     439        */
     440        file = emalloc(otherLen + cp - start + 1);
     441        if (brace != word) {
     442            strncpy(file, word, brace-word);
     443        }
     444        if (cp != start) {
     445            strncpy(&file[brace-word], start, cp-start);
     446        }
     447        strcpy(&file[(brace-word)+(cp-start)], end);
     448
     449        /*
     450        * See if the result has any wildcards in it. If we find one, call
     451        * Dir_Expand right away, telling it to place the result on our list
     452        * of expansions.
     453        */
     454        for (cp2 = file; *cp2 != '\0'; cp2++) {
     455            switch(*cp2) {
     456            case '*':
     457            case '?':
     458            case '{':
     459            case '[':
     460                Dir_Expand(file, path, expansions);
     461                goto next;
     462            }
     463        }
     464        if (*cp2 == '\0') {
     465            /*
     466             * Hit the end w/o finding any wildcards, so stick the expansion
     467             * on the end of the list.
     468             */
     469            (void)Lst_AtEnd(expansions, file);
     470        } else {
     471        next:
     472            efree(file);
     473        }
     474        start = cp+1;
    474475    }
    475476}
     
    479480 *-----------------------------------------------------------------------
    480481 * DirExpandInt --
    481  *      Internal expand routine. Passes through the directories in the
    482  *      path one by one, calling DirMatchFiles for each. NOTE: This still
    483  *      doesn't handle patterns in directories...
    484  *
    485  * Results:
    486  *      None.
    487  *
    488  * Side Effects:
    489  *      Things are added to the expansions list.
     482 *      Internal expand routine. Passes through the directories in the
     483 *      path one by one, calling DirMatchFiles for each. NOTE: This still
     484 *      doesn't handle patterns in directories...
     485 *
     486 * Results:
     487 *      None.
     488 *
     489 * Side Effects:
     490 *      Things are added to the expansions list.
    490491 *
    491492 *-----------------------------------------------------------------------
     
    493494static void
    494495DirExpandInt(word, path, expansions)
    495     char          *word;        /* Word to expand */
    496     Lst           path;         /* Path on which to look */
    497     Lst           expansions;   /* Place to store the result */
    498 {
    499     LstNode       ln;           /* Current node */
    500     Path          *p;           /* Directory in the node */
     496    char          *word;        /* Word to expand */
     497    Lst           path;         /* Path on which to look */
     498    Lst           expansions;   /* Place to store the result */
     499{
     500    LstNode       ln;           /* Current node */
     501    Path          *p;           /* Directory in the node */
    501502
    502503    if (Lst_Open(path) == SUCCESS) {
    503         while ((ln = Lst_Next(path)) != NILLNODE) {
    504             p = (Path *)Lst_Datum(ln);
    505             DirMatchFiles(word, p, expansions);
    506         }
    507         Lst_Close(path);
     504        while ((ln = Lst_Next(path)) != NILLNODE) {
     505            p = (Path *)Lst_Datum(ln);
     506            DirMatchFiles(word, p, expansions);
     507        }
     508        Lst_Close(path);
    508509    }
    509510}
     
    512513 *-----------------------------------------------------------------------
    513514 * DirPrintWord --
    514  *      Print a word in the list of expansions. Callback for Dir_Expand
    515  *      when DEBUG(DIR), via Lst_ForEach.
    516  *
    517  * Results:
    518  *      === 0
    519  *
    520  * Side Effects:
    521  *      The passed word is printed, followed by a space.
     515 *      Print a word in the list of expansions. Callback for Dir_Expand
     516 *      when DEBUG(DIR), via Lst_ForEach.
     517 *
     518 * Results:
     519 *      === 0
     520 *
     521 * Side Effects:
     522 *      The passed word is printed, followed by a space.
    522523 *
    523524 *-----------------------------------------------------------------------
     
    536537 *-----------------------------------------------------------------------
    537538 * Dir_Expand  --
    538  *      Expand the given word into a list of words by globbing it looking
    539  *      in the directories on the given search path.
    540  *
    541  * Results:
    542  *      A list of words consisting of the files which exist along the search
    543  *      path matching the given pattern.
    544  *
    545  * Side Effects:
    546  *      Directories may be opened. Who knows?
     539 *      Expand the given word into a list of words by globbing it looking
     540 *      in the directories on the given search path.
     541 *
     542 * Results:
     543 *      A list of words consisting of the files which exist along the search
     544 *      path matching the given pattern.
     545 *
     546 * Side Effects:
     547 *      Directories may be opened. Who knows?
    547548 *-----------------------------------------------------------------------
    548549 */
     
    550551Dir_Expand (word, path, expansions)
    551552    char    *word;      /* the word to expand */
    552     Lst     path;       /* the list of directories in which to find
    553                         * the resulting files */
    554     Lst     expansions; /* the list on which to place the results */
    555 {
    556     char          *cp;
     553    Lst     path;       /* the list of directories in which to find
     554                        * the resulting files */
     555    Lst     expansions; /* the list on which to place the results */
     556{
     557    char          *cp;
    557558
    558559    if (DEBUG(DIR)) {
    559         printf("expanding \"%s\"...", word);
     560        printf("expanding \"%s\"...", word);
    560561    }
    561562
    562563    cp = strchr(word, '{');
    563564    if (cp) {
    564         DirExpandCurly(word, cp, path, expansions);
     565        DirExpandCurly(word, cp, path, expansions);
    565566    } else {
    566         cp = strchr(word, '/');
    567         if (cp) {
    568             /*
    569              * The thing has a directory component -- find the first wildcard
    570              * in the string.
    571              */
    572             for (cp = word; *cp; cp++) {
    573                 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') {
    574                     break;
    575                 }
    576             }
    577             if (*cp == '{') {
    578                 /*
    579                 * This one will be fun.
    580                 */
    581                 DirExpandCurly(word, cp, path, expansions);
    582                 return;
    583             } else if (*cp != '\0') {
    584                 /*
    585                 * Back up to the start of the component
    586                 */
    587                 char  *dirpath;
    588 
    589                 while (cp > word && *cp != '/') {
    590                     cp--;
    591                 }
    592                 if (cp != word) {
    593                     char sc;
    594                     /*
    595                      * If the glob isn't in the first component, try and find
    596                      * all the components up to the one with a wildcard.
    597                      */
    598                     sc = cp[1];
    599                     cp[1] = '\0';
    600                     dirpath = Dir_FindFile(word, path);
    601                     cp[1] = sc;
    602                     /*
    603                      * dirpath is null if can't find the leading component
    604                      * XXX: Dir_FindFile won't find internal components.
    605                      * i.e. if the path contains ../Etc/Object and we're
    606                      * looking for Etc, it won't be found. Ah well.
    607                      * Probably not important.
    608                      */
    609                     if (dirpath != (char *)NULL) {
    610                         char *dp = &dirpath[strlen(dirpath) - 1];
    611                         if (*dp == '/')
    612                             *dp = '\0';
    613                         path = Lst_Init(FALSE);
    614                         Dir_AddDir(path, dirpath);
    615                         DirExpandInt(cp+1, path, expansions);
    616                         Lst_Destroy(path, NOFREE);
    617                     }
    618                 } else {
    619                     /*
    620                      * Start the search from the local directory
    621                      */
    622                     DirExpandInt(word, path, expansions);
    623                 }
    624             } else {
    625                 /*
    626                 * Return the file -- this should never happen.
    627                 */
    628                 DirExpandInt(word, path, expansions);
    629             }
    630         } else {
    631             /*
    632              * First the files in dot
    633              */
    634             DirMatchFiles(word, dot, expansions);
    635 
    636             /*
    637              * Then the files in every other directory on the path.
    638              */
    639             DirExpandInt(word, path, expansions);
    640         }
     567        cp = strchr(word, '/');
     568        if (cp) {
     569            /*
     570             * The thing has a directory component -- find the first wildcard
     571             * in the string.
     572             */
     573            for (cp = word; *cp; cp++) {
     574                if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') {
     575                    break;
     576                }
     577            }
     578            if (*cp == '{') {
     579                /*
     580                * This one will be fun.
     581                */
     582                DirExpandCurly(word, cp, path, expansions);
     583                return;
     584            } else if (*cp != '\0') {
     585                /*
     586                * Back up to the start of the component
     587                */
     588                char  *dirpath;
     589
     590                while (cp > word && *cp != '/') {
     591                    cp--;
     592                }
     593                if (cp != word) {
     594                    char sc;
     595                    /*
     596                     * If the glob isn't in the first component, try and find
     597                     * all the components up to the one with a wildcard.
     598                     */
     599                    sc = cp[1];
     600                    cp[1] = '\0';
     601                    dirpath = Dir_FindFile(word, path);
     602                    cp[1] = sc;
     603                    /*
     604                     * dirpath is null if can't find the leading component
     605                     * XXX: Dir_FindFile won't find internal components.
     606                     * i.e. if the path contains ../Etc/Object and we're
     607                     * looking for Etc, it won't be found. Ah well.
     608                     * Probably not important.
     609                     */
     610                    if (dirpath != (char *)NULL) {
     611                        char *dp = &dirpath[strlen(dirpath) - 1];
     612                        if (*dp == '/')
     613                            *dp = '\0';
     614                        path = Lst_Init(FALSE);
     615                        Dir_AddDir(path, dirpath);
     616                        DirExpandInt(cp+1, path, expansions);
     617                        Lst_Destroy(path, NOFREE);
     618                    }
     619                } else {
     620                    /*
     621                     * Start the search from the local directory
     622                     */
     623                    DirExpandInt(word, path, expansions);
     624                }
     625            } else {
     626                /*
     627                * Return the file -- this should never happen.
     628                */
     629                DirExpandInt(word, path, expansions);
     630            }
     631        } else {
     632            /*
     633             * First the files in dot
     634             */
     635            DirMatchFiles(word, dot, expansions);
     636
     637            /*
     638             * Then the files in every other directory on the path.
     639             */
     640            DirExpandInt(word, path, expansions);
     641        }
    641642    }
    642643    if (DEBUG(DIR)) {
    643         Lst_ForEach(expansions, DirPrintWord, (ClientData) 0);
    644         fputc('\n', stdout);
     644        Lst_ForEach(expansions, DirPrintWord, (ClientData) 0);
     645        fputc('\n', stdout);
    645646    }
    646647}
     
    649650 *-----------------------------------------------------------------------
    650651 * Dir_FindFile  --
    651  *      Find the file with the given name along the given search path.
    652  *
    653  * Results:
    654  *      The path to the file or NULL. This path is guaranteed to be in a
    655  *      different part of memory than name and so may be safely efree'd.
    656  *
    657  * Side Effects:
    658  *      If the file is found in a directory which is not on the path
    659  *      already (either 'name' is absolute or it is a relative path
    660  *      [ dir1/.../dirn/file ] which exists below one of the directories
    661  *      already on the search path), its directory is added to the end
    662  *      of the path on the assumption that there will be more files in
    663  *      that directory later on. Sometimes this is true. Sometimes not.
     652 *      Find the file with the given name along the given search path.
     653 *
     654 * Results:
     655 *      The path to the file or NULL. This path is guaranteed to be in a
     656 *      different part of memory than name and so may be safely efree'd.
     657 *
     658 * Side Effects:
     659 *      If the file is found in a directory which is not on the path
     660 *      already (either 'name' is absolute or it is a relative path
     661 *      [ dir1/.../dirn/file ] which exists below one of the directories
     662 *      already on the search path), its directory is added to the end
     663 *      of the path on the assumption that there will be more files in
     664 *      that directory later on. Sometimes this is true. Sometimes not.
    664665 *-----------------------------------------------------------------------
    665666 */
    666667char *
    667668Dir_FindFile (name, path)
    668     char          *name;    /* the file to find */
    669     Lst           path;     /* the Lst of directories to search */
    670 {
    671     register char *p1;      /* pointer into p->name */
    672     register char *p2;      /* pointer into name */
    673     LstNode       ln;       /* a list element */
     669    char          *name;    /* the file to find */
     670    Lst           path;     /* the Lst of directories to search */
     671{
     672    register char *p1;      /* pointer into p->name */
     673    register char *p2;      /* pointer into name */
     674    LstNode       ln;       /* a list element */
    674675    register char *file;    /* the current filename to check */
    675     register Path *p;       /* current path member */
    676     register char *cp;      /* index of first slash, if any */
    677     Boolean       hasSlash; /* true if 'name' contains a / */
    678     struct stat   stb;      /* Buffer for stat, if necessary */
    679     Hash_Entry    *entry;   /* Entry for mtimes table */
     676    register Path *p;       /* current path member */
     677    register char *cp;      /* index of first slash, if any */
     678    Boolean       hasSlash; /* true if 'name' contains a / */
     679    struct stat   stb;      /* Buffer for stat, if necessary */
     680    Hash_Entry    *entry;   /* Entry for mtimes table */
    680681
    681682#ifdef NMAKE
     
    691692    cp = strrchr (name, '/');
    692693    if (cp) {
    693         hasSlash = TRUE;
    694         cp += 1;
     694        hasSlash = TRUE;
     695        cp += 1;
    695696    } else {
    696         hasSlash = FALSE;
    697         cp = name;
     697        hasSlash = FALSE;
     698        cp = name;
    698699    }
    699700
    700701    if (DEBUG(DIR)) {
    701         printf("Searching for %s...", name);
     702        printf("Searching for %s...", name);
    702703    }
    703704    /*
     
    708709     */
    709710    if ((!hasSlash || (cp - name == 2 && *name == '.')) &&
    710         (Hash_FindEntry (&dot->files, cp) != (Hash_Entry *)NULL)) {
    711             if (DEBUG(DIR)) {
    712                 printf("in '.'\n");
    713             }
    714             hits += 1;
    715             dot->hits += 1;
    716             return (estrdup (name));
     711        (Hash_FindEntry (&dot->files, cp) != (Hash_Entry *)NULL)) {
     712            if (DEBUG(DIR)) {
     713                printf("in '.'\n");
     714            }
     715            hits += 1;
     716            dot->hits += 1;
     717            return (estrdup (name));
    717718    }
    718719
    719720    if (Lst_Open (path) == FAILURE) {
    720         if (DEBUG(DIR)) {
    721             printf("couldn't open path, file not found\n");
    722         }
    723         misses += 1;
    724         return ((char *) NULL);
     721        if (DEBUG(DIR)) {
     722            printf("couldn't open path, file not found\n");
     723        }
     724        misses += 1;
     725        return ((char *) NULL);
    725726    }
    726727
     
    734735     */
    735736    while ((ln = Lst_Next (path)) != NILLNODE) {
    736         p = (Path *) Lst_Datum (ln);
    737         if (DEBUG(DIR)) {
    738             printf("%s...", p->name);
    739         }
    740         if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) {
    741             if (DEBUG(DIR)) {
    742                 printf("here...");
    743             }
    744             if (hasSlash) {
    745                 /*
    746                 * If the name had a slash, its initial components and p's
    747                 * final components must match. This is false if a mismatch
    748                 * is encountered before all of the initial components
    749                 * have been checked (p2 > name at the end of the loop), or
    750                 * we matched only part of one of the components of p
    751                 * along with all the rest of them (*p1 != '/').
    752                 */
    753                 p1 = p->name + strlen (p->name) - 1;
    754                 p2 = cp - 2;
    755                 while (p2 >= name && p1 >= p->name && *p1 == *p2) {
    756                     p1 -= 1; p2 -= 1;
    757                 }
    758                 if (p2 >= name || (p1 >= p->name && *p1 != '/')) {
    759                     if (DEBUG(DIR)) {
    760                         printf("component mismatch -- continuing...");
    761                     }
    762                     continue;
    763                 }
    764             }
    765             file = str_concat (p->name, cp, STR_ADDSLASH);
    766             if (DEBUG(DIR)) {
    767                 printf("returning %s\n", file);
    768             }
    769             Lst_Close (path);
    770             p->hits += 1;
    771             hits += 1;
    772             return (file);
    773         } else if (hasSlash) {
    774             /*
    775              * If the file has a leading path component and that component
    776              * exactly matches the entire name of the current search
    777              * directory, we assume the file doesn't exist and return NULL.
    778              */
    779             for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
    780                 continue;
    781             }
    782             if (*p1 == '\0' && p2 == cp - 1) {
    783                 if (DEBUG(DIR)) {
    784                     printf("must be here but isn't -- returing NULL\n");
    785                 }
    786                 Lst_Close (path);
    787                 return ((char *) NULL);
    788             }
    789         }
     737        p = (Path *) Lst_Datum (ln);
     738        if (DEBUG(DIR)) {
     739            printf("%s...", p->name);
     740        }
     741        if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) {
     742            if (DEBUG(DIR)) {
     743                printf("here...");
     744            }
     745            if (hasSlash) {
     746                /*
     747                * If the name had a slash, its initial components and p's
     748                * final components must match. This is false if a mismatch
     749                * is encountered before all of the initial components
     750                * have been checked (p2 > name at the end of the loop), or
     751                * we matched only part of one of the components of p
     752                * along with all the rest of them (*p1 != '/').
     753                */
     754                p1 = p->name + strlen (p->name) - 1;
     755                p2 = cp - 2;
     756                while (p2 >= name && p1 >= p->name && *p1 == *p2) {
     757                    p1 -= 1; p2 -= 1;
     758                }
     759                if (p2 >= name || (p1 >= p->name && *p1 != '/')) {
     760                    if (DEBUG(DIR)) {
     761                        printf("component mismatch -- continuing...");
     762                    }
     763                    continue;
     764                }
     765            }
     766            file = str_concat (p->name, cp, STR_ADDSLASH);
     767            if (DEBUG(DIR)) {
     768                printf("returning %s\n", file);
     769            }
     770            Lst_Close (path);
     771            p->hits += 1;
     772            hits += 1;
     773            return (file);
     774        } else if (hasSlash) {
     775            /*
     776             * If the file has a leading path component and that component
     777             * exactly matches the entire name of the current search
     778             * directory, we assume the file doesn't exist and return NULL.
     779             */
     780            for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
     781                continue;
     782            }
     783            if (*p1 == '\0' && p2 == cp - 1) {
     784                if (DEBUG(DIR)) {
     785                    printf("must be here but isn't -- returing NULL\n");
     786                }
     787                Lst_Close (path);
     788                return ((char *) NULL);
     789            }
     790        }
    790791    }
    791792
     
    803804     */
    804805    if (!hasSlash) {
    805         if (DEBUG(DIR)) {
    806             printf("failed.\n");
    807         }
    808         misses += 1;
    809         return ((char *) NULL);
     806        if (DEBUG(DIR)) {
     807            printf("failed.\n");
     808        }
     809        misses += 1;
     810        return ((char *) NULL);
    810811    }
    811812
    812813    if (*name != '/') {
    813         Boolean checkedDot = FALSE;
    814 
    815         if (DEBUG(DIR)) {
    816             printf("failed. Trying subdirectories...");
    817         }
    818         (void) Lst_Open (path);
    819         while ((ln = Lst_Next (path)) != NILLNODE) {
    820             p = (Path *) Lst_Datum (ln);
    821             if (p != dot) {
    822                 file = str_concat (p->name, name, STR_ADDSLASH);
    823             } else {
    824                 /*
    825                 * Checking in dot -- DON'T put a leading ./ on the thing.
    826                 */
    827                 file = estrdup(name);
    828                 checkedDot = TRUE;
    829             }
    830             if (DEBUG(DIR)) {
    831                 printf("checking %s...", file);
    832             }
    833 
    834 
    835             if (stat (file, &stb) == 0) {
    836                 if (DEBUG(DIR)) {
    837                     printf("got it.\n");
    838                 }
    839 
    840                 Lst_Close (path);
    841 
    842                 /*
    843                 * We've found another directory to search. We know there's
    844                 * a slash in 'file' because we put one there. We nuke it after
    845                 * finding it and call Dir_AddDir to add this new directory
    846                 * onto the existing search path. Once that's done, we restore
    847                 * the slash and triumphantly return the file name, knowing
    848                 * that should a file in this directory every be referenced
    849                 * again in such a manner, we will find it without having to do
    850                 * numerous numbers of access calls. Hurrah!
    851                 */
    852                 cp = strrchr (file, '/');
    853                 *cp = '\0';
    854                 Dir_AddDir (path, file);
    855                 *cp = '/';
    856 
    857                 /*
    858                 * Save the modification time so if it's needed, we don't have
    859                 * to fetch it again.
    860                 */
    861                 if (DEBUG(DIR)) {
    862                     printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
    863                             file);
    864                 }
    865                 entry = Hash_CreateEntry(&mtimes, (char *) file,
    866                                         (Boolean *)NULL);
    867                 Hash_SetValue(entry, (long)stb.st_mtime);
    868                 nearmisses += 1;
    869                 return (file);
    870             } else {
    871                 efree (file);
    872             }
    873         }
    874 
    875         if (DEBUG(DIR)) {
    876             printf("failed. ");
    877         }
    878         Lst_Close (path);
    879 
    880         if (checkedDot) {
    881             /*
    882              * Already checked by the given name, since . was in the path,
    883              * so no point in proceeding...
    884              */
    885             if (DEBUG(DIR)) {
    886                 printf("Checked . already, returning NULL\n");
    887             }
    888             return(NULL);
    889         }
     814        Boolean checkedDot = FALSE;
     815
     816        if (DEBUG(DIR)) {
     817            printf("failed. Trying subdirectories...");
     818        }
     819        (void) Lst_Open (path);
     820        while ((ln = Lst_Next (path)) != NILLNODE) {
     821            p = (Path *) Lst_Datum (ln);
     822            if (p != dot) {
     823                file = str_concat (p->name, name, STR_ADDSLASH);
     824            } else {
     825                /*
     826                * Checking in dot -- DON'T put a leading ./ on the thing.
     827                */
     828                file = estrdup(name);
     829                checkedDot = TRUE;
     830            }
     831            if (DEBUG(DIR)) {
     832                printf("checking %s...", file);
     833            }
     834
     835
     836            if (stat (file, &stb) == 0) {
     837                if (DEBUG(DIR)) {
     838                    printf("got it.\n");
     839                }
     840
     841                Lst_Close (path);
     842
     843                /*
     844                * We've found another directory to search. We know there's
     845                * a slash in 'file' because we put one there. We nuke it after
     846                * finding it and call Dir_AddDir to add this new directory
     847                * onto the existing search path. Once that's done, we restore
     848                * the slash and triumphantly return the file name, knowing
     849                * that should a file in this directory every be referenced
     850                * again in such a manner, we will find it without having to do
     851                * numerous numbers of access calls. Hurrah!
     852                */
     853                cp = strrchr (file, '/');
     854                *cp = '\0';
     855                Dir_AddDir (path, file);
     856                *cp = '/';
     857
     858                /*
     859                * Save the modification time so if it's needed, we don't have
     860                * to fetch it again.
     861                */
     862                if (DEBUG(DIR)) {
     863                    printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
     864                            file);
     865                }
     866                entry = Hash_CreateEntry(&mtimes, (char *) file,
     867                                        (Boolean *)NULL);
     868                Hash_SetValue(entry, (long)stb.st_mtime);
     869                nearmisses += 1;
     870                return (file);
     871            } else {
     872                efree (file);
     873            }
     874        }
     875
     876        if (DEBUG(DIR)) {
     877            printf("failed. ");
     878        }
     879        Lst_Close (path);
     880
     881        if (checkedDot) {
     882            /*
     883             * Already checked by the given name, since . was in the path,
     884             * so no point in proceeding...
     885             */
     886            if (DEBUG(DIR)) {
     887                printf("Checked . already, returning NULL\n");
     888            }
     889            return(NULL);
     890        }
    890891    }
    891892
     
    915916    ln = Lst_Last (path);
    916917    if (ln == NILLNODE) {
    917         return ((char *) NULL);
     918        return ((char *) NULL);
    918919    } else {
    919         p = (Path *) Lst_Datum (ln);
     920        p = (Path *) Lst_Datum (ln);
    920921    }
    921922
    922923    if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) {
    923         return (estrdup (name));
     924        return (estrdup (name));
    924925    } else {
    925         return ((char *) NULL);
     926        return ((char *) NULL);
    926927    }
    927928#else /* !notdef */
    928929    if (DEBUG(DIR)) {
    929         printf("Looking for \"%s\"...", name);
     930        printf("Looking for \"%s\"...", name);
    930931    }
    931932
     
    933934    entry = Hash_FindEntry(&mtimes, name);
    934935    if (entry != (Hash_Entry *)NULL) {
    935         if (DEBUG(DIR)) {
    936             printf("got it (in mtime cache)\n");
    937         }
    938         return(estrdup(name));
     936        if (DEBUG(DIR)) {
     937            printf("got it (in mtime cache)\n");
     938        }
     939        return(estrdup(name));
    939940    } else if (stat (name, &stb) == 0) {
    940         entry = Hash_CreateEntry(&mtimes, name, (Boolean *)NULL);
    941         if (DEBUG(DIR)) {
    942             printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
    943                     name);
    944         }
    945         Hash_SetValue(entry, (long)stb.st_mtime);
    946         return (estrdup (name));
     941        entry = Hash_CreateEntry(&mtimes, name, (Boolean *)NULL);
     942        if (DEBUG(DIR)) {
     943            printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
     944                    name);
     945        }
     946        Hash_SetValue(entry, (long)stb.st_mtime);
     947        return (estrdup (name));
    947948    } else {
    948         if (DEBUG(DIR)) {
    949             printf("failed. Returning NULL\n");
    950         }
    951         return ((char *)NULL);
     949        if (DEBUG(DIR)) {
     950            printf("failed. Returning NULL\n");
     951        }
     952        return ((char *)NULL);
    952953    }
    953954#endif /* notdef */
     
    957958 *-----------------------------------------------------------------------
    958959 * Dir_MTime  --
    959  *      Find the modification time of the file described by gn along the
    960  *      search path dirSearchPath.
    961  *
    962  * Results:
    963  *      The modification time or 0 if it doesn't exist
    964  *
    965  * Side Effects:
    966  *      The modification time is placed in the node's mtime slot.
    967  *      If the node didn't have a path entry before, and Dir_FindFile
    968  *      found one for it, the full name is placed in the path slot.
     960 *      Find the modification time of the file described by gn along the
     961 *      search path dirSearchPath.
     962 *
     963 * Results:
     964 *      The modification time or 0 if it doesn't exist
     965 *
     966 * Side Effects:
     967 *      The modification time is placed in the node's mtime slot.
     968 *      If the node didn't have a path entry before, and Dir_FindFile
     969 *      found one for it, the full name is placed in the path slot.
    969970 *-----------------------------------------------------------------------
    970971 */
    971972int
    972973Dir_MTime (gn)
    973     GNode         *gn;        /* the file whose modification time is
    974                                * desired */
     974    GNode         *gn;        /* the file whose modification time is
     975                               * desired */
    975976{
    976977    char          *fullName;  /* the full pathname of name */
    977     struct stat   stb;        /* buffer for finding the mod time */
    978     Hash_Entry    *entry;
     978    struct stat   stb;        /* buffer for finding the mod time */
     979    Hash_Entry    *entry;
    979980
    980981    #ifdef USE_ARCHIVES
    981982    if (gn->type & OP_ARCHV) {
    982         return Arch_MTime (gn);
     983        return Arch_MTime (gn);
    983984    } else
    984985    #endif
    985986        if (gn->path == (char *)NULL) {
    986         fullName = Dir_FindFile (gn->name, dirSearchPath);
     987        fullName = Dir_FindFile (gn->name, dirSearchPath);
    987988    } else {
    988         fullName = gn->path;
     989        fullName = gn->path;
    989990    }
    990991
    991992    if (fullName == (char *)NULL) {
    992         fullName = estrdup(gn->name);
     993        fullName = estrdup(gn->name);
    993994    }
    994995
    995996    entry = Hash_FindEntry(&mtimes, fullName);
    996997    if (entry != (Hash_Entry *)NULL) {
    997         /*
    998         * Only do this once -- the second time folks are checking to
    999         * see if the file was actually updated, so we need to actually go
    1000         * to the file system.
    1001         */
    1002         if (DEBUG(DIR)) {
    1003             printf("Using cached time %s for %s\n",
    1004                     Targ_FmtTime((time_t)(long)Hash_GetValue(entry)), fullName);
    1005         }
    1006         stb.st_mtime = (time_t)(long)Hash_GetValue(entry);
    1007         Hash_DeleteEntry(&mtimes, entry);
     998        /*
     999        * Only do this once -- the second time folks are checking to
     1000        * see if the file was actually updated, so we need to actually go
     1001        * to the file system.
     1002        */
     1003        if (DEBUG(DIR)) {
     1004            printf("Using cached time %s for %s\n",
     1005                    Targ_FmtTime((time_t)(long)Hash_GetValue(entry)), fullName);
     1006        }
     1007        stb.st_mtime = (time_t)(long)Hash_GetValue(entry);
     1008        Hash_DeleteEntry(&mtimes, entry);
    10081009    } else if (stat (fullName, &stb) < 0) {
    10091010        #ifdef USE_ARCHIVES
    1010         if (gn->type & OP_MEMBER) {
    1011             if (fullName != gn->path)
    1012                 efree(fullName);
    1013             return Arch_MemMTime (gn);
    1014         } else
     1011        if (gn->type & OP_MEMBER) {
     1012            if (fullName != gn->path)
     1013                efree(fullName);
     1014            return Arch_MemMTime (gn);
     1015        } else
    10151016        #endif
    1016             stb.st_mtime = 0;
     1017            stb.st_mtime = 0;
    10171018    }
    10181019    if (fullName && gn->path == (char *)NULL) {
    1019         gn->path = fullName;
     1020        gn->path = fullName;
    10201021    }
    10211022
     
    10271028 *-----------------------------------------------------------------------
    10281029 * Dir_AddDir --
    1029  *      Add the given name to the end of the given path. The order of
    1030  *      the arguments is backwards so ParseDoDependency can do a
    1031  *      Lst_ForEach of its list of paths...
    1032  *
    1033  * Results:
    1034  *      none
    1035  *
    1036  * Side Effects:
    1037  *      A structure is added to the list and the directory is
    1038  *      read and hashed.
     1030 *      Add the given name to the end of the given path. The order of
     1031 *      the arguments is backwards so ParseDoDependency can do a
     1032 *      Lst_ForEach of its list of paths...
     1033 *
     1034 * Results:
     1035 *      none
     1036 *
     1037 * Side Effects:
     1038 *      A structure is added to the list and the directory is
     1039 *      read and hashed.
    10391040 *-----------------------------------------------------------------------
    10401041 */
    10411042void
    10421043Dir_AddDir (path, name)
    1043     Lst           path;       /* the path to which the directory should be
    1044                                * added */
     1044    Lst           path;       /* the path to which the directory should be
     1045                               * added */
    10451046    char          *name;      /* the name of the directory to add */
    10461047{
    1047     LstNode       ln;         /* node in case Path structure is found */
    1048     register Path *p;         /* pointer to new Path structure */
    1049     DIR           *d;         /* for reading directory */
     1048    LstNode       ln;         /* node in case Path structure is found */
     1049    register Path *p;         /* pointer to new Path structure */
     1050    DIR           *d;         /* for reading directory */
    10501051    register struct dirent *dp; /* entry in directory */
    10511052
    10521053    ln = Lst_Find (openDirectories, (ClientData)name, DirFindName);
    10531054    if (ln != NILLNODE) {
    1054         p = (Path *)Lst_Datum (ln);
    1055         if (Lst_Member(path, (ClientData)p) == NILLNODE) {
    1056             p->refCount += 1;
    1057             (void)Lst_AtEnd (path, (ClientData)p);
    1058         }
     1055        p = (Path *)Lst_Datum (ln);
     1056        if (Lst_Member(path, (ClientData)p) == NILLNODE) {
     1057            p->refCount += 1;
     1058            (void)Lst_AtEnd (path, (ClientData)p);
     1059        }
    10591060    } else {
    1060         if (DEBUG(DIR)) {
    1061             printf("Caching %s...", name);
    1062             fflush(stdout);
    1063         }
    1064 
    1065         if ((d = opendir (name)) != (DIR *) NULL) {
    1066             p = (Path *) emalloc (sizeof (Path));
    1067             p->name = estrdup (name);
    1068             p->hits = 0;
    1069             p->refCount = 1;
    1070             Hash_InitTable (&p->files, -1);
    1071 
    1072             while ((dp = readdir (d)) != (struct dirent *) NULL) {
     1061        if (DEBUG(DIR)) {
     1062            printf("Caching %s...", name);
     1063            fflush(stdout);
     1064        }
     1065
     1066        if ((d = opendir (name)) != (DIR *) NULL) {
     1067            p = (Path *) emalloc (sizeof (Path));
     1068            p->name = estrdup (name);
     1069            p->hits = 0;
     1070            p->refCount = 1;
     1071            Hash_InitTable (&p->files, -1);
     1072
     1073            while ((dp = readdir (d)) != (struct dirent *) NULL) {
    10731074#if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */
    1074                 /*
    1075                 * The sun directory library doesn't check for a 0 inode
    1076                 * (0-inode slots just take up space), so we have to do
    1077                 * it ourselves.
    1078                 */
    1079                 if (dp->d_fileno == 0) {
    1080                     continue;
    1081                 }
     1075                /*
     1076                * The sun directory library doesn't check for a 0 inode
     1077                * (0-inode slots just take up space), so we have to do
     1078                * it ourselves.
     1079                */
     1080                if (dp->d_fileno == 0) {
     1081                    continue;
     1082                }
    10821083#endif /* sun && d_ino */
    10831084
    1084                 /* Skip the '.' and '..' entries by checking for them
    1085                 * specifically instead of assuming readdir() reuturns them in
    1086                 * that order when first going through a directory.  This is
    1087                 * needed for XFS over NFS filesystems since SGI does not
    1088                 * guarantee that these are * the first two entries returned
    1089                 * from readdir().
    1090                 */
    1091                 if (ISDOT(dp->d_name) || ISDOTDOT(dp->d_name))
    1092                         continue;
    1093 
    1094                 (void)Hash_CreateEntry(&p->files, dp->d_name, (Boolean *)NULL);
    1095             }
    1096             (void) closedir (d);
    1097             (void)Lst_AtEnd (openDirectories, (ClientData)p);
    1098             (void)Lst_AtEnd (path, (ClientData)p);
    1099         }
    1100         if (DEBUG(DIR)) {
    1101             printf("done\n");
    1102         }
     1085                /* Skip the '.' and '..' entries by checking for them
     1086                * specifically instead of assuming readdir() reuturns them in
     1087                * that order when first going through a directory.  This is
     1088                * needed for XFS over NFS filesystems since SGI does not
     1089                * guarantee that these are * the first two entries returned
     1090                * from readdir().
     1091                */
     1092                if (ISDOT(dp->d_name) || ISDOTDOT(dp->d_name))
     1093                        continue;
     1094
     1095                (void)Hash_CreateEntry(&p->files, dp->d_name, (Boolean *)NULL);
     1096            }
     1097            (void) closedir (d);
     1098            (void)Lst_AtEnd (openDirectories, (ClientData)p);
     1099            (void)Lst_AtEnd (path, (ClientData)p);
     1100        }
     1101        if (DEBUG(DIR)) {
     1102            printf("done\n");
     1103        }
    11031104    }
    11041105}
     
    11071108 *-----------------------------------------------------------------------
    11081109 * Dir_CopyDir --
    1109  *      Callback function for duplicating a search path via Lst_Duplicate.
    1110  *      Ups the reference count for the directory.
    1111  *
    1112  * Results:
    1113  *      Returns the Path it was given.
    1114  *
    1115  * Side Effects:
    1116  *      The refCount of the path is incremented.
     1110 *      Callback function for duplicating a search path via Lst_Duplicate.
     1111 *      Ups the reference count for the directory.
     1112 *
     1113 * Results:
     1114 *      Returns the Path it was given.
     1115 *
     1116 * Side Effects:
     1117 *      The refCount of the path is incremented.
    11171118 *
    11181119 *-----------------------------------------------------------------------
     
    11301131 *-----------------------------------------------------------------------
    11311132 * Dir_MakeFlags --
    1132  *      Make a string by taking all the directories in the given search
    1133  *      path and preceding them by the given flag. Used by the suffix
    1134  *      module to create variables for compilers based on suffix search
    1135  *      paths.
    1136  *
    1137  * Results:
    1138  *      The string mentioned above. Note that there is no space between
    1139  *      the given flag and each directory. The empty string is returned if
    1140  *      Things don't go well.
    1141  *
    1142  * Side Effects:
    1143  *      None
     1133 *      Make a string by taking all the directories in the given search
     1134 *      path and preceding them by the given flag. Used by the suffix
     1135 *      module to create variables for compilers based on suffix search
     1136 *      paths.
     1137 *
     1138 * Results:
     1139 *      The string mentioned above. Note that there is no space between
     1140 *      the given flag and each directory. The empty string is returned if
     1141 *      Things don't go well.
     1142 *
     1143 * Side Effects:
     1144 *      None
    11441145 *-----------------------------------------------------------------------
    11451146 */
    11461147char *
    11471148Dir_MakeFlags (flag, path)
    1148     char          *flag;  /* flag which should precede each directory */
    1149     Lst           path;   /* list of directories */
    1150 {
    1151     char          *str;   /* the string which will be returned */
    1152     char          *tstr;  /* the current directory preceded by 'flag' */
    1153     LstNode       ln;     /* the node of the current directory */
    1154     Path          *p;     /* the structure describing the current directory */
     1149    char          *flag;  /* flag which should precede each directory */
     1150    Lst           path;   /* list of directories */
     1151{
     1152    char          *str;   /* the string which will be returned */
     1153    char          *tstr;  /* the current directory preceded by 'flag' */
     1154    LstNode       ln;     /* the node of the current directory */
     1155    Path          *p;     /* the structure describing the current directory */
    11551156
    11561157    str = estrdup ("");
    11571158
    11581159    if (Lst_Open (path) == SUCCESS) {
    1159         while ((ln = Lst_Next (path)) != NILLNODE) {
    1160             p = (Path *) Lst_Datum (ln);
    1161             tstr = str_concat (flag, p->name, 0);
    1162             str = str_concat (str, tstr, STR_ADDSPACE | STR_DOFREE);
    1163         }
    1164         Lst_Close (path);
     1160        while ((ln = Lst_Next (path)) != NILLNODE) {
     1161            p = (Path *) Lst_Datum (ln);
     1162            tstr = str_concat (flag, p->name, 0);
     1163            str = str_concat (str, tstr, STR_ADDSPACE | STR_DOFREE);
     1164        }
     1165        Lst_Close (path);
    11651166    }
    11661167
     
    11711172 *-----------------------------------------------------------------------
    11721173 * Dir_Destroy --
    1173  *      Nuke a directory descriptor, if possible. Callback procedure
    1174  *      for the suffixes module when destroying a search path.
    1175  *
    1176  * Results:
    1177  *      None.
    1178  *
    1179  * Side Effects:
    1180  *      If no other path references this directory (refCount == 0),
    1181  *      the Path and all its data are freed.
     1174 *      Nuke a directory descriptor, if possible. Callback procedure
     1175 *      for the suffixes module when destroying a search path.
     1176 *
     1177 * Results:
     1178 *      None.
     1179 *
     1180 * Side Effects:
     1181 *      If no other path references this directory (refCount == 0),
     1182 *      the Path and all its data are freed.
    11821183 *
    11831184 *-----------------------------------------------------------------------
     
    11851186void
    11861187Dir_Destroy (pp)
    1187     ClientData    pp;       /* The directory descriptor to nuke */
    1188 {
    1189     Path          *p = (Path *) pp;
     1188    ClientData    pp;       /* The directory descriptor to nuke */
     1189{
     1190    Path          *p = (Path *) pp;
    11901191    p->refCount -= 1;
    11911192
    11921193    if (p->refCount == 0) {
    1193         LstNode ln;
    1194 
    1195         ln = Lst_Member (openDirectories, (ClientData)p);
    1196         (void) Lst_Remove (openDirectories, ln);
    1197 
    1198         Hash_DeleteTable (&p->files);
    1199         efree((Address)p->name);
    1200         efree((Address)p);
     1194        LstNode ln;
     1195
     1196        ln = Lst_Member (openDirectories, (ClientData)p);
     1197        (void) Lst_Remove (openDirectories, ln);
     1198
     1199        Hash_DeleteTable (&p->files);
     1200        efree((Address)p->name);
     1201        efree((Address)p);
    12011202    }
    12021203}
     
    12051206 *-----------------------------------------------------------------------
    12061207 * Dir_ClearPath --
    1207  *      Clear out all elements of the given search path. This is different
    1208  *      from destroying the list, notice.
    1209  *
    1210  * Results:
    1211  *      None.
    1212  *
    1213  * Side Effects:
    1214  *      The path is set to the empty list.
     1208 *      Clear out all elements of the given search path. This is different
     1209 *      from destroying the list, notice.
     1210 *
     1211 * Results:
     1212 *      None.
     1213 *
     1214 * Side Effects:
     1215 *      The path is set to the empty list.
    12151216 *
    12161217 *-----------------------------------------------------------------------
     
    12181219void
    12191220Dir_ClearPath(path)
    1220     Lst     path;       /* Path to clear */
     1221    Lst     path;       /* Path to clear */
    12211222{
    12221223    Path    *p;
    12231224    while (!Lst_IsEmpty(path)) {
    1224         p = (Path *)Lst_DeQueue(path);
    1225         Dir_Destroy((ClientData) p);
     1225        p = (Path *)Lst_DeQueue(path);
     1226        Dir_Destroy((ClientData) p);
    12261227    }
    12271228}
     
    12311232 *-----------------------------------------------------------------------
    12321233 * Dir_Concat --
    1233  *      Concatenate two paths, adding the second to the end of the first.
    1234  *      Makes sure to avoid duplicates.
    1235  *
    1236  * Results:
    1237  *      None
    1238  *
    1239  * Side Effects:
    1240  *      Reference counts for added dirs are upped.
     1234 *      Concatenate two paths, adding the second to the end of the first.
     1235 *      Makes sure to avoid duplicates.
     1236 *
     1237 * Results:
     1238 *      None
     1239 *
     1240 * Side Effects:
     1241 *      Reference counts for added dirs are upped.
    12411242 *
    12421243 *-----------------------------------------------------------------------
     
    12441245void
    12451246Dir_Concat(path1, path2)
    1246     Lst     path1;      /* Dest */
    1247     Lst     path2;      /* Source */
     1247    Lst     path1;      /* Dest */
     1248    Lst     path2;      /* Source */
    12481249{
    12491250    LstNode ln;
     
    12511252
    12521253    for (ln = Lst_First(path2); ln != NILLNODE; ln = Lst_Succ(ln)) {
    1253         p = (Path *)Lst_Datum(ln);
    1254         if (Lst_Member(path1, (ClientData)p) == NILLNODE) {
    1255             p->refCount += 1;
    1256             (void)Lst_AtEnd(path1, (ClientData)p);
    1257         }
     1254        p = (Path *)Lst_Datum(ln);
     1255        if (Lst_Member(path1, (ClientData)p) == NILLNODE) {
     1256            p->refCount += 1;
     1257            (void)Lst_AtEnd(path1, (ClientData)p);
     1258        }
    12581259    }
    12591260}
     
    12631264Dir_PrintDirectories()
    12641265{
    1265     LstNode     ln;
    1266     Path        *p;
     1266    LstNode     ln;
     1267    Path        *p;
    12671268
    12681269    printf ("#*** Directory Cache:\n");
    12691270    printf ("# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n",
    1270               hits, misses, nearmisses, bigmisses,
    1271               (hits+bigmisses+nearmisses ?
    1272                hits * 100 / (hits + bigmisses + nearmisses) : 0));
     1271              hits, misses, nearmisses, bigmisses,
     1272              (hits+bigmisses+nearmisses ?
     1273               hits * 100 / (hits + bigmisses + nearmisses) : 0));
    12731274    printf ("# %-20s referenced\thits\n", "directory");
    12741275    if (Lst_Open (openDirectories) == SUCCESS) {
    1275         while ((ln = Lst_Next (openDirectories)) != NILLNODE) {
    1276             p = (Path *) Lst_Datum (ln);
    1277             printf ("# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits);
    1278         }
    1279         Lst_Close (openDirectories);
     1276        while ((ln = Lst_Next (openDirectories)) != NILLNODE) {
     1277            p = (Path *) Lst_Datum (ln);
     1278            printf ("# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits);
     1279        }
     1280        Lst_Close (openDirectories);
    12801281    }
    12811282}
    12821283
    12831284static int DirPrintDir (p, dummy)
    1284     ClientData  p;
    1285     ClientData  dummy;
     1285    ClientData  p;
     1286    ClientData  dummy;
    12861287{
    12871288    printf ("%s ", ((Path *) p)->name);
     
    12911292void
    12921293Dir_PrintPath (path)
    1293     Lst path;
     1294    Lst path;
    12941295{
    12951296    Lst_ForEach (path, DirPrintDir, (ClientData)0);
Note: See TracChangeset for help on using the changeset viewer.