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

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

1.121   ! rillig      1: /*     $NetBSD: dir.c,v 1.120 2020/08/28 04:59:17 rillig Exp $ */
1.8       christos    2:
1.1       cgd         3: /*
                      4:  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
1.37      agc         5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to Berkeley by
                      8:  * Adam de Boor.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. Neither the name of the University nor the names of its contributors
                     19:  *    may be used to endorse or promote products derived from this software
                     20:  *    without specific prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  */
                     34:
                     35: /*
1.1       cgd        36:  * Copyright (c) 1988, 1989 by Adam de Boor
                     37:  * Copyright (c) 1989 by Berkeley Softworks
                     38:  * All rights reserved.
                     39:  *
                     40:  * This code is derived from software contributed to Berkeley by
                     41:  * Adam de Boor.
                     42:  *
                     43:  * Redistribution and use in source and binary forms, with or without
                     44:  * modification, are permitted provided that the following conditions
                     45:  * are met:
                     46:  * 1. Redistributions of source code must retain the above copyright
                     47:  *    notice, this list of conditions and the following disclaimer.
                     48:  * 2. Redistributions in binary form must reproduce the above copyright
                     49:  *    notice, this list of conditions and the following disclaimer in the
                     50:  *    documentation and/or other materials provided with the distribution.
                     51:  * 3. All advertising materials mentioning features or use of this software
                     52:  *    must display the following acknowledgement:
                     53:  *     This product includes software developed by the University of
                     54:  *     California, Berkeley and its contributors.
                     55:  * 4. Neither the name of the University nor the names of its contributors
                     56:  *    may be used to endorse or promote products derived from this software
                     57:  *    without specific prior written permission.
                     58:  *
                     59:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     60:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     61:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     62:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     63:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     64:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     65:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     66:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     67:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     68:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     69:  * SUCH DAMAGE.
                     70:  */
                     71:
1.41      ross       72: #ifndef MAKE_NATIVE
1.121   ! rillig     73: static char rcsid[] = "$NetBSD: dir.c,v 1.120 2020/08/28 04:59:17 rillig Exp $";
1.20      lukem      74: #else
1.19      christos   75: #include <sys/cdefs.h>
1.1       cgd        76: #ifndef lint
1.8       christos   77: #if 0
1.12      christos   78: static char sccsid[] = "@(#)dir.c      8.2 (Berkeley) 1/2/94";
1.8       christos   79: #else
1.121   ! rillig     80: __RCSID("$NetBSD: dir.c,v 1.120 2020/08/28 04:59:17 rillig Exp $");
1.8       christos   81: #endif
1.1       cgd        82: #endif /* not lint */
1.20      lukem      83: #endif
1.1       cgd        84:
                     85: /*-
                     86:  * dir.c --
                     87:  *     Directory searching using wildcards and/or normal names...
                     88:  *     Used both for source wildcarding in the Makefile and for finding
                     89:  *     implicit sources.
                     90:  *
                     91:  * The interface for this module is:
                     92:  *     Dir_Init            Initialize the module.
                     93:  *
1.35      sjg        94:  *     Dir_InitCur         Set the cur Path.
                     95:  *
                     96:  *     Dir_InitDot         Set the dot Path.
                     97:  *
1.6       jtc        98:  *     Dir_End             Cleanup the module.
                     99:  *
1.35      sjg       100:  *     Dir_SetPATH         Set ${.PATH} to reflect state of dirSearchPath.
                    101:  *
1.1       cgd       102:  *     Dir_HasWildcards    Returns TRUE if the name given it needs to
                    103:  *                         be wildcard-expanded.
                    104:  *
                    105:  *     Dir_Expand          Given a pattern and a path, return a Lst of names
                    106:  *                         which match the pattern on the search path.
                    107:  *
                    108:  *     Dir_FindFile        Searches for a file on a given search path.
                    109:  *                         If it exists, the entire path is returned.
                    110:  *                         Otherwise NULL is returned.
                    111:  *
1.40      chuck     112:  *     Dir_FindHereOrAbove Search for a path in the current directory and
                    113:  *                         then all the directories above it in turn until
                    114:  *                         the path is found or we reach the root ("/").
1.76      rillig    115:  *
1.1       cgd       116:  *     Dir_MTime           Return the modification time of a node. The file
                    117:  *                         is searched for along the default search path.
                    118:  *                         The path and mtime fields of the node are filled
                    119:  *                         in.
                    120:  *
                    121:  *     Dir_AddDir          Add a directory to a search path.
                    122:  *
                    123:  *     Dir_MakeFlags       Given a search path and a command flag, create
                    124:  *                         a string with each of the directories in the path
                    125:  *                         preceded by the command flag and all of them
                    126:  *                         separated by a space.
                    127:  *
                    128:  *     Dir_Destroy         Destroy an element of a search path. Frees up all
                    129:  *                         things that can be freed for the element as long
                    130:  *                         as the element is no longer referenced by any other
                    131:  *                         search path.
                    132:  *     Dir_ClearPath       Resets a search path to the empty list.
                    133:  *
                    134:  * For debugging:
                    135:  *     Dir_PrintDirectories    Print stats about the directory cache.
                    136:  */
                    137:
                    138: #include <sys/types.h>
1.34      wiz       139: #include <sys/stat.h>
                    140:
1.5       cgd       141: #include <dirent.h>
1.34      wiz       142: #include <errno.h>
                    143: #include <stdio.h>
                    144:
1.1       cgd       145: #include "make.h"
1.5       cgd       146: #include "dir.h"
1.67      christos  147: #include "job.h"
1.1       cgd       148:
1.92      rillig    149:
                    150: #define DIR_DEBUG0(fmt) \
                    151:     if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt)
                    152:
                    153: #define DIR_DEBUG1(fmt, arg1) \
                    154:     if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1)
                    155:
                    156: #define DIR_DEBUG2(fmt, arg1, arg2) \
                    157:     if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1, arg2)
                    158:
                    159:
1.1       cgd       160: /*
                    161:  *     A search path consists of a Lst of Path structures. A Path structure
                    162:  *     has in it the name of the directory and a hash table of all the files
                    163:  *     in the directory. This is used to cut down on the number of system
                    164:  *     calls necessary to find implicit dependents and their like. Since
                    165:  *     these searches are made before any actions are taken, we need not
                    166:  *     worry about the directory changing due to creation commands. If this
                    167:  *     hampers the style of some makefiles, they must be changed.
                    168:  *
                    169:  *     A list of all previously-read directories is kept in the
                    170:  *     openDirectories Lst. This list is checked first before a directory
                    171:  *     is opened.
                    172:  *
                    173:  *     The need for the caching of whole directories is brought about by
                    174:  *     the multi-level transformation code in suff.c, which tends to search
                    175:  *     for far more files than regular make does. In the initial
                    176:  *     implementation, the amount of time spent performing "stat" calls was
                    177:  *     truly astronomical. The problem with hashing at the start is,
                    178:  *     of course, that pmake doesn't then detect changes to these directories
                    179:  *     during the course of the make. Three possibilities suggest themselves:
                    180:  *
                    181:  *         1) just use stat to test for a file's existence. As mentioned
                    182:  *            above, this is very inefficient due to the number of checks
                    183:  *            engendered by the multi-level transformation code.
                    184:  *         2) use readdir() and company to search the directories, keeping
                    185:  *            them open between checks. I have tried this and while it
                    186:  *            didn't slow down the process too much, it could severely
                    187:  *            affect the amount of parallelism available as each directory
                    188:  *            open would take another file descriptor out of play for
                    189:  *            handling I/O for another job. Given that it is only recently
                    190:  *            that UNIX OS's have taken to allowing more than 20 or 32
                    191:  *            file descriptors for a process, this doesn't seem acceptable
                    192:  *            to me.
                    193:  *         3) record the mtime of the directory in the Path structure and
                    194:  *            verify the directory hasn't changed since the contents were
                    195:  *            hashed. This will catch the creation or deletion of files,
                    196:  *            but not the updating of files. However, since it is the
                    197:  *            creation and deletion that is the problem, this could be
                    198:  *            a good thing to do. Unfortunately, if the directory (say ".")
                    199:  *            were fairly large and changed fairly frequently, the constant
                    200:  *            rehashing could seriously degrade performance. It might be
                    201:  *            good in such cases to keep track of the number of rehashes
                    202:  *            and if the number goes over a (small) limit, resort to using
                    203:  *            stat in its place.
                    204:  *
                    205:  *     An additional thing to consider is that pmake is used primarily
                    206:  *     to create C programs and until recently pcc-based compilers refused
                    207:  *     to allow you to specify where the resulting object file should be
                    208:  *     placed. This forced all objects to be created in the current
                    209:  *     directory. This isn't meant as a full excuse, just an explanation of
                    210:  *     some of the reasons for the caching used here.
                    211:  *
                    212:  *     One more note: the location of a target's file is only performed
                    213:  *     on the downward traversal of the graph and then only for terminal
                    214:  *     nodes in the graph. This could be construed as wrong in some cases,
                    215:  *     but prevents inadvertent modification of files when the "installed"
                    216:  *     directory for a file is provided in the search path.
                    217:  *
                    218:  *     Another data structure maintained by this module is an mtime
                    219:  *     cache used when the searching of cached directories fails to find
                    220:  *     a file. In the past, Dir_FindFile would simply perform an access()
                    221:  *     call in such a case to determine if the file could be found using
                    222:  *     just the name given. When this hit, however, all that was gained
                    223:  *     was the knowledge that the file existed. Given that an access() is
                    224:  *     essentially a stat() without the copyout() call, and that the same
                    225:  *     filesystem overhead would have to be incurred in Dir_MTime, it made
                    226:  *     sense to replace the access() with a stat() and record the mtime
                    227:  *     in a cache for when Dir_MTime was actually called.
                    228:  */
                    229:
