1 /* Lisp functions for making directory listings.
2 Copyright (C) 1985, 1986, 1992 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs 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 1, or (at your option)
11 GNU Emacs 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 Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
22 #include <sys/types.h>
33 /* The d_nameln member of a struct dirent includes the '\0' character
34 on some systems, but not on others. What's worse, you can't tell
35 at compile-time which one it will be, since it really depends on
36 the sort of system providing the filesystem you're reading from,
37 not the system you are running on. Paul Eggert
38 <eggert@bi.twinsun.com> says this occurs when Emacs is running on a
39 SunOS 4.1.2 host, reading a directory that is remote-mounted from a
40 Solaris 2.1 host and is in a native Solaris 2.1 filesystem.
42 Since applying strlen to the name always works, we'll just do that. */
43 #define NAMLEN(p) strlen (p->d_name)
45 #ifdef SYSV_SYSTEM_DIR
48 #define DIRENTRY struct dirent
52 #ifdef NONSYSTEM_DIR_LIBRARY
54 #else /* not NONSYSTEM_DIR_LIBRARY */
56 #endif /* not NONSYSTEM_DIR_LIBRARY */
58 #define DIRENTRY struct direct
60 extern DIR *opendir ();
61 extern struct direct
*readdir ();
71 #define min(a, b) ((a) < (b) ? (a) : (b))
73 /* if system does not have symbolic links, it does not have lstat.
74 In that case, use ordinary stat instead. */
80 extern Lisp_Object
Ffind_file_name_handler ();
82 Lisp_Object Vcompletion_ignored_extensions
;
84 Lisp_Object Qcompletion_ignore_case
;
86 Lisp_Object Qdirectory_files
;
87 Lisp_Object Qfile_name_completion
;
88 Lisp_Object Qfile_name_all_completions
;
89 Lisp_Object Qfile_attributes
;
91 DEFUN ("directory-files", Fdirectory_files
, Sdirectory_files
, 1, 4, 0,
92 "Return a list of names of files in DIRECTORY.\n\
93 There are three optional arguments:\n\
94 If FULL is non-nil, absolute pathnames of the files are returned.\n\
95 If MATCH is non-nil, only pathnames containing that regexp are returned.\n\
96 If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\
97 NOSORT is useful if you plan to sort the result yourself.")
98 (dirname
, full
, match
, nosort
)
99 Lisp_Object dirname
, full
, match
, nosort
;
103 Lisp_Object list
, name
, dirfilename
;
106 /* If the file name has special constructs in it,
107 call the corresponding file handler. */
108 handler
= Ffind_file_name_handler (dirname
);
114 args
[1] = Qdirectory_files
;
119 return Ffuncall (6, args
);
123 struct gcpro gcpro1
, gcpro2
;
125 /* Because of file name handlers, these functions might call
126 Ffuncall, and cause a GC. */
128 dirname
= Fexpand_file_name (dirname
, Qnil
);
130 GCPRO2 (match
, dirname
);
131 dirfilename
= Fdirectory_file_name (dirname
);
137 CHECK_STRING (match
, 3);
139 /* MATCH might be a flawed regular expression. Rather than
140 catching and signalling our own errors, we just call
141 compile_pattern to do the work for us. */
143 compile_pattern (match
, &searchbuf
, 0,
144 buffer_defaults
.downcase_table
->contents
);
146 compile_pattern (match
, &searchbuf
, 0, 0);
150 /* Now searchbuf is the compiled form of MATCH; don't call anything
151 which might compile a new regexp until we're done with the loop! */
153 /* Do this opendir after anything which might signal an error; if
154 an error is signalled while the directory stream is open, we
155 have to make sure it gets closed, and setting up an
156 unwind_protect to do so would be a pain. */
157 d
= opendir (XSTRING (dirfilename
)->data
);
159 report_file_error ("Opening directory", Fcons (dirname
, Qnil
));
162 length
= XSTRING (dirname
)->size
;
164 /* Loop reading blocks */
167 DIRENTRY
*dp
= readdir (d
);
175 || (0 <= re_search (&searchbuf
, dp
->d_name
, len
, 0, len
, 0)))
179 int index
= XSTRING (dirname
)->size
;
180 int total
= len
+ index
;
183 || XSTRING (dirname
)->data
[length
- 1] != '/')
187 name
= make_uninit_string (total
);
188 bcopy (XSTRING (dirname
)->data
, XSTRING (name
)->data
,
192 || XSTRING (dirname
)->data
[length
- 1] != '/')
193 XSTRING (name
)->data
[index
++] = '/';
195 bcopy (dp
->d_name
, XSTRING (name
)->data
+ index
, len
);
198 name
= make_string (dp
->d_name
, len
);
199 list
= Fcons (name
, list
);
206 return Fsort (Fnreverse (list
), Qstring_lessp
);
209 Lisp_Object
file_name_completion ();
211 DEFUN ("file-name-completion", Ffile_name_completion
, Sfile_name_completion
,
213 "Complete file name FILE in directory DIR.\n\
214 Returns the longest string\n\
215 common to all filenames in DIR that start with FILE.\n\
216 If there is only one and FILE matches it exactly, returns t.\n\
217 Returns nil if DIR contains no name starting with FILE.")
219 Lisp_Object file
, dirname
;
222 /* Don't waste time trying to complete a null string.
223 Besides, this case happens when user is being asked for
224 a directory name and has supplied one ending in a /.
225 We would not want to add anything in that case
226 even if there are some unique characters in that directory. */
227 if (XTYPE (file
) == Lisp_String
&& XSTRING (file
)->size
== 0)
230 /* If the file name has special constructs in it,
231 call the corresponding file handler. */
232 handler
= Ffind_file_name_handler (dirname
);
234 return call3 (handler
, Qfile_name_completion
, file
, dirname
);
236 return file_name_completion (file
, dirname
, 0, 0);
239 DEFUN ("file-name-all-completions", Ffile_name_all_completions
,
240 Sfile_name_all_completions
, 2, 2, 0,
241 "Return a list of all completions of file name FILE in directory DIR.\n\
242 These are all file names in directory DIR which begin with FILE.")
244 Lisp_Object file
, dirname
;
248 /* If the file name has special constructs in it,
249 call the corresponding file handler. */
250 handler
= Ffind_file_name_handler (dirname
);
252 return call3 (handler
, Qfile_name_all_completions
, file
, dirname
);
254 return file_name_completion (file
, dirname
, 1, 0);
258 file_name_completion (file
, dirname
, all_flag
, ver_flag
)
259 Lisp_Object file
, dirname
;
260 int all_flag
, ver_flag
;
264 int bestmatchsize
, skip
;
265 register int compare
, matchsize
;
266 unsigned char *p1
, *p2
;
268 Lisp_Object bestmatch
, tem
, elt
, name
;
272 int count
= specpdl_ptr
- specpdl
;
274 extern DIRENTRY
* readdirver ();
276 DIRENTRY
*((* readfunc
) ());
278 /* Filename completion on VMS ignores case, since VMS filesys does. */
279 specbind (Qcompletion_ignore_case
, Qt
);
283 readfunc
= readdirver
;
284 file
= Fupcase (file
);
286 CHECK_STRING (file
, 0);
289 dirname
= Fexpand_file_name (dirname
, Qnil
);
292 /* With passcount = 0, ignore files that end in an ignored extension.
293 If nothing found then try again with passcount = 1, don't ignore them.
294 If looking for all completions, start with passcount = 1,
295 so always take even the ignored ones.
297 ** It would not actually be helpful to the user to ignore any possible
298 completions when making a list of them.** */
300 for (passcount
= !!all_flag
; NILP (bestmatch
) && passcount
< 2; passcount
++)
302 if (!(d
= opendir (XSTRING (Fdirectory_file_name (dirname
))->data
)))
303 report_file_error ("Opening directory", Fcons (dirname
, Qnil
));
305 /* Loop reading blocks */
306 /* (att3b compiler bug requires do a null comparison this way) */
313 dp
= (*readfunc
) (d
);
321 if (!NILP (Vquit_flag
) && NILP (Vinhibit_quit
))
324 || len
< XSTRING (file
)->size
325 || 0 <= scmp (dp
->d_name
, XSTRING (file
)->data
,
326 XSTRING (file
)->size
))
329 if (file_name_completion_stat (dirname
, dp
, &st
) < 0)
332 directoryp
= ((st
.st_mode
& S_IFMT
) == S_IFDIR
);
336 /* Compare extensions-to-be-ignored against end of this file name */
337 /* if name is not an exact match against specified string */
338 if (!passcount
&& len
> XSTRING (file
)->size
)
339 /* and exit this for loop if a match is found */
340 for (tem
= Vcompletion_ignored_extensions
;
341 CONSP (tem
); tem
= XCONS (tem
)->cdr
)
343 elt
= XCONS (tem
)->car
;
344 if (XTYPE (elt
) != Lisp_String
) continue;
345 skip
= len
- XSTRING (elt
)->size
;
346 if (skip
< 0) continue;
348 if (0 <= scmp (dp
->d_name
+ skip
,
350 XSTRING (elt
)->size
))
356 /* Unless an ignored-extensions match was found,
357 process this name as a completion */
358 if (passcount
|| !CONSP (tem
))
360 /* Update computation of how much all possible completions match */
364 if (all_flag
|| NILP (bestmatch
))
366 /* This is a possible completion */
369 /* This completion is a directory; make it end with '/' */
370 name
= Ffile_name_as_directory (make_string (dp
->d_name
, len
));
373 name
= make_string (dp
->d_name
, len
);
376 bestmatch
= Fcons (name
, bestmatch
);
381 bestmatchsize
= XSTRING (name
)->size
;
386 compare
= min (bestmatchsize
, len
);
387 p1
= XSTRING (bestmatch
)->data
;
388 p2
= (unsigned char *) dp
->d_name
;
389 matchsize
= scmp(p1
, p2
, compare
);
392 /* If this dirname all matches,
393 see if implicit following slash does too. */
395 && compare
== matchsize
396 && bestmatchsize
> matchsize
397 && p1
[matchsize
] == '/')
399 bestmatchsize
= min (matchsize
, bestmatchsize
);
406 unbind_to (count
, Qnil
);
408 if (all_flag
|| NILP (bestmatch
))
410 if (matchcount
== 1 && bestmatchsize
== XSTRING (file
)->size
)
412 return Fsubstring (bestmatch
, make_number (0), make_number (bestmatchsize
));
416 return Fsignal (Qquit
, Qnil
);
419 file_name_completion_stat (dirname
, dp
, st_addr
)
422 struct stat
*st_addr
;
424 int len
= NAMLEN (dp
);
425 int pos
= XSTRING (dirname
)->size
;
426 char *fullname
= (char *) alloca (len
+ pos
+ 2);
428 bcopy (XSTRING (dirname
)->data
, fullname
, pos
);
430 if (fullname
[pos
- 1] != '/')
431 fullname
[pos
++] = '/';
434 bcopy (dp
->d_name
, fullname
+ pos
, len
);
435 fullname
[pos
+ len
] = 0;
437 return stat (fullname
, st_addr
);
442 DEFUN ("file-name-all-versions", Ffile_name_all_versions
,
443 Sfile_name_all_versions
, 2, 2, 0,
444 "Return a list of all versions of file name FILE in directory DIR.")
446 Lisp_Object file
, dirname
;
448 return file_name_completion (file
, dirname
, 1, 1);
451 DEFUN ("file-version-limit", Ffile_version_limit
, Sfile_version_limit
, 1, 1, 0,
452 "Return the maximum number of versions allowed for FILE.\n\
453 Returns nil if the file cannot be opened or if there is no version limit.")
455 Lisp_Object filename
;
460 struct XABFHC xabfhc
;
463 filename
= Fexpand_file_name (filename
, Qnil
);
465 xabfhc
= cc$rms_xabfhc
;
466 fab
.fab$l_fna
= XSTRING (filename
)->data
;
467 fab
.fab$b_fns
= strlen (fab
.fab$l_fna
);
468 fab
.fab$l_xab
= (char *) &xabfhc
;
469 status
= sys$
open (&fab
, 0, 0);
470 if (status
!= RMS$_NORMAL
) /* Probably non-existent file */
472 sys$
close (&fab
, 0, 0);
473 if (xabfhc
.xab$w_verlimit
== 32767)
474 return Qnil
; /* No version limit */
476 return make_number (xabfhc
.xab$w_verlimit
);
485 return Fcons (make_number (time
>> 16),
486 Fcons (make_number (time
& 0177777), Qnil
));
489 DEFUN ("file-attributes", Ffile_attributes
, Sfile_attributes
, 1, 1, 0,
490 "Return a list of attributes of file FILENAME.\n\
491 Value is nil if specified file cannot be opened.\n\
492 Otherwise, list elements are:\n\
493 0. t for directory, string (name linked to) for symbolic link, or nil.\n\
494 1. Number of links to file.\n\
497 4. Last access time, as a list of two integers.\n\
498 First integer has high-order 16 bits of time, second has low 16 bits.\n\
499 5. Last modification time, likewise.\n\
500 6. Last status change time, likewise.\n\
502 8. File modes, as a string of ten letters or dashes as in ls -l.\n\
503 9. t iff file's gid would change if file were deleted and recreated.\n\
505 11. Device number.\n\
507 If file does not exist, returns nil.")
509 Lisp_Object filename
;
511 Lisp_Object values
[12];
518 filename
= Fexpand_file_name (filename
, Qnil
);
520 /* If the file name has special constructs in it,
521 call the corresponding file handler. */
522 handler
= Ffind_file_name_handler (filename
);
524 return call2 (handler
, Qfile_attributes
, filename
);
526 if (lstat (XSTRING (filename
)->data
, &s
) < 0)
529 switch (s
.st_mode
& S_IFMT
)
532 values
[0] = Qnil
; break;
534 values
[0] = Qt
; break;
537 values
[0] = Ffile_symlink_p (filename
); break;
540 values
[1] = make_number (s
.st_nlink
);
541 values
[2] = make_number (s
.st_uid
);
542 values
[3] = make_number (s
.st_gid
);
543 values
[4] = make_time (s
.st_atime
);
544 values
[5] = make_time (s
.st_mtime
);
545 values
[6] = make_time (s
.st_ctime
);
546 /* perhaps we should set this to most-positive-fixnum if it is too large? */
547 values
[7] = make_number (s
.st_size
);
548 filemodestring (&s
, modes
);
549 values
[8] = make_string (modes
, 10);
550 #ifdef BSD4_3 /* Gross kludge to avoid lack of "#if defined(...)" in VMS */
551 #define BSD4_2 /* A new meaning to the term `backwards compatability' */
553 #ifdef BSD4_2 /* file gid will be dir gid */
554 dirname
= Ffile_name_directory (filename
);
555 if (! NILP (dirname
) && stat (XSTRING (dirname
)->data
, &sdir
) == 0)
556 values
[9] = (sdir
.st_gid
!= s
.st_gid
) ? Qt
: Qnil
;
557 else /* if we can't tell, assume worst */
559 #else /* file gid will be egid */
560 values
[9] = (s
.st_gid
!= getegid ()) ? Qt
: Qnil
;
561 #endif /* BSD4_2 (or BSD4_3) */
563 #undef BSD4_2 /* ok, you can look again without throwing up */
565 values
[10] = make_number (s
.st_ino
);
566 values
[11] = make_number (s
.st_dev
);
567 return Flist (sizeof(values
) / sizeof(values
[0]), values
);
572 Qdirectory_files
= intern ("directory-files");
573 Qfile_name_completion
= intern ("file-name-completion");
574 Qfile_name_all_completions
= intern ("file-name-all-completions");
575 Qfile_attributes
= intern ("file-attributes");
577 defsubr (&Sdirectory_files
);
578 defsubr (&Sfile_name_completion
);
580 defsubr (&Sfile_name_all_versions
);
581 defsubr (&Sfile_version_limit
);
583 defsubr (&Sfile_name_all_completions
);
584 defsubr (&Sfile_attributes
);
587 Qcompletion_ignore_case
= intern ("completion-ignore-case");
588 staticpro (&Qcompletion_ignore_case
);
591 DEFVAR_LISP ("completion-ignored-extensions", &Vcompletion_ignored_extensions
,
592 "*Completion ignores filenames ending in any string in this list.\n\
593 This variable does not affect lists of possible completions,\n\
594 but does affect the commands that actually do completions.");
595 Vcompletion_ignored_extensions
= Qnil
;