[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.25

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