1.85      rillig    230: Lst dirSearchPath;             /* main search path */
1.1       cgd       231:
1.85      rillig    232: static Lst openDirectories;    /* the list of all open directories */
1.1       cgd       233:
                    234: /*
                    235:  * Variables for gathering statistics on the efficiency of the hashing
                    236:  * mechanism.
                    237:  */
1.85      rillig    238: static int hits;               /* Found in directory cache */
                    239: static int misses;             /* Sad, but not evil misses */
                    240: static int nearmisses;         /* Found under search path */
                    241: static int bigmisses;          /* Sought by itself */
                    242:
                    243: static Path *dot;              /* contents of current directory */
                    244: static Path *cur;              /* contents of current directory, if not dot */
                    245: static Path *dotLast;          /* a fake path entry indicating we need to
                    246:                                 * look for . last */
                    247:
                    248: /* Results of doing a last-resort stat in Dir_FindFile -- if we have to go to
                    249:  * the system to find the file, we might as well have its mtime on record.
                    250:  *
                    251:  * XXX: If this is done way early, there's a chance other rules will have
                    252:  * already updated the file, in which case we'll update it again. Generally,
                    253:  * there won't be two rules to update a single file, so this should be ok,
                    254:  * but... */
                    255: static Hash_Table mtimes;
1.1       cgd       256:
1.85      rillig    257: static Hash_Table lmtimes;     /* same as mtimes but for lstat */
1.1       cgd       258:
1.36      christos  259: static void DirExpandCurly(const char *, const char *, Lst, Lst);
                    260: static void DirExpandInt(const char *, Lst, Lst);
1.59      dsl       261: static int DirPrintWord(void *, void *);
                    262: static int DirPrintDir(void *, void *);
1.36      christos  263: static char *DirLookup(Path *, const char *, const char *, Boolean);
                    264: static char *DirLookupSubdir(Path *, const char *);
                    265: static char *DirFindDot(Boolean, const char *, const char *);
                    266: static char *DirLookupAbs(Path *, const char *, const char *);
1.5       cgd       267:
1.68      sjg       268:
                    269: /*
1.89      rillig    270:  * We use stat(2) a lot, cache the results.
1.68      sjg       271:  * mtime and mode are all we care about.
                    272:  */
                    273: struct cache_st {
1.85      rillig    274:     time_t lmtime;             /* lstat */
                    275:     time_t mtime;              /* stat */
                    276:     mode_t mode;
1.68      sjg       277: };
                    278:
                    279: /* minimize changes below */
1.89      rillig    280: typedef enum {
                    281:     CST_LSTAT = 0x01,          /* call lstat(2) instead of stat(2) */
                    282:     CST_UPDATE = 0x02          /* ignore existing cached entry */
                    283: } CachedStatsFlags;
1.68      sjg       284:
1.89      rillig    285: /* Returns 0 and the result of stat(2) or lstat(2) in *st, or -1 on error.
                    286:  * Only st->st_mode and st->st_mtime are filled. */
1.68      sjg       287: static int
1.89      rillig    288: cached_stats(Hash_Table *htp, const char *pathname, struct stat *st,
                    289:             CachedStatsFlags flags)
1.68      sjg       290: {
                    291:     Hash_Entry *entry;
                    292:     struct cache_st *cst;
                    293:     int rc;
                    294:
                    295:     if (!pathname || !pathname[0])
                    296:        return -1;
                    297:
                    298:     entry = Hash_FindEntry(htp, pathname);
                    299:
1.89      rillig    300:     if (entry && !(flags & CST_UPDATE)) {
1.68      sjg       301:        cst = entry->clientPtr;
                    302:
                    303:        memset(st, 0, sizeof(*st));
                    304:        st->st_mode = cst->mode;
1.74      sjg       305:        st->st_mtime = (flags & CST_LSTAT) ? cst->lmtime : cst->mtime;
                    306:        if (st->st_mtime) {
1.92      rillig    307:            DIR_DEBUG2("Using cached time %s for %s\n",
                    308:                       Targ_FmtTime(st->st_mtime), pathname);
1.74      sjg       309:            return 0;
1.73      christos  310:        }
1.68      sjg       311:     }
                    312:
                    313:     rc = (flags & CST_LSTAT) ? lstat(pathname, st) : stat(pathname, st);
                    314:     if (rc == -1)
                    315:        return -1;
                    316:
                    317:     if (st->st_mtime == 0)
1.85      rillig    318:        st->st_mtime = 1;       /* avoid confusion with missing file */
1.68      sjg       319:
                    320:     if (!entry)
                    321:        entry = Hash_CreateEntry(htp, pathname, NULL);
1.74      sjg       322:     if (!entry->clientPtr) {
1.68      sjg       323:        entry->clientPtr = bmake_malloc(sizeof(*cst));
1.74      sjg       324:        memset(entry->clientPtr, 0, sizeof(*cst));
                    325:     }
1.68      sjg       326:     cst = entry->clientPtr;
1.89      rillig    327:     if (flags & CST_LSTAT) {
1.74      sjg       328:        cst->lmtime = st->st_mtime;
                    329:     } else {
                    330:        cst->mtime = st->st_mtime;
                    331:     }
1.68      sjg       332:     cst->mode = st->st_mode;
1.92      rillig    333:     DIR_DEBUG2("   Caching %s for %s\n",
                    334:               Targ_FmtTime(st->st_mtime), pathname);
1.68      sjg       335:
                    336:     return 0;
                    337: }
                    338:
                    339: int
                    340: cached_stat(const char *pathname, void *st)
                    341: {
                    342:     return cached_stats(&mtimes, pathname, st, 0);
                    343: }
                    344:
                    345: int
                    346: cached_lstat(const char *pathname, void *st)
                    347: {
                    348:     return cached_stats(&lmtimes, pathname, st, CST_LSTAT);
                    349: }
                    350:
1.101     rillig    351: /* Initialize things for this module. */
1.1       cgd       352: void
1.97      rillig    353: Dir_Init(void)
                    354: {
                    355:     dirSearchPath = Lst_Init();
                    356:     openDirectories = Lst_Init();
                    357:     Hash_InitTable(&mtimes, 0);
                    358:     Hash_InitTable(&lmtimes, 0);
                    359: }
                    360:
                    361: void
                    362: Dir_InitDir(const char *cdname)
1.1       cgd       363: {
1.35      sjg       364:     Dir_InitCur(cdname);
                    365:
1.56      joerg     366:     dotLast = bmake_malloc(sizeof(Path));
1.35      sjg       367:     dotLast->refCount = 1;
                    368:     dotLast->hits = 0;
1.56      joerg     369:     dotLast->name = bmake_strdup(".DOTLAST");
1.45      christos  370:     Hash_InitTable(&dotLast->files, -1);
1.35      sjg       371: }
                    372:
                    373: /*
1.97      rillig    374:  * Called by Dir_InitDir and whenever .CURDIR is assigned to.
1.35      sjg       375:  */
                    376: void
1.45      christos  377: Dir_InitCur(const char *cdname)
1.35      sjg       378: {
                    379:     Path *p;
1.76      rillig    380:
1.17      gwr       381:     if (cdname != NULL) {
                    382:        /*
                    383:         * Our build directory is not the same as our source directory.
                    384:         * Keep this one around too.
                    385:         */
1.55      christos  386:        if ((p = Dir_AddDir(NULL, cdname))) {
1.35      sjg       387:            p->refCount += 1;
                    388:            if (cur && cur != p) {
                    389:                /*
                    390:                 * We've been here before, cleanup.
                    391:                 */
                    392:                cur->refCount -= 1;
1.51      dsl       393:                Dir_Destroy(cur);
1.35      sjg       394:            }
                    395:            cur = p;
                    396:        }
1.17      gwr       397:     }
1.28      tv        398: }
                    399:
                    400: /*-
                    401:  *-----------------------------------------------------------------------
                    402:  * Dir_InitDot --
                    403:  *     (re)initialize "dot" (current/object directory) path hash
                    404:  *
                    405:  * Results:
                    406:  *     none
                    407:  *
                    408:  * Side Effects:
                    409:  *     some directories may be opened.
                    410:  *-----------------------------------------------------------------------
                    411:  */
                    412: void
1.34      wiz       413: Dir_InitDot(void)
1.28      tv        414: {
                    415:     if (dot != NULL) {
                    416:        LstNode ln;
                    417:
                    418:        /* Remove old entry from openDirectories, but do not destroy. */
1.119     rillig    419:        ln = Lst_Member(openDirectories, dot);
                    420:        Lst_Remove(openDirectories, ln);
1.28      tv        421:     }
                    422:
1.45      christos  423:     dot = Dir_AddDir(NULL, ".");
1.28      tv        424:
                    425:     if (dot == NULL) {
                    426:        Error("Cannot open `.' (%s)", strerror(errno));
                    427:        exit(1);
                    428:     }
                    429:
                    430:     /*
                    431:      * We always need to have dot around, so we increment its reference count
                    432:      * to make sure it's not destroyed.
                    433:      */
                    434:     dot->refCount += 1;
1.85      rillig    435:     Dir_SetPATH();             /* initialize */
1.1       cgd       436: }
                    437:
                    438: /*-
                    439:  *-----------------------------------------------------------------------
1.6       jtc       440:  * Dir_End --
                    441:  *     cleanup things for this module
                    442:  *
                    443:  * Results:
                    444:  *     none
                    445:  *
                    446:  * Side Effects:
                    447:  *     none
                    448:  *-----------------------------------------------------------------------
                    449:  */
                    450: void
1.34      wiz       451: Dir_End(void)
1.6       jtc       452: {
1.24      mycroft   453: #ifdef CLEANUP
1.17      gwr       454:     if (cur) {
                    455:        cur->refCount -= 1;
1.51      dsl       456:        Dir_Destroy(cur);
1.17      gwr       457:     }
1.6       jtc       458:     dot->refCount -= 1;
1.21      thorpej   459:     dotLast->refCount -= 1;
1.51      dsl       460:     Dir_Destroy(dotLast);
                    461:     Dir_Destroy(dot);
1.6       jtc       462:     Dir_ClearPath(dirSearchPath);
1.119     rillig    463:     Lst_Free(dirSearchPath);
1.6       jtc       464:     Dir_ClearPath(openDirectories);
1.119     rillig    465:     Lst_Free(openDirectories);
1.6       jtc       466:     Hash_DeleteTable(&mtimes);
1.24      mycroft   467: #endif
1.6       jtc       468: }
                    469:
