XEmacs 21.2.4
[chise/xemacs-chise.git.1] / src / dired.c
1  /* Lisp functions for making directory listings.
2    Copyright (C) 1985, 1986, 1992, 1993, 1994 Free Software Foundation, Inc.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; 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.  */
20
21 /* Synched up with: FSF 19.30. */
22
23 #include <config.h>
24 #include "lisp.h"
25
26 #include "buffer.h"
27 #include "commands.h"
28 #include "elhash.h"
29 #include "regex.h"
30 #include "opaque.h"
31 #include "sysfile.h"
32 #include "sysdir.h"
33 #include "systime.h"
34 #include "syspwd.h"
35
36 Lisp_Object Vcompletion_ignored_extensions;
37 Lisp_Object Qdirectory_files;
38 Lisp_Object Qfile_name_completion;
39 Lisp_Object Qfile_name_all_completions;
40 Lisp_Object Qfile_attributes;
41 \f
42 static Lisp_Object
43 close_directory_unwind (Lisp_Object unwind_obj)
44 {
45   DIR *d = (DIR *)get_opaque_ptr (unwind_obj);
46   closedir (d);
47   free_opaque_ptr (unwind_obj);
48   return Qnil;
49 }
50
51 DEFUN ("directory-files", Fdirectory_files, 1, 5, 0, /*
52 Return a list of names of files in DIRECTORY.
53 There are four optional arguments:
54 If FULL is non-nil, absolute pathnames of the files are returned.
55 If MATCH is non-nil, only pathnames containing that regexp are returned.
56 If NOSORT is non-nil, the list is not sorted--its order is unpredictable.
57  NOSORT is useful if you plan to sort the result yourself.
58 If FILES-ONLY is the symbol t, then only the "files" in the directory
59  will be returned; subdirectories will be excluded.  If FILES-ONLY is not
60  nil and not t, then only the subdirectories will be returned.  Otherwise,
61  if FILES-ONLY is nil (the default) then both files and subdirectories will
62  be returned.
63 */
64        (dirname, full, match, nosort, files_only))
65 {
66   /* This function can GC */
67   DIR *d;
68   Lisp_Object list = Qnil;
69   Bytecount dirnamelen;
70   Lisp_Object handler;
71   struct re_pattern_buffer *bufp = NULL;
72   int speccount = specpdl_depth ();
73   char *statbuf, *statbuf_tail;
74
75   struct gcpro gcpro1, gcpro2;
76   GCPRO2 (dirname, list);
77
78   /* If the file name has special constructs in it,
79      call the corresponding file handler.  */
80   handler = Ffind_file_name_handler (dirname, Qdirectory_files);
81   if (!NILP (handler))
82     {
83       UNGCPRO;
84       if (!NILP (files_only))
85         return call6 (handler, Qdirectory_files, dirname, full, match, nosort,
86                       files_only);
87       else
88         return call5 (handler, Qdirectory_files, dirname, full, match,
89                       nosort);
90     }
91
92   /* #### why do we do Fexpand_file_name after file handlers here,
93      but earlier everywhere else? */
94   dirname = Fexpand_file_name (dirname, Qnil);
95   dirname = Ffile_name_as_directory (dirname);
96   dirnamelen = XSTRING_LENGTH (dirname);
97
98   statbuf = (char *)alloca (dirnamelen + MAXNAMLEN + 1);
99   memcpy (statbuf, XSTRING_DATA (dirname), dirnamelen);
100   statbuf_tail = statbuf + dirnamelen;
101
102   /* XEmacs: this should come after Ffile_name_as_directory() to avoid
103      potential regexp cache smashage.  It comes before the opendir()
104      because it might signal an error.  */
105   if (!NILP (match))
106     {
107       CHECK_STRING (match);
108
109       /* MATCH might be a flawed regular expression.  Rather than
110          catching and signalling our own errors, we just call
111          compile_pattern to do the work for us.  */
112       bufp = compile_pattern (match, 0, 0, 0, ERROR_ME);
113     }
114
115   /* Now *bufp is the compiled form of MATCH; don't call anything
116      which might compile a new regexp until we're done with the loop!  */
117
118   /* Do this opendir after anything which might signal an error.
119      NOTE: the above comment is old; previosly, there was no
120      unwind-protection in case of error, but now there is.  */
121   d = opendir ((char *) XSTRING_DATA (dirname));
122   if (!d)
123     report_file_error ("Opening directory", list1 (dirname));
124
125   record_unwind_protect (close_directory_unwind, make_opaque_ptr ((void *)d));
126
127   /* Loop reading blocks */
128   while (1)
129     {
130       DIRENTRY *dp = readdir (d);
131       Lisp_Object name;
132       int len;
133
134       if (!dp)
135         break;
136       len = NAMLEN (dp);
137       if (DIRENTRY_NONEMPTY (dp)
138           && (NILP (match)
139               || (0 <= re_search (bufp, dp->d_name, len, 0, len, 0))))
140         {
141           if (!NILP (files_only))
142             {
143               int dir_p;
144               struct stat st;
145               char *cur_statbuf = statbuf;
146               char *cur_statbuf_tail = statbuf_tail;
147
148               /* #### I don't think the code under `if' is necessary
149                  anymore.  The crashes in this function were reported
150                  because MAXNAMLEN was used to remember the *whole*
151                  statbuf, instead of using MAXPATHLEN.  This should be
152                  tested after 21.0 is released.  */
153
154               /* We normally use the buffer created by alloca.
155                  However, if the file name we get too big, we'll use a
156                  malloced buffer, and free it.  It is undefined how
157                  stat() will react to this, but we avoid a buffer
158                  overrun.  */
159               if (len > MAXNAMLEN)
160                 {
161                   cur_statbuf = (char *)xmalloc (dirnamelen + len + 1);
162                   memcpy (cur_statbuf, statbuf, dirnamelen);
163                   cur_statbuf_tail = cur_statbuf + dirnamelen;
164                 }
165               memcpy (cur_statbuf_tail, dp->d_name, len);
166               cur_statbuf_tail[len] = 0;
167
168               if (stat (cur_statbuf, &st) < 0)
169                 dir_p = 0;
170               else
171                 dir_p = ((st.st_mode & S_IFMT) == S_IFDIR);
172
173               if (cur_statbuf != statbuf)
174                 xfree (cur_statbuf);
175
176               if (EQ (files_only, Qt) && dir_p)
177                 continue;
178               else if (!EQ (files_only, Qt) && !dir_p)
179                 continue;
180             }
181
182           if (!NILP (full))
183             name = concat2 (dirname, make_ext_string ((Bufbyte *)dp->d_name,
184                                                       len, FORMAT_FILENAME));
185           else
186             name = make_ext_string ((Bufbyte *)dp->d_name,
187                                     len, FORMAT_FILENAME);
188
189           list = Fcons (name, list);
190         }
191     }
192   unbind_to (speccount, Qnil);  /* This will close the dir */
193
194   if (!NILP (nosort))
195     RETURN_UNGCPRO (list);
196   else
197     RETURN_UNGCPRO (Fsort (Fnreverse (list), Qstring_lessp));
198 }
199 \f
200 static Lisp_Object file_name_completion (Lisp_Object file,
201                                          Lisp_Object dirname,
202                                          int all_flag, int ver_flag);
203
204 DEFUN ("file-name-completion", Ffile_name_completion, 2, 2, 0, /*
205 Complete file name FILE in directory DIR.
206 Returns the longest string common to all filenames in DIR
207 that start with FILE.
208 If there is only one and FILE matches it exactly, returns t.
209 Returns nil if DIR contains no name starting with FILE.
210
211 Filenames which end with any member of `completion-ignored-extensions'
212 are not considered as possible completions for FILE unless there is no
213 other possible completion.  `completion-ignored-extensions' is not applied
214 to the names of directories.
215 */
216        (file, dirname))
217 {
218   /* This function can GC.  GC checked 1996.04.06. */
219   Lisp_Object handler;
220
221   /* If the directory name has special constructs in it,
222      call the corresponding file handler.  */
223   handler = Ffind_file_name_handler (dirname, Qfile_name_completion);
224   if (!NILP (handler))
225     return call3 (handler, Qfile_name_completion, file, dirname);
226
227   /* If the file name has special constructs in it,
228      call the corresponding file handler.  */
229   handler = Ffind_file_name_handler (file, Qfile_name_completion);
230   if (!NILP (handler))
231     return call3 (handler, Qfile_name_completion, file, dirname);
232
233   return file_name_completion (file, dirname, 0, 0);
234 }
235
236 DEFUN ("file-name-all-completions", Ffile_name_all_completions, 2, 2, 0, /*
237 Return a list of all completions of file name FILE in directory DIR.
238 These are all file names in directory DIR which begin with FILE.
239
240 Filenames which end with any member of `completion-ignored-extensions'
241 are not considered as possible completions for FILE unless there is no
242 other possible completion.  `completion-ignored-extensions' is not applied
243 to the names of directories.
244 */
245        (file, dirname))
246 {
247   /* This function can GC. GC checked 1997.06.04. */
248   Lisp_Object handler;
249   struct gcpro gcpro1;
250
251   GCPRO1 (dirname);
252   dirname = Fexpand_file_name (dirname, Qnil);
253   /* If the file name has special constructs in it,
254      call the corresponding file handler.  */
255   handler = Ffind_file_name_handler (dirname, Qfile_name_all_completions);
256   UNGCPRO;
257   if (!NILP (handler))
258     return call3 (handler, Qfile_name_all_completions, file,
259                   dirname);
260
261   return file_name_completion (file, dirname, 1, 0);
262 }
263
264 static int
265 file_name_completion_stat (Lisp_Object dirname, DIRENTRY *dp,
266                            struct stat *st_addr)
267 {
268   Bytecount len = NAMLEN (dp);
269   Bytecount pos = XSTRING_LENGTH (dirname);
270   int value;
271   char *fullname = (char *) alloca (len + pos + 2);
272
273   memcpy (fullname, XSTRING_DATA (dirname), pos);
274   if (!IS_DIRECTORY_SEP (fullname[pos - 1]))
275     fullname[pos++] = DIRECTORY_SEP;
276
277   memcpy (fullname + pos, dp->d_name, len);
278   fullname[pos + len] = 0;
279
280 #ifdef S_IFLNK
281   /* We want to return success if a link points to a nonexistent file,
282      but we want to return the status for what the link points to,
283      in case it is a directory.  */
284   value = lstat (fullname, st_addr);
285   if (S_ISLNK (st_addr->st_mode))
286     stat (fullname, st_addr);
287 #else
288   value = stat (fullname, st_addr);
289 #endif
290   return value;
291 }
292
293 static Lisp_Object
294 file_name_completion_unwind (Lisp_Object locative)
295 {
296   DIR *d;
297   Lisp_Object obj = XCAR (locative);
298
299   if (!NILP (obj))
300     {
301       d = (DIR *)get_opaque_ptr (obj);
302       closedir (d);
303       free_opaque_ptr (obj);
304     }
305   free_cons (XCONS (locative));
306   return Qnil;
307 }
308
309 static Lisp_Object
310 file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag,
311                       int ver_flag)
312 {
313   /* This function can GC */
314   DIR *d = 0;
315   int matchcount = 0;
316   Lisp_Object bestmatch = Qnil;
317   Charcount bestmatchsize = 0;
318   struct stat st;
319   int passcount;
320   int speccount = specpdl_depth ();
321   Charcount file_name_length;
322   Lisp_Object locative;
323   struct gcpro gcpro1, gcpro2, gcpro3;
324
325   GCPRO3 (file, dirname, bestmatch);
326
327   CHECK_STRING (file);
328
329 #ifdef WINDOWSNT
330   /* Filename completion on Windows ignores case, since Windows
331      filesystems do.  */
332   specbind (Qcompletion_ignore_case, Qt);
333 #endif /* WINDOWSNT */
334
335 #ifdef FILE_SYSTEM_CASE
336   file = FILE_SYSTEM_CASE (file);
337 #endif
338   dirname = Fexpand_file_name (dirname, Qnil);
339   file_name_length = XSTRING_CHAR_LENGTH (file);
340
341   /* With passcount = 0, ignore files that end in an ignored extension.
342      If nothing found then try again with passcount = 1, don't ignore them.
343      If looking for all completions, start with passcount = 1,
344      so always take even the ignored ones.
345
346      ** It would not actually be helpful to the user to ignore any possible
347      completions when making a list of them.**  */
348
349   /* We cannot use close_directory_unwind() because we change the
350      directory.  The old code used to just avoid signaling errors, and
351      call closedir, but it was wrong, because it made sane handling of
352      QUIT impossible and, besides, various utility functions like
353      regexp_ignore_completion_p can signal errors.  */
354   locative = noseeum_cons (Qnil, Qnil);
355   record_unwind_protect (file_name_completion_unwind, locative);
356
357   for (passcount = !!all_flag; NILP (bestmatch) && passcount < 2; passcount++)
358     {
359       d = opendir ((char *) XSTRING_DATA (Fdirectory_file_name (dirname)));
360       if (!d)
361         report_file_error ("Opening directory", list1 (dirname));
362       XCAR (locative) = make_opaque_ptr ((void *)d);
363
364       /* Loop reading blocks */
365       while (1)
366         {
367           DIRENTRY *dp;
368           Bytecount len;
369           /* scmp() works in characters, not bytes, so we have to compute
370              this value: */
371           Charcount cclen;
372           int directoryp;
373           int ignored_extension_p = 0;
374           Bufbyte *d_name;
375
376           dp = readdir (d);
377           if (!dp) break;
378
379           /* Cast to Bufbyte* is OK, as readdir() Mule-encapsulates.  */
380           d_name = (Bufbyte *) dp->d_name;
381           len = NAMLEN (dp);
382           cclen = bytecount_to_charcount (d_name, len);
383
384           QUIT;
385
386           if (! DIRENTRY_NONEMPTY (dp)
387               || cclen < file_name_length
388               || 0 <= scmp (d_name, XSTRING_DATA (file), file_name_length))
389             continue;
390
391           if (file_name_completion_stat (dirname, dp, &st) < 0)
392             continue;
393
394           directoryp = ((st.st_mode & S_IFMT) == S_IFDIR);
395           if (directoryp)
396             {
397 #ifndef TRIVIAL_DIRECTORY_ENTRY
398 #define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, ".."))
399 #endif
400               /* "." and ".." are never interesting as completions, but are
401                  actually in the way in a directory containing only one file.  */
402               if (!passcount && TRIVIAL_DIRECTORY_ENTRY (dp->d_name))
403                 continue;
404             }
405           else
406             {
407               /* Compare extensions-to-be-ignored against end of this file name */
408               /* if name is not an exact match against specified string.  */
409               if (!passcount && cclen > file_name_length)
410                 {
411                   Lisp_Object tem;
412                   /* and exit this for loop if a match is found */
413                   EXTERNAL_LIST_LOOP (tem, Vcompletion_ignored_extensions)
414                     {
415                       Lisp_Object elt = XCAR (tem);
416                       Charcount skip;
417
418                       CHECK_STRING (elt);
419
420                       skip = cclen - XSTRING_CHAR_LENGTH (elt);
421                       if (skip < 0) continue;
422
423                       if (0 > scmp (charptr_n_addr (d_name, skip),
424                                     XSTRING_DATA (elt),
425                                     XSTRING_CHAR_LENGTH (elt)))
426                         {
427                           ignored_extension_p = 1;
428                           break;
429                         }
430                     }
431                 }
432             }
433
434           /* If an ignored-extensions match was found,
435              don't process this name as a completion.  */
436           if (!passcount && ignored_extension_p)
437             continue;
438
439           if (!passcount && regexp_ignore_completion_p (d_name, Qnil, 0, cclen))
440             continue;
441
442           /* Update computation of how much all possible completions match */
443           matchcount++;
444
445           if (all_flag || NILP (bestmatch))
446             {
447               Lisp_Object name = Qnil;
448               struct gcpro ngcpro1;
449               NGCPRO1 (name);
450               /* This is a possible completion */
451               name = make_string (d_name, len);
452               if (directoryp) /* Completion is a directory; end it with '/' */
453                 name = Ffile_name_as_directory (name);
454               if (all_flag)
455                 {
456                   bestmatch = Fcons (name, bestmatch);
457                 }
458               else
459                 {
460                   bestmatch = name;
461                   bestmatchsize = XSTRING_CHAR_LENGTH (name);
462                 }
463               NUNGCPRO;
464             }
465           else
466             {
467               Charcount compare = min (bestmatchsize, cclen);
468               Bufbyte *p1 = XSTRING_DATA (bestmatch);
469               Bufbyte *p2 = d_name;
470               Charcount matchsize = scmp (p1, p2, compare);
471
472               if (matchsize < 0)
473                 matchsize = compare;
474               if (completion_ignore_case)
475                 {
476                   /* If this is an exact match except for case,
477                      use it as the best match rather than one that is not
478                      an exact match.  This way, we get the case pattern
479                      of the actual match.  */
480                   if ((matchsize == cclen
481                        && matchsize + !!directoryp
482                        < XSTRING_CHAR_LENGTH (bestmatch))
483                       ||
484                       /* If there is no exact match ignoring case,
485                          prefer a match that does not change the case
486                          of the input.  */
487                       (((matchsize == cclen)
488                         ==
489                         (matchsize + !!directoryp
490                          == XSTRING_CHAR_LENGTH (bestmatch)))
491                        /* If there is more than one exact match aside from
492                           case, and one of them is exact including case,
493                           prefer that one.  */
494                        && 0 > scmp_1 (p2, XSTRING_DATA (file),
495                                       file_name_length, 0)
496                        && 0 <= scmp_1 (p1, XSTRING_DATA (file),
497                                        file_name_length, 0)))
498                     {
499                       bestmatch = make_string (d_name, len);
500                       if (directoryp)
501                         bestmatch = Ffile_name_as_directory (bestmatch);
502                     }
503                 }
504
505               /* If this dirname all matches,
506                  see if implicit following slash does too.  */
507               if (directoryp
508                   && compare == matchsize
509                   && bestmatchsize > matchsize
510                   && IS_ANY_SEP (charptr_emchar_n (p1, matchsize)))
511                 matchsize++;
512               bestmatchsize = matchsize;
513             }
514         }
515       closedir (d);
516       free_opaque_ptr (XCAR (locative));
517       XCAR (locative) = Qnil;
518     }
519
520   unbind_to (speccount, Qnil);
521
522   UNGCPRO;
523
524   if (all_flag || NILP (bestmatch))
525     return bestmatch;
526   if (matchcount == 1 && bestmatchsize == file_name_length)
527     return Qt;
528   return Fsubstring (bestmatch, Qzero, make_int (bestmatchsize));
529 }
530
531 \f
532
533 /* The *pwent() functions do not exist on NT */
534 #ifndef  WINDOWSNT
535
536 static Lisp_Object user_name_completion (Lisp_Object user,
537                                          int all_flag,
538                                          int *uniq);
539
540 DEFUN ("user-name-completion", Fuser_name_completion, 1, 1, 0, /*
541 Complete user name USER.
542
543 Returns the longest string common to all user names that start
544 with USER.  If there is only one and USER matches it exactly,
545 returns t.  Returns nil if there is no user name starting with USER.
546 */
547        (user))
548 {
549   return user_name_completion (user, 0, NULL);
550 }
551
552 DEFUN ("user-name-completion-1", Fuser_name_completion_1, 1, 1, 0, /*
553 Complete user name USER.
554
555 This function is identical to `user-name-completion', except that
556 the cons of the completion and an indication of whether the
557 completion was unique is returned.
558
559 The car of the returned value is the longest string common to all
560 user names that start with USER.  If there is only one and USER
561 matches it exactly, the car is t.  The car is nil if there is no
562 user name starting with USER.  The cdr of the result is non-nil
563 if and only if the completion returned in the car was unique.
564 */
565        (user))
566 {
567   int uniq;
568   Lisp_Object completed;
569
570   completed = user_name_completion (user, 0, &uniq);
571   return Fcons (completed, uniq ? Qt : Qnil);
572 }
573
574 DEFUN ("user-name-all-completions", Fuser_name_all_completions, 1, 1, 0, /*
575 Return a list of all completions of user name USER.
576 These are all user names which begin with USER.
577 */
578        (user))
579 {
580   return user_name_completion (user, 1, NULL);
581 }
582
583 static Lisp_Object
584 user_name_completion_unwind (Lisp_Object locative)
585 {
586   Lisp_Object obj1 = XCAR (locative);
587   Lisp_Object obj2 = XCDR (locative);
588   char **cache;
589   int clen, i;
590
591
592   if (!NILP (obj1) && !NILP (obj2))
593     {
594       /* clean up if interrupted building cache */
595       cache = *(char ***)get_opaque_ptr (obj1);
596       clen  = *(int *)get_opaque_ptr (obj2);
597       free_opaque_ptr (obj1);
598       free_opaque_ptr (obj2);
599       for (i = 0; i < clen; i++)
600         free (cache[i]);
601       free (cache);
602     }
603
604   free_cons (XCONS (locative));
605   endpwent ();
606
607   return Qnil;
608 }
609
610 static char **user_cache;
611 static int user_cache_len;
612 static int user_cache_max;
613 static long user_cache_time;
614
615 #define  USER_CACHE_REBUILD  (24*60*60)  /* 1 day, in seconds */
616
617 static Lisp_Object
618 user_name_completion (Lisp_Object user, int all_flag, int *uniq)
619 {
620   /* This function can GC */
621   struct passwd *pw;
622   int matchcount = 0;
623   Lisp_Object bestmatch = Qnil;
624   Charcount bestmatchsize = 0;
625   int speccount = specpdl_depth ();
626   int i, cmax, clen;
627   char **cache;
628   Charcount user_name_length;
629   Lisp_Object locative;
630   EMACS_TIME t;
631   struct gcpro gcpro1, gcpro2;
632
633   GCPRO2 (user, bestmatch);
634
635   CHECK_STRING (user);
636
637   user_name_length = XSTRING_CHAR_LENGTH (user);
638
639   /* Cache user name lookups because it tends to be quite slow.
640    * Rebuild the cache occasionally to catch changes */
641   EMACS_GET_TIME (t);
642   if (user_cache  &&
643       EMACS_SECS (t) - user_cache_time > USER_CACHE_REBUILD)
644     {
645       for (i = 0; i < user_cache_len; i++)
646         free (user_cache[i]);
647       free (user_cache);
648       user_cache = NULL;
649       user_cache_len = 0;
650       user_cache_max = 0;
651     }
652
653   if (user_cache == NULL || user_cache_max <= 0)
654     {
655       cmax  = 200;
656       clen  = 0;
657       cache = (char **) malloc (cmax*sizeof (char *));
658
659       setpwent ();
660       locative = noseeum_cons (Qnil, Qnil);
661       XCAR (locative) = make_opaque_ptr ((void *) &cache);
662       XCDR (locative) = make_opaque_ptr ((void *) &clen);
663       record_unwind_protect (user_name_completion_unwind, locative);
664       /* #### may need to slow down interrupts around call to getpwent
665        * below.  at least the call to getpwnam in Fuser_full_name
666        * is documented as needing it on irix. */
667       while ((pw = getpwent ()))
668         {
669           if (clen >= cmax)
670             {
671               cmax *= 2;
672               cache = (char **) realloc (cache, cmax*sizeof (char *));
673             }
674
675           QUIT;
676
677           cache[clen++] = strdup (pw->pw_name);
678         }
679       free_opaque_ptr (XCAR (locative));
680       free_opaque_ptr (XCDR (locative));
681       XCAR (locative) = Qnil;
682       XCDR (locative) = Qnil;
683
684       unbind_to (speccount, Qnil); /* free locative cons, endpwent() */
685
686       user_cache_max = cmax;
687       user_cache_len = clen;
688       user_cache = cache;
689       user_cache_time = EMACS_SECS (t);
690     }
691
692   for (i = 0; i < user_cache_len; i++)
693     {
694       Bytecount len;
695       /* scmp() works in chars, not bytes, so we have to compute this: */
696       Charcount cclen;
697       Bufbyte *d_name;
698
699       d_name = (Bufbyte *) user_cache[i];
700       len = strlen (d_name);
701       cclen = bytecount_to_charcount (d_name, len);
702
703       QUIT;
704
705       if (cclen < user_name_length   ||
706           0 <= scmp (d_name, XSTRING_DATA (user), user_name_length))
707         continue;
708
709       matchcount++;    /* count matching completions */
710
711       if (all_flag || NILP (bestmatch))
712         {
713           Lisp_Object name = Qnil;
714           struct gcpro ngcpro1;
715           NGCPRO1 (name);
716           /* This is a possible completion */
717           name = make_string (d_name, len);
718           if (all_flag)
719             {
720               bestmatch = Fcons (name, bestmatch);
721             }
722           else
723             {
724               bestmatch = name;
725               bestmatchsize = XSTRING_CHAR_LENGTH (name);
726             }
727           NUNGCPRO;
728         }
729       else
730         {
731           Charcount compare = min (bestmatchsize, cclen);
732           Bufbyte *p1 = XSTRING_DATA (bestmatch);
733           Bufbyte *p2 = d_name;
734           Charcount matchsize = scmp (p1, p2, compare);
735
736           if (matchsize < 0)
737             matchsize = compare;
738           if (completion_ignore_case)
739             {
740               /* If this is an exact match except for case,
741                  use it as the best match rather than one that is not
742                  an exact match.  This way, we get the case pattern
743                  of the actual match.  */
744               if ((matchsize == cclen
745                    && matchsize < XSTRING_CHAR_LENGTH (bestmatch))
746                   ||
747                   /* If there is no exact match ignoring case,
748                      prefer a match that does not change the case
749                      of the input.  */
750                   (((matchsize == cclen)
751                     ==
752                     (matchsize == XSTRING_CHAR_LENGTH (bestmatch)))
753                    /* If there is more than one exact match aside from
754                       case, and one of them is exact including case,
755                       prefer that one.  */
756                    && 0 > scmp_1 (p2, XSTRING_DATA (user),
757                                   user_name_length, 0)
758                    && 0 <= scmp_1 (p1, XSTRING_DATA (user),
759                                    user_name_length, 0)))
760                 {
761                   bestmatch = make_string (d_name, len);
762                 }
763             }
764
765           bestmatchsize = matchsize;
766         }
767     }
768
769   UNGCPRO;
770
771   if (uniq)
772     *uniq = (matchcount == 1);
773
774   if (all_flag || NILP (bestmatch))
775     return bestmatch;
776   if (matchcount == 1 && bestmatchsize == user_name_length)
777     return Qt;
778   return Fsubstring (bestmatch, Qzero, make_int (bestmatchsize));
779 }
780 #endif   /* ! defined WINDOWSNT */
781
782 \f
783 Lisp_Object
784 make_directory_hash_table (CONST char *path)
785 {
786   DIR *d;
787   Lisp_Object hash = make_lisp_hashtable (100, HASHTABLE_NONWEAK,
788                                           HASHTABLE_EQUAL);
789   if ((d = opendir (path)))
790     {
791       DIRENTRY *dp;
792
793       while ((dp = readdir (d)))
794         {
795           Bytecount len = NAMLEN (dp);
796           if (DIRENTRY_NONEMPTY (dp))
797             /* Cast to Bufbyte* is OK, as readdir() Mule-encapsulates.  */
798             Fputhash (make_string ((Bufbyte *) dp->d_name, len), Qt, hash);
799         }
800       closedir (d);
801     }
802   return hash;
803 }
804 \f
805 Lisp_Object
806 wasteful_word_to_lisp (unsigned int item)
807 {
808   /* Compatibility: in other versions, file-attributes returns a LIST
809      of two 16 bit integers... */
810   Lisp_Object cons = word_to_lisp (item);
811   XCDR (cons) = Fcons (XCDR (cons), Qnil);
812   return cons;
813 }
814
815 DEFUN ("file-attributes", Ffile_attributes, 1, 1, 0, /*
816 Return a list of attributes of file FILENAME.
817 Value is nil if specified file cannot be opened.
818 Otherwise, list elements are:
819  0. t for directory, string (name linked to) for symbolic link, or nil.
820  1. Number of links to file.
821  2. File uid.
822  3. File gid.
823  4. Last access time, as a list of two integers.
824   First integer has high-order 16 bits of time, second has low 16 bits.
825  5. Last modification time, likewise.
826  6. Last status change time, likewise.
827  7. Size in bytes. (-1, if number is out of range).
828  8. File modes, as a string of ten letters or dashes as in ls -l.
829  9. t iff file's gid would change if file were deleted and recreated.
830 10. inode number.
831 11. Device number.
832
833 If file does not exist, returns nil.
834 */
835        (filename))
836 {
837   /* This function can GC. GC checked 1997.06.04. */
838   Lisp_Object values[12];
839   Lisp_Object dirname = Qnil;
840   struct stat s;
841   char modes[10];
842   Lisp_Object handler;
843   struct gcpro gcpro1, gcpro2;
844
845   GCPRO2 (filename, dirname);
846   filename = Fexpand_file_name (filename, Qnil);
847
848   /* If the file name has special constructs in it,
849      call the corresponding file handler.  */
850   handler = Ffind_file_name_handler (filename, Qfile_attributes);
851   if (!NILP (handler))
852     {
853       UNGCPRO;
854       return call2 (handler, Qfile_attributes, filename);
855     }
856
857   if (lstat ((char *) XSTRING_DATA (filename), &s) < 0)
858     {
859       UNGCPRO;
860       return Qnil;
861     }
862
863 #ifdef BSD4_2
864   dirname = Ffile_name_directory (filename);
865 #endif
866
867 #ifdef MSDOS
868   {
869     char *tmpnam = (char *) XSTRING_DATA (Ffile_name_nondirectory (filename));
870     int l = strlen (tmpnam);
871
872     if (l >= 5
873         && S_ISREG (s.st_mode)
874         && (stricmp (&tmpnam[l - 4], ".com") == 0 ||
875             stricmp (&tmpnam[l - 4], ".exe") == 0 ||
876             stricmp (&tmpnam[l - 4], ".bat") == 0))
877       {
878         s.st_mode |= S_IEXEC;
879       }
880   }
881 #endif /* MSDOS */
882
883   switch (s.st_mode & S_IFMT)
884     {
885     default:
886       values[0] = Qnil;
887       break;
888     case S_IFDIR:
889       values[0] = Qt;
890       break;
891 #ifdef S_IFLNK
892     case S_IFLNK:
893       values[0] = Ffile_symlink_p (filename);
894       break;
895 #endif
896     }
897   values[1] = make_int (s.st_nlink);
898   values[2] = make_int (s.st_uid);
899   values[3] = make_int (s.st_gid);
900   values[4] = wasteful_word_to_lisp (s.st_atime);
901   values[5] = wasteful_word_to_lisp (s.st_mtime);
902   values[6] = wasteful_word_to_lisp (s.st_ctime);
903   values[7] = make_int ((EMACS_INT) s.st_size);
904   /* If the size is out of range, give back -1.  */
905   /* #### Fix when Emacs gets bignums! */
906   if (XINT (values[7]) != s.st_size)
907     values[7] = make_int (-1);
908   filemodestring (&s, modes);
909   values[8] = make_string ((Bufbyte *) modes, 10);
910 #if defined (BSD4_2) || defined (BSD4_3)        /* file gid will be dir gid */
911   {
912     struct stat sdir;
913
914     if (!NILP (dirname) && stat ((char *) XSTRING_DATA (dirname), &sdir) == 0)
915       values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil;
916     else                        /* if we can't tell, assume worst */
917       values[9] = Qt;
918   }
919 #else                           /* file gid will be egid */
920   values[9] = (s.st_gid != getegid ()) ? Qt : Qnil;
921 #endif  /* BSD4_2 or BSD4_3 */
922   values[10] = make_int (s.st_ino);
923   values[11] = make_int (s.st_dev);
924   UNGCPRO;
925   return Flist (countof (values), values);
926 }
927
928 \f
929 /************************************************************************/
930 /*                            initialization                            */
931 /************************************************************************/
932
933 void
934 syms_of_dired (void)
935 {
936   defsymbol (&Qdirectory_files, "directory-files");
937   defsymbol (&Qfile_name_completion, "file-name-completion");
938   defsymbol (&Qfile_name_all_completions, "file-name-all-completions");
939   defsymbol (&Qfile_attributes, "file-attributes");
940
941   DEFSUBR (Fdirectory_files);
942   DEFSUBR (Ffile_name_completion);
943   DEFSUBR (Ffile_name_all_completions);
944 #ifndef  WINDOWSNT
945   DEFSUBR (Fuser_name_completion);
946   DEFSUBR (Fuser_name_completion_1);
947   DEFSUBR (Fuser_name_all_completions);
948 #endif
949   DEFSUBR (Ffile_attributes);
950 }
951
952 void
953 vars_of_dired (void)
954 {
955   DEFVAR_LISP ("completion-ignored-extensions", &Vcompletion_ignored_extensions /*
956 *Completion ignores filenames ending in any string in this list.
957 This variable does not affect lists of possible completions,
958 but does affect the commands that actually do completions.
959 It is used by the functions `file-name-completion' and
960 `file-name-all-completions'.
961 */ );
962   Vcompletion_ignored_extensions = Qnil;
963
964   user_cache = NULL;
965   user_cache_len = 0;
966   user_cache_max = 0;
967 }