Fix bug #2515: the .SECONDARY target with no prerequisites wasn't
[make/kirr.git] / dir.c
blob1de62e5c2929d2f88f660ad8c67997efdd5d2850
1 /* Directory hashing for GNU Make.
2 Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
3 2002 Free Software Foundation, Inc.
4 This file is part of GNU Make.
6 GNU Make is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Make is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Make; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #include "make.h"
22 #include "hash.h"
24 #ifdef HAVE_DIRENT_H
25 # include <dirent.h>
26 # define NAMLEN(dirent) strlen((dirent)->d_name)
27 # ifdef VMS
28 extern char *vmsify PARAMS ((char *name, int type));
29 # endif
30 #else
31 # define dirent direct
32 # define NAMLEN(dirent) (dirent)->d_namlen
33 # ifdef HAVE_SYS_NDIR_H
34 # include <sys/ndir.h>
35 # endif
36 # ifdef HAVE_SYS_DIR_H
37 # include <sys/dir.h>
38 # endif
39 # ifdef HAVE_NDIR_H
40 # include <ndir.h>
41 # endif
42 # ifdef HAVE_VMSDIR_H
43 # include "vmsdir.h"
44 # endif /* HAVE_VMSDIR_H */
45 #endif
47 /* In GNU systems, <dirent.h> defines this macro for us. */
48 #ifdef _D_NAMLEN
49 # undef NAMLEN
50 # define NAMLEN(d) _D_NAMLEN(d)
51 #endif
53 #if (defined (POSIX) || defined (VMS) || defined (WINDOWS32)) && !defined (__GNU_LIBRARY__)
54 /* Posix does not require that the d_ino field be present, and some
55 systems do not provide it. */
56 # define REAL_DIR_ENTRY(dp) 1
57 # define FAKE_DIR_ENTRY(dp)
58 #else
59 # define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
60 # define FAKE_DIR_ENTRY(dp) (dp->d_ino = 1)
61 #endif /* POSIX */
63 #ifdef __MSDOS__
64 #include <ctype.h>
65 #include <fcntl.h>
67 /* If it's MSDOS that doesn't have _USE_LFN, disable LFN support. */
68 #ifndef _USE_LFN
69 #define _USE_LFN 0
70 #endif
72 static char *
73 dosify (char *filename)
75 static char dos_filename[14];
76 char *df;
77 int i;
79 if (filename == 0 || _USE_LFN)
80 return filename;
82 /* FIXME: what about filenames which violate
83 8+3 constraints, like "config.h.in", or ".emacs"? */
84 if (strpbrk (filename, "\"*+,;<=>?[\\]|") != 0)
85 return filename;
87 df = dos_filename;
89 /* First, transform the name part. */
90 for (i = 0; *filename != '\0' && i < 8 && *filename != '.'; ++i)
91 *df++ = tolower ((unsigned char)*filename++);
93 /* Now skip to the next dot. */
94 while (*filename != '\0' && *filename != '.')
95 ++filename;
96 if (*filename != '\0')
98 *df++ = *filename++;
99 for (i = 0; *filename != '\0' && i < 3 && *filename != '.'; ++i)
100 *df++ = tolower ((unsigned char)*filename++);
103 /* Look for more dots. */
104 while (*filename != '\0' && *filename != '.')
105 ++filename;
106 if (*filename == '.')
107 return filename;
108 *df = 0;
109 return dos_filename;
111 #endif /* __MSDOS__ */
113 #ifdef WINDOWS32
114 #include "pathstuff.h"
115 #endif
117 #ifdef _AMIGA
118 #include <ctype.h>
119 #endif
121 #ifdef HAVE_CASE_INSENSITIVE_FS
122 static char *
123 downcase (char *filename)
125 #ifdef _AMIGA
126 static char new_filename[136];
127 #else
128 static char new_filename[PATH_MAX];
129 #endif
130 char *df;
131 int i;
133 if (filename == 0)
134 return 0;
136 df = new_filename;
138 /* First, transform the name part. */
139 for (i = 0; *filename != '\0'; ++i)
141 *df++ = tolower ((unsigned char)*filename);
142 ++filename;
145 *df = 0;
147 return new_filename;
149 #endif /* HAVE_CASE_INSENSITIVE_FS */
151 #ifdef VMS
153 static int
154 vms_hash (char *name)
156 int h = 0;
157 int g;
159 while (*name)
161 unsigned char uc = *name;
162 h = (h << 4) + (isupper (uc) ? tolower (uc) : uc);
163 name++;
164 g = h & 0xf0000000;
165 if (g)
167 h = h ^ (g >> 24);
168 h = h ^ g;
171 return h;
174 /* fake stat entry for a directory */
175 static int
176 vmsstat_dir (char *name, struct stat *st)
178 char *s;
179 int h;
180 DIR *dir;
182 dir = opendir (name);
183 if (dir == 0)
184 return -1;
185 closedir (dir);
186 s = strchr (name, ':'); /* find device */
187 if (s)
189 *s++ = 0;
190 st->st_dev = (char *)vms_hash (name);
191 h = vms_hash (s);
192 *(s-1) = ':';
194 else
196 st->st_dev = 0;
197 s = name;
198 h = vms_hash (s);
201 st->st_ino[0] = h & 0xff;
202 st->st_ino[1] = h & 0xff00;
203 st->st_ino[2] = h >> 16;
205 return 0;
207 #endif /* VMS */
209 /* Hash table of directories. */
211 #ifndef DIRECTORY_BUCKETS
212 #define DIRECTORY_BUCKETS 199
213 #endif
215 struct directory_contents
217 dev_t dev; /* Device and inode numbers of this dir. */
218 #ifdef WINDOWS32
220 * Inode means nothing on WINDOWS32. Even file key information is
221 * unreliable because it is random per file open and undefined
222 * for remote filesystems. The most unique attribute I can
223 * come up with is the fully qualified name of the directory. Beware
224 * though, this is also unreliable. I'm open to suggestion on a better
225 * way to emulate inode.
227 char *path_key;
228 int ctime;
229 int mtime; /* controls check for stale directory cache */
230 int fs_flags; /* FS_FAT, FS_NTFS, ... */
231 #define FS_FAT 0x1
232 #define FS_NTFS 0x2
233 #define FS_UNKNOWN 0x4
234 #else
235 #ifdef VMS
236 ino_t ino[3];
237 #else
238 ino_t ino;
239 #endif
240 #endif /* WINDOWS32 */
241 struct hash_table dirfiles; /* Files in this directory. */
242 DIR *dirstream; /* Stream reading this directory. */
245 static unsigned long
246 directory_contents_hash_1 (const void *key_0)
248 struct directory_contents const *key = (struct directory_contents const *) key_0;
249 unsigned long hash;
251 #ifdef WINDOWS32
252 ISTRING_HASH_1 (key->path_key, hash);
253 hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) key->ctime;
254 #else
255 # ifdef VMS
256 hash = (((unsigned int) key->dev << 4)
257 ^ ((unsigned int) key->ino[0]
258 + (unsigned int) key->ino[1]
259 + (unsigned int) key->ino[2]));
260 # else
261 hash = ((unsigned int) key->dev << 4) ^ (unsigned int) key->ino;
262 # endif
263 #endif /* WINDOWS32 */
264 return hash;
267 static unsigned long
268 directory_contents_hash_2 (const void *key_0)
270 struct directory_contents const *key = (struct directory_contents const *) key_0;
271 unsigned long hash;
273 #ifdef WINDOWS32
274 ISTRING_HASH_2 (key->path_key, hash);
275 hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ctime;
276 #else
277 # ifdef VMS
278 hash = (((unsigned int) key->dev << 4)
279 ^ ~((unsigned int) key->ino[0]
280 + (unsigned int) key->ino[1]
281 + (unsigned int) key->ino[2]));
282 # else
283 hash = ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ino;
284 # endif
285 #endif /* WINDOWS32 */
287 return hash;
290 static int
291 directory_contents_hash_cmp (const void *xv, const void *yv)
293 struct directory_contents const *x = (struct directory_contents const *) xv;
294 struct directory_contents const *y = (struct directory_contents const *) yv;
295 int result;
297 #ifdef WINDOWS32
298 ISTRING_COMPARE (x->path_key, y->path_key, result);
299 if (result)
300 return result;
301 result = x->ctime - y->ctime;
302 if (result)
303 return result;
304 #else
305 # ifdef VMS
306 result = x->ino[0] - y->ino[0];
307 if (result)
308 return result;
309 result = x->ino[1] - y->ino[1];
310 if (result)
311 return result;
312 result = x->ino[2] - y->ino[2];
313 if (result)
314 return result;
315 # else
316 result = x->ino - y->ino;
317 if (result)
318 return result;
319 # endif
320 #endif /* WINDOWS32 */
322 return x->dev - y->dev;
325 /* Table of directory contents hashed by device and inode number. */
326 static struct hash_table directory_contents;
328 struct directory
330 char *name; /* Name of the directory. */
332 /* The directory's contents. This data may be shared by several
333 entries in the hash table, which refer to the same directory
334 (identified uniquely by `dev' and `ino') under different names. */
335 struct directory_contents *contents;
338 static unsigned long
339 directory_hash_1 (const void *key)
341 return_ISTRING_HASH_1 (((struct directory const *) key)->name);
344 static unsigned long
345 directory_hash_2 (const void *key)
347 return_ISTRING_HASH_2 (((struct directory const *) key)->name);
350 static int
351 directory_hash_cmp (const void *x, const void *y)
353 return_ISTRING_COMPARE (((struct directory const *) x)->name,
354 ((struct directory const *) y)->name);
357 /* Table of directories hashed by name. */
358 static struct hash_table directories;
360 /* Never have more than this many directories open at once. */
362 #define MAX_OPEN_DIRECTORIES 10
364 static unsigned int open_directories = 0;
367 /* Hash table of files in each directory. */
369 struct dirfile
371 char *name; /* Name of the file. */
372 short length;
373 short impossible; /* This file is impossible. */
376 static unsigned long
377 dirfile_hash_1 (const void *key)
379 return_ISTRING_HASH_1 (((struct dirfile const *) key)->name);
382 static unsigned long
383 dirfile_hash_2 (const void *key)
385 return_ISTRING_HASH_2 (((struct dirfile const *) key)->name);
388 static int
389 dirfile_hash_cmp (const void *xv, const void *yv)
391 struct dirfile const *x = ((struct dirfile const *) xv);
392 struct dirfile const *y = ((struct dirfile const *) yv);
393 int result = x->length - y->length;
394 if (result)
395 return result;
396 return_ISTRING_COMPARE (x->name, y->name);
399 #ifndef DIRFILE_BUCKETS
400 #define DIRFILE_BUCKETS 107
401 #endif
403 static int dir_contents_file_exists_p PARAMS ((struct directory_contents *dir, char *filename));
404 static struct directory *find_directory PARAMS ((char *name));
406 /* Find the directory named NAME and return its `struct directory'. */
408 static struct directory *
409 find_directory (char *name)
411 register char *p;
412 register struct directory *dir;
413 register struct directory **dir_slot;
414 struct directory dir_key;
415 int r;
416 #ifdef WINDOWS32
417 char* w32_path;
418 char fs_label[BUFSIZ];
419 char fs_type[BUFSIZ];
420 long fs_serno;
421 long fs_flags;
422 long fs_len;
423 #endif
424 #ifdef VMS
425 if ((*name == '.') && (*(name+1) == 0))
426 name = "[]";
427 else
428 name = vmsify (name,1);
429 #endif
431 dir_key.name = name;
432 dir_slot = (struct directory **) hash_find_slot (&directories, &dir_key);
433 dir = *dir_slot;
435 if (HASH_VACANT (dir))
437 struct stat st;
439 /* The directory was not found. Create a new entry for it. */
441 p = name + strlen (name);
442 dir = (struct directory *) xmalloc (sizeof (struct directory));
443 dir->name = savestring (name, p - name);
444 hash_insert_at (&directories, dir, dir_slot);
445 /* The directory is not in the name hash table.
446 Find its device and inode numbers, and look it up by them. */
448 #ifdef WINDOWS32
449 /* Remove any trailing '\'. Windows32 stat fails even on valid
450 directories if they end in '\'. */
451 if (p[-1] == '\\')
452 p[-1] = '\0';
453 #endif
455 #ifdef VMS
456 r = vmsstat_dir (name, &st);
457 #else
458 EINTRLOOP (r, stat (name, &st));
459 #endif
461 #ifdef WINDOWS32
462 /* Put back the trailing '\'. If we don't, we're permanently
463 truncating the value! */
464 if (p[-1] == '\0')
465 p[-1] = '\\';
466 #endif
468 if (r < 0)
470 /* Couldn't stat the directory. Mark this by
471 setting the `contents' member to a nil pointer. */
472 dir->contents = 0;
474 else
476 /* Search the contents hash table; device and inode are the key. */
478 struct directory_contents *dc;
479 struct directory_contents **dc_slot;
480 struct directory_contents dc_key;
482 dc_key.dev = st.st_dev;
483 #ifdef WINDOWS32
484 dc_key.path_key = w32_path = w32ify (name, 1);
485 dc_key.ctime = st.st_ctime;
486 #else
487 # ifdef VMS
488 dc_key.ino[0] = st.st_ino[0];
489 dc_key.ino[1] = st.st_ino[1];
490 dc_key.ino[2] = st.st_ino[2];
491 # else
492 dc_key.ino = st.st_ino;
493 # endif
494 #endif
495 dc_slot = (struct directory_contents **) hash_find_slot (&directory_contents, &dc_key);
496 dc = *dc_slot;
498 if (HASH_VACANT (dc))
500 /* Nope; this really is a directory we haven't seen before. */
502 dc = (struct directory_contents *)
503 xmalloc (sizeof (struct directory_contents));
505 /* Enter it in the contents hash table. */
506 dc->dev = st.st_dev;
507 #ifdef WINDOWS32
508 dc->path_key = xstrdup (w32_path);
509 dc->ctime = st.st_ctime;
510 dc->mtime = st.st_mtime;
513 * NTFS is the only WINDOWS32 filesystem that bumps mtime
514 * on a directory when files are added/deleted from
515 * a directory.
517 w32_path[3] = '\0';
518 if (GetVolumeInformation(w32_path,
519 fs_label, sizeof (fs_label),
520 &fs_serno, &fs_len,
521 &fs_flags, fs_type, sizeof (fs_type)) == FALSE)
522 dc->fs_flags = FS_UNKNOWN;
523 else if (!strcmp(fs_type, "FAT"))
524 dc->fs_flags = FS_FAT;
525 else if (!strcmp(fs_type, "NTFS"))
526 dc->fs_flags = FS_NTFS;
527 else
528 dc->fs_flags = FS_UNKNOWN;
529 #else
530 # ifdef VMS
531 dc->ino[0] = st.st_ino[0];
532 dc->ino[1] = st.st_ino[1];
533 dc->ino[2] = st.st_ino[2];
534 # else
535 dc->ino = st.st_ino;
536 # endif
537 #endif /* WINDOWS32 */
538 hash_insert_at (&directory_contents, dc, dc_slot);
539 ENULLLOOP (dc->dirstream, opendir (name));
540 if (dc->dirstream == 0)
541 /* Couldn't open the directory. Mark this by
542 setting the `files' member to a nil pointer. */
543 dc->dirfiles.ht_vec = 0;
544 else
546 hash_init (&dc->dirfiles, DIRFILE_BUCKETS,
547 dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
548 /* Keep track of how many directories are open. */
549 ++open_directories;
550 if (open_directories == MAX_OPEN_DIRECTORIES)
551 /* We have too many directories open already.
552 Read the entire directory and then close it. */
553 (void) dir_contents_file_exists_p (dc, (char *) 0);
557 /* Point the name-hashed entry for DIR at its contents data. */
558 dir->contents = dc;
562 return dir;
565 /* Return 1 if the name FILENAME is entered in DIR's hash table.
566 FILENAME must contain no slashes. */
568 static int
569 dir_contents_file_exists_p (struct directory_contents *dir, char *filename)
571 unsigned int hash;
572 struct dirfile *df;
573 struct dirent *d;
574 #ifdef WINDOWS32
575 struct stat st;
576 int rehash = 0;
577 #endif
579 if (dir == 0 || dir->dirfiles.ht_vec == 0)
581 /* The directory could not be stat'd or opened. */
582 return 0;
584 #ifdef __MSDOS__
585 filename = dosify (filename);
586 #endif
588 #ifdef HAVE_CASE_INSENSITIVE_FS
589 filename = downcase (filename);
590 #endif
592 #ifdef __EMX__
593 _fnlwr(filename); /* lower case for FAT drives */
594 #endif
596 #ifdef VMS
597 filename = vmsify (filename,0);
598 #endif
600 hash = 0;
601 if (filename != 0)
603 struct dirfile dirfile_key;
605 if (*filename == '\0')
607 /* Checking if the directory exists. */
608 return 1;
610 dirfile_key.name = filename;
611 dirfile_key.length = strlen (filename);
612 df = (struct dirfile *) hash_find_item (&dir->dirfiles, &dirfile_key);
613 if (df)
615 return !df->impossible;
619 /* The file was not found in the hashed list.
620 Try to read the directory further. */
622 if (dir->dirstream == 0)
624 #ifdef WINDOWS32
626 * Check to see if directory has changed since last read. FAT
627 * filesystems force a rehash always as mtime does not change
628 * on directories (ugh!).
630 if (dir->path_key
631 && (dir->fs_flags & FS_FAT
632 || (stat(dir->path_key, &st) == 0
633 && st.st_mtime > dir->mtime)))
635 /* reset date stamp to show most recent re-process */
636 dir->mtime = st.st_mtime;
638 /* make sure directory can still be opened */
639 dir->dirstream = opendir(dir->path_key);
641 if (dir->dirstream)
642 rehash = 1;
643 else
644 return 0; /* couldn't re-read - fail */
646 else
647 #endif
648 /* The directory has been all read in. */
649 return 0;
652 while (1)
654 /* Enter the file in the hash table. */
655 unsigned int len;
656 struct dirfile dirfile_key;
657 struct dirfile **dirfile_slot;
659 ENULLLOOP (d, readdir (dir->dirstream));
660 if (d == 0)
661 break;
663 #if defined(VMS) && defined(HAVE_DIRENT_H)
664 /* In VMS we get file versions too, which have to be stripped off */
666 char *p = strrchr (d->d_name, ';');
667 if (p)
668 *p = '\0';
670 #endif
671 if (!REAL_DIR_ENTRY (d))
672 continue;
674 len = NAMLEN (d);
675 dirfile_key.name = d->d_name;
676 dirfile_key.length = len;
677 dirfile_slot = (struct dirfile **) hash_find_slot (&dir->dirfiles, &dirfile_key);
678 #ifdef WINDOWS32
680 * If re-reading a directory, don't cache files that have
681 * already been discovered.
683 if (! rehash || HASH_VACANT (*dirfile_slot))
684 #endif
686 df = (struct dirfile *) xmalloc (sizeof (struct dirfile));
687 df->name = savestring (d->d_name, len);
688 df->length = len;
689 df->impossible = 0;
690 hash_insert_at (&dir->dirfiles, df, dirfile_slot);
692 /* Check if the name matches the one we're searching for. */
693 if (filename != 0 && strieq (d->d_name, filename))
695 return 1;
699 /* If the directory has been completely read in,
700 close the stream and reset the pointer to nil. */
701 if (d == 0)
703 --open_directories;
704 closedir (dir->dirstream);
705 dir->dirstream = 0;
707 return 0;
710 /* Return 1 if the name FILENAME in directory DIRNAME
711 is entered in the dir hash table.
712 FILENAME must contain no slashes. */
715 dir_file_exists_p (char *dirname, char *filename)
717 return dir_contents_file_exists_p (find_directory (dirname)->contents,
718 filename);
721 /* Return 1 if the file named NAME exists. */
724 file_exists_p (char *name)
726 char *dirend;
727 char *dirname;
728 char *slash;
730 #ifndef NO_ARCHIVES
731 if (ar_name (name))
732 return ar_member_date (name) != (time_t) -1;
733 #endif
735 #ifdef VMS
736 dirend = strrchr (name, ']');
737 if (dirend == 0)
738 dirend = strrchr (name, ':');
739 dirend++;
740 if (dirend == (char *)1)
741 return dir_file_exists_p ("[]", name);
742 #else /* !VMS */
743 dirend = strrchr (name, '/');
744 #ifdef HAVE_DOS_PATHS
745 /* Forward and backslashes might be mixed. We need the rightmost one. */
747 char *bslash = strrchr(name, '\\');
748 if (!dirend || bslash > dirend)
749 dirend = bslash;
750 /* The case of "d:file". */
751 if (!dirend && name[0] && name[1] == ':')
752 dirend = name + 1;
754 #endif /* HAVE_DOS_PATHS */
755 if (dirend == 0)
756 #ifndef _AMIGA
757 return dir_file_exists_p (".", name);
758 #else /* !VMS && !AMIGA */
759 return dir_file_exists_p ("", name);
760 #endif /* AMIGA */
761 #endif /* VMS */
763 slash = dirend;
764 if (dirend == name)
765 dirname = "/";
766 else
768 #ifdef HAVE_DOS_PATHS
769 /* d:/ and d: are *very* different... */
770 if (dirend < name + 3 && name[1] == ':' &&
771 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
772 dirend++;
773 #endif
774 dirname = (char *) alloca (dirend - name + 1);
775 bcopy (name, dirname, dirend - name);
776 dirname[dirend - name] = '\0';
778 return dir_file_exists_p (dirname, slash + 1);
781 /* Mark FILENAME as `impossible' for `file_impossible_p'.
782 This means an attempt has been made to search for FILENAME
783 as an intermediate file, and it has failed. */
785 void
786 file_impossible (char *filename)
788 char *dirend;
789 register char *p = filename;
790 register struct directory *dir;
791 register struct dirfile *new;
793 #ifdef VMS
794 dirend = strrchr (p, ']');
795 if (dirend == 0)
796 dirend = strrchr (p, ':');
797 dirend++;
798 if (dirend == (char *)1)
799 dir = find_directory ("[]");
800 #else
801 dirend = strrchr (p, '/');
802 # ifdef HAVE_DOS_PATHS
803 /* Forward and backslashes might be mixed. We need the rightmost one. */
805 char *bslash = strrchr(p, '\\');
806 if (!dirend || bslash > dirend)
807 dirend = bslash;
808 /* The case of "d:file". */
809 if (!dirend && p[0] && p[1] == ':')
810 dirend = p + 1;
812 # endif /* HAVE_DOS_PATHS */
813 if (dirend == 0)
814 # ifdef _AMIGA
815 dir = find_directory ("");
816 # else /* !VMS && !AMIGA */
817 dir = find_directory (".");
818 # endif /* AMIGA */
819 #endif /* VMS */
820 else
822 char *dirname;
823 char *slash = dirend;
824 if (dirend == p)
825 dirname = "/";
826 else
828 #ifdef HAVE_DOS_PATHS
829 /* d:/ and d: are *very* different... */
830 if (dirend < p + 3 && p[1] == ':' &&
831 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
832 dirend++;
833 #endif
834 dirname = (char *) alloca (dirend - p + 1);
835 bcopy (p, dirname, dirend - p);
836 dirname[dirend - p] = '\0';
838 dir = find_directory (dirname);
839 filename = p = slash + 1;
842 if (dir->contents == 0)
844 /* The directory could not be stat'd. We allocate a contents
845 structure for it, but leave it out of the contents hash table. */
846 dir->contents = (struct directory_contents *)
847 xmalloc (sizeof (struct directory_contents));
848 bzero ((char *) dir->contents, sizeof (struct directory_contents));
851 if (dir->contents->dirfiles.ht_vec == 0)
853 hash_init (&dir->contents->dirfiles, DIRFILE_BUCKETS,
854 dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
857 /* Make a new entry and put it in the table. */
859 new = (struct dirfile *) xmalloc (sizeof (struct dirfile));
860 new->name = xstrdup (filename);
861 new->length = strlen (filename);
862 new->impossible = 1;
863 hash_insert (&dir->contents->dirfiles, new);
866 /* Return nonzero if FILENAME has been marked impossible. */
869 file_impossible_p (char *filename)
871 char *dirend;
872 register char *p = filename;
873 register struct directory_contents *dir;
874 register struct dirfile *dirfile;
875 struct dirfile dirfile_key;
877 #ifdef VMS
878 dirend = strrchr (filename, ']');
879 if (dirend == 0)
880 dir = find_directory ("[]")->contents;
881 #else
882 dirend = strrchr (filename, '/');
883 #ifdef HAVE_DOS_PATHS
884 /* Forward and backslashes might be mixed. We need the rightmost one. */
886 char *bslash = strrchr(filename, '\\');
887 if (!dirend || bslash > dirend)
888 dirend = bslash;
889 /* The case of "d:file". */
890 if (!dirend && filename[0] && filename[1] == ':')
891 dirend = filename + 1;
893 #endif /* HAVE_DOS_PATHS */
894 if (dirend == 0)
895 #ifdef _AMIGA
896 dir = find_directory ("")->contents;
897 #else /* !VMS && !AMIGA */
898 dir = find_directory (".")->contents;
899 #endif /* AMIGA */
900 #endif /* VMS */
901 else
903 char *dirname;
904 char *slash = dirend;
905 if (dirend == filename)
906 dirname = "/";
907 else
909 #ifdef HAVE_DOS_PATHS
910 /* d:/ and d: are *very* different... */
911 if (dirend < filename + 3 && filename[1] == ':' &&
912 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
913 dirend++;
914 #endif
915 dirname = (char *) alloca (dirend - filename + 1);
916 bcopy (p, dirname, dirend - p);
917 dirname[dirend - p] = '\0';
919 dir = find_directory (dirname)->contents;
920 p = filename = slash + 1;
923 if (dir == 0 || dir->dirfiles.ht_vec == 0)
924 /* There are no files entered for this directory. */
925 return 0;
927 #ifdef __MSDOS__
928 filename = dosify (p);
929 #endif
930 #ifdef HAVE_CASE_INSENSITIVE_FS
931 filename = downcase (p);
932 #endif
933 #ifdef VMS
934 filename = vmsify (p, 1);
935 #endif
937 dirfile_key.name = filename;
938 dirfile_key.length = strlen (filename);
939 dirfile = (struct dirfile *) hash_find_item (&dir->dirfiles, &dirfile_key);
940 if (dirfile)
941 return dirfile->impossible;
943 return 0;
946 /* Return the already allocated name in the
947 directory hash table that matches DIR. */
949 char *
950 dir_name (char *dir)
952 return find_directory (dir)->name;
955 /* Print the data base of directories. */
957 void
958 print_dir_data_base (void)
960 register unsigned int files;
961 register unsigned int impossible;
962 register struct directory **dir_slot;
963 register struct directory **dir_end;
965 puts (_("\n# Directories\n"));
967 files = impossible = 0;
969 dir_slot = (struct directory **) directories.ht_vec;
970 dir_end = dir_slot + directories.ht_size;
971 for ( ; dir_slot < dir_end; dir_slot++)
973 register struct directory *dir = *dir_slot;
974 if (! HASH_VACANT (dir))
976 if (dir->contents == 0)
977 printf (_("# %s: could not be stat'd.\n"), dir->name);
978 else if (dir->contents->dirfiles.ht_vec == 0)
980 #ifdef WINDOWS32
981 printf (_("# %s (key %s, mtime %d): could not be opened.\n"),
982 dir->name, dir->contents->path_key,dir->contents->mtime);
983 #else /* WINDOWS32 */
984 #ifdef VMS
985 printf (_("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n"),
986 dir->name, dir->contents->dev,
987 dir->contents->ino[0], dir->contents->ino[1],
988 dir->contents->ino[2]);
989 #else
990 printf (_("# %s (device %ld, inode %ld): could not be opened.\n"),
991 dir->name, (long int) dir->contents->dev,
992 (long int) dir->contents->ino);
993 #endif
994 #endif /* WINDOWS32 */
996 else
998 register unsigned int f = 0;
999 register unsigned int im = 0;
1000 register struct dirfile **files_slot;
1001 register struct dirfile **files_end;
1003 files_slot = (struct dirfile **) dir->contents->dirfiles.ht_vec;
1004 files_end = files_slot + dir->contents->dirfiles.ht_size;
1005 for ( ; files_slot < files_end; files_slot++)
1007 register struct dirfile *df = *files_slot;
1008 if (! HASH_VACANT (df))
1010 if (df->impossible)
1011 ++im;
1012 else
1013 ++f;
1016 #ifdef WINDOWS32
1017 printf (_("# %s (key %s, mtime %d): "),
1018 dir->name, dir->contents->path_key, dir->contents->mtime);
1019 #else /* WINDOWS32 */
1020 #ifdef VMS
1021 printf (_("# %s (device %d, inode [%d,%d,%d]): "),
1022 dir->name, dir->contents->dev,
1023 dir->contents->ino[0], dir->contents->ino[1],
1024 dir->contents->ino[2]);
1025 #else
1026 printf (_("# %s (device %ld, inode %ld): "),
1027 dir->name,
1028 (long)dir->contents->dev, (long)dir->contents->ino);
1029 #endif
1030 #endif /* WINDOWS32 */
1031 if (f == 0)
1032 fputs (_("No"), stdout);
1033 else
1034 printf ("%u", f);
1035 fputs (_(" files, "), stdout);
1036 if (im == 0)
1037 fputs (_("no"), stdout);
1038 else
1039 printf ("%u", im);
1040 fputs (_(" impossibilities"), stdout);
1041 if (dir->contents->dirstream == 0)
1042 puts (".");
1043 else
1044 puts (_(" so far."));
1045 files += f;
1046 impossible += im;
1051 fputs ("\n# ", stdout);
1052 if (files == 0)
1053 fputs (_("No"), stdout);
1054 else
1055 printf ("%u", files);
1056 fputs (_(" files, "), stdout);
1057 if (impossible == 0)
1058 fputs (_("no"), stdout);
1059 else
1060 printf ("%u", impossible);
1061 printf (_(" impossibilities in %lu directories.\n"), directories.ht_fill);
1064 /* Hooks for globbing. */
1066 #include <glob.h>
1068 /* Structure describing state of iterating through a directory hash table. */
1070 struct dirstream
1072 struct directory_contents *contents; /* The directory being read. */
1073 struct dirfile **dirfile_slot; /* Current slot in table. */
1076 /* Forward declarations. */
1077 static __ptr_t open_dirstream PARAMS ((const char *));
1078 static struct dirent *read_dirstream PARAMS ((__ptr_t));
1080 static __ptr_t
1081 open_dirstream (const char *directory)
1083 struct dirstream *new;
1084 struct directory *dir = find_directory ((char *)directory);
1086 if (dir->contents == 0 || dir->contents->dirfiles.ht_vec == 0)
1087 /* DIR->contents is nil if the directory could not be stat'd.
1088 DIR->contents->dirfiles is nil if it could not be opened. */
1089 return 0;
1091 /* Read all the contents of the directory now. There is no benefit
1092 in being lazy, since glob will want to see every file anyway. */
1094 (void) dir_contents_file_exists_p (dir->contents, (char *) 0);
1096 new = (struct dirstream *) xmalloc (sizeof (struct dirstream));
1097 new->contents = dir->contents;
1098 new->dirfile_slot = (struct dirfile **) new->contents->dirfiles.ht_vec;
1100 return (__ptr_t) new;
1103 static struct dirent *
1104 read_dirstream (__ptr_t stream)
1106 struct dirstream *const ds = (struct dirstream *) stream;
1107 struct directory_contents *dc = ds->contents;
1108 struct dirfile **dirfile_end = (struct dirfile **) dc->dirfiles.ht_vec + dc->dirfiles.ht_size;
1109 static char *buf;
1110 static unsigned int bufsz;
1112 while (ds->dirfile_slot < dirfile_end)
1114 register struct dirfile *df = *ds->dirfile_slot++;
1115 if (! HASH_VACANT (df) && !df->impossible)
1117 /* The glob interface wants a `struct dirent',
1118 so mock one up. */
1119 struct dirent *d;
1120 unsigned int len = df->length + 1;
1121 if (sizeof *d - sizeof d->d_name + len > bufsz)
1123 if (buf != 0)
1124 free (buf);
1125 bufsz *= 2;
1126 if (sizeof *d - sizeof d->d_name + len > bufsz)
1127 bufsz = sizeof *d - sizeof d->d_name + len;
1128 buf = xmalloc (bufsz);
1130 d = (struct dirent *) buf;
1131 FAKE_DIR_ENTRY (d);
1132 #ifdef _DIRENT_HAVE_D_NAMLEN
1133 d->d_namlen = len - 1;
1134 #endif
1135 #ifdef _DIRENT_HAVE_D_TYPE
1136 d->d_type = DT_UNKNOWN;
1137 #endif
1138 memcpy (d->d_name, df->name, len);
1139 return d;
1143 return 0;
1146 static void
1147 ansi_free(void *p)
1149 if (p)
1150 free(p);
1153 /* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a
1154 * macro for stat64(). If stat is a macro, make a local wrapper function to
1155 * invoke it.
1157 #ifndef stat
1158 # ifndef VMS
1159 extern int stat PARAMS ((const char *path, struct stat *sbuf));
1160 # endif
1161 # define local_stat stat
1162 #else
1163 static int
1164 local_stat (const char *path, struct stat *buf)
1166 int e;
1168 EINTRLOOP (e, stat (path, buf));
1169 return e;
1171 #endif
1173 void
1174 dir_setup_glob (glob_t *gl)
1176 /* Bogus sunos4 compiler complains (!) about & before functions. */
1177 gl->gl_opendir = open_dirstream;
1178 gl->gl_readdir = read_dirstream;
1179 gl->gl_closedir = ansi_free;
1180 gl->gl_stat = local_stat;
1181 /* We don't bother setting gl_lstat, since glob never calls it.
1182 The slot is only there for compatibility with 4.4 BSD. */
1185 void
1186 hash_init_directories (void)
1188 hash_init (&directories, DIRECTORY_BUCKETS,
1189 directory_hash_1, directory_hash_2, directory_hash_cmp);
1190 hash_init (&directory_contents, DIRECTORY_BUCKETS,
1191 directory_contents_hash_1, directory_contents_hash_2, directory_contents_hash_cmp);