076e339fea99054c2dddc1461d9f6ca823d7a205
[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           /* #### This is a bad idea, because d_name can contain
380              control characters, which can make XEmacs crash.  This
381              should be handled properly with FORMAT_FILENAME.  */
382           d_name = (Bufbyte *) dp->d_name;
383           len = NAMLEN (dp);
384           cclen = bytecount_to_charcount (d_name, len);
385
386           QUIT;
387
388           if (! DIRENTRY_NONEMPTY (dp)
389               || cclen < file_name_length
390               || 0 <= scmp (d_name, XSTRING_DATA (file), file_name_length))
391             continue;
392
393           if (file_name_completion_stat (dirname, dp, &st) < 0)
394             continue;
395
396           directoryp = ((st.st_mode & S_IFMT) == S_IFDIR);
397           if (directoryp)
398             {
399 #ifndef TRIVIAL_DIRECTORY_ENTRY
400 #define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, ".."))
401 #endif
402               /* "." and ".." are never interesting as completions, but are
403                  actually in the way in a directory containing only one file.  */
404               if (!passcount && TRIVIAL_DIRECTORY_ENTRY (dp->d_name))
405                 continue;
406             }
407           else
408             {
409               /* Compare extensions-to-be-ignored against end of this file name */
410               /* if name is not an exact match against specified string.  */
411               if (!passcount && cclen > file_name_length)
412                 {
413                   Lisp_Object tem;
414                   /* and exit this for loop if a match is found */
415                   EXTERNAL_LIST_LOOP (tem, Vcompletion_ignored_extensions)
416                     {
417                       Lisp_Object elt = XCAR (tem);
418                       Charcount skip;
419
420                       CHECK_STRING (elt);
421
422                       skip = cclen - XSTRING_CHAR_LENGTH (elt);
423                       if (skip < 0) continue;
424
425                       if (0 > scmp (charptr_n_addr (d_name, skip),
426                                     XSTRING_DATA (elt),
427                                     XSTRING_CHAR_LENGTH (elt)))
428                         {
429                           ignored_extension_p = 1;
430                           break;
431                         }
432                     }
433                 }
434             }
435
436           /* If an ignored-extensions match was found,
437              don't process this name as a completion.  */
438           if (!passcount && ignored_extension_p)
439             continue;
440
441           if (!passcount && regexp_ignore_completion_p (d_name, Qnil, 0, cclen))
442             continue;
443
444           /* Update computation of how much all possible completions match */
445           matchcount++;
446
447           if (all_flag || NILP (bestmatch))
448             {
449               Lisp_Object name = Qnil;
450               struct gcpro ngcpro1;
451               NGCPRO1 (name);
452               /* This is a possible completion */
453               name = make_string (d_name, len);
454               if (directoryp) /* Completion is a directory; end it with '/' */
455                 name = Ffile_name_as_directory (name);
456               if (all_flag)
457                 {
458                   bestmatch = Fcons (name, bestmatch);
459                 }
460               else
461                 {
462                   bestmatch = name;
463                   bestmatchsize = XSTRING_CHAR_LENGTH (name);
464                 }
465               NUNGCPRO;
466             }
467           else
468             {
469               Charcount compare = min (bestmatchsize, cclen);
470               Bufbyte *p1 = XSTRING_DATA (bestmatch);
471               Bufbyte *p2 = d_name;
472               Charcount matchsize = scmp (p1, p2, compare);
473
474               if (matchsize < 0)
475                 matchsize = compare;
476               if (completion_ignore_case)
477                 {
478                   /* If this is an exact match except for case,
479                      use it as the best match rather than one that is not
480                      an exact match.  This way, we get the case pattern
481                      of the actual match.  */
482                   if ((matchsize == cclen
483                        && matchsize + !!directoryp
484                        < XSTRING_CHAR_LENGTH (bestmatch))
485                       ||
486                       /* If there is no exact match ignoring case,
487                          prefer a match that does not change the case
488                          of the input.  */
489                       (((matchsize == cclen)
490                         ==
491                         (matchsize + !!directoryp
492                          == XSTRING_CHAR_LENGTH (bestmatch)))
493                        /* If there is more than one exact match aside from
494                           case, and one of them is exact including case,
495                           prefer that one.  */
496                        && 0 > scmp_1 (p2, XSTRING_DATA (file),
497                                       file_name_length, 0)
498                        && 0 <= scmp_1 (p1, XSTRING_DATA (file),
499                                        file_name_length, 0)))
500                     {
501                       bestmatch = make_string (d_name, len);
502                       if (directoryp)
503                         bestmatch = Ffile_name_as_directory (bestmatch);
504                     }
505                 }
506
507               /* If this dirname all matches,
508                  see if implicit following slash does too.  */
509               if (directoryp
510                   && compare == matchsize
511                   && bestmatchsize > matchsize
512                   && IS_ANY_SEP (charptr_emchar_n (p1, matchsize)))
513                 matchsize++;
514               bestmatchsize = matchsize;
515             }
516         }
517       closedir (d);
518       free_opaque_ptr (XCAR (locative));
519       XCAR (locative) = Qnil;
520     }
521
522   unbind_to (speccount, Qnil);
523
524   UNGCPRO;
525
526   if (all_flag || NILP (bestmatch))
527     return bestmatch;
528   if (matchcount == 1 && bestmatchsize == file_name_length)
529     return Qt;
530   return Fsubstring (bestmatch, Qzero, make_int (bestmatchsize));
531 }
532
533 \f
534 static Lisp_Object user_name_completion (Lisp_Object user,
535                                          int all_flag,
536                                          int *uniq);
537
538 DEFUN ("user-name-completion", Fuser_name_completion, 1, 1, 0, /*
539 Complete user name USER.
540
541 Returns the longest string common to all user names that start
542 with USER.  If there is only one and USER matches it exactly,
543 returns t.  Returns nil if there is no user name starting with USER.
544 */
545        (user))
546 {
547   return user_name_completion (user, 0, NULL);
548 }
549
550 DEFUN ("user-name-completion-1", Fuser_name_completion_1, 1, 1, 0, /*
551 Complete user name USER.
552
553 This function is identical to `user-name-completion', except that
554 the cons of the completion and an indication of whether the
555 completion was unique is returned.
556
557 The car of the returned value is the longest string common to all
558 user names that start with USER.  If there is only one and USER
559 matches it exactly, the car is t.  The car is nil if there is no
560 user name starting with USER.  The cdr of the result is non-nil
561 if and only if the completion returned in the car was unique.
562 */
563        (user))
564 {
565   int uniq;
566   Lisp_Object completed;
567
568   completed = user_name_completion (user, 0, &uniq);
569   return Fcons (completed, uniq ? Qt : Qnil);
570 }
571
572 DEFUN ("user-name-all-completions", Fuser_name_all_completions, 1, 1, 0, /*
573 Return a list of all completions of user name USER.
574 These are all user names which begin with USER.
575 */
576        (user))
577 {
578   return user_name_completion (user, 1, NULL);
579 }
580
581 static Lisp_Object
582 user_name_completion_unwind (Lisp_Object locative)
583 {
584   Lisp_Object obj1 = XCAR (locative);
585   Lisp_Object obj2 = XCDR (locative);
586   char **cache;
587   int clen, i;
588
589
590   if (!NILP (obj1) && !NILP (obj2))
591     {
592       /* clean up if interrupted building cache */
593       cache = *(char ***)get_opaque_ptr (obj1);
594       clen  = *(int *)get_opaque_ptr (obj2);
595       free_opaque_ptr (obj1);
596       free_opaque_ptr (obj2);
597       for (i = 0; i < clen; i++)
598         free (cache[i]);
599       free (cache);
600     }
601
602   free_cons (XCONS (locative));
603   endpwent ();
604
605   return Qnil;
606 }
607
608 static char **user_cache;
609 static int user_cache_len;
610 static int user_cache_max;
611 static long user_cache_time;
612
613 #define  USER_CACHE_REBUILD  (24*60*60)  /* 1 day, in seconds */
614
615 static Lisp_Object
616 user_name_completion (Lisp_Object user, int all_flag, int *uniq)
617 {
618   /* This function can GC */
619   struct passwd *pw;
620   int matchcount = 0;
621   Lisp_Object bestmatch = Qnil;
622   Charcount bestmatchsize = 0;
623   int speccount = specpdl_depth ();
624   int i, cmax, clen;
625   char **cache;
626   Charcount user_name_length;
627   Lisp_Object locative;
628   EMACS_TIME t;
629   struct gcpro gcpro1, gcpro2;
630
631   GCPRO2 (user, bestmatch);
632
633   CHECK_STRING (user);
634
635   user_name_length = XSTRING_CHAR_LENGTH (user);
636
637   /* Cache user name lookups because it tends to be quite slow.
638    * Rebuild the cache occasionally to catch changes */
639   EMACS_GET_TIME (t);
640   if (user_cache  &&
641       EMACS_SECS (t) - user_cache_time > USER_CACHE_REBUILD)
642     {
643       for (i = 0; i < user_cache_len; i++)
644         free (user_cache[i]);
645       free (user_cache);
646       user_cache = NULL;
647       user_cache_len = 0;
648       user_cache_max = 0;
649     }
650
651   if (user_cache == NULL || user_cache_max <= 0)
652     {
653       cmax  = 200;
654       clen  = 0;
655       cache = (char **) malloc (cmax*sizeof (char *));
656
657       setpwent ();
658       locative = noseeum_cons (Qnil, Qnil);
659       XCAR (locative) = make_opaque_ptr ((void *) &cache);
660       XCDR (locative) = make_opaque_ptr ((void *) &clen);
661       record_unwind_protect (user_name_completion_unwind, locative);
662       /* #### may need to slow down interrupts around call to getpwent
663        * below.  at least the call to getpwnam in Fuser_full_name
664        * is documented as needing it on irix. */
665       while ((pw = getpwent ()))
666         {
667           if (clen >= cmax)
668             {
669               cmax *= 2;
670               cache = (char **) realloc (cache, cmax*sizeof (char *));
671             }
672
673           QUIT;
674
675           cache[clen++] = strdup (pw->pw_name);
676         }
677       free_opaque_ptr (XCAR (locative));
678       free_opaque_ptr (XCDR (locative));
679       XCAR (locative) = Qnil;
680       XCDR (locative) = Qnil;
681
682       unbind_to (speccount, Qnil); /* free locative cons, endpwent() */
683
684       user_cache_max = cmax;
685       user_cache_len = clen;
686       user_cache = cache;
687       user_cache_time = EMACS_SECS (t);
688     }
689
690   for (i = 0; i < user_cache_len; i++)
691     {
692       Bytecount len;
693       /* scmp() works in chars, not bytes, so we have to compute this: */
694       Charcount cclen;
695       Bufbyte *d_name;
696
697       d_name = (Bufbyte *) user_cache[i];
698       len = strlen (d_name);
699       cclen = bytecount_to_charcount (d_name, len);
700
701       QUIT;
702
703       if (cclen < user_name_length   ||
704           0 <= scmp (d_name, XSTRING_DATA (user), user_name_length))
705         continue;
706
707       matchcount++;    /* count matching completions */
708
709       if (all_flag || NILP (bestmatch))
710         {
711           Lisp_Object name = Qnil;
712           struct gcpro ngcpro1;
713           NGCPRO1 (name);
714           /* This is a possible completion */
715           name = make_string (d_name, len);
716           if (all_flag)
717             {
718               bestmatch = Fcons (name, bestmatch);
719             }
720           else
721             {
722               bestmatch = name;
723               bestmatchsize = XSTRING_CHAR_LENGTH (name);
724             }
725           NUNGCPRO;
726         }
727       else
728         {
729           Charcount compare = min (bestmatchsize, cclen);
730           Bufbyte *p1 = XSTRING_DATA (bestmatch);
731           Bufbyte *p2 = d_name;
732           Charcount matchsize = scmp (p1, p2, compare);
733
734           if (matchsize < 0)
735             matchsize = compare;
736           if (completion_ignore_case)
737             {
738               /* If this is an exact match except for case,
739                  use it as the best match rather than one that is not
740                  an exact match.  This way, we get the case pattern
741                  of the actual match.  */
742               if ((matchsize == cclen
743                    && matchsize < XSTRING_CHAR_LENGTH (bestmatch))
744                   ||
745                   /* If there is no exact match ignoring case,
746                      prefer a match that does not change the case
747                      of the input.  */
748                   (((matchsize == cclen)
749                     ==
750                     (matchsize == XSTRING_CHAR_LENGTH (bestmatch)))
751                    /* If there is more than one exact match aside from
752                       case, and one of them is exact including case,
753                       prefer that one.  */
754                    && 0 > scmp_1 (p2, XSTRING_DATA (user),
755                                   user_name_length, 0)
756                    && 0 <= scmp_1 (p1, XSTRING_DATA (user),
757                                    user_name_length, 0)))
758                 {
759                   bestmatch = make_string (d_name, len);
760                 }
761             }
762
763           bestmatchsize = matchsize;
764         }
765     }
766
767   UNGCPRO;
768
769   if (uniq)
770     *uniq = (matchcount == 1);
771
772   if (all_flag || NILP (bestmatch))
773     return bestmatch;
774   if (matchcount == 1 && bestmatchsize == user_name_length)
775     return Qt;
776   return Fsubstring (bestmatch, Qzero, make_int (bestmatchsize));
777 }
778
779 \f
780 Lisp_Object
781 make_directory_hash_table (CONST char *path)
782 {
783   DIR *d;
784   Lisp_Object hash = make_lisp_hashtable (100, HASHTABLE_NONWEAK,
785                                           HASHTABLE_EQUAL);
786   if ((d = opendir (path)))
787     {
788       DIRENTRY *dp;
789
790       while ((dp = readdir (d)))
791         {
792           Bytecount len = NAMLEN (dp);
793           if (DIRENTRY_NONEMPTY (dp))
794             Fputhash (make_ext_string ((Bufbyte *) dp->d_name, len,
795                                        FORMAT_FILENAME), Qt, hash);
796         }
797       closedir (d);
798     }
799   return hash;
800 }
801 \f
802 Lisp_Object
803 wasteful_word_to_lisp (unsigned int item)
804 {
805   /* Compatibility: in other versions, file-attributes returns a LIST
806      of two 16 bit integers... */
807   Lisp_Object cons = word_to_lisp (item);
808   XCDR (cons) = Fcons (XCDR (cons), Qnil);
809   return cons;
810 }
811
812 DEFUN ("file-attributes", Ffile_attributes, 1, 1, 0, /*
813 Return a list of attributes of file FILENAME.
814 Value is nil if specified file cannot be opened.
815 Otherwise, list elements are:
816  0. t for directory, string (name linked to) for symbolic link, or nil.
817  1. Number of links to file.
818  2. File uid.
819  3. File gid.
820  4. Last access time, as a list of two integers.
821   First integer has high-order 16 bits of time, second has low 16 bits.
822  5. Last modification time, likewise.
823  6. Last status change time, likewise.
824  7. Size in bytes. (-1, if number is out of range).
825  8. File modes, as a string of ten letters or dashes as in ls -l.
826  9. t iff file's gid would change if file were deleted and recreated.
827 10. inode number.
828 11. Device number.
829
830 If file does not exist, returns nil.
831 */
832        (filename))
833 {
834   /* This function can GC. GC checked 1997.06.04. */
835   Lisp_Object values[12];
836   Lisp_Object dirname = Qnil;
837   struct stat s;
838   char modes[10];
839   Lisp_Object handler;
840   struct gcpro gcpro1, gcpro2;
841
842   GCPRO2 (filename, dirname);
843   filename = Fexpand_file_name (filename, Qnil);
844
845   /* If the file name has special constructs in it,
846      call the corresponding file handler.  */
847   handler = Ffind_file_name_handler (filename, Qfile_attributes);
848   if (!NILP (handler))
849     {
850       UNGCPRO;
851       return call2 (handler, Qfile_attributes, filename);
852     }
853
854   if (lstat ((char *) XSTRING_DATA (filename), &s) < 0)
855     {
856       UNGCPRO;
857       return Qnil;
858     }
859
860 #ifdef BSD4_2
861   dirname = Ffile_name_directory (filename);
862 #endif
863
864 #ifdef MSDOS
865   {
866     char *tmpnam = (char *) XSTRING_DATA (Ffile_name_nondirectory (filename));
867     int l = strlen (tmpnam);
868
869     if (l >= 5
870         && S_ISREG (s.st_mode)
871         && (stricmp (&tmpnam[l - 4], ".com") == 0 ||
872             stricmp (&tmpnam[l - 4], ".exe") == 0 ||
873             stricmp (&tmpnam[l - 4], ".bat") == 0))
874       {
875         s.st_mode |= S_IEXEC;
876       }
877   }
878 #endif /* MSDOS */
879
880   switch (s.st_mode & S_IFMT)
881     {
882     default:
883       values[0] = Qnil;
884       break;
885     case S_IFDIR:
886       values[0] = Qt;
887       break;
888 #ifdef S_IFLNK
889     case S_IFLNK:
890       values[0] = Ffile_symlink_p (filename);
891       break;
892 #endif
893     }
894   values[1] = make_int (s.st_nlink);
895   values[2] = make_int (s.st_uid);
896   values[3] = make_int (s.st_gid);
897   values[4] = wasteful_word_to_lisp (s.st_atime);
898   values[5] = wasteful_word_to_lisp (s.st_mtime);
899   values[6] = wasteful_word_to_lisp (s.st_ctime);
900   values[7] = make_int ((EMACS_INT) s.st_size);
901   /* If the size is out of range, give back -1.  */
902   /* #### Fix when Emacs gets bignums! */
903   if (XINT (values[7]) != s.st_size)
904     values[7] = make_int (-1);
905   filemodestring (&s, modes);
906   values[8] = make_string ((Bufbyte *) modes, 10);
907 #if defined (BSD4_2) || defined (BSD4_3)        /* file gid will be dir gid */
908   {
909     struct stat sdir;
910
911     if (!NILP (dirname) && stat ((char *) XSTRING_DATA (dirname), &sdir) == 0)
912       values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil;
913     else                        /* if we can't tell, assume worst */
914       values[9] = Qt;
915   }
916 #else                           /* file gid will be egid */
917   values[9] = (s.st_gid != getegid ()) ? Qt : Qnil;
918 #endif  /* BSD4_2 or BSD4_3 */
919   values[10] = make_int (s.st_ino);
920   values[11] = make_int (s.st_dev);
921   UNGCPRO;
922   return Flist (countof (values), values);
923 }
924
925 \f
926 /************************************************************************/
927 /*                            initialization                            */
928 /************************************************************************/
929
930 void
931 syms_of_dired (void)
932 {
933   defsymbol (&Qdirectory_files, "directory-files");
934   defsymbol (&Qfile_name_completion, "file-name-completion");
935   defsymbol (&Qfile_name_all_completions, "file-name-all-completions");
936   defsymbol (&Qfile_attributes, "file-attributes");
937
938   DEFSUBR (Fdirectory_files);
939   DEFSUBR (Ffile_name_completion);
940   DEFSUBR (Ffile_name_all_completions);
941   DEFSUBR (Fuser_name_completion);
942   DEFSUBR (Fuser_name_completion_1);
943   DEFSUBR (Fuser_name_all_completions);
944   DEFSUBR (Ffile_attributes);
945 }
946
947 void
948 vars_of_dired (void)
949 {
950   DEFVAR_LISP ("completion-ignored-extensions", &Vcompletion_ignored_extensions /*
951 *Completion ignores filenames ending in any string in this list.
952 This variable does not affect lists of possible completions,
953 but does affect the commands that actually do completions.
954 It is used by the functions `file-name-completion' and
955 `file-name-all-completions'.
956 */ );
957   Vcompletion_ignored_extensions = Qnil;
958
959   user_cache = NULL;
960   user_cache_len = 0;
961   user_cache_max = 0;
962 }