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)
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. */
26 # define NAMLEN(dirent) strlen((dirent)->d_name)
28 extern char *vmsify
PARAMS ((char *name
, int type
));
31 # define dirent direct
32 # define NAMLEN(dirent) (dirent)->d_namlen
33 # ifdef HAVE_SYS_NDIR_H
34 # include <sys/ndir.h>
36 # ifdef HAVE_SYS_DIR_H
44 # endif /* HAVE_VMSDIR_H */
47 /* In GNU systems, <dirent.h> defines this macro for us. */
50 # define NAMLEN(d) _D_NAMLEN(d)
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)
59 # define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
60 # define FAKE_DIR_ENTRY(dp) (dp->d_ino = 1)
67 /* If it's MSDOS that doesn't have _USE_LFN, disable LFN support. */
76 static char dos_filename
[14];
80 if (filename
== 0 || _USE_LFN
)
83 /* FIXME: what about filenames which violate
84 8+3 constraints, like "config.h.in", or ".emacs"? */
85 if (strpbrk (filename
, "\"*+,;<=>?[\\]|") != 0)
90 /* First, transform the name part. */
91 for (i
= 0; *filename
!= '\0' && i
< 8 && *filename
!= '.'; ++i
)
92 *df
++ = tolower ((unsigned char)*filename
++);
94 /* Now skip to the next dot. */
95 while (*filename
!= '\0' && *filename
!= '.')
97 if (*filename
!= '\0')
100 for (i
= 0; *filename
!= '\0' && i
< 3 && *filename
!= '.'; ++i
)
101 *df
++ = tolower ((unsigned char)*filename
++);
104 /* Look for more dots. */
105 while (*filename
!= '\0' && *filename
!= '.')
107 if (*filename
== '.')
112 #endif /* __MSDOS__ */
115 #include "pathstuff.h"
122 #ifdef HAVE_CASE_INSENSITIVE_FS
128 static char new_filename
[136];
130 static char new_filename
[PATH_MAX
];
140 /* First, transform the name part. */
141 for (i
= 0; *filename
!= '\0'; ++i
)
143 *df
++ = tolower ((unsigned char)*filename
);
151 #endif /* HAVE_CASE_INSENSITIVE_FS */
164 unsigned char uc
= *name
;
165 h
= (h
<< 4) + (isupper (uc
) ? tolower (uc
) : uc
);
177 /* fake stat entry for a directory */
179 vmsstat_dir (name
, st
)
187 dir
= opendir (name
);
191 s
= strchr (name
, ':'); /* find device */
195 st
->st_dev
= (char *)vms_hash (name
);
206 st
->st_ino
[0] = h
& 0xff;
207 st
->st_ino
[1] = h
& 0xff00;
208 st
->st_ino
[2] = h
>> 16;
214 /* Hash table of directories. */
216 #ifndef DIRECTORY_BUCKETS
217 #define DIRECTORY_BUCKETS 199
220 struct directory_contents
222 dev_t dev
; /* Device and inode numbers of this dir. */
225 * Inode means nothing on WINDOWS32. Even file key information is
226 * unreliable because it is random per file open and undefined
227 * for remote filesystems. The most unique attribute I can
228 * come up with is the fully qualified name of the directory. Beware
229 * though, this is also unreliable. I'm open to suggestion on a better
230 * way to emulate inode.
234 int mtime
; /* controls check for stale directory cache */
235 int fs_flags
; /* FS_FAT, FS_NTFS, ... */
238 #define FS_UNKNOWN 0x4
245 #endif /* WINDOWS32 */
246 struct hash_table dirfiles
; /* Files in this directory. */
247 DIR *dirstream
; /* Stream reading this directory. */
251 directory_contents_hash_1 (void const *key_0
)
253 struct directory_contents
const *key
= (struct directory_contents
const *) key_0
;
257 ISTRING_HASH_1 (key
->path_key
, hash
);
258 hash
^= ((unsigned int) key
->dev
<< 4) ^ (unsigned int) key
->ctime
;
261 hash
= (((unsigned int) key
->dev
<< 4)
262 ^ ((unsigned int) key
->ino
[0]
263 + (unsigned int) key
->ino
[1]
264 + (unsigned int) key
->ino
[2]));
266 hash
= ((unsigned int) key
->dev
<< 4) ^ (unsigned int) key
->ino
;
268 #endif /* WINDOWS32 */
273 directory_contents_hash_2 (void const *key_0
)
275 struct directory_contents
const *key
= (struct directory_contents
const *) key_0
;
279 ISTRING_HASH_2 (key
->path_key
, hash
);
280 hash
^= ((unsigned int) key
->dev
<< 4) ^ (unsigned int) ~key
->ctime
;
283 hash
= (((unsigned int) key
->dev
<< 4)
284 ^ ~((unsigned int) key
->ino
[0]
285 + (unsigned int) key
->ino
[1]
286 + (unsigned int) key
->ino
[2]));
288 hash
= ((unsigned int) key
->dev
<< 4) ^ (unsigned int) ~key
->ino
;
290 #endif /* WINDOWS32 */
296 directory_contents_hash_cmp (void const *xv
, void const *yv
)
298 struct directory_contents
const *x
= (struct directory_contents
const *) xv
;
299 struct directory_contents
const *y
= (struct directory_contents
const *) yv
;
303 ISTRING_COMPARE (x
->path_key
, y
->path_key
, result
);
306 result
= x
->ctime
- y
->ctime
;
311 result
= x
->ino
[0] - y
->ino
[0];
314 result
= x
->ino
[1] - y
->ino
[1];
317 result
= x
->ino
[2] - y
->ino
[2];
321 result
= x
->ino
- y
->ino
;
325 #endif /* WINDOWS32 */
327 return x
->dev
- y
->dev
;
330 /* Table of directory contents hashed by device and inode number. */
331 static struct hash_table directory_contents
;
335 char *name
; /* Name of the directory. */
337 /* The directory's contents. This data may be shared by several
338 entries in the hash table, which refer to the same directory
339 (identified uniquely by `dev' and `ino') under different names. */
340 struct directory_contents
*contents
;
344 directory_hash_1 (void const *key
)
346 return_ISTRING_HASH_1 (((struct directory
const *) key
)->name
);
350 directory_hash_2 (void const *key
)
352 return_ISTRING_HASH_2 (((struct directory
const *) key
)->name
);
356 directory_hash_cmp (void const *x
, void const *y
)
358 return_ISTRING_COMPARE (((struct directory
const *) x
)->name
,
359 ((struct directory
const *) y
)->name
);
362 /* Table of directories hashed by name. */
363 static struct hash_table directories
;
365 /* Never have more than this many directories open at once. */
367 #define MAX_OPEN_DIRECTORIES 10
369 static unsigned int open_directories
= 0;
372 /* Hash table of files in each directory. */
376 char *name
; /* Name of the file. */
378 short impossible
; /* This file is impossible. */
382 dirfile_hash_1 (void const *key
)
384 return_ISTRING_HASH_1 (((struct dirfile
const *) key
)->name
);
388 dirfile_hash_2 (void const *key
)
390 return_ISTRING_HASH_2 (((struct dirfile
const *) key
)->name
);
394 dirfile_hash_cmp (void const *xv
, void const *yv
)
396 struct dirfile
const *x
= ((struct dirfile
const *) xv
);
397 struct dirfile
const *y
= ((struct dirfile
const *) yv
);
398 int result
= x
->length
- y
->length
;
401 return_ISTRING_COMPARE (x
->name
, y
->name
);
404 #ifndef DIRFILE_BUCKETS
405 #define DIRFILE_BUCKETS 107
408 static int dir_contents_file_exists_p
PARAMS ((struct directory_contents
*dir
, char *filename
));
409 static struct directory
*find_directory
PARAMS ((char *name
));
411 /* Find the directory named NAME and return its `struct directory'. */
413 static struct directory
*
414 find_directory (name
)
418 register struct directory
*dir
;
419 register struct directory
**dir_slot
;
420 struct directory dir_key
;
424 char fs_label
[BUFSIZ
];
425 char fs_type
[BUFSIZ
];
431 if ((*name
== '.') && (*(name
+1) == 0))
434 name
= vmsify (name
,1);
438 dir_slot
= (struct directory
**) hash_find_slot (&directories
, &dir_key
);
441 if (HASH_VACANT (dir
))
445 /* The directory was not found. Create a new entry for it. */
447 p
= name
+ strlen (name
);
448 dir
= (struct directory
*) xmalloc (sizeof (struct directory
));
449 dir
->name
= savestring (name
, p
- name
);
450 hash_insert_at (&directories
, dir
, dir_slot
);
451 /* The directory is not in the name hash table.
452 Find its device and inode numbers, and look it up by them. */
455 /* Remove any trailing '\'. Windows32 stat fails even on valid
456 directories if they end in '\'. */
462 r
= vmsstat_dir (name
, &st
);
464 r
= stat (name
, &st
);
468 /* Put back the trailing '\'. If we don't, we're permanently
469 truncating the value! */
476 /* Couldn't stat the directory. Mark this by
477 setting the `contents' member to a nil pointer. */
482 /* Search the contents hash table; device and inode are the key. */
484 struct directory_contents
*dc
;
485 struct directory_contents
**dc_slot
;
486 struct directory_contents dc_key
;
488 dc_key
.dev
= st
.st_dev
;
490 dc_key
.path_key
= w32_path
= w32ify (name
, 1);
491 dc_key
.ctime
= st
.st_ctime
;
494 dc_key
.ino
[0] = st
.st_ino
[0];
495 dc_key
.ino
[1] = st
.st_ino
[1];
496 dc_key
.ino
[2] = st
.st_ino
[2];
498 dc_key
.ino
= st
.st_ino
;
501 dc_slot
= (struct directory_contents
**) hash_find_slot (&directory_contents
, &dc_key
);
504 if (HASH_VACANT (dc
))
506 /* Nope; this really is a directory we haven't seen before. */
508 dc
= (struct directory_contents
*)
509 xmalloc (sizeof (struct directory_contents
));
511 /* Enter it in the contents hash table. */
514 dc
->path_key
= xstrdup (w32_path
);
515 dc
->ctime
= st
.st_ctime
;
516 dc
->mtime
= st
.st_mtime
;
519 * NTFS is the only WINDOWS32 filesystem that bumps mtime
520 * on a directory when files are added/deleted from
524 if (GetVolumeInformation(w32_path
,
525 fs_label
, sizeof (fs_label
),
527 &fs_flags
, fs_type
, sizeof (fs_type
)) == FALSE
)
528 dc
->fs_flags
= FS_UNKNOWN
;
529 else if (!strcmp(fs_type
, "FAT"))
530 dc
->fs_flags
= FS_FAT
;
531 else if (!strcmp(fs_type
, "NTFS"))
532 dc
->fs_flags
= FS_NTFS
;
534 dc
->fs_flags
= FS_UNKNOWN
;
537 dc
->ino
[0] = st
.st_ino
[0];
538 dc
->ino
[1] = st
.st_ino
[1];
539 dc
->ino
[2] = st
.st_ino
[2];
543 #endif /* WINDOWS32 */
544 hash_insert_at (&directory_contents
, dc
, dc_slot
);
545 dc
->dirstream
= opendir (name
);
546 if (dc
->dirstream
== 0)
547 /* Couldn't open the directory. Mark this by
548 setting the `files' member to a nil pointer. */
549 dc
->dirfiles
.ht_vec
= 0;
552 hash_init (&dc
->dirfiles
, DIRFILE_BUCKETS
,
553 dirfile_hash_1
, dirfile_hash_2
, dirfile_hash_cmp
);
554 /* Keep track of how many directories are open. */
556 if (open_directories
== MAX_OPEN_DIRECTORIES
)
557 /* We have too many directories open already.
558 Read the entire directory and then close it. */
559 (void) dir_contents_file_exists_p (dc
, (char *) 0);
563 /* Point the name-hashed entry for DIR at its contents data. */
571 /* Return 1 if the name FILENAME is entered in DIR's hash table.
572 FILENAME must contain no slashes. */
575 dir_contents_file_exists_p (dir
, filename
)
576 register struct directory_contents
*dir
;
577 register char *filename
;
587 if (dir
== 0 || dir
->dirfiles
.ht_vec
== 0)
589 /* The directory could not be stat'd or opened. */
593 filename
= dosify (filename
);
596 #ifdef HAVE_CASE_INSENSITIVE_FS
597 filename
= downcase (filename
);
601 filename
= vmsify (filename
,0);
607 struct dirfile dirfile_key
;
609 if (*filename
== '\0')
611 /* Checking if the directory exists. */
614 dirfile_key
.name
= filename
;
615 dirfile_key
.length
= strlen (filename
);
616 df
= (struct dirfile
*) hash_find_item (&dir
->dirfiles
, &dirfile_key
);
619 return !df
->impossible
;
623 /* The file was not found in the hashed list.
624 Try to read the directory further. */
626 if (dir
->dirstream
== 0)
630 * Check to see if directory has changed since last read. FAT
631 * filesystems force a rehash always as mtime does not change
632 * on directories (ugh!).
635 && (dir
->fs_flags
& FS_FAT
636 || (stat(dir
->path_key
, &st
) == 0
637 && st
.st_mtime
> dir
->mtime
)))
639 /* reset date stamp to show most recent re-process */
640 dir
->mtime
= st
.st_mtime
;
642 /* make sure directory can still be opened */
643 dir
->dirstream
= opendir(dir
->path_key
);
648 return 0; /* couldn't re-read - fail */
652 /* The directory has been all read in. */
656 while ((d
= readdir (dir
->dirstream
)) != 0)
658 /* Enter the file in the hash table. */
660 struct dirfile dirfile_key
;
661 struct dirfile
**dirfile_slot
;
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
, ';');
671 if (!REAL_DIR_ENTRY (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
);
680 * If re-reading a directory, don't cache files that have
681 * already been discovered.
683 if (! rehash
|| HASH_VACANT (*dirfile_slot
))
686 df
= (struct dirfile
*) xmalloc (sizeof (struct dirfile
));
687 df
->name
= savestring (d
->d_name
, len
);
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
))
699 /* If the directory has been completely read in,
700 close the stream and reset the pointer to nil. */
704 closedir (dir
->dirstream
);
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 (dirname
, filename
)
716 register char *dirname
;
717 register char *filename
;
719 return dir_contents_file_exists_p (find_directory (dirname
)->contents
,
723 /* Return 1 if the file named NAME exists. */
735 return ar_member_date (name
) != (time_t) -1;
739 dirend
= strrchr (name
, ']');
741 dirend
= strrchr (name
, ':');
743 if (dirend
== (char *)1)
744 return dir_file_exists_p ("[]", name
);
746 dirend
= strrchr (name
, '/');
747 #ifdef HAVE_DOS_PATHS
748 /* Forward and backslashes might be mixed. We need the rightmost one. */
750 char *bslash
= strrchr(name
, '\\');
751 if (!dirend
|| bslash
> dirend
)
753 /* The case of "d:file". */
754 if (!dirend
&& name
[0] && name
[1] == ':')
757 #endif /* HAVE_DOS_PATHS */
760 return dir_file_exists_p (".", name
);
761 #else /* !VMS && !AMIGA */
762 return dir_file_exists_p ("", name
);
771 #ifdef HAVE_DOS_PATHS
772 /* d:/ and d: are *very* different... */
773 if (dirend
< name
+ 3 && name
[1] == ':' &&
774 (*dirend
== '/' || *dirend
== '\\' || *dirend
== ':'))
777 dirname
= (char *) alloca (dirend
- name
+ 1);
778 bcopy (name
, dirname
, dirend
- name
);
779 dirname
[dirend
- name
] = '\0';
781 return dir_file_exists_p (dirname
, slash
+ 1);
784 /* Mark FILENAME as `impossible' for `file_impossible_p'.
785 This means an attempt has been made to search for FILENAME
786 as an intermediate file, and it has failed. */
789 file_impossible (filename
)
790 register char *filename
;
793 register char *p
= filename
;
794 register struct directory
*dir
;
795 register struct dirfile
*new;
798 dirend
= strrchr (p
, ']');
800 dirend
= strrchr (p
, ':');
802 if (dirend
== (char *)1)
803 dir
= find_directory ("[]");
805 dirend
= strrchr (p
, '/');
806 # ifdef HAVE_DOS_PATHS
807 /* Forward and backslashes might be mixed. We need the rightmost one. */
809 char *bslash
= strrchr(p
, '\\');
810 if (!dirend
|| bslash
> dirend
)
812 /* The case of "d:file". */
813 if (!dirend
&& p
[0] && p
[1] == ':')
816 # endif /* HAVE_DOS_PATHS */
819 dir
= find_directory ("");
820 # else /* !VMS && !AMIGA */
821 dir
= find_directory (".");
827 char *slash
= dirend
;
832 #ifdef HAVE_DOS_PATHS
833 /* d:/ and d: are *very* different... */
834 if (dirend
< p
+ 3 && p
[1] == ':' &&
835 (*dirend
== '/' || *dirend
== '\\' || *dirend
== ':'))
838 dirname
= (char *) alloca (dirend
- p
+ 1);
839 bcopy (p
, dirname
, dirend
- p
);
840 dirname
[dirend
- p
] = '\0';
842 dir
= find_directory (dirname
);
843 filename
= p
= slash
+ 1;
846 if (dir
->contents
== 0)
848 /* The directory could not be stat'd. We allocate a contents
849 structure for it, but leave it out of the contents hash table. */
850 dir
->contents
= (struct directory_contents
*)
851 xmalloc (sizeof (struct directory_contents
));
852 bzero ((char *) dir
->contents
, sizeof (struct directory_contents
));
855 if (dir
->contents
->dirfiles
.ht_vec
== 0)
857 hash_init (&dir
->contents
->dirfiles
, DIRFILE_BUCKETS
,
858 dirfile_hash_1
, dirfile_hash_2
, dirfile_hash_cmp
);
861 /* Make a new entry and put it in the table. */
863 new = (struct dirfile
*) xmalloc (sizeof (struct dirfile
));
864 new->name
= xstrdup (filename
);
865 new->length
= strlen (filename
);
867 hash_insert (&dir
->contents
->dirfiles
, new);
870 /* Return nonzero if FILENAME has been marked impossible. */
873 file_impossible_p (filename
)
877 register char *p
= filename
;
878 register struct directory_contents
*dir
;
879 register struct dirfile
*dirfile
;
880 struct dirfile dirfile_key
;
883 dirend
= strrchr (filename
, ']');
885 dir
= find_directory ("[]")->contents
;
887 dirend
= strrchr (filename
, '/');
888 #ifdef HAVE_DOS_PATHS
889 /* Forward and backslashes might be mixed. We need the rightmost one. */
891 char *bslash
= strrchr(filename
, '\\');
892 if (!dirend
|| bslash
> dirend
)
894 /* The case of "d:file". */
895 if (!dirend
&& filename
[0] && filename
[1] == ':')
896 dirend
= filename
+ 1;
898 #endif /* HAVE_DOS_PATHS */
901 dir
= find_directory ("")->contents
;
902 #else /* !VMS && !AMIGA */
903 dir
= find_directory (".")->contents
;
909 char *slash
= dirend
;
910 if (dirend
== filename
)
914 #ifdef HAVE_DOS_PATHS
915 /* d:/ and d: are *very* different... */
916 if (dirend
< filename
+ 3 && filename
[1] == ':' &&
917 (*dirend
== '/' || *dirend
== '\\' || *dirend
== ':'))
920 dirname
= (char *) alloca (dirend
- filename
+ 1);
921 bcopy (p
, dirname
, dirend
- p
);
922 dirname
[dirend
- p
] = '\0';
924 dir
= find_directory (dirname
)->contents
;
925 p
= filename
= slash
+ 1;
928 if (dir
== 0 || dir
->dirfiles
.ht_vec
== 0)
929 /* There are no files entered for this directory. */
933 filename
= dosify (p
);
935 #ifdef HAVE_CASE_INSENSITIVE_FS
936 filename
= downcase (p
);
939 filename
= vmsify (p
, 1);
942 dirfile_key
.name
= filename
;
943 dirfile_key
.length
= strlen (filename
);
944 dirfile
= (struct dirfile
*) hash_find_item (&dir
->dirfiles
, &dirfile_key
);
946 return dirfile
->impossible
;
951 /* Return the already allocated name in the
952 directory hash table that matches DIR. */
958 return find_directory (dir
)->name
;
961 /* Print the data base of directories. */
964 print_dir_data_base ()
966 register unsigned int files
;
967 register unsigned int impossible
;
968 register struct directory
**dir_slot
;
969 register struct directory
**dir_end
;
971 puts (_("\n# Directories\n"));
973 files
= impossible
= 0;
975 dir_slot
= (struct directory
**) directories
.ht_vec
;
976 dir_end
= dir_slot
+ directories
.ht_size
;
977 for ( ; dir_slot
< dir_end
; dir_slot
++)
979 register struct directory
*dir
= *dir_slot
;
980 if (! HASH_VACANT (dir
))
982 if (dir
->contents
== 0)
983 printf (_("# %s: could not be stat'd.\n"), dir
->name
);
984 else if (dir
->contents
->dirfiles
.ht_vec
== 0)
987 printf (_("# %s (key %s, mtime %d): could not be opened.\n"),
988 dir
->name
, dir
->contents
->path_key
,dir
->contents
->mtime
);
989 #else /* WINDOWS32 */
991 printf (_("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n"),
992 dir
->name
, dir
->contents
->dev
,
993 dir
->contents
->ino
[0], dir
->contents
->ino
[1],
994 dir
->contents
->ino
[2]);
996 printf (_("# %s (device %ld, inode %ld): could not be opened.\n"),
997 dir
->name
, (long int) dir
->contents
->dev
,
998 (long int) dir
->contents
->ino
);
1000 #endif /* WINDOWS32 */
1004 register unsigned int f
= 0;
1005 register unsigned int im
= 0;
1006 register struct dirfile
**files_slot
;
1007 register struct dirfile
**files_end
;
1009 files_slot
= (struct dirfile
**) dir
->contents
->dirfiles
.ht_vec
;
1010 files_end
= files_slot
+ dir
->contents
->dirfiles
.ht_size
;
1011 for ( ; files_slot
< files_end
; files_slot
++)
1013 register struct dirfile
*df
= *files_slot
;
1014 if (! HASH_VACANT (df
))
1023 printf (_("# %s (key %s, mtime %d): "),
1024 dir
->name
, dir
->contents
->path_key
, dir
->contents
->mtime
);
1025 #else /* WINDOWS32 */
1027 printf (_("# %s (device %d, inode [%d,%d,%d]): "),
1028 dir
->name
, dir
->contents
->dev
,
1029 dir
->contents
->ino
[0], dir
->contents
->ino
[1],
1030 dir
->contents
->ino
[2]);
1032 printf (_("# %s (device %ld, inode %ld): "),
1034 (long)dir
->contents
->dev
, (long)dir
->contents
->ino
);
1036 #endif /* WINDOWS32 */
1038 fputs (_("No"), stdout
);
1041 fputs (_(" files, "), stdout
);
1043 fputs (_("no"), stdout
);
1046 fputs (_(" impossibilities"), stdout
);
1047 if (dir
->contents
->dirstream
== 0)
1050 puts (_(" so far."));
1057 fputs ("\n# ", stdout
);
1059 fputs (_("No"), stdout
);
1061 printf ("%u", files
);
1062 fputs (_(" files, "), stdout
);
1063 if (impossible
== 0)
1064 fputs (_("no"), stdout
);
1066 printf ("%u", impossible
);
1067 printf (_(" impossibilities in %lu directories.\n"), directories
.ht_fill
);
1070 /* Hooks for globbing. */
1074 /* Structure describing state of iterating through a directory hash table. */
1078 struct directory_contents
*contents
; /* The directory being read. */
1079 struct dirfile
**dirfile_slot
; /* Current slot in table. */
1082 /* Forward declarations. */
1083 static __ptr_t open_dirstream
PARAMS ((const char *));
1084 static struct dirent
*read_dirstream
PARAMS ((__ptr_t
));
1087 open_dirstream (directory
)
1088 const char *directory
;
1090 struct dirstream
*new;
1091 struct directory
*dir
= find_directory ((char *)directory
);
1093 if (dir
->contents
== 0 || dir
->contents
->dirfiles
.ht_vec
== 0)
1094 /* DIR->contents is nil if the directory could not be stat'd.
1095 DIR->contents->dirfiles is nil if it could not be opened. */
1098 /* Read all the contents of the directory now. There is no benefit
1099 in being lazy, since glob will want to see every file anyway. */
1101 (void) dir_contents_file_exists_p (dir
->contents
, (char *) 0);
1103 new = (struct dirstream
*) xmalloc (sizeof (struct dirstream
));
1104 new->contents
= dir
->contents
;
1105 new->dirfile_slot
= (struct dirfile
**) new->contents
->dirfiles
.ht_vec
;
1107 return (__ptr_t
) new;
1110 static struct dirent
*
1111 read_dirstream (stream
)
1114 struct dirstream
*const ds
= (struct dirstream
*) stream
;
1115 struct directory_contents
*dc
= ds
->contents
;
1116 struct dirfile
**dirfile_end
= (struct dirfile
**) dc
->dirfiles
.ht_vec
+ dc
->dirfiles
.ht_size
;
1118 static unsigned int bufsz
;
1120 while (ds
->dirfile_slot
< dirfile_end
)
1122 register struct dirfile
*df
= *ds
->dirfile_slot
++;
1123 if (! HASH_VACANT (df
) && !df
->impossible
)
1125 /* The glob interface wants a `struct dirent',
1128 unsigned int len
= df
->length
+ 1;
1129 if (sizeof *d
- sizeof d
->d_name
+ len
> bufsz
)
1134 if (sizeof *d
- sizeof d
->d_name
+ len
> bufsz
)
1135 bufsz
= sizeof *d
- sizeof d
->d_name
+ len
;
1136 buf
= xmalloc (bufsz
);
1138 d
= (struct dirent
*) buf
;
1140 #ifdef _DIRENT_HAVE_D_NAMLEN
1141 d
->d_namlen
= len
- 1;
1143 #ifdef _DIRENT_HAVE_D_TYPE
1144 d
->d_type
= DT_UNKNOWN
;
1146 memcpy (d
->d_name
, df
->name
, len
);
1162 /* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a
1163 * macro for stat64(). If stat is a macro, make a local wrapper function to
1170 # define local_stat stat
1172 static int local_stat (path
, buf
)
1176 return stat (path
, buf
);
1184 /* Bogus sunos4 compiler complains (!) about & before functions. */
1185 gl
->gl_opendir
= open_dirstream
;
1186 gl
->gl_readdir
= read_dirstream
;
1187 gl
->gl_closedir
= ansi_free
;
1188 gl
->gl_stat
= local_stat
;
1189 /* We don't bother setting gl_lstat, since glob never calls it.
1190 The slot is only there for compatibility with 4.4 BSD. */
1194 hash_init_directories ()
1196 hash_init (&directories
, DIRECTORY_BUCKETS
,
1197 directory_hash_1
, directory_hash_2
, directory_hash_cmp
);
1198 hash_init (&directory_contents
, DIRECTORY_BUCKETS
,
1199 directory_contents_hash_1
, directory_contents_hash_2
, directory_contents_hash_cmp
);