[BACK]Return to dir.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / make

Annotation of src/usr.bin/make/dir.c, Revision 1.30

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