1.35      sjg       470: /*
                    471:  * We want ${.PATH} to indicate the order in which we will actually
                    472:  * search, so we rebuild it after any .PATH: target.
                    473:  * This is the simplest way to deal with the effect of .DOTLAST.
                    474:  */
                    475: void
1.45      christos  476: Dir_SetPATH(void)
1.35      sjg       477: {
1.85      rillig    478:     LstNode ln;                        /* a list element */
1.35      sjg       479:     Path *p;
1.107     rillig    480:     Boolean hasLastDot = FALSE;        /* true if we should search dot last */
1.35      sjg       481:
                    482:     Var_Delete(".PATH", VAR_GLOBAL);
1.76      rillig    483:
1.119     rillig    484:     Lst_Open(dirSearchPath);
                    485:     if ((ln = Lst_First(dirSearchPath)) != NULL) {
                    486:        p = Lst_Datum(ln);
1.107     rillig    487:        if (p == dotLast) {
                    488:            hasLastDot = TRUE;
                    489:            Var_Append(".PATH", dotLast->name, VAR_GLOBAL);
1.35      sjg       490:        }
1.107     rillig    491:     }
1.35      sjg       492:
1.107     rillig    493:     if (!hasLastDot) {
                    494:        if (dot)
                    495:            Var_Append(".PATH", dot->name, VAR_GLOBAL);
                    496:        if (cur)
                    497:            Var_Append(".PATH", cur->name, VAR_GLOBAL);
                    498:     }
1.35      sjg       499:
1.119     rillig    500:     while ((ln = Lst_Next(dirSearchPath)) != NULL) {
                    501:        p = Lst_Datum(ln);
1.107     rillig    502:        if (p == dotLast)
                    503:            continue;
                    504:        if (p == dot && hasLastDot)
                    505:            continue;
                    506:        Var_Append(".PATH", p->name, VAR_GLOBAL);
                    507:     }
1.35      sjg       508:
1.107     rillig    509:     if (hasLastDot) {
                    510:        if (dot)
                    511:            Var_Append(".PATH", dot->name, VAR_GLOBAL);
                    512:        if (cur)
                    513:            Var_Append(".PATH", cur->name, VAR_GLOBAL);
1.35      sjg       514:     }
1.119     rillig    515:     Lst_Close(dirSearchPath);
1.35      sjg       516: }
                    517:
1.121   ! rillig    518: /* See if the Path structure describes the same directory as the
        !           519:  * given one by comparing their names. Called from Dir_AddDir via
        !           520:  * Lst_FindB when searching the list of open directories. */
        !           521: static Boolean
        !           522: DirFindName(const void *p, const void *desiredName)
1.1       cgd       523: {
1.121   ! rillig    524:     return strcmp(((const Path *)p)->name, desiredName) == 0;
1.1       cgd       525: }
                    526:
                    527: /*-
                    528:  *-----------------------------------------------------------------------
                    529:  * Dir_HasWildcards  --
                    530:  *     see if the given name has any wildcard characters in it
1.13      christos  531:  *     be careful not to expand unmatching brackets or braces.
1.76      rillig    532:  *     XXX: This code is not 100% correct. ([^]] fails etc.)
1.13      christos  533:  *     I really don't think that make(1) should be expanding
                    534:  *     patterns, because then you have to set a mechanism for
1.14      christos  535:  *     escaping the expansion!
1.1       cgd       536:  *
1.34      wiz       537:  * Input:
                    538:  *     name            name to check
                    539:  *
1.1       cgd       540:  * Results:
                    541:  *     returns TRUE if the word should be expanded, FALSE otherwise
                    542:  *
                    543:  * Side Effects:
                    544:  *     none
                    545:  *-----------------------------------------------------------------------
                    546:  */
                    547: Boolean
1.34      wiz       548: Dir_HasWildcards(char *name)
1.1       cgd       549: {
1.34      wiz       550:     char *cp;
1.13      christos  551:     int wild = 0, brace = 0, bracket = 0;
1.12      christos  552:
1.1       cgd       553:     for (cp = name; *cp; cp++) {
1.85      rillig    554:        switch (*cp) {
1.1       cgd       555:        case '{':
1.85      rillig    556:            brace++;
                    557:            wild = 1;
                    558:            break;
1.13      christos  559:        case '}':
1.85      rillig    560:            brace--;
                    561:            break;
1.1       cgd       562:        case '[':
1.85      rillig    563:            bracket++;
                    564:            wild = 1;
                    565:            break;
1.13      christos  566:        case ']':
1.85      rillig    567:            bracket--;
                    568:            break;
1.1       cgd       569:        case '?':
                    570:        case '*':
1.85      rillig    571:            wild = 1;
                    572:            break;
1.13      christos  573:        default:
1.85      rillig    574:            break;
1.1       cgd       575:        }
                    576:     }
1.13      christos  577:     return wild && bracket == 0 && brace == 0;
1.1       cgd       578: }
                    579:
                    580: /*-
                    581:  *-----------------------------------------------------------------------
                    582:  * DirMatchFiles --
                    583:  *     Given a pattern and a Path structure, see if any files
                    584:  *     match the pattern and add their names to the 'expansions' list if
                    585:  *     any do. This is incomplete -- it doesn't take care of patterns like
1.5       cgd       586:  *     src / *src / *.c properly (just *.c on any of the directories), but it
1.1       cgd       587:  *     will do for now.
                    588:  *
1.34      wiz       589:  * Input:
                    590:  *     pattern         Pattern to look for
                    591:  *     p               Directory to search
                    592:  *     expansion       Place to store the results
                    593:  *
1.1       cgd       594:  * Side Effects:
                    595:  *     File names are added to the expansions lst. The directory will be
                    596:  *     fully hashed when this is done.
                    597:  *-----------------------------------------------------------------------
                    598:  */
1.98      rillig    599: static void
1.36      christos  600: DirMatchFiles(const char *pattern, Path *p, Lst expansions)
1.1       cgd       601: {
1.85      rillig    602:     Hash_Search search;                /* Index into the directory's table */
                    603:     Hash_Entry *entry;         /* Current entry in the table */
                    604:     Boolean isDot;             /* TRUE if the directory being searched is . */
1.12      christos  605:
1.1       cgd       606:     isDot = (*p->name == '.' && p->name[1] == '\0');
1.12      christos  607:
1.1       cgd       608:     for (entry = Hash_EnumFirst(&p->files, &search);
1.48      christos  609:         entry != NULL;
1.1       cgd       610:         entry = Hash_EnumNext(&search))
                    611:     {
                    612:        /*
                    613:         * See if the file matches the given pattern. Note we follow the UNIX
                    614:         * convention that dot files will only be found if the pattern
                    615:         * begins with a dot (note also that as a side effect of the hashing
                    616:         * scheme, .* won't match . or .. since they aren't hashed).
                    617:         */
                    618:        if (Str_Match(entry->name, pattern) &&
                    619:            ((entry->name[0] != '.') ||
                    620:             (pattern[0] == '.')))
                    621:        {
1.119     rillig    622:            Lst_Append(expansions,
1.100     rillig    623:                        (isDot ? bmake_strdup(entry->name) :
                    624:                         str_concat3(p->name, "/", entry->name)));
1.1       cgd       625:        }
                    626:     }
                    627: }
                    628:
1.91      rillig    629: /* Find the next closing brace in the string, taking nested braces into
                    630:  * account. */
1.80      rillig    631: static const char *
                    632: closing_brace(const char *p)
                    633: {
                    634:     int nest = 0;
1.91      rillig    635:     while (*p != '\0') {
1.106     rillig    636:        if (*p == '}' && nest == 0)
1.91      rillig    637:            break;
1.80      rillig    638:        if (*p == '{')
                    639:            nest++;
                    640:        if (*p == '}')
                    641:            nest--;
                    642:        p++;
                    643:     }
                    644:     return p;
                    645: }
                    646:
1.91      rillig    647: /* Find the next closing brace or comma in the string, taking nested braces
                    648:  * into account. */
1.80      rillig    649: static const char *
                    650: separator_comma(const char *p)
                    651: {
                    652:     int nest = 0;
1.91      rillig    653:     while (*p != '\0') {
1.106     rillig    654:        if ((*p == '}' || *p == ',') && nest == 0)
1.91      rillig    655:            break;
1.80      rillig    656:        if (*p == '{')
                    657:            nest++;
                    658:        if (*p == '}')
                    659:            nest--;
                    660:        p++;
                    661:     }
                    662:     return p;
                    663: }
                    664:
                    665: static Boolean
                    666: contains_wildcard(const char *p)
                    667: {
                    668:     for (; *p != '\0'; p++) {
1.85      rillig    669:        switch (*p) {
1.80      rillig    670:        case '*':
                    671:        case '?':
                    672:        case '{':
                    673:        case '[':
                    674:            return TRUE;
                    675:        }
                    676:     }
                    677:     return FALSE;
                    678: }
                    679:
                    680: static char *
                    681: concat3(const char *a, size_t a_len, const char *b, size_t b_len,
                    682:        const char *c, size_t c_len)
                    683: {
                    684:     size_t s_len = a_len + b_len + c_len;
                    685:     char *s = bmake_malloc(s_len + 1);
                    686:     memcpy(s, a, a_len);
                    687:     memcpy(s + a_len, b, b_len);
                    688:     memcpy(s + a_len + b_len, c, c_len);
                    689:     s[s_len] = '\0';
                    690:     return s;
                    691: }
                    692:
1.1       cgd       693: /*-
                    694:  *-----------------------------------------------------------------------
                    695:  * DirExpandCurly --
                    696:  *     Expand curly braces like the C shell. Does this recursively.
                    697:  *     Note the special case: if after the piece of the curly brace is
                    698:  *     done there are no wildcard characters in the result, the result is
                    699:  *     placed on the list WITHOUT CHECKING FOR ITS EXISTENCE.
                    700:  *
1.34      wiz       701:  * Input:
                    702:  *     word            Entire word to expand
                    703:  *     brace           First curly brace in it
                    704:  *     path            Search path to use
                    705:  *     expansions      Place to store the expansions
                    706:  *
1.1       cgd       707:  * Results:
                    708:  *     None.
                    709:  *
                    710:  * Side Effects:
                    711:  *     The given list is filled with the expansions...
                    712:  *
                    713:  *-----------------------------------------------------------------------
                    714:  */
                    715: static void
1.36      christos  716: DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions)
1.1       cgd       717: {
1.90      rillig    718:     const char *prefix, *middle, *piece, *middle_end, *suffix;
                    719:     size_t prefix_len, suffix_len;
                    720:
1.80      rillig    721:     /* Split the word into prefix '{' middle '}' suffix. */
1.1       cgd       722:
1.90      rillig    723:     middle = brace + 1;
                    724:     middle_end = closing_brace(middle);
1.80      rillig    725:     if (*middle_end == '\0') {
                    726:        Error("Unterminated {} clause \"%s\"", middle);
1.1       cgd       727:        return;
                    728:     }
1.78      rillig    729:
1.84      rillig    730:     prefix = word;
                    731:     prefix_len = (size_t)(brace - prefix);
                    732:     suffix = middle_end + 1;
                    733:     suffix_len = strlen(suffix);
1.80      rillig    734:
                    735:     /* Split the middle into pieces, separated by commas. */
                    736:
1.84      rillig    737:     piece = middle;
1.81      rillig    738:     while (piece < middle_end + 1) {
1.80      rillig    739:        const char *piece_end = separator_comma(piece);
                    740:        size_t piece_len = (size_t)(piece_end - piece);
1.1       cgd       741:
1.80      rillig    742:        char *file = concat3(prefix, prefix_len, piece, piece_len,
                    743:                             suffix, suffix_len);
                    744:
                    745:        if (contains_wildcard(file)) {
                    746:            Dir_Expand(file, path, expansions);
                    747:            free(file);
                    748:        } else {
1.119     rillig    749:            Lst_Append(expansions, file);
1.1       cgd       750:        }
1.80      rillig    751:
                    752:        piece = piece_end + 1;  /* skip over the comma or closing brace */
1.1       cgd       753:     }
                    754: }
                    755:
                    756:
                    757: /*-
                    758:  *-----------------------------------------------------------------------
                    759:  * DirExpandInt --
                    760:  *     Internal expand routine. Passes through the directories in the
                    761:  *     path one by one, calling DirMatchFiles for each. NOTE: This still
                    762:  *     doesn't handle patterns in directories...
                    763:  *
1.34      wiz       764:  * Input:
                    765:  *     word            Word to expand
                    766:  *     path            Path on which to look
                    767:  *     expansions      Place to store the result
                    768:  *
1.1       cgd       769:  * Results:
                    770:  *     None.
                    771:  *
                    772:  * Side Effects:
                    773:  *     Things are added to the expansions list.
                    774:  *
                    775:  *-----------------------------------------------------------------------
                    776:  */
                    777: static void
1.36      christos  778: DirExpandInt(const char *word, Lst path, Lst expansions)
1.1       cgd       779: {
1.85      rillig    780:     LstNode ln;                        /* Current node */
1.1       cgd       781:
1.119     rillig    782:     Lst_Open(path);
                    783:     while ((ln = Lst_Next(path)) != NULL) {
                    784:        Path *p = Lst_Datum(ln);
1.112     rillig    785:        DirMatchFiles(word, p, expansions);
1.1       cgd       786:     }
1.119     rillig    787:     Lst_Close(path);
1.1       cgd       788: }
                    789:
1.92      rillig    790: /* Print a word in the list of expansions.
                    791:  * Callback for Dir_Expand when DEBUG(DIR), via Lst_ForEach. */
1.1       cgd       792: static int
1.70      riastrad  793: DirPrintWord(void *word, void *dummy MAKE_ATTR_UNUSED)
1.1       cgd       794: {
1.50      dsl       795:     fprintf(debug_file, "%s ", (char *)word);
1.1       cgd       796:
1.70      riastrad  797:     return 0;
1.1       cgd       798: }
                    799:
                    800: /*-
                    801:  *-----------------------------------------------------------------------
                    802:  * Dir_Expand  --
                    803:  *     Expand the given word into a list of words by globbing it looking
                    804:  *     in the directories on the given search path.
                    805:  *
1.34      wiz       806:  * Input:
                    807:  *     word            the word to expand
                    808:  *     path            the list of directories in which to find the
                    809:  *                     resulting files
                    810:  *     expansions      the list on which to place the results
                    811:  *
1.1       cgd       812:  * Results:
                    813:  *     A list of words consisting of the files which exist along the search
                    814:  *     path matching the given pattern.
                    815:  *
                    816:  * Side Effects:
                    817:  *     Directories may be opened. Who knows?
1.82      rillig    818:  *     Undefined behavior if the word is really in read-only memory.
1.1       cgd       819:  *-----------------------------------------------------------------------
                    820:  */
                    821: void
1.36      christos  822: Dir_Expand(const char *word, Lst path, Lst expansions)
1.1       cgd       823: {
1.85      rillig    824:     const char *cp;
1.1       cgd       825:
1.112     rillig    826:     assert(path != NULL);
                    827:     assert(expansions != NULL);
                    828:
1.92      rillig    829:     DIR_DEBUG1("Expanding \"%s\"... ", word);
1.12      christos  830:
1.5       cgd       831:     cp = strchr(word, '{');
1.1       cgd       832:     if (cp) {
                    833:        DirExpandCurly(word, cp, path, expansions);
                    834:     } else {
1.5       cgd       835:        cp = strchr(word, '/');
1.1       cgd       836:        if (cp) {
                    837:            /*
                    838:             * The thing has a directory component -- find the first wildcard
                    839:             * in the string.
                    840:             */
                    841:            for (cp = word; *cp; cp++) {
                    842:                if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') {
                    843:                    break;
                    844:                }
                    845:            }
                    846:            if (*cp == '{') {
                    847:                /*
                    848:                 * This one will be fun.
                    849:                 */
                    850:                DirExpandCurly(word, cp, path, expansions);
                    851:                return;
                    852:            } else if (*cp != '\0') {
                    853:                /*
                    854:                 * Back up to the start of the component
                    855:                 */
                    856:                while (cp > word && *cp != '/') {
                    857:                    cp--;
                    858:                }
                    859:                if (cp != word) {
1.5       cgd       860:                    char sc;
1.92      rillig    861:                    char *dirpath;
1.1       cgd       862:                    /*
                    863:                     * If the glob isn't in the first component, try and find
                    864:                     * all the components up to the one with a wildcard.
                    865:                     */
1.5       cgd       866:                    sc = cp[1];
1.36      christos  867:                    ((char *)UNCONST(cp))[1] = '\0';
1.1       cgd       868:                    dirpath = Dir_FindFile(word, path);
1.36      christos  869:                    ((char *)UNCONST(cp))[1] = sc;
1.1       cgd       870:                    /*
                    871:                     * dirpath is null if can't find the leading component
                    872:                     * XXX: Dir_FindFile won't find internal components.
                    873:                     * i.e. if the path contains ../Etc/Object and we're
                    874:                     * looking for Etc, it won't be found. Ah well.
                    875:                     * Probably not important.
                    876:                     */
1.48      christos  877:                    if (dirpath != NULL) {
1.5       cgd       878:                        char *dp = &dirpath[strlen(dirpath) - 1];
                    879:                        if (*dp == '/')
                    880:                            *dp = '\0';
1.93      rillig    881:                        path = Lst_Init();
1.46      christos  882:                        (void)Dir_AddDir(path, dirpath);
1.85      rillig    883:                        DirExpandInt(cp + 1, path, expansions);
1.119     rillig    884:                        Lst_Free(path);
1.1       cgd       885:                    }
                    886:                } else {
                    887:                    /*
                    888:                     * Start the search from the local directory
                    889:                     */
                    890:                    DirExpandInt(word, path, expansions);
                    891:                }
                    892:            } else {
                    893:                /*
                    894:                 * Return the file -- this should never happen.
                    895:                 */
                    896:                DirExpandInt(word, path, expansions);
                    897:            }
                    898:        } else {
                    899:            /*
                    900:             * First the files in dot
                    901:             */
                    902:            DirMatchFiles(word, dot, expansions);
1.12      christos  903:
1.1       cgd       904:            /*
                    905:             * Then the files in every other directory on the path.
                    906:             */
                    907:            DirExpandInt(word, path, expansions);
                    908:        }
                    909:     }
                    910:     if (DEBUG(DIR)) {
1.119     rillig    911:        Lst_ForEach(expansions, DirPrintWord, NULL);
1.50      dsl       912:        fprintf(debug_file, "\n");
1.1       cgd       913:     }
                    914: }
                    915:
                    916: /*-
                    917:  *-----------------------------------------------------------------------
1.18      christos  918:  * DirLookup  --
                    919:  *     Find if the file with the given name exists in the given path.
                    920:  *
                    921:  * Results:
1.32      pk        922:  *     The path to the file or NULL. This path is guaranteed to be in a
1.18      christos  923:  *     different part of memory than name and so may be safely free'd.
                    924:  *
                    925:  * Side Effects:
                    926:  *     None.
                    927:  *-----------------------------------------------------------------------
                    928:  */
                    929: static char *
1.76      rillig    930: DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp,
1.83      rillig    931:          Boolean hasSlash MAKE_ATTR_UNUSED)
1.18      christos  932: {
1.85      rillig    933:     char *file;                        /* the current filename to check */
1.18      christos  934:
1.92      rillig    935:     DIR_DEBUG1("   %s ...\n", p->name);
1.32      pk        936:
1.48      christos  937:     if (Hash_FindEntry(&p->files, cp) == NULL)
1.32      pk        938:        return NULL;
                    939:
1.87      rillig    940:     file = str_concat3(p->name, "/", cp);
1.92      rillig    941:     DIR_DEBUG1("   returning %s\n", file);
1.32      pk        942:     p->hits += 1;
                    943:     hits += 1;
                    944:     return file;
1.18      christos  945: }
                    946:
                    947:
                    948: /*-
                    949:  *-----------------------------------------------------------------------
                    950:  * DirLookupSubdir  --
                    951:  *     Find if the file with the given name exists in the given path.
                    952:  *
                    953:  * Results:
                    954:  *     The path to the file or NULL. This path is guaranteed to be in a
                    955:  *     different part of memory than name and so may be safely free'd.
                    956:  *
                    957:  * Side Effects:
                    958:  *     If the file is found, it is added in the modification times hash
                    959:  *     table.
                    960:  *-----------------------------------------------------------------------
                    961:  */
                    962: static char *
1.36      christos  963: DirLookupSubdir(Path *p, const char *name)
1.18      christos  964: {
1.85      rillig    965:     struct stat stb;           /* Buffer for stat, if necessary */
                    966:     char *file;                        /* the current filename to check */
1.18      christos  967:
                    968:     if (p != dot) {
1.87      rillig    969:        file = str_concat3(p->name, "/", name);
1.18      christos  970:     } else {
                    971:        /*
                    972:         * Checking in dot -- DON'T put a leading ./ on the thing.
                    973:         */
1.56      joerg     974:        file = bmake_strdup(name);
1.18      christos  975:     }
                    976:
1.92      rillig    977:     DIR_DEBUG1("checking %s ...\n", file);
1.18      christos  978:
1.68      sjg       979:     if (cached_stat(file, &stb) == 0) {
1.18      christos  980:        nearmisses += 1;
1.75      rillig    981:        return file;
1.18      christos  982:     }
1.46      christos  983:     free(file);
1.18      christos  984:     return NULL;
                    985: }
                    986:
                    987: /*-
                    988:  *-----------------------------------------------------------------------
1.32      pk        989:  * DirLookupAbs  --
                    990:  *     Find if the file with the given name exists in the given path.
                    991:  *
                    992:  * Results:
                    993:  *     The path to the file, the empty string or NULL. If the file is
                    994:  *     the empty string, the search should be terminated.
                    995:  *     This path is guaranteed to be in a different part of memory
                    996:  *     than name and so may be safely free'd.
                    997:  *
                    998:  * Side Effects:
                    999:  *     None.
                   1000:  *-----------------------------------------------------------------------
                   1001:  */
                   1002: static char *
1.36      christos 1003: DirLookupAbs(Path *p, const char *name, const char *cp)
1.32      pk       1004: {
1.85      rillig   1005:     char *p1;                  /* pointer into p->name */
                   1006:     const char *p2;            /* pointer into name */
1.32      pk       1007:
1.92      rillig   1008:     DIR_DEBUG1("   %s ...\n", p->name);
1.32      pk       1009:
1.85      rillig   1010:     /*
                   1011:      * If the file has a leading path component and that component
                   1012:      * exactly matches the entire name of the current search
                   1013:      * directory, we can attempt another cache lookup. And if we don't
                   1014:      * have a hit, we can safely assume the file does not exist at all.
                   1015:      */
                   1016:     for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
                   1017:        continue;
                   1018:     }
                   1019:     if (*p1 != '\0' || p2 != cp - 1) {
                   1020:        return NULL;
                   1021:     }
1.32      pk       1022:
1.85      rillig   1023:     if (Hash_FindEntry(&p->files, cp) == NULL) {
1.92      rillig   1024:        DIR_DEBUG0("   must be here but isn't -- returning\n");
1.85      rillig   1025:        /* Return empty string: terminates search */
                   1026:        return bmake_strdup("");
                   1027:     }
1.32      pk       1028:
1.85      rillig   1029:     p->hits += 1;
                   1030:     hits += 1;
1.92      rillig   1031:     DIR_DEBUG1("   returning %s\n", name);
1.85      rillig   1032:     return bmake_strdup(name);
1.32      pk       1033: }
                   1034:
                   1035: /*-
                   1036:  *-----------------------------------------------------------------------
1.21      thorpej  1037:  * DirFindDot  --
                   1038:  *     Find the file given on "." or curdir
                   1039:  *
                   1040:  * Results:
                   1041:  *     The path to the file or NULL. This path is guaranteed to be in a
                   1042:  *     different part of memory than name and so may be safely free'd.
                   1043:  *
                   1044:  * Side Effects:
                   1045:  *     Hit counts change
                   1046:  *-----------------------------------------------------------------------
                   1047:  */
                   1048: static char *
1.65      joerg    1049: DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp)
1.21      thorpej  1050: {
                   1051:
1.85      rillig   1052:     if (Hash_FindEntry(&dot->files, cp) != NULL) {
1.92      rillig   1053:        DIR_DEBUG0("   in '.'\n");
1.85      rillig   1054:        hits += 1;
                   1055:        dot->hits += 1;
                   1056:        return bmake_strdup(name);
                   1057:     }
                   1058:     if (cur && Hash_FindEntry(&cur->files, cp) != NULL) {
1.92      rillig   1059:        DIR_DEBUG1("   in ${.CURDIR} = %s\n", cur->name);
1.85      rillig   1060:        hits += 1;
                   1061:        cur->hits += 1;
1.87      rillig   1062:        return str_concat3(cur->name, "/", cp);
1.85      rillig   1063:     }
1.21      thorpej  1064:
1.85      rillig   1065:     return NULL;
1.21      thorpej  1066: }
                   1067:
                   1068: /*-
                   1069:  *-----------------------------------------------------------------------
1.1       cgd      1070:  * Dir_FindFile  --
                   1071:  *     Find the file with the given name along the given search path.
                   1072:  *
1.34      wiz      1073:  * Input:
                   1074:  *     name            the file to find
                   1075:  *     path            the Lst of directories to search
                   1076:  *
1.1       cgd      1077:  * Results:
                   1078:  *     The path to the file or NULL. This path is guaranteed to be in a
                   1079:  *     different part of memory than name and so may be safely free'd.
                   1080:  *
                   1081:  * Side Effects:
                   1082:  *     If the file is found in a directory which is not on the path
                   1083:  *     already (either 'name' is absolute or it is a relative path
                   1084:  *     [ dir1/.../dirn/file ] which exists below one of the directories
                   1085:  *     already on the search path), its directory is added to the end
                   1086:  *     of the path on the assumption that there will be more files in
                   1087:  *     that directory later on. Sometimes this is true. Sometimes not.
                   1088:  *-----------------------------------------------------------------------
                   1089:  */
                   1090: char *
1.36      christos 1091: Dir_FindFile(const char *name, Lst path)
1.1       cgd      1092: {
1.85      rillig   1093:     LstNode ln;                        /* a list element */
                   1094:     char *file;                        /* the current filename to check */
                   1095:     Path *p;                   /* current path member */
                   1096:     const char *cp;            /* Terminal name of file */
                   1097:     Boolean hasLastDot = FALSE;        /* true we should search dot last */
                   1098:     Boolean hasSlash;          /* true if 'name' contains a / */
                   1099:     struct stat stb;           /* Buffer for stat, if necessary */
                   1100:     const char *trailing_dot = ".";
1.12      christos 1101:
1.1       cgd      1102:     /*
                   1103:      * Find the final component of the name and note whether it has a
                   1104:      * slash in it (the name, I mean)
                   1105:      */
1.46      christos 1106:     cp = strrchr(name, '/');
1.1       cgd      1107:     if (cp) {
                   1108:        hasSlash = TRUE;
                   1109:        cp += 1;
                   1110:     } else {
                   1111:        hasSlash = FALSE;
                   1112:        cp = name;
                   1113:     }
1.12      christos 1114:
1.92      rillig   1115:     DIR_DEBUG1("Searching for %s ...", name);
1.12      christos 1116:
1.112     rillig   1117:     if (path == NULL) {
1.92      rillig   1118:        DIR_DEBUG0("couldn't open path, file not found\n");
1.1       cgd      1119:        misses += 1;
1.57      dsl      1120:        return NULL;
1.1       cgd      1121:     }
1.12      christos 1122:
1.119     rillig   1123:     Lst_Open(path);
                   1124:     if ((ln = Lst_First(path)) != NULL) {
                   1125:        p = Lst_Datum(ln);
1.31      reinoud  1126:        if (p == dotLast) {
                   1127:            hasLastDot = TRUE;
1.92      rillig   1128:            DIR_DEBUG0("[dot last]...");
1.21      thorpej  1129:        }
1.18      christos 1130:     }
1.92      rillig   1131:     DIR_DEBUG0("\n");
1.18      christos 1132:
1.1       cgd      1133:     /*
1.32      pk       1134:      * If there's no leading directory components or if the leading
                   1135:      * directory component is exactly `./', consult the cached contents
                   1136:      * of each of the directories on the search path.
1.21      thorpej  1137:      */
1.52      dsl      1138:     if (!hasSlash || (cp - name == 2 && *name == '.')) {
1.85      rillig   1139:        /*
                   1140:         * We look through all the directories on the path seeking one which
                   1141:         * contains the final component of the given name.  If such a beast
                   1142:         * is found, we concatenate the directory name and the final
                   1143:         * component and return the resulting string. If we don't find any
                   1144:         * such thing, we go on to phase two...
                   1145:         *
                   1146:         * No matter what, we always look for the file in the current
                   1147:         * directory before anywhere else (unless we found the magic
                   1148:         * DOTLAST path, in which case we search it last) and we *do not*
                   1149:         * add the ./ to it if it exists.
                   1150:         * This is so there are no conflicts between what the user
                   1151:         * specifies (fish.c) and what pmake finds (./fish.c).
                   1152:         */
                   1153:        if (!hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) {
1.119     rillig   1154:            Lst_Close(path);
1.85      rillig   1155:            return file;
                   1156:        }
1.32      pk       1157:
1.119     rillig   1158:        while ((ln = Lst_Next(path)) != NULL) {
                   1159:            p = Lst_Datum(ln);
1.85      rillig   1160:            if (p == dotLast)
                   1161:                continue;
                   1162:            if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) {
1.119     rillig   1163:                Lst_Close(path);
1.85      rillig   1164:                return file;
1.32      pk       1165:            }
1.85      rillig   1166:        }
1.21      thorpej  1167:
1.85      rillig   1168:        if (hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) {
1.119     rillig   1169:            Lst_Close(path);
1.85      rillig   1170:            return file;
                   1171:        }
1.1       cgd      1172:     }
1.119     rillig   1173:     Lst_Close(path);
1.12      christos 1174:
1.1       cgd      1175:     /*
1.32      pk       1176:      * We didn't find the file on any directory in the search path.
1.1       cgd      1177:      * If the name doesn't contain a slash, that means it doesn't exist.
                   1178:      * If it *does* contain a slash, however, there is still hope: it
                   1179:      * could be in a subdirectory of one of the members of the search
                   1180:      * path. (eg. /usr/include and sys/types.h. The above search would
                   1181:      * fail to turn up types.h in /usr/include, but it *is* in
1.32      pk       1182:      * /usr/include/sys/types.h).
                   1183:      * [ This no longer applies: If we find such a beast, we assume there
1.1       cgd      1184:      * will be more (what else can we assume?) and add all but the last
                   1185:      * component of the resulting name onto the search path (at the
1.32      pk       1186:      * end).]
                   1187:      * This phase is only performed if the file is *not* absolute.
1.1       cgd      1188:      */
                   1189:     if (!hasSlash) {
1.92      rillig   1190:        DIR_DEBUG0("   failed.\n");
1.1       cgd      1191:        misses += 1;
1.57      dsl      1192:        return NULL;
1.1       cgd      1193:     }
1.12      christos 1194:
1.63      sjg      1195:     if (*cp == '\0') {
                   1196:        /* we were given a trailing "/" */
                   1197:        cp = trailing_dot;
                   1198:     }
                   1199:
1.32      pk       1200:     if (name[0] != '/') {
1.85      rillig   1201:        Boolean checkedDot = FALSE;
1.12      christos 1202:
1.92      rillig   1203:        DIR_DEBUG0("   Trying subdirectories...\n");
1.18      christos 1204:
1.35      sjg      1205:        if (!hasLastDot) {
1.85      rillig   1206:            if (dot) {
                   1207:                checkedDot = TRUE;
                   1208:                if ((file = DirLookupSubdir(dot, name)) != NULL)
                   1209:                    return file;
                   1210:            }
                   1211:            if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
                   1212:                return file;
1.35      sjg      1213:        }
1.18      christos 1214:
1.119     rillig   1215:        Lst_Open(path);
                   1216:        while ((ln = Lst_Next(path)) != NULL) {
                   1217:            p = Lst_Datum(ln);
1.21      thorpej  1218:            if (p == dotLast)
                   1219:                continue;
1.35      sjg      1220:            if (p == dot) {
1.85      rillig   1221:                if (checkedDot)
                   1222:                    continue;
1.1       cgd      1223:                checkedDot = TRUE;
1.35      sjg      1224:            }
1.18      christos 1225:            if ((file = DirLookupSubdir(p, name)) != NULL) {
1.119     rillig   1226:                Lst_Close(path);
1.18      christos 1227:                return file;
1.1       cgd      1228:            }
                   1229:        }
1.119     rillig   1230:        Lst_Close(path);
1.12      christos 1231:
1.35      sjg      1232:        if (hasLastDot) {
1.85      rillig   1233:            if (dot && !checkedDot) {
                   1234:                checkedDot = TRUE;
                   1235:                if ((file = DirLookupSubdir(dot, name)) != NULL)
                   1236:                    return file;
                   1237:            }
                   1238:            if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
                   1239:                return file;
1.35      sjg      1240:        }
1.21      thorpej  1241:
1.1       cgd      1242:        if (checkedDot) {
                   1243:            /*
                   1244:             * Already checked by the given name, since . was in the path,
                   1245:             * so no point in proceeding...
                   1246:             */
1.92      rillig   1247:            DIR_DEBUG0("   Checked . already, returning NULL\n");
1.57      dsl      1248:            return NULL;
1.32      pk       1249:        }
                   1250:
                   1251:     } else { /* name[0] == '/' */
                   1252:
                   1253:        /*
                   1254:         * For absolute names, compare directory path prefix against the
                   1255:         * the directory path of each member on the search path for an exact
                   1256:         * match. If we have an exact match on any member of the search path,
                   1257:         * use the cached contents of that member to lookup the final file
                   1258:         * component. If that lookup fails we can safely assume that the
                   1259:         * file does not exist at all.  This is signified by DirLookupAbs()
                   1260:         * returning an empty string.
                   1261:         */
1.92      rillig   1262:        DIR_DEBUG0("   Trying exact path matches...\n");
1.32      pk       1263:
1.85      rillig   1264:        if (!hasLastDot && cur &&
                   1265:            ((file = DirLookupAbs(cur, name, cp)) != NULL)) {
1.71      riastrad 1266:            if (file[0] == '\0') {
                   1267:                free(file);
                   1268:                return NULL;
                   1269:            }
                   1270:            return file;
                   1271:        }
1.32      pk       1272:
1.119     rillig   1273:        Lst_Open(path);
                   1274:        while ((ln = Lst_Next(path)) != NULL) {
                   1275:            p = Lst_Datum(ln);
1.32      pk       1276:            if (p == dotLast)
                   1277:                continue;
                   1278:            if ((file = DirLookupAbs(p, name, cp)) != NULL) {
1.119     rillig   1279:                Lst_Close(path);
1.71      riastrad 1280:                if (file[0] == '\0') {
                   1281:                    free(file);
                   1282:                    return NULL;
                   1283:                }
                   1284:                return file;
1.32      pk       1285:            }
                   1286:        }
1.119     rillig   1287:        Lst_Close(path);
1.32      pk       1288:
1.85      rillig   1289:        if (hasLastDot && cur &&
                   1290:            ((file = DirLookupAbs(cur, name, cp)) != NULL)) {
1.71      riastrad 1291:            if (file[0] == '\0') {
                   1292:                free(file);
                   1293:                return NULL;
                   1294:            }
                   1295:            return file;
                   1296:        }
1.1       cgd      1297:     }
1.12      christos 1298:
1.1       cgd      1299:     /*
                   1300:      * Didn't find it that way, either. Sigh. Phase 3. Add its directory
                   1301:      * onto the search path in any case, just in case, then look for the
                   1302:      * thing in the hash table. If we find it, grand. We return a new
                   1303:      * copy of the name. Otherwise we sadly return a NULL pointer. Sigh.
                   1304:      * Note that if the directory holding the file doesn't exist, this will
                   1305:      * do an extra search of the final directory on the path. Unless something
                   1306:      * weird happens, this search won't succeed and life will be groovy.
                   1307:      *
                   1308:      * Sigh. We cannot add the directory onto the search path because
                   1309:      * of this amusing case:
                   1310:      * $(INSTALLDIR)/$(FILE): $(FILE)
                   1311:      *
                   1312:      * $(FILE) exists in $(INSTALLDIR) but not in the current one.
                   1313:      * When searching for $(FILE), we will find it in $(INSTALLDIR)
                   1314:      * b/c we added it here. This is not good...
                   1315:      */
                   1316: #ifdef notdef
1.63      sjg      1317:     if (cp == traling_dot) {
                   1318:        cp = strrchr(name, '/');
                   1319:        cp += 1;
                   1320:     }
1.1       cgd      1321:     cp[-1] = '\0';
1.46      christos 1322:     (void)Dir_AddDir(path, name);
1.1       cgd      1323:     cp[-1] = '/';
1.12      christos 1324:
1.1       cgd      1325:     bigmisses += 1;
1.119     rillig   1326:     ln = Lst_Last(path);
1.57      dsl      1327:     if (ln == NULL) {
                   1328:        return NULL;
1.1       cgd      1329:     } else {
1.119     rillig   1330:        p = Lst_Datum(ln);
1.1       cgd      1331:     }
1.12      christos 1332:
1.48      christos 1333:     if (Hash_FindEntry(&p->files, cp) != NULL) {
1.75      rillig   1334:        return bmake_strdup(name);
1.1       cgd      1335:     } else {
1.57      dsl      1336:        return NULL;
1.1       cgd      1337:     }
                   1338: #else /* !notdef */
1.92      rillig   1339:     DIR_DEBUG1("   Looking for \"%s\" ...\n", name);
1.12      christos 1340:
1.1       cgd      1341:     bigmisses += 1;
1.72      reinoud  1342:     if (cached_stat(name, &stb) == 0) {
1.75      rillig   1343:        return bmake_strdup(name);
1.1       cgd      1344:     }
1.73      christos 1345:
1.92      rillig   1346:     DIR_DEBUG0("   failed. Returning NULL\n");
1.73      christos 1347:     return NULL;
1.1       cgd      1348: #endif /* notdef */
                   1349: }
                   1350:
1.40      chuck    1351:
                   1352: /*-
                   1353:  *-----------------------------------------------------------------------
                   1354:  * Dir_FindHereOrAbove  --
1.76      rillig   1355:  *     search for a path starting at a given directory and then working
1.40      chuck    1356:  *     our way up towards the root.
                   1357:  *
                   1358:  * Input:
                   1359:  *     here            starting directory
                   1360:  *     search_path     the path we are looking for
                   1361:  *     result          the result of a successful search is placed here
1.76      rillig   1362:  *     rlen            the length of the result buffer
1.40      chuck    1363:  *                     (typically MAXPATHLEN + 1)
                   1364:  *
                   1365:  * Results:
                   1366:  *     0 on failure, 1 on success [in which case the found path is put
                   1367:  *     in the result buffer].
                   1368:  *
                   1369:  * Side Effects:
                   1370:  *-----------------------------------------------------------------------
                   1371:  */
1.76      rillig   1372: int
1.85      rillig   1373: Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen)
                   1374: {
                   1375:     struct stat st;
                   1376:     char dirbase[MAXPATHLEN + 1], *db_end;
                   1377:     char try[MAXPATHLEN + 1], *try_end;
                   1378:
                   1379:     /* copy out our starting point */
                   1380:     snprintf(dirbase, sizeof(dirbase), "%s", here);
                   1381:     db_end = dirbase + strlen(dirbase);
                   1382:
                   1383:     /* loop until we determine a result */
                   1384:     while (1) {
                   1385:
                   1386:        /* try and stat(2) it ... */
                   1387:        snprintf(try, sizeof(try), "%s/%s", dirbase, search_path);
                   1388:        if (cached_stat(try, &st) != -1) {
                   1389:            /*
                   1390:             * success!  if we found a file, chop off
                   1391:             * the filename so we return a directory.
                   1392:             */
                   1393:            if ((st.st_mode & S_IFMT) != S_IFDIR) {
                   1394:                try_end = try + strlen(try);
                   1395:                while (try_end > try && *try_end != '/')
                   1396:                    try_end--;
                   1397:                if (try_end > try)
                   1398:                    *try_end = 0;       /* chop! */
                   1399:            }
1.40      chuck    1400:
1.85      rillig   1401:            /*
                   1402:             * done!
                   1403:             */
                   1404:            snprintf(result, rlen, "%s", try);
                   1405:            return 1;
                   1406:        }
1.40      chuck    1407:
1.85      rillig   1408:        /*
                   1409:         * nope, we didn't find it.  if we used up dirbase we've
                   1410:         * reached the root and failed.
                   1411:         */
                   1412:        if (db_end == dirbase)
                   1413:            break;              /* failed! */
1.40      chuck    1414:
1.85      rillig   1415:        /*
                   1416:         * truncate dirbase from the end to move up a dir
                   1417:         */
                   1418:        while (db_end > dirbase && *db_end != '/')
                   1419:            db_end--;
                   1420:        *db_end = 0;            /* chop! */
1.40      chuck    1421:
1.85      rillig   1422:     } /* while (1) */
1.40      chuck    1423:
1.85      rillig   1424:     /*
                   1425:      * we failed...
                   1426:      */
                   1427:     return 0;
1.40      chuck    1428: }
                   1429:
1.1       cgd      1430: /*-
                   1431:  *-----------------------------------------------------------------------
                   1432:  * Dir_MTime  --
                   1433:  *     Find the modification time of the file described by gn along the
                   1434:  *     search path dirSearchPath.
1.12      christos 1435:  *
1.34      wiz      1436:  * Input:
                   1437:  *     gn              the file whose modification time is desired
                   1438:  *
1.1       cgd      1439:  * Results:
                   1440:  *     The modification time or 0 if it doesn't exist
                   1441:  *
                   1442:  * Side Effects:
                   1443:  *     The modification time is placed in the node's mtime slot.
                   1444:  *     If the node didn't have a path entry before, and Dir_FindFile
                   1445:  *     found one for it, the full name is placed in the path slot.
                   1446:  *-----------------------------------------------------------------------
                   1447:  */
                   1448: int
1.64      christos 1449: Dir_MTime(GNode *gn, Boolean recheck)
1.1       cgd      1450: {
1.85      rillig   1451:     char *fullName;            /* the full pathname of name */
                   1452:     struct stat stb;           /* buffer for finding the mod time */
1.12      christos 1453:
1.1       cgd      1454:     if (gn->type & OP_ARCHV) {
1.45      christos 1455:        return Arch_MTime(gn);
1.33      pk       1456:     } else if (gn->type & OP_PHONY) {
                   1457:        gn->mtime = 0;
                   1458:        return 0;
1.48      christos 1459:     } else if (gn->path == NULL) {
1.33      pk       1460:        if (gn->type & OP_NOPATH)
1.16      mycroft  1461:            fullName = NULL;
1.53      dsl      1462:        else {
1.45      christos 1463:            fullName = Dir_FindFile(gn->name, Suff_FindPath(gn));
1.62      sjg      1464:            if (fullName == NULL && gn->flags & FROM_DEPEND &&
1.119     rillig   1465:                !Lst_IsEmpty(gn->iParents)) {
1.62      sjg      1466:                char *cp;
                   1467:
                   1468:                cp = strrchr(gn->name, '/');
                   1469:                if (cp) {
                   1470:                    /*
                   1471:                     * This is an implied source, and it may have moved,
                   1472:                     * see if we can find it via the current .PATH
                   1473:                     */
                   1474:                    cp++;
1.76      rillig   1475:
1.62      sjg      1476:                    fullName = Dir_FindFile(cp, Suff_FindPath(gn));
                   1477:                    if (fullName) {
                   1478:                        /*
                   1479:                         * Put the found file in gn->path
                   1480:                         * so that we give that to the compiler.
                   1481:                         */
                   1482:                        gn->path = bmake_strdup(fullName);
1.67      christos 1483:                        if (!Job_RunTarget(".STALE", gn->fname))
                   1484:                            fprintf(stdout,
1.85      rillig   1485:                                    "%s: %s, %d: ignoring stale %s for %s, "
                   1486:                                    "found %s\n", progname, gn->fname,
                   1487:                                    gn->lineno,
                   1488:                                    makeDependfile, gn->name, fullName);
1.62      sjg      1489:                    }
                   1490:                }
                   1491:            }
1.92      rillig   1492:            DIR_DEBUG2("Found '%s' as '%s'\n",
                   1493:                       gn->name, fullName ? fullName : "(not found)");
1.53      dsl      1494:        }
1.1       cgd      1495:     } else {
                   1496:        fullName = gn->path;
                   1497:     }
1.12      christos 1498:
1.48      christos 1499:     if (fullName == NULL) {
1.56      joerg    1500:        fullName = bmake_strdup(gn->name);
1.1       cgd      1501:     }
                   1502:
1.72      reinoud  1503:     if (cached_stats(&mtimes, fullName, &stb, recheck ? CST_UPDATE : 0) < 0) {
1.1       cgd      1504:        if (gn->type & OP_MEMBER) {
1.6       jtc      1505:            if (fullName != gn->path)
                   1506:                free(fullName);
1.45      christos 1507:            return Arch_MemMTime(gn);
1.1       cgd      1508:        } else {
                   1509:            stb.st_mtime = 0;
                   1510:        }
                   1511:     }
1.68      sjg      1512:
1.48      christos 1513:     if (fullName && gn->path == NULL) {
1.1       cgd      1514:        gn->path = fullName;
                   1515:     }
1.12      christos 1516:
1.1       cgd      1517:     gn->mtime = stb.st_mtime;
1.75      rillig   1518:     return gn->mtime;
1.1       cgd      1519: }
                   1520:
                   1521: /*-
                   1522:  *-----------------------------------------------------------------------
                   1523:  * Dir_AddDir --
                   1524:  *     Add the given name to the end of the given path. The order of
                   1525:  *     the arguments is backwards so ParseDoDependency can do a
                   1526:  *     Lst_ForEach of its list of paths...
                   1527:  *
1.34      wiz      1528:  * Input:
                   1529:  *     path            the path to which the directory should be
                   1530:  *                     added
1.118     rillig   1531:  *                     XXX: Why would this ever be NULL, and what does
                   1532:  *                     that mean?
1.34      wiz      1533:  *     name            the name of the directory to add
                   1534:  *
1.1       cgd      1535:  * Results:
                   1536:  *     none
                   1537:  *
                   1538:  * Side Effects:
1.12      christos 1539:  *     A structure is added to the list and the directory is
1.1       cgd      1540:  *     read and hashed.
                   1541:  *-----------------------------------------------------------------------
                   1542:  */
1.17      gwr      1543: Path *
1.34      wiz      1544: Dir_AddDir(Lst path, const char *name)
1.1       cgd      1545: {
1.85      rillig   1546:     LstNode ln = NULL;         /* node in case Path structure is found */
                   1547:     Path *p = NULL;            /* pointer to new Path structure */
                   1548:     DIR *d;                    /* for reading directory */
                   1549:     struct dirent *dp;         /* entry in directory */
1.21      thorpej  1550:
1.120     rillig   1551:     if (path != NULL && strcmp(name, ".DOTLAST") == 0) {
1.121   ! rillig   1552:        ln = Lst_FindB(path, DirFindName, name);
1.57      dsl      1553:        if (ln != NULL)
1.119     rillig   1554:            return Lst_Datum(ln);
1.120     rillig   1555:
                   1556:        dotLast->refCount++;
                   1557:        Lst_Prepend(path, dotLast);
1.21      thorpej  1558:     }
1.12      christos 1559:
1.120     rillig   1560:     if (path != NULL)
1.121   ! rillig   1561:        ln = Lst_FindB(openDirectories, DirFindName, name);
1.57      dsl      1562:     if (ln != NULL) {
1.119     rillig   1563:        p = Lst_Datum(ln);
1.120     rillig   1564:        if (Lst_Member(path, p) == NULL) {
1.1       cgd      1565:            p->refCount += 1;
1.119     rillig   1566:            Lst_Append(path, p);
1.1       cgd      1567:        }
1.120     rillig   1568:        return p;
                   1569:     }
                   1570:
                   1571:     DIR_DEBUG1("Caching %s ...", name);
1.12      christos 1572:
1.120     rillig   1573:     if ((d = opendir(name)) != NULL) {
                   1574:        p = bmake_malloc(sizeof(Path));
                   1575:        p->name = bmake_strdup(name);
                   1576:        p->hits = 0;
                   1577:        p->refCount = 1;
                   1578:        Hash_InitTable(&p->files, -1);
1.12      christos 1579:
1.120     rillig   1580:        while ((dp = readdir(d)) != NULL) {
1.10      christos 1581: #if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */
1.120     rillig   1582:            /*
                   1583:             * The sun directory library doesn't check for a 0 inode
                   1584:             * (0-inode slots just take up space), so we have to do
                   1585:             * it ourselves.
                   1586:             */
                   1587:            if (dp->d_fileno == 0) {
                   1588:                continue;
                   1589:            }
1.10      christos 1590: #endif /* sun && d_ino */
1.120     rillig   1591:            (void)Hash_CreateEntry(&p->files, dp->d_name, NULL);
1.1       cgd      1592:        }
1.120     rillig   1593:        (void)closedir(d);
                   1594:        Lst_Append(openDirectories, p);
                   1595:        if (path != NULL)
                   1596:            Lst_Append(path, p);
1.1       cgd      1597:     }
1.120     rillig   1598:     DIR_DEBUG0("done\n");
1.17      gwr      1599:     return p;
1.1       cgd      1600: }
                   1601:
                   1602: /*-
                   1603:  *-----------------------------------------------------------------------
                   1604:  * Dir_CopyDir --
1.119     rillig   1605:  *     Callback function for duplicating a search path via Lst_Copy.
1.1       cgd      1606:  *     Ups the reference count for the directory.
                   1607:  *
                   1608:  * Results:
                   1609:  *     Returns the Path it was given.
                   1610:  *-----------------------------------------------------------------------
                   1611:  */
1.59      dsl      1612: void *
                   1613: Dir_CopyDir(void *p)
1.1       cgd      1614: {
1.48      christos 1615:     ((Path *)p)->refCount += 1;
1.1       cgd      1616:
1.75      rillig   1617:     return p;
1.1       cgd      1618: }
                   1619:
                   1620: /*-
                   1621:  *-----------------------------------------------------------------------
                   1622:  * Dir_MakeFlags --
                   1623:  *     Make a string by taking all the directories in the given search
                   1624:  *     path and preceding them by the given flag. Used by the suffix
                   1625:  *     module to create variables for compilers based on suffix search
                   1626:  *     paths.
                   1627:  *
1.34      wiz      1628:  * Input:
                   1629:  *     flag            flag which should precede each directory
                   1630:  *     path            list of directories
                   1631:  *
1.1       cgd      1632:  * Results:
                   1633:  *     The string mentioned above. Note that there is no space between
                   1634:  *     the given flag and each directory. The empty string is returned if
                   1635:  *     Things don't go well.
                   1636:  *
                   1637:  * Side Effects:
                   1638:  *     None
                   1639:  *-----------------------------------------------------------------------
                   1640:  */
                   1641: char *
1.36      christos 1642: Dir_MakeFlags(const char *flag, Lst path)
1.1       cgd      1643: {
1.88      rillig   1644:     Buffer buf;
1.85      rillig   1645:     LstNode ln;                        /* the node of the current directory */
1.12      christos 1646:
1.88      rillig   1647:     Buf_Init(&buf, 0);
1.12      christos 1648:
1.112     rillig   1649:     if (path != NULL) {
1.119     rillig   1650:        Lst_Open(path);
                   1651:        while ((ln = Lst_Next(path)) != NULL) {
                   1652:            Path *p = Lst_Datum(ln);
1.88      rillig   1653:            Buf_AddStr(&buf, " ");
                   1654:            Buf_AddStr(&buf, flag);
                   1655:            Buf_AddStr(&buf, p->name);
1.1       cgd      1656:        }
1.119     rillig   1657:        Lst_Close(path);
1.1       cgd      1658:     }
1.12      christos 1659:
1.88      rillig   1660:     return Buf_Destroy(&buf, FALSE);
1.1       cgd      1661: }
                   1662:
                   1663: /*-
                   1664:  *-----------------------------------------------------------------------
                   1665:  * Dir_Destroy --
                   1666:  *     Nuke a directory descriptor, if possible. Callback procedure
                   1667:  *     for the suffixes module when destroying a search path.
                   1668:  *
1.34      wiz      1669:  * Input:
                   1670:  *     pp              The directory descriptor to nuke
                   1671:  *
1.1       cgd      1672:  * Results:
                   1673:  *     None.
                   1674:  *
                   1675:  * Side Effects:
                   1676:  *     If no other path references this directory (refCount == 0),
                   1677:  *     the Path and all its data are freed.
                   1678:  *
                   1679:  *-----------------------------------------------------------------------
                   1680:  */
                   1681: void
1.59      dsl      1682: Dir_Destroy(void *pp)
1.1       cgd      1683: {
1.85      rillig   1684:     Path *p = (Path *)pp;
1.1       cgd      1685:     p->refCount -= 1;
                   1686:
                   1687:     if (p->refCount == 0) {
1.85      rillig   1688:        LstNode ln;
1.1       cgd      1689:
1.119     rillig   1690:        ln = Lst_Member(openDirectories, p);
                   1691:        Lst_Remove(openDirectories, ln);
1.1       cgd      1692:
1.45      christos 1693:        Hash_DeleteTable(&p->files);
1.47      christos 1694:        free(p->name);
                   1695:        free(p);
1.1       cgd      1696:     }
                   1697: }
                   1698:
                   1699: /*-
                   1700:  *-----------------------------------------------------------------------
                   1701:  * Dir_ClearPath --
                   1702:  *     Clear out all elements of the given search path. This is different
                   1703:  *     from destroying the list, notice.
                   1704:  *
1.34      wiz      1705:  * Input:
                   1706:  *     path            Path to clear
                   1707:  *
1.1       cgd      1708:  * Results:
                   1709:  *     None.
                   1710:  *
                   1711:  * Side Effects:
                   1712:  *     The path is set to the empty list.
                   1713:  *
                   1714:  *-----------------------------------------------------------------------
                   1715:  */
                   1716: void
1.34      wiz      1717: Dir_ClearPath(Lst path)
1.1       cgd      1718: {
1.119     rillig   1719:     while (!Lst_IsEmpty(path)) {
                   1720:        Path *p = Lst_Dequeue(path);
1.51      dsl      1721:        Dir_Destroy(p);
1.1       cgd      1722:     }
                   1723: }
1.12      christos 1724:
1.1       cgd      1725:
                   1726: /*-
                   1727:  *-----------------------------------------------------------------------
                   1728:  * Dir_Concat --
                   1729:  *     Concatenate two paths, adding the second to the end of the first.
                   1730:  *     Makes sure to avoid duplicates.
                   1731:  *
1.34      wiz      1732:  * Input:
                   1733:  *     path1           Dest
                   1734:  *     path2           Source
                   1735:  *
1.1       cgd      1736:  * Results:
                   1737:  *     None
                   1738:  *
                   1739:  * Side Effects:
                   1740:  *     Reference counts for added dirs are upped.
                   1741:  *
                   1742:  *-----------------------------------------------------------------------
                   1743:  */
                   1744: void
1.34      wiz      1745: Dir_Concat(Lst path1, Lst path2)
1.1       cgd      1746: {
                   1747:     LstNode ln;
1.85      rillig   1748:     Path *p;
1.1       cgd      1749:
1.119     rillig   1750:     for (ln = Lst_First(path2); ln != NULL; ln = Lst_Succ(ln)) {
                   1751:        p = Lst_Datum(ln);
                   1752:        if (Lst_Member(path1, p) == NULL) {
1.1       cgd      1753:            p->refCount += 1;
1.119     rillig   1754:            Lst_Append(path1, p);
1.1       cgd      1755:        }
                   1756:     }
                   1757: }
                   1758:
1.105     rillig   1759: static int
                   1760: percentage(int num, int den)
                   1761: {
                   1762:     return den != 0 ? num * 100 / den : 0;
                   1763: }
                   1764:
1.1       cgd      1765: /********** DEBUG INFO **********/
1.5       cgd      1766: void
1.34      wiz      1767: Dir_PrintDirectories(void)
1.1       cgd      1768: {
1.85      rillig   1769:     LstNode ln;
1.12      christos 1770:
1.50      dsl      1771:     fprintf(debug_file, "#*** Directory Cache:\n");
1.85      rillig   1772:     fprintf(debug_file,
                   1773:            "# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n",
                   1774:            hits, misses, nearmisses, bigmisses,
1.105     rillig   1775:            percentage(hits, hits + bigmisses + nearmisses));
1.50      dsl      1776:     fprintf(debug_file, "# %-20s referenced\thits\n", "directory");
1.112     rillig   1777:
1.119     rillig   1778:     Lst_Open(openDirectories);
                   1779:     while ((ln = Lst_Next(openDirectories)) != NULL) {
                   1780:        Path *p = Lst_Datum(ln);
1.112     rillig   1781:        fprintf(debug_file, "# %-20s %10d\t%4d\n", p->name, p->refCount,
                   1782:                p->hits);
1.1       cgd      1783:     }
1.119     rillig   1784:     Lst_Close(openDirectories);
1.1       cgd      1785: }
                   1786:
1.34      wiz      1787: static int
1.70      riastrad 1788: DirPrintDir(void *p, void *dummy MAKE_ATTR_UNUSED)
1.12      christos 1789: {
1.50      dsl      1790:     fprintf(debug_file, "%s ", ((Path *)p)->name);
1.70      riastrad 1791:     return 0;
1.6       jtc      1792: }
1.1       cgd      1793:
1.5       cgd      1794: void
1.34      wiz      1795: Dir_PrintPath(Lst path)
1.1       cgd      1796: {
1.119     rillig   1797:     Lst_ForEach(path, DirPrintDir, NULL);
1.1       cgd      1798: }

CVSweb <webmaster@jp.NetBSD.org>