Convert the source code to use ANSI C style function definitions and
[make.git] / dir.c
blob39f3e2af2df80658300272845e8d3e47a20e7035
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 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 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 VMS
593 filename = vmsify (filename,0);
594 #endif
596 hash = 0;
597 if (filename != 0)
599 struct dirfile dirfile_key;
601 if (*filename == '\0')
603 /* Checking if the directory exists. */
604 return 1;
606 dirfile_key.name = filename;
607 dirfile_key.length = strlen (filename);
608 df = (struct dirfile *) hash_find_item (&dir->dirfiles, &dirfile_key);
609 if (df)
611 return !df->impossible;
615 /* The file was not found in the hashed list.
616 Try to read the directory further. */
618 if (dir->dirstream == 0)
620 #ifdef WINDOWS32
622 * Check to see if directory has changed since last read. FAT
623 * filesystems force a rehash always as mtime does not change
624 * on directories (ugh!).
626 if (dir->path_key
627 && (dir->fs_flags & FS_FAT
628 || (stat(dir->path_key, &st) == 0
629 && st.st_mtime > dir->mtime)))
631 /* reset date stamp to show most recent re-process */
632 dir->mtime = st.st_mtime;
634 /* make sure directory can still be opened */
635 dir->dirstream = opendir(dir->path_key);
637 if (dir->dirstream)
638 rehash = 1;
639 else
640 return 0; /* couldn't re-read - fail */
642 else
643 #endif
644 /* The directory has been all read in. */
645 return 0;
648 while ((d = readdir (dir->dirstream)) != 0)
650 /* Enter the file in the hash table. */
651 unsigned int len;
652 struct dirfile dirfile_key;
653 struct dirfile **dirfile_slot;
655 #if defined(VMS) && defined(HAVE_DIRENT_H)
656 /* In VMS we get file versions too, which have to be stripped off */
658 char *p = strrchr (d->d_name, ';');
659 if (p)
660 *p = '\0';
662 #endif
663 if (!REAL_DIR_ENTRY (d))
664 continue;
666 len = NAMLEN (d);
667 dirfile_key.name = d->d_name;
668 dirfile_key.length = len;
669 dirfile_slot = (struct dirfile **) hash_find_slot (&dir->dirfiles, &dirfile_key);
670 #ifdef WINDOWS32
672 * If re-reading a directory, don't cache files that have
673 * already been discovered.
675 if (! rehash || HASH_VACANT (*dirfile_slot))
676 #endif
678 df = (struct dirfile *) xmalloc (sizeof (struct dirfile));
679 df->name = savestring (d->d_name, len);
680 df->length = len;
681 df->impossible = 0;
682 hash_insert_at (&dir->dirfiles, df, dirfile_slot);
684 /* Check if the name matches the one we're searching for. */
685 if (filename != 0 && strieq (d->d_name, filename))
687 return 1;
691 /* If the directory has been completely read in,
692 close the stream and reset the pointer to nil. */
693 if (d == 0)
695 --open_directories;
696 closedir (dir->dirstream);
697 dir->dirstream = 0;
699 return 0;
702 /* Return 1 if the name FILENAME in directory DIRNAME
703 is entered in the dir hash table.
704 FILENAME must contain no slashes. */
707 dir_file_exists_p (char *dirname, char *filename)
709 return dir_contents_file_exists_p (find_directory (dirname)->contents,
710 filename);
713 /* Return 1 if the file named NAME exists. */
716 file_exists_p (char *name)
718 char *dirend;
719 char *dirname;
720 char *slash;
722 #ifndef NO_ARCHIVES
723 if (ar_name (name))
724 return ar_member_date (name) != (time_t) -1;
725 #endif
727 #ifdef VMS
728 dirend = strrchr (name, ']');
729 if (dirend == 0)
730 dirend = strrchr (name, ':');
731 dirend++;
732 if (dirend == (char *)1)
733 return dir_file_exists_p ("[]", name);
734 #else /* !VMS */
735 dirend = strrchr (name, '/');
736 #ifdef HAVE_DOS_PATHS
737 /* Forward and backslashes might be mixed. We need the rightmost one. */
739 char *bslash = strrchr(name, '\\');
740 if (!dirend || bslash > dirend)
741 dirend = bslash;
742 /* The case of "d:file". */
743 if (!dirend && name[0] && name[1] == ':')
744 dirend = name + 1;
746 #endif /* HAVE_DOS_PATHS */
747 if (dirend == 0)
748 #ifndef _AMIGA
749 return dir_file_exists_p (".", name);
750 #else /* !VMS && !AMIGA */
751 return dir_file_exists_p ("", name);
752 #endif /* AMIGA */
753 #endif /* VMS */
755 slash = dirend;
756 if (dirend == name)
757 dirname = "/";
758 else
760 #ifdef HAVE_DOS_PATHS
761 /* d:/ and d: are *very* different... */
762 if (dirend < name + 3 && name[1] == ':' &&
763 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
764 dirend++;
765 #endif
766 dirname = (char *) alloca (dirend - name + 1);
767 bcopy (name, dirname, dirend - name);
768 dirname[dirend - name] = '\0';
770 return dir_file_exists_p (dirname, slash + 1);
773 /* Mark FILENAME as `impossible' for `file_impossible_p'.
774 This means an attempt has been made to search for FILENAME
775 as an intermediate file, and it has failed. */
777 void
778 file_impossible (char *filename)
780 char *dirend;
781 register char *p = filename;
782 register struct directory *dir;
783 register struct dirfile *new;
785 #ifdef VMS
786 dirend = strrchr (p, ']');
787 if (dirend == 0)
788 dirend = strrchr (p, ':');
789 dirend++;
790 if (dirend == (char *)1)
791 dir = find_directory ("[]");
792 #else
793 dirend = strrchr (p, '/');
794 # ifdef HAVE_DOS_PATHS
795 /* Forward and backslashes might be mixed. We need the rightmost one. */
797 char *bslash = strrchr(p, '\\');
798 if (!dirend || bslash > dirend)
799 dirend = bslash;
800 /* The case of "d:file". */
801 if (!dirend && p[0] && p[1] == ':')
802 dirend = p + 1;
804 # endif /* HAVE_DOS_PATHS */
805 if (dirend == 0)
806 # ifdef _AMIGA
807 dir = find_directory ("");
808 # else /* !VMS && !AMIGA */
809 dir = find_directory (".");
810 # endif /* AMIGA */
811 #endif /* VMS */
812 else
814 char *dirname;
815 char *slash = dirend;
816 if (dirend == p)
817 dirname = "/";
818 else
820 #ifdef HAVE_DOS_PATHS
821 /* d:/ and d: are *very* different... */
822 if (dirend < p + 3 && p[1] == ':' &&
823 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
824 dirend++;
825 #endif
826 dirname = (char *) alloca (dirend - p + 1);
827 bcopy (p, dirname, dirend - p);
828 dirname[dirend - p] = '\0';
830 dir = find_directory (dirname);
831 filename = p = slash + 1;
834 if (dir->contents == 0)
836 /* The directory could not be stat'd. We allocate a contents
837 structure for it, but leave it out of the contents hash table. */
838 dir->contents = (struct directory_contents *)
839 xmalloc (sizeof (struct directory_contents));
840 bzero ((char *) dir->contents, sizeof (struct directory_contents));
843 if (dir->contents->dirfiles.ht_vec == 0)
845 hash_init (&dir->contents->dirfiles, DIRFILE_BUCKETS,
846 dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
849 /* Make a new entry and put it in the table. */
851 new = (struct dirfile *) xmalloc (sizeof (struct dirfile));
852 new->name = xstrdup (filename);
853 new->length = strlen (filename);
854 new->impossible = 1;
855 hash_insert (&dir->contents->dirfiles, new);
858 /* Return nonzero if FILENAME has been marked impossible. */
861 file_impossible_p (char *filename)
863 char *dirend;
864 register char *p = filename;
865 register struct directory_contents *dir;
866 register struct dirfile *dirfile;
867 struct dirfile dirfile_key;
869 #ifdef VMS
870 dirend = strrchr (filename, ']');
871 if (dirend == 0)
872 dir = find_directory ("[]")->contents;
873 #else
874 dirend = strrchr (filename, '/');
875 #ifdef HAVE_DOS_PATHS
876 /* Forward and backslashes might be mixed. We need the rightmost one. */
878 char *bslash = strrchr(filename, '\\');
879 if (!dirend || bslash > dirend)
880 dirend = bslash;
881 /* The case of "d:file". */
882 if (!dirend && filename[0] && filename[1] == ':')
883 dirend = filename + 1;
885 #endif /* HAVE_DOS_PATHS */
886 if (dirend == 0)
887 #ifdef _AMIGA
888 dir = find_directory ("")->contents;
889 #else /* !VMS && !AMIGA */
890 dir = find_directory (".")->contents;
891 #endif /* AMIGA */
892 #endif /* VMS */
893 else
895 char *dirname;
896 char *slash = dirend;
897 if (dirend == filename)
898 dirname = "/";
899 else
901 #ifdef HAVE_DOS_PATHS
902 /* d:/ and d: are *very* different... */
903 if (dirend < filename + 3 && filename[1] == ':' &&
904 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
905 dirend++;
906 #endif
907 dirname = (char *) alloca (dirend - filename + 1);
908 bcopy (p, dirname, dirend - p);
909 dirname[dirend - p] = '\0';
911 dir = find_directory (dirname)->contents;
912 p = filename = slash + 1;
915 if (dir == 0 || dir->dirfiles.ht_vec == 0)
916 /* There are no files entered for this directory. */
917 return 0;
919 #ifdef __MSDOS__
920 filename = dosify (p);
921 #endif
922 #ifdef HAVE_CASE_INSENSITIVE_FS
923 filename = downcase (p);
924 #endif
925 #ifdef VMS
926 filename = vmsify (p, 1);
927 #endif
929 dirfile_key.name = filename;
930 dirfile_key.length = strlen (filename);
931 dirfile = (struct dirfile *) hash_find_item (&dir->dirfiles, &dirfile_key);
932 if (dirfile)
933 return dirfile->impossible;
935 return 0;
938 /* Return the already allocated name in the
939 directory hash table that matches DIR. */
941 char *
942 dir_name (char *dir)
944 return find_directory (dir)->name;
947 /* Print the data base of directories. */
949 void
950 print_dir_data_base (void)
952 register unsigned int files;
953 register unsigned int impossible;
954 register struct directory **dir_slot;
955 register struct directory **dir_end;
957 puts (_("\n# Directories\n"));
959 files = impossible = 0;
961 dir_slot = (struct directory **) directories.ht_vec;
962 dir_end = dir_slot + directories.ht_size;
963 for ( ; dir_slot < dir_end; dir_slot++)
965 register struct directory *dir = *dir_slot;
966 if (! HASH_VACANT (dir))
968 if (dir->contents == 0)
969 printf (_("# %s: could not be stat'd.\n"), dir->name);
970 else if (dir->contents->dirfiles.ht_vec == 0)
972 #ifdef WINDOWS32
973 printf (_("# %s (key %s, mtime %d): could not be opened.\n"),
974 dir->name, dir->contents->path_key,dir->contents->mtime);
975 #else /* WINDOWS32 */
976 #ifdef VMS
977 printf (_("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n"),
978 dir->name, dir->contents->dev,
979 dir->contents->ino[0], dir->contents->ino[1],
980 dir->contents->ino[2]);
981 #else
982 printf (_("# %s (device %ld, inode %ld): could not be opened.\n"),
983 dir->name, (long int) dir->contents->dev,
984 (long int) dir->contents->ino);
985 #endif
986 #endif /* WINDOWS32 */
988 else
990 register unsigned int f = 0;
991 register unsigned int im = 0;
992 register struct dirfile **files_slot;
993 register struct dirfile **files_end;
995 files_slot = (struct dirfile **) dir->contents->dirfiles.ht_vec;
996 files_end = files_slot + dir->contents->dirfiles.ht_size;
997 for ( ; files_slot < files_end; files_slot++)
999 register struct dirfile *df = *files_slot;
1000 if (! HASH_VACANT (df))
1002 if (df->impossible)
1003 ++im;
1004 else
1005 ++f;
1008 #ifdef WINDOWS32
1009 printf (_("# %s (key %s, mtime %d): "),
1010 dir->name, dir->contents->path_key, dir->contents->mtime);
1011 #else /* WINDOWS32 */
1012 #ifdef VMS
1013 printf (_("# %s (device %d, inode [%d,%d,%d]): "),
1014 dir->name, dir->contents->dev,
1015 dir->contents->ino[0], dir->contents->ino[1],
1016 dir->contents->ino[2]);
1017 #else
1018 printf (_("# %s (device %ld, inode %ld): "),
1019 dir->name,
1020 (long)dir->contents->dev, (long)dir->contents->ino);
1021 #endif
1022 #endif /* WINDOWS32 */
1023 if (f == 0)
1024 fputs (_("No"), stdout);
1025 else
1026 printf ("%u", f);
1027 fputs (_(" files, "), stdout);
1028 if (im == 0)
1029 fputs (_("no"), stdout);
1030 else
1031 printf ("%u", im);
1032 fputs (_(" impossibilities"), stdout);
1033 if (dir->contents->dirstream == 0)
1034 puts (".");
1035 else
1036 puts (_(" so far."));
1037 files += f;
1038 impossible += im;
1043 fputs ("\n# ", stdout);
1044 if (files == 0)
1045 fputs (_("No"), stdout);
1046 else
1047 printf ("%u", files);
1048 fputs (_(" files, "), stdout);
1049 if (impossible == 0)
1050 fputs (_("no"), stdout);
1051 else
1052 printf ("%u", impossible);
1053 printf (_(" impossibilities in %lu directories.\n"), directories.ht_fill);
1056 /* Hooks for globbing. */
1058 #include <glob.h>
1060 /* Structure describing state of iterating through a directory hash table. */
1062 struct dirstream
1064 struct directory_contents *contents; /* The directory being read. */
1065 struct dirfile **dirfile_slot; /* Current slot in table. */
1068 /* Forward declarations. */
1069 static __ptr_t open_dirstream PARAMS ((const char *));
1070 static struct dirent *read_dirstream PARAMS ((__ptr_t));
1072 static __ptr_t
1073 open_dirstream (const char *directory)
1075 struct dirstream *new;
1076 struct directory *dir = find_directory ((char *)directory);
1078 if (dir->contents == 0 || dir->contents->dirfiles.ht_vec == 0)
1079 /* DIR->contents is nil if the directory could not be stat'd.
1080 DIR->contents->dirfiles is nil if it could not be opened. */
1081 return 0;
1083 /* Read all the contents of the directory now. There is no benefit
1084 in being lazy, since glob will want to see every file anyway. */
1086 (void) dir_contents_file_exists_p (dir->contents, (char *) 0);
1088 new = (struct dirstream *) xmalloc (sizeof (struct dirstream));
1089 new->contents = dir->contents;
1090 new->dirfile_slot = (struct dirfile **) new->contents->dirfiles.ht_vec;
1092 return (__ptr_t) new;
1095 static struct dirent *
1096 read_dirstream (__ptr_t stream)
1098 struct dirstream *const ds = (struct dirstream *) stream;
1099 struct directory_contents *dc = ds->contents;
1100 struct dirfile **dirfile_end = (struct dirfile **) dc->dirfiles.ht_vec + dc->dirfiles.ht_size;
1101 static char *buf;
1102 static unsigned int bufsz;
1104 while (ds->dirfile_slot < dirfile_end)
1106 register struct dirfile *df = *ds->dirfile_slot++;
1107 if (! HASH_VACANT (df) && !df->impossible)
1109 /* The glob interface wants a `struct dirent',
1110 so mock one up. */
1111 struct dirent *d;
1112 unsigned int len = df->length + 1;
1113 if (sizeof *d - sizeof d->d_name + len > bufsz)
1115 if (buf != 0)
1116 free (buf);
1117 bufsz *= 2;
1118 if (sizeof *d - sizeof d->d_name + len > bufsz)
1119 bufsz = sizeof *d - sizeof d->d_name + len;
1120 buf = xmalloc (bufsz);
1122 d = (struct dirent *) buf;
1123 FAKE_DIR_ENTRY (d);
1124 #ifdef _DIRENT_HAVE_D_NAMLEN
1125 d->d_namlen = len - 1;
1126 #endif
1127 #ifdef _DIRENT_HAVE_D_TYPE
1128 d->d_type = DT_UNKNOWN;
1129 #endif
1130 memcpy (d->d_name, df->name, len);
1131 return d;
1135 return 0;
1138 static void
1139 ansi_free(void *p)
1141 if (p)
1142 free(p);
1145 /* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a
1146 * macro for stat64(). If stat is a macro, make a local wrapper function to
1147 * invoke it.
1149 #ifndef stat
1150 # ifndef VMS
1151 extern int stat PARAMS ((const char *path, struct stat *sbuf));
1152 # endif
1153 # define local_stat stat
1154 #else
1155 static int
1156 local_stat (const char *path, struct stat *buf)
1158 return stat (path, buf);
1160 #endif
1162 void
1163 dir_setup_glob (glob_t *gl)
1165 /* Bogus sunos4 compiler complains (!) about & before functions. */
1166 gl->gl_opendir = open_dirstream;
1167 gl->gl_readdir = read_dirstream;
1168 gl->gl_closedir = ansi_free;
1169 gl->gl_stat = local_stat;
1170 /* We don't bother setting gl_lstat, since glob never calls it.
1171 The slot is only there for compatibility with 4.4 BSD. */
1174 void
1175 hash_init_directories (void)
1177 hash_init (&directories, DIRECTORY_BUCKETS,
1178 directory_hash_1, directory_hash_2, directory_hash_cmp);
1179 hash_init (&directory_contents, DIRECTORY_BUCKETS,
1180 directory_contents_hash_1, directory_contents_hash_2, directory_contents_hash_cmp);