1 /* Lisp functions for making directory listings.
2 Copyright (C) 1985, 1986, 1992, 1993, 1994 Free Software Foundation, Inc.
4 This file is part of SXEmacs
6 SXEmacs 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 3 of the License, or
9 (at your option) any later version.
11 SXEmacs 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 this program. If not, see <http://www.gnu.org/licenses/>. */
20 /* Synched up with: FSF 19.30. */
41 #include "mule/file-coding.h"
46 Lisp_Object Vcompletion_ignored_extensions;
47 Lisp_Object Vdirectory_files_no_trivial_p;
48 Lisp_Object Qdirectory_files;
49 Lisp_Object Qdirectory_files_recur;
50 Lisp_Object Qfile_name_completion;
51 Lisp_Object Qfile_name_all_completions;
52 Lisp_Object Qfile_attributes;
54 Lisp_Object Qcompanion_bf;
55 Lisp_Object Qsorted_list, Qdesc_sorted_list, Qunsorted_list;
56 Lisp_Object Qmatch_full;
57 Lisp_Object Qsubdir, Qsymlinks, Qfiles, Qdirs;
58 Lisp_Object Qnoncyclic_directory, Qcyclic_directory;
59 Lisp_Object Qwhiteout;
61 /* On GNU libc systems the declaration is only visible with _GNU_SOURCE. */
62 #if defined(HAVE_CANONICALIZE_FILE_NAME)
63 # if defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME)
64 extern char *canonicalize_file_name(const char *);
66 #define CANONICALISE_FILENAME(f) canonicalize_file_name(f)
68 #else /* !defined(HAVE_CANONICALIZE_FILE_NAME) */
70 static char *dired_realpath(const char *);
71 #define CANONICALISE_FILENAME(f) dired_realpath(f)
72 #endif /* defined(HAVE_CANONICALIZE_FILE_NAME) */
74 #ifndef TRIVIAL_DIRECTORY_ENTRY
75 #define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (".", n) || !strcmp ("..", n))
79 /* this variant is much too slow */
80 #define FAST_CONCAT(tgt, s1, s2) tgt = concat2(s1, s2);
83 #define FAST_CONCAT(tgt, s1, s2) \
85 tgt = make_uninit_string(XSTRING_LENGTH(s1)+XSTRING_LENGTH(s2)); \
86 memcpy(XSTRING_DATA(tgt), XSTRING_DATA(s1), XSTRING_LENGTH(s1)); \
87 memcpy(XSTRING_DATA(tgt)+XSTRING_LENGTH(s1), \
88 XSTRING_DATA(s2), XSTRING_LENGTH(s2)); \
92 /* some more declarations */
93 typedef struct dired_stack_item_s *dired_stack_item_t;
94 typedef struct dfr_options_s *dfr_options_t;
96 struct dired_stack_item_s {
101 struct dfr_options_s {
102 long unsigned int maxdepth;
104 _Bool symlink_file_p:1;
108 static Lisp_Object fname_as_directory(Lisp_Object);
109 static int pathname_matches_p(Lisp_Object, Lisp_Object,
110 struct re_pattern_buffer*);
112 #define dired_stack_t dllist_t
113 #define new_dired_stack() make_noseeum_dllist()
114 #define free_dired_stack(ds) free_noseeum_dllist(ds)
115 #define dired_stack_pop(ds) (dired_stack_item_t)dllist_pop_car(ds)
116 #define dired_stack_push(ds, p) dllist_append(ds, p)
117 #define dired_stack_size(ds) dllist_size(ds)
120 #if defined(HAVE_LARGEFILE)
121 #define dirent_t struct dirent64
122 #define DFR_READDIR readdir64_r
124 #define dirent_t struct dirent
125 #define DFR_READDIR readdir_r
128 #if !defined(HAVE_CANONICALIZE_FILE_NAME)
130 dired_realpath(const char *file)
132 char *result = xmalloc_atomic(4096);
134 if ( xrealpath(file, result) == NULL ) {
143 fname_as_directory(Lisp_Object fname)
145 if (XSTRING_LENGTH(fname) > 0)
146 return Ffile_name_as_directory(fname);
152 pathname_matches_p(Lisp_Object pathname, Lisp_Object match,
153 struct re_pattern_buffer *bufp)
160 if (STRINGP(match)) {
161 mstr = (char*)XSTRING_DATA(pathname);
162 mlen = XSTRING_LENGTH(pathname);
163 if (re_search(bufp, mstr, mlen, 0, mlen, 0) < 0)
166 speccount2 = specpdl_depth();
167 record_unwind_protect(restore_gc_inhibit,
168 make_int(gc_currently_forbidden));
169 gc_currently_forbidden = 1;
170 if (NILP(call1_trapping_errors(
171 "Error in match function",
176 restore_match_data();
177 unbind_to(speccount2, Qnil);
184 static Lisp_Object close_directory_unwind(Lisp_Object unwind_obj)
186 DIR *d = (DIR *) get_opaque_ptr(unwind_obj);
188 free_opaque_ptr(unwind_obj);
194 dfr_inner(dirent_t *res,
195 Lisp_Object fulldir, Lisp_Object dir, Lisp_Object compbf,
196 dfr_options_t opts, Lisp_Object files_only,
197 unsigned int curdepth, dired_stack_t ds, Lisp_Object match,
198 struct re_pattern_buffer *bufp, Lisp_Object result,
199 Lisp_Object bloom_filter)
201 /* this function can GC */
206 Lisp_Object name = Qnil;
207 Lisp_Object fullname = Qnil;
208 Lisp_Object resname = Qnil;
211 char *statnam = NULL;
212 struct gcpro gcpro1, gcpro2, gcpro3;
214 GCPRO3(name, fullname, resname);
216 if (!DIRENTRY_NONEMPTY(res) ||
217 (TRIVIAL_DIRECTORY_ENTRY(res->d_name) &&
218 !(NILP(Vdirectory_files_no_trivial_p)
219 && opts->maxdepth == 0))) {
225 resname = make_ext_string(res->d_name, len, Qfile_name);
227 FAST_CONCAT(fullname, fulldir, resname);
228 FAST_CONCAT(name, dir, resname);
230 /* we want full file names? */
237 /* check if we have to recur, i.e. if res was a
238 directory, otherwise we assume name to be a
239 file and cons it to the result */
240 statnam = (char*)XSTRING_DATA(fullname);
241 #if defined(_DIRENT_HAVE_D_TYPE) && USE_D_TYPE
242 dir_p = (res->d_type == DT_DIR);
243 symlink_p = (res->d_type == DT_LNK);
244 #else /* defined(_DIRENT_HAVE_D_TYPE) && USE_D_TYPE */
245 if (lstat(statnam, &st) == 0) {
246 dir_p = (st.st_mode & S_IFMT) == S_IFDIR);
247 symlink_p = (st.st_mode & S_IFMT) == S_IFLNK);
249 #endif /* defined(_DIRENT_HAVE_D_TYPE) && USE_D_TYPE */
250 if (symlink_p && !opts->symlink_file_p) {
251 char *canon_name = NULL;
253 /* ugly things may happen when a link
254 * points back to a directory in our recurring
255 * area, ln -s . foo is a candidate
256 * now, we canonicalise the filename, i.e.
257 * resolve all symlinks and afterwards we
258 * store it to our companion bloom filter
260 canon_name = CANONICALISE_FILENAME(statnam);
262 /* now, recycle full name */
263 fullname = make_ext_string(
264 canon_name, strlen(canon_name), Qfile_name);
266 fullname = fname_as_directory(fullname);
268 /* now stat statnam */
269 if (sxemacs_stat(statnam, &st) == 0 &&
270 (st.st_mode & S_IFMT) == S_IFDIR &&
272 !(bloom_owns_p(XBLOOM(compbf), fullname))) {
281 /* argh, here is a design flaw!
282 these operations are not commutable, and it's a
283 hard-coded how `match' is interpreted.
284 * There are two possibilites:
285 * (1) check pathname against `match'
286 if nil, do not process further
287 if a directory, recur
288 if non-nil, add to result according to files_only
289 * (2) if a directory, recur
290 check pathname against `match'
291 if nil, do not add to result
292 if non-nil, add to result according to files_only
294 * Hm, I think I'd choose the latter variant, it is
295 not that performant, but it avoids two problems:
297 - With the former variant it is NOT possible to have
298 the trivial filenames on the result list, since a
299 match against "^[.]$" would exclude everything, while
300 actually it was likely meant to _solely_ exclude "."
302 - Furthermore, we _MUST_ traverse in preorder,
303 otherwise there is the possibility that pathnames are
304 on the file list already which turn out later to be
306 * Anyone wants to help brainstorming?
309 /* check if we put it on the list of matches */
310 if (NILP(files_only)) {
312 } else if (EQ(files_only, Qt) && !dir_p) {
314 } else if (EQ(files_only, Qdirs) && dir_p) {
316 } else if (EQ(files_only, Qfiles) && !dir_p && !symlink_p) {
318 } else if (EQ(files_only, Qsubdir) && !symlink_p && dir_p
319 && !TRIVIAL_DIRECTORY_ENTRY(res->d_name)) {
321 } else if (EQ(files_only, Qsymlinks) && symlink_p) {
328 && !TRIVIAL_DIRECTORY_ENTRY(res->d_name)
329 && (curdepth < opts->maxdepth);
330 if (symlink_p && !opts->symlink_file_p) {
335 dired_stack_item_t dsi;
336 dsi = xnew_and_zero(struct dired_stack_item_s);
338 dsi->depth = 1+curdepth;
339 dired_stack_push(ds, dsi);
342 if (result_p && !NILP(match)
343 && !pathname_matches_p((opts->matchfullp?fullname:name),
349 dllist_append(XDLLIST(result), (void*)resname);
350 /* add the result to the companion bloom-f */
351 /* hm, for large trees this yields a bf which
352 owns everything :( ... we need far better and
353 faster bloom techniques for it -hroptatyr */
354 if (!NILP(bloom_filter)) {
355 bloom_add(XBLOOM(bloom_filter), resname);
364 dfr_outer(Lisp_Object directory, dirent_t *ent,
365 Lisp_Object compbf, dfr_options_t opts,
366 Lisp_Object files_only, dired_stack_t ds, Lisp_Object match,
367 struct re_pattern_buffer *bufp, Lisp_Object result,
368 Lisp_Object bloom_filter)
370 dired_stack_item_t dir_dpt = dired_stack_pop(ds);
371 Lisp_Object dir = dir_dpt->dir;
372 unsigned int dpt = dir_dpt->depth;
373 Lisp_Object fulldir = Fexpand_file_name(dir, directory);
375 dirent_t *res = NULL;
376 struct gcpro gcpro1, gcpro2;
378 GCPRO2(dir, fulldir);
382 dir = fname_as_directory(dir);
383 fulldir = fname_as_directory(fulldir);
385 /* add the full directory name to the companion bloom filter */
387 bloom_add(XBLOOM(compbf), fulldir);
389 /* external format conversion is done in the encapsulation of
390 * opendir in sysdep.c
392 d = opendir((char*)XSTRING_DATA(fulldir));
394 /* why should we want this? I think spitting a warning
400 report_file_error("Opening directory", list1(fulldir));
405 warn_when_safe(Qfile, Qwarning,
406 "Opening directory `%s' failed",
407 (char*)XSTRING_DATA(fulldir));
413 record_unwind_protect(close_directory_unwind,
414 make_opaque_ptr((void *)d));
416 while (DFR_READDIR(d, ent, &res) == 0 && res != NULL) {
417 dfr_inner(res, fulldir, dir,
419 files_only, dpt, ds, match, bufp,
420 result, bloom_filter);
427 dired_stack_mark(Lisp_Object obj)
429 dired_stack_t ds = get_dynacat(obj);
430 WITH_DLLIST_TRAVERSE(
432 dired_stack_item_t dsi = dllist_item;
433 mark_object(dsi->dir));
439 dired_stack_fini(Lisp_Object obj)
441 dired_stack_t ds = get_dynacat(obj);
442 free_dired_stack(ds);
448 directory_files_magic(Lisp_Object directory, Lisp_Object match,
449 Lisp_Object files_only, Lisp_Object bloom_filter,
452 /* This function can GC */
453 Lisp_Object result = wrap_dllist(make_dllist());
454 Lisp_Object lds = Qnil;
455 dired_stack_t ds = NULL;
456 dired_stack_item_t ds_item = NULL;
457 /* this is a companion bloom filter,
458 * we register processed directories in here and hence avoid
459 * processing an entry twice */
460 Lisp_Object compbf = Qnil;
461 int speccount = specpdl_depth();
462 struct re_pattern_buffer *bufp = NULL;
463 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
465 ds = new_dired_stack();
466 lds = make_dynacat(ds);
467 set_dynacat_marker(lds, dired_stack_mark);
468 set_dynacat_finaliser(lds, (dynacat_finaliser_f)dired_stack_fini);
469 GCPRO5(directory, result, compbf, bloom_filter, lds);
471 /* SXEmacs: this should come after Ffile_name_as_directory() to avoid
472 potential regexp cache smashage. It comes before the opendir()
473 because it might signal an error. */
475 if (STRINGP(match)) {
477 /* MATCH might be a flawed regular expression. Rather
478 than catching and signalling our own errors, we just
479 call compile_pattern to do the work for us. */
480 bufp = compile_pattern(match, 0, Qnil, 0, ERROR_ME);
481 /* Now *bufp is the compiled form of MATCH; don't call
482 anything which might compile a new regexp until we
483 are done with the loop! */
485 } else if (!NILP(Ffunctionp(match))) {
488 return wrong_type_argument(Qstringp, match);
492 regex_match_object = Qnil;
493 regex_emacs_buffer = current_buffer;
495 if (opts->maxdepth > 0) {
496 compbf = make_bloom(8192, 8);
499 /* set up the directories queue */
500 ds_item = xnew_and_zero(struct dired_stack_item_s);
501 ds_item->dir = make_string((Bufbyte*)"", 0);
503 dired_stack_push(ds, ds_item);
505 /* alloc the directory entry pointer */
507 dirent_t _ent, *ent = &_ent;
510 memset(ent, 0, sizeof(dirent_t));
512 while (dired_stack_size(ds) > 0) {
513 dfr_outer(directory, ent, compbf,
514 opts, files_only, ds, match,
515 bufp, result, bloom_filter);
516 /* This will close the dir */
517 unbind_to(speccount, Qnil);
522 /* save the companion bloom filter */
523 Fput(result, Qcompanion_bf, compbf);
530 directory_files_canonicalise_dn(Lisp_Object directory)
535 /* expand the directory argument and canonicalise */
536 directory = Fexpand_file_name(directory, Qnil);
537 directory = fname_as_directory(directory);
539 RETURN_UNGCPRO(directory);
543 directory_files_resultify(Lisp_Object result, Lisp_Object result_type)
545 /* This function can GC */
546 Lisp_Object final_result = Qnil;
547 struct gcpro gcpro1, gcpro2, gcpro3;
548 GCPRO3(result, result_type, final_result);
550 /* see if the user requested a dllist */
551 if (EQ(result_type, Qdllist)) {
552 final_result = result;
553 } else if (NILP(result_type) || EQ(result_type, Qsorted_list)) {
554 final_result = Fdllist_to_list_reversed(result);
555 final_result = Fsort(final_result, Qstring_lessp);
556 } else if (EQ(result_type, Qdesc_sorted_list)) {
557 final_result = Fdllist_to_list(result);
558 final_result = Fsort(final_result, Qstring_greaterp);
559 } else if (!NILP(result_type) || EQ(result_type, Qlist)) {
560 final_result = Fdllist_to_list(result);
568 call9(Lisp_Object fn,
569 Lisp_Object arg0, Lisp_Object arg1, Lisp_Object arg2,
570 Lisp_Object arg3, Lisp_Object arg4, Lisp_Object arg5,
571 Lisp_Object arg6, Lisp_Object arg7, Lisp_Object arg8)
573 /* This function can GC */
575 Lisp_Object res, args[10] = {fn, arg0, arg1, arg2, arg3,
576 arg4, arg5, arg6, arg7, arg8};
578 GCPROn(args, countof(args));
579 res = Ffuncall(10, args);
586 EXFUN(Fdirectory_files_recur, 8);
588 DEFUN("directory-files", Fdirectory_files, 1, 5, 0, /*
589 Return a list of names of files in DIRECTORY.
590 Args are DIRECTORY &optional FULL MATCH RESULT-TYPE FILES_ONLY
592 There are four optional arguments:
594 - t to return absolute pathnames of the files.
595 - match-full to return and match on absolute pathnames of the files.
596 - nil to return relative filenames.
598 If MATCH is non-nil, it may be a string indicating a regular
599 expression which pathnames must meet in order to be returned.
600 Moreover, a predicate function can be specified which is called with
601 one argument, the pathname in question. On non-nil return value, the
602 pathname is considered in the final result, otherwise it is ignored.
603 Note that FULL affects whether the match is done on the filename of
606 Optional argument RESULT-TYPE can be one of:
607 - sorted-list (default) to return a list, sorted in alphabetically
609 - desc-sorted-list to return a list, sorted in alphabetically
611 - list to return an unsorted list
612 - dllist to return an unsorted dllist
613 The two latter types can be useful if you plan to sort the result
614 yourself, or want to feed the result to further processing.
616 For compatibility with XEmacs' NOSORT argument to this function,
617 RESULT-TYPE can also be any non-nil value. In that case it will
618 return an unsorted list. (https://issues.sxemacs.org/show_bug.cgi?id=163)
620 Optional argument FILES-ONLY can be one of:
621 - nil (default) to return all entries (files, symlinks, and
622 subdirectories) in DIRECTORY
623 - t to return only files and symlinks to files in DIRECTORY
624 - dirs to return only directories and symlinks to directories
625 - files to return only files -- but *NOT* symlinks to files
626 - subdir to return only subdirectories -- but *NOT* symlinks to
627 directories, nor the current or parent directories
628 - symlinks to return only symlinks -- but *NOT* real files
631 (directory, full, match, result_type, files_only))
633 Lisp_Object handler = Qnil;
634 Lisp_Object result = Qnil;
635 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
636 /* just a convenience array for gc pro'ing */
637 Lisp_Object args[6] = {
638 directory, match, result_type, files_only,
641 struct dfr_options_s opts = {
643 .fullp = !NILP(full),
645 .matchfullp = EQ(full,Qmatch_full),
649 /* argument checks */
650 CHECK_STRING(directory);
652 GCPROn(args, countof(args));
654 directory = directory_files_canonicalise_dn(directory);
656 /* If the file name has special constructs in it,
657 call the corresponding file handler. */
658 handler = Ffind_file_name_handler(directory, Qdirectory_files);
659 if (!NILP(handler)) {
661 return call6(handler, Qdirectory_files,
662 directory, full, match, result_type, files_only);
665 result = directory_files_magic(directory, match,
666 files_only, Qnil /* bloom_filter */,
670 return directory_files_resultify(result, result_type);
673 DEFUN("directory-files-recur", Fdirectory_files_recur, 1, 8, 0, /*
674 Like `directory-files' but recursive and much faster.
675 Args are DIRECTORY &optional FULL MATCH RESULT_TYPE FILES-ONLY MAXDEPTH
676 SYMLINK_IS_FILE BLOOM_FILTER
678 `directory-files-recur' will not include the any of the current and
679 parent directory entries.
682 - t to return absolute pathnames of the files.
683 - match-full to return and match on absolute pathnames of the files.
684 - nil to return relative filenames.
686 If MATCH is non-nil, it may be a string indicating a regular
687 expression which pathnames must meet in order to be returned.
688 Moreover, a predicate function can be specified which is called with
689 one argument, the pathname in question. On non-nil return value, the
690 pathname is considered in the final result, otherwise it is ignored.
691 Note that FULL affects whether the match is done on the filename of
694 Optional argument RESULT-TYPE can be one of:
695 - sorted-list (default) to return a list, sorted in alphabetically
697 - desc-sorted-list to return a list, sorted in alphabetically
699 - list to return an unsorted list
700 - dllist to return an unsorted dllist
701 The two latter types can be useful if you plan to sort the result
702 yourself, or want to feed the result to further processing.
704 Optional argument FILES-ONLY can be one of:
705 - nil (default) to return all entries (files, symlinks, and
707 - t to return only files and symlinks to files
708 - dirs to return only directories and symlinks to directories
709 - files to return only files -- but *NOT* symlinks to files
710 - subdir to return only subdirectories -- but *NOT* symlinks to
712 - symlinks to return only symlinks -- but *NOT* real files
715 Optional argument MAXDEPTH \(a positive integer\) specifies the
716 maximal recursion depth, use 0 to emulate old `directory-files'.
718 Optional argument SYMLINK-IS-FILE specifies whether symlinks should be
719 recursed into \(which is the default behaviour\). When symlinks to
720 directories are not recursed the FILES-ONLY option takes effect.
722 Optional argument BLOOM-FILTER specifies a bloom filter where
723 to put results in addition to the ordinary result list.
725 (directory, full, match, result_type, files_only, maxdepth,
726 symlink_is_file, bloom_filter))
728 Lisp_Object handler = Qnil, result = Qnil;
729 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
730 /* just a convenience array for gc pro'ing */
731 Lisp_Object args[8] = {
732 directory, match, result_type, files_only,
733 symlink_is_file, bloom_filter, handler, result};
735 struct dfr_options_s opts = {
737 .fullp = !NILP(full),
738 .symlink_file_p = !NILP(symlink_is_file),
739 .matchfullp = EQ(full, Qmatch_full),
743 /* argument checks */
744 CHECK_STRING(directory);
745 if (!NILP(maxdepth)) {
746 CHECK_NATNUM(maxdepth);
747 opts.maxdepth = XUINT(maxdepth);
750 GCPROn(args, countof(args));
752 directory = directory_files_canonicalise_dn(directory);
754 /* If the file name has special constructs in it,
755 call the corresponding file handler. */
756 handler = Ffind_file_name_handler(directory, Qdirectory_files_recur);
757 if (!NILP(handler)) {
760 res = call9(handler, Qdirectory_files_recur,
761 directory, full, match, result_type, files_only,
762 maxdepth, symlink_is_file, bloom_filter);
767 result = directory_files_magic(directory, match,
768 files_only, bloom_filter,
770 /* convert to final result type */
771 result = directory_files_resultify(result, result_type);
777 static Lisp_Object file_name_completion(Lisp_Object file,
778 Lisp_Object directory,
779 int all_flag, int ver_flag);
781 DEFUN("file-name-completion", Ffile_name_completion, 2, 2, 0, /*
782 Complete file name PARTIAL-FILENAME in directory DIRECTORY.
783 Return the longest prefix common to all file names in DIRECTORY
784 that start with PARTIAL-FILENAME.
785 If there is only one and PARTIAL-FILENAME matches it exactly, return t.
786 Return nil if DIRECTORY contains no name starting with PARTIAL-FILENAME.
788 File names which end with any member of `completion-ignored-extensions'
789 are not considered as possible completions for PARTIAL-FILENAME unless
790 there is no other possible completion. `completion-ignored-extensions'
791 is not applied to the names of directories.
793 (partial_filename, directory))
795 /* This function can GC. GC checked 1996.04.06. */
798 /* If the directory name has special constructs in it,
799 call the corresponding file handler. */
800 handler = Ffind_file_name_handler(directory, Qfile_name_completion);
802 return call3(handler, Qfile_name_completion, partial_filename,
805 /* If the file name has special constructs in it,
806 call the corresponding file handler. */
808 Ffind_file_name_handler(partial_filename, Qfile_name_completion);
810 return call3(handler, Qfile_name_completion, partial_filename,
813 return file_name_completion(partial_filename, directory, 0, 0);
816 DEFUN("file-name-all-completions", Ffile_name_all_completions, 2, 2, 0, /*
817 Return a list of all completions of PARTIAL-FILENAME in DIRECTORY.
818 These are all file names in DIRECTORY which begin with PARTIAL-FILENAME.
820 (partial_filename, directory))
822 /* This function can GC. GC checked 1997.06.04. */
827 directory = Fexpand_file_name(directory, Qnil);
828 /* If the file name has special constructs in it,
829 call the corresponding file handler. */
831 Ffind_file_name_handler(directory, Qfile_name_all_completions);
834 return call3(handler, Qfile_name_all_completions,
835 partial_filename, directory);
837 return file_name_completion(partial_filename, directory, 1, 0);
841 file_name_completion_stat(Lisp_Object directory, DIRENTRY * dp,
842 struct stat *st_addr)
844 Bytecount len = NAMLEN(dp);
845 Bytecount pos = XSTRING_LENGTH(directory);
847 char *fullname = (char *)alloca(len + pos + 2);
849 memcpy(fullname, XSTRING_DATA(directory), pos);
850 if (!IS_DIRECTORY_SEP(fullname[pos - 1]))
851 fullname[pos++] = DIRECTORY_SEP;
853 memcpy(fullname + pos, dp->d_name, len);
854 fullname[pos + len] = 0;
857 /* We want to return success if a link points to a nonexistent file,
858 but we want to return the status for what the link points to,
859 in case it is a directory. */
860 value = lstat(fullname, st_addr);
861 if (S_ISLNK(st_addr->st_mode))
862 (void)sxemacs_stat(fullname, st_addr);
864 value = sxemacs_stat(fullname, st_addr);
869 static Lisp_Object file_name_completion_unwind(Lisp_Object locative)
872 Lisp_Object obj = XCAR(locative);
875 d = (DIR *) get_opaque_ptr(obj);
877 free_opaque_ptr(obj);
879 free_cons(XCONS(locative));
884 file_name_completion(Lisp_Object file, Lisp_Object directory, int all_flag,
887 /* This function can GC */
890 Lisp_Object bestmatch = Qnil;
891 Charcount bestmatchsize = 0;
894 int speccount = specpdl_depth();
895 Charcount file_name_length;
896 Lisp_Object locative;
897 struct gcpro gcpro1, gcpro2, gcpro3;
899 GCPRO3(file, directory, bestmatch);
903 #ifdef FILE_SYSTEM_CASE
904 file = FILE_SYSTEM_CASE(file);
906 directory = Fexpand_file_name(directory, Qnil);
907 file_name_length = XSTRING_CHAR_LENGTH(file);
909 /* With passcount = 0, ignore files that end in an ignored extension.
910 If nothing found then try again with passcount = 1, don't ignore them.
911 If looking for all completions, start with passcount = 1,
912 so always take even the ignored ones.
914 ** It would not actually be helpful to the user to ignore any possible
915 completions when making a list of them.** */
917 /* We cannot use close_directory_unwind() because we change the
918 directory. The old code used to just avoid signaling errors, and
919 call closedir, but it was wrong, because it made sane handling of
920 QUIT impossible and, besides, various utility functions like
921 regexp_ignore_completion_p can signal errors. */
922 locative = noseeum_cons(Qnil, Qnil);
923 record_unwind_protect(file_name_completion_unwind, locative);
925 for (passcount = !!all_flag; NILP(bestmatch) && passcount < 2;
927 Lisp_Object tmp_dfn = Fdirectory_file_name(directory);
928 d = opendir((char *)XSTRING_DATA(tmp_dfn));
930 report_file_error("Opening directory",
933 XCAR(locative) = make_opaque_ptr((void *)d);
935 /* Loop reading blocks */
939 /* scmp() works in characters, not bytes, so we have to compute
943 int ignored_extension_p = 0;
950 /* Cast to Bufbyte* is OK, as readdir() Mule-encapsulates. */
951 d_name = (Bufbyte *) dp->d_name;
953 cclen = bytecount_to_charcount(d_name, len);
957 if (!DIRENTRY_NONEMPTY(dp)
958 || cclen < file_name_length
959 || 0 <= scmp(d_name, XSTRING_DATA(file),
963 if (file_name_completion_stat(directory, dp, &st) < 0)
966 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR);
968 /* "." and ".." are never interesting as completions, but are
969 actually in the way in a directory containing only one file. */
971 && TRIVIAL_DIRECTORY_ENTRY(dp->d_name))
974 /* Compare extensions-to-be-ignored against end of this file name */
975 /* if name is not an exact match against specified string. */
976 if (!passcount && cclen > file_name_length) {
978 /* and exit this for loop if a match is found */
979 EXTERNAL_LIST_LOOP(tem,
980 Vcompletion_ignored_extensions)
982 Lisp_Object elt = XCAR(tem);
989 XSTRING_CHAR_LENGTH(elt);
999 ignored_extension_p = 1;
1006 /* If an ignored-extensions match was found,
1007 don't process this name as a completion. */
1008 if (!passcount && ignored_extension_p)
1012 && regexp_ignore_completion_p(d_name, Qnil, 0,
1016 /* Update computation of how much all possible completions match */
1019 if (all_flag || NILP(bestmatch)) {
1020 Lisp_Object name = Qnil;
1021 struct gcpro ngcpro1;
1023 /* This is a possible completion */
1024 name = make_string(d_name, len);
1025 if (directoryp) /* Completion is a directory; end it with '/' */
1026 name = Ffile_name_as_directory(name);
1028 bestmatch = Fcons(name, bestmatch);
1032 XSTRING_CHAR_LENGTH(name);
1036 Charcount compare = min(bestmatchsize, cclen);
1037 Bufbyte *p1 = XSTRING_DATA(bestmatch);
1038 Bufbyte *p2 = d_name;
1039 Charcount matchsize = scmp(p1, p2, compare);
1042 matchsize = compare;
1043 if (completion_ignore_case) {
1044 /* If this is an exact match except for case,
1045 use it as the best match rather than one that is not
1046 an exact match. This way, we get the case pattern
1047 of the actual match. */
1048 if ((matchsize == cclen
1049 && matchsize + !!directoryp
1050 < XSTRING_CHAR_LENGTH(bestmatch))
1052 /* If there is no exact match ignoring case,
1053 prefer a match that does not change the case
1055 (((matchsize == cclen)
1057 (matchsize + !!directoryp
1059 XSTRING_CHAR_LENGTH(bestmatch)))
1060 /* If there is more than one exact match aside from
1061 case, and one of them is exact including case,
1065 file_name_length, 0)
1071 make_string(d_name, len);
1074 Ffile_name_as_directory
1079 /* If this directory all matches,
1080 see if implicit following slash does too. */
1082 && compare == matchsize
1083 && bestmatchsize > matchsize
1085 IS_ANY_SEP(charptr_emchar_n(p1, matchsize)))
1087 bestmatchsize = matchsize;
1091 free_opaque_ptr(XCAR(locative));
1092 XCAR(locative) = Qnil;
1095 unbind_to(speccount, Qnil);
1099 if (all_flag || NILP(bestmatch))
1101 if (matchcount == 1 && bestmatchsize == file_name_length)
1103 return Fsubstring(bestmatch, Qzero, make_int(bestmatchsize));
1106 static Lisp_Object user_name_completion(Lisp_Object user,
1107 int all_flag, int *uniq);
1109 DEFUN("user-name-completion", Fuser_name_completion, 1, 1, 0, /*
1110 Complete user name from PARTIAL-USERNAME.
1111 Return the longest prefix common to all user names starting with
1112 PARTIAL-USERNAME. If there is only one and PARTIAL-USERNAME matches
1113 it exactly, returns t. Return nil if there is no user name starting
1114 with PARTIAL-USERNAME.
1118 return user_name_completion(partial_username, 0, NULL);
1121 DEFUN("user-name-completion-1", Fuser_name_completion_1, 1, 1, 0, /*
1122 Complete user name from PARTIAL-USERNAME.
1124 This function is identical to `user-name-completion', except that
1125 the cons of the completion and an indication of whether the
1126 completion was unique is returned.
1128 The car of the returned value is the longest prefix common to all user
1129 names that start with PARTIAL-USERNAME. If there is only one and
1130 PARTIAL-USERNAME matches it exactly, the car is t. The car is nil if
1131 there is no user name starting with PARTIAL-USERNAME. The cdr of the
1132 result is non-nil if and only if the completion returned in the car
1138 Lisp_Object completed =
1139 user_name_completion(partial_username, 0, &uniq);
1140 return Fcons(completed, uniq ? Qt : Qnil);
1143 DEFUN("user-name-all-completions", Fuser_name_all_completions, 1, 1, 0, /*
1144 Return a list of all user name completions from PARTIAL-USERNAME.
1145 These are all the user names which begin with PARTIAL-USERNAME.
1149 return user_name_completion(partial_username, 1, NULL);
1158 struct user_name *user_names;
1161 EMACS_TIME last_rebuild_time;
1163 static struct user_cache user_cache;
1165 static void free_user_cache(struct user_cache *cache)
1168 for (i = 0; i < cache->length; i++)
1169 xfree(cache->user_names[i].ptr);
1170 xfree(cache->user_names);
1174 static Lisp_Object user_name_completion_unwind(Lisp_Object cache_incomplete_p)
1177 speed_up_interrupts();
1179 if (!NILP(XCAR(cache_incomplete_p)))
1180 free_user_cache(&user_cache);
1182 free_cons(XCONS(cache_incomplete_p));
1187 #define USER_CACHE_TTL (24*60*60) /* Time to live: 1 day, in seconds */
1190 user_name_completion(Lisp_Object user, int all_flag, int *uniq)
1192 /* This function can GC */
1194 Lisp_Object bestmatch = Qnil;
1195 Charcount bestmatchsize = 0;
1196 Charcount user_name_length;
1199 struct gcpro gcpro1, gcpro2;
1201 GCPRO2(user, bestmatch);
1205 user_name_length = XSTRING_CHAR_LENGTH(user);
1207 /* Cache user name lookups because it tends to be quite slow.
1208 * Rebuild the cache occasionally to catch changes */
1210 if (user_cache.user_names &&
1211 (EMACS_SECS(t) - EMACS_SECS(user_cache.last_rebuild_time)
1213 free_user_cache(&user_cache);
1215 if (!user_cache.user_names) {
1217 Lisp_Object cache_incomplete_p = noseeum_cons(Qt, Qnil);
1218 int speccount = specpdl_depth();
1220 slow_down_interrupts();
1222 record_unwind_protect(user_name_completion_unwind,
1223 cache_incomplete_p);
1224 while ((pwd = getpwent())) {
1226 DO_REALLOC(user_cache.user_names, user_cache.size,
1227 user_cache.length + 1, struct user_name);
1228 TO_INTERNAL_FORMAT(C_STRING, pwd->pw_name,
1231 user_names[user_cache.length].ptr,
1232 user_cache.user_names[user_cache.
1235 user_cache.length++;
1237 XCAR(cache_incomplete_p) = Qnil;
1238 unbind_to(speccount, Qnil);
1240 EMACS_GET_TIME(user_cache.last_rebuild_time);
1243 for (i = 0; i < user_cache.length; i++) {
1244 Bufbyte *u_name = user_cache.user_names[i].ptr;
1245 Bytecount len = user_cache.user_names[i].len;
1246 /* scmp() works in chars, not bytes, so we have to compute this: */
1247 Charcount cclen = bytecount_to_charcount(u_name, len);
1251 if (cclen < user_name_length
1252 || 0 <= scmp_1(u_name, XSTRING_DATA(user), user_name_length,
1256 matchcount++; /* count matching completions */
1258 if (all_flag || NILP(bestmatch)) {
1259 Lisp_Object name = Qnil;
1260 struct gcpro ngcpro1;
1262 /* This is a possible completion */
1263 name = make_string(u_name, len);
1265 bestmatch = Fcons(name, bestmatch);
1268 bestmatchsize = XSTRING_CHAR_LENGTH(name);
1272 Charcount compare = min(bestmatchsize, cclen);
1273 Bufbyte *p1 = XSTRING_DATA(bestmatch);
1274 Bufbyte *p2 = u_name;
1275 Charcount matchsize = scmp_1(p1, p2, compare, 0);
1278 matchsize = compare;
1280 bestmatchsize = matchsize;
1287 *uniq = (matchcount == 1);
1289 if (all_flag || NILP(bestmatch))
1291 if (matchcount == 1 && bestmatchsize == user_name_length)
1293 return Fsubstring(bestmatch, Qzero, make_int(bestmatchsize));
1296 Lisp_Object make_directory_hash_table(const char *path)
1299 if ((d = opendir(path))) {
1302 make_lisp_hash_table(20, HASH_TABLE_NON_WEAK,
1305 while ((dp = readdir(d))) {
1306 Bytecount len = NAMLEN(dp);
1307 if (DIRENTRY_NONEMPTY(dp))
1308 /* Cast to Bufbyte* is OK, as readdir() Mule-encapsulates. */
1309 Fputhash(make_string
1310 ((Bufbyte *) dp->d_name, len), Qt,
1320 /* ... never used ... should use list2 directly anyway ... */
1321 /* NOTE: This function can never return a negative value. */
1322 Lisp_Object wasteful_word_to_lisp(unsigned int item)
1324 /* Compatibility: in other versions, file-attributes returns a LIST
1325 of two 16 bit integers... */
1326 Lisp_Object cons = word_to_lisp(item);
1327 XCDR(cons) = Fcons(XCDR(cons), Qnil);
1332 DEFUN("file-attributes", Ffile_attributes, 1, 1, 0, /*
1333 Return a list of attributes of file FILENAME.
1334 Value is nil if specified file cannot be opened.
1335 Otherwise, list elements are:
1336 0. t for directory, string (name linked to) for symbolic link, or nil.
1337 1. Number of links to file.
1340 4. Last access time, as a list of two integers.
1341 First integer has high-order 16 bits of time, second has low 16 bits.
1342 5. Last modification time, likewise.
1343 6. Last status change time, likewise.
1344 7. Size in bytes. (-1, if number is out of range).
1345 8. File modes, as a string of ten letters or dashes as in ls -l.
1346 9. t iff file's gid would change if file were deleted and recreated.
1350 If file does not exist, returns nil.
1354 /* This function can GC. GC checked 1997.06.04. */
1355 Lisp_Object values[12];
1356 #if defined (BSD4_2) || defined (BSD4_3) || \
1357 !defined HAVE_BDWGC || !defined EF_USE_BDWGC
1358 Lisp_Object directory = Qnil;
1359 #endif /* BSD4_2 || BSD4_3 || !BDWGC */
1362 Lisp_Object handler;
1363 struct gcpro gcpro1, gcpro2;
1365 GCPRO2(filename, directory);
1366 filename = Fexpand_file_name(filename, Qnil);
1368 /* If the file name has special constructs in it,
1369 call the corresponding file handler. */
1370 handler = Ffind_file_name_handler(filename, Qfile_attributes);
1371 if (!NILP(handler)) {
1373 return call2(handler, Qfile_attributes, filename);
1376 if (lstat((char *)XSTRING_DATA(filename), &s) < 0) {
1381 directory = Ffile_name_directory(filename);
1384 switch (s.st_mode & S_IFMT) {
1393 values[0] = Ffile_symlink_p(filename);
1397 values[1] = make_int(s.st_nlink);
1398 values[2] = make_int(s.st_uid);
1399 values[3] = make_int(s.st_gid);
1400 values[4] = make_time(s.st_atime);
1401 values[5] = make_time(s.st_mtime);
1402 values[6] = make_time(s.st_ctime);
1403 values[7] = make_int((EMACS_INT) s.st_size);
1404 /* If the size is out of range, give back -1. */
1405 /* #### Fix when Emacs gets bignums! */
1406 if (XINT(values[7]) != s.st_size)
1407 values[7] = make_int(-1);
1408 filemodestring(&s, modes);
1409 values[8] = make_string((Bufbyte *) modes, 10);
1410 #if defined (BSD4_2) || defined (BSD4_3) /* file gid will be dir gid */
1414 if (!NILP(directory)
1415 && sxemacs_stat((char *)XSTRING_DATA(directory), &sdir) == 0)
1416 values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil;
1417 else /* if we can't tell, assume worst */
1420 #else /* file gid will be egid */
1421 values[9] = (s.st_gid != getegid())? Qt : Qnil;
1422 #endif /* BSD4_2 or BSD4_3 */
1423 values[10] = make_int(s.st_ino);
1424 values[11] = make_int(s.st_dev);
1426 return Flist(countof(values), values);
1430 /************************************************************************/
1431 /* initialization */
1432 /************************************************************************/
1434 void syms_of_dired(void)
1436 defsymbol(&Qdirectory_files, "directory-files");
1437 defsymbol(&Qdirectory_files_recur, "directory-files-recur");
1438 defsymbol(&Qfile_name_completion, "file-name-completion");
1439 defsymbol(&Qfile_name_all_completions, "file-name-all-completions");
1440 defsymbol(&Qfile_attributes, "file-attributes");
1442 defsymbol(&Qcompanion_bf, "companion-bf");
1443 defsymbol(&Qsorted_list, "sorted-list");
1444 defsymbol(&Qdesc_sorted_list, "desc-sorted-list");
1445 defsymbol(&Qunsorted_list, "unsorted-list");
1446 defsymbol(&Qmatch_full, "match-full");
1447 defsymbol(&Qsubdir, "subdir");
1448 defsymbol(&Qfiles, "files");
1449 defsymbol(&Qdirs, "dirs");
1450 defsymbol(&Qsymlinks, "symlinks");
1452 DEFSUBR(Fdirectory_files);
1453 DEFSUBR(Fdirectory_files_recur);
1454 DEFSUBR(Ffile_name_completion);
1455 DEFSUBR(Ffile_name_all_completions);
1456 DEFSUBR(Fuser_name_completion);
1457 DEFSUBR(Fuser_name_completion_1);
1458 DEFSUBR(Fuser_name_all_completions);
1459 DEFSUBR(Ffile_attributes);
1462 void vars_of_dired(void)
1464 DEFVAR_LISP("completion-ignored-extensions",
1465 &Vcompletion_ignored_extensions /*
1466 *Completion ignores filenames ending in any string in this list.
1467 This variable does not affect lists of possible completions,
1468 but does affect the commands that actually do completions.
1469 It is used by the function `file-name-completion'.
1471 Vcompletion_ignored_extensions = Qnil;
1473 DEFVAR_LISP("directory-files-no-trivial-p",
1474 &Vdirectory_files_no_trivial_p /*
1475 Determine whether to _not_ add the trivial directory entries
1477 ATTENTION: This variable is definitely NOT for users.
1478 For easy temporary circumvention use a let binding.
1480 Vdirectory_files_no_trivial_p = Qnil;