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