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 Qnoncyclic_directory, Qcyclic_directory;
57 Lisp_Object Qsymlink, Qalive_symlink, Qdead_symlink;
58 Lisp_Object Qwhiteout;
60 /* On GNU libc systems the declaration is only visible with _GNU_SOURCE. */
61 #if defined(HAVE_CANONICALIZE_FILE_NAME)
62 # if defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME)
63 extern char *canonicalize_file_name(const char *);
65 #define CANONICALISE_FILENAME(f) canonicalize_file_name(f)
67 #else /* !defined(HAVE_CANONICALIZE_FILE_NAME) */
69 static char *dired_realpath(const char *);
70 #define CANONICALISE_FILENAME(f) dired_realpath(f)
71 #endif /* defined(HAVE_CANONICALIZE_FILE_NAME) */
73 #ifndef TRIVIAL_DIRECTORY_ENTRY
74 #define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, ".."))
78 /* this variant is much too slow */
79 #define FAST_CONCAT(tgt, s1, s2) tgt = concat2(s1, s2);
82 #define FAST_CONCAT(tgt, s1, s2) \
84 tgt = make_uninit_string(XSTRING_LENGTH(s1)+XSTRING_LENGTH(s2)); \
85 memcpy(XSTRING_DATA(tgt), XSTRING_DATA(s1), XSTRING_LENGTH(s1)); \
86 memcpy(XSTRING_DATA(tgt)+XSTRING_LENGTH(s1), \
87 XSTRING_DATA(s2), XSTRING_LENGTH(s2)); \
91 /* some more declarations */
92 typedef struct dired_stack_item_s *dired_stack_item_t;
93 typedef struct dfr_options_s *dfr_options_t;
95 struct dired_stack_item_s {
100 struct dfr_options_s {
101 long unsigned int maxdepth;
103 _Bool symlink_file_p:1;
106 static Lisp_Object fname_as_directory(Lisp_Object);
107 static int pathname_matches_p(Lisp_Object, Lisp_Object,
108 struct re_pattern_buffer*);
110 #define dired_stack_t dllist_t
111 #define new_dired_stack() make_noseeum_dllist()
112 #define free_dired_stack(ds) free_noseeum_dllist(ds)
113 #define dired_stack_pop(ds) (dired_stack_item_t)dllist_pop_car(ds)
114 #define dired_stack_push(ds, p) dllist_append(ds, p)
115 #define dired_stack_size(ds) dllist_size(ds)
118 #if defined(HAVE_LARGEFILE)
119 #define dirent_t struct dirent64
120 #define DFR_READDIR readdir64_r
122 #define dirent_t struct dirent
123 #define DFR_READDIR readdir_r
126 #if !defined(HAVE_CANONICALIZE_FILE_NAME)
128 dired_realpath(const char *file)
130 char *result = xmalloc_atomic(4096);
132 if ( xrealpath(file, result) == NULL ) {
141 fname_as_directory(Lisp_Object fname)
143 if (XSTRING_LENGTH(fname) > 0)
144 return Ffile_name_as_directory(fname);
150 pathname_matches_p(Lisp_Object pathname, Lisp_Object match,
151 struct re_pattern_buffer *bufp)
158 if (STRINGP(match)) {
159 mstr = (char*)XSTRING_DATA(pathname);
160 mlen = XSTRING_LENGTH(pathname);
161 if (re_search(bufp, mstr, mlen, 0, mlen, 0) < 0)
164 speccount2 = specpdl_depth();
165 record_unwind_protect(restore_gc_inhibit,
166 make_int(gc_currently_forbidden));
167 gc_currently_forbidden = 1;
168 if (NILP(call1_trapping_errors(
169 "Error in match function",
174 restore_match_data();
175 unbind_to(speccount2, Qnil);
182 static Lisp_Object close_directory_unwind(Lisp_Object unwind_obj)
184 DIR *d = (DIR *) get_opaque_ptr(unwind_obj);
186 free_opaque_ptr(unwind_obj);
192 dfr_inner(dirent_t *res,
193 Lisp_Object fulldir, Lisp_Object dir, Lisp_Object compbf,
194 dfr_options_t opts, Lisp_Object files_only,
195 unsigned int curdepth, dired_stack_t ds, Lisp_Object match,
196 struct re_pattern_buffer *bufp, Lisp_Object result,
197 Lisp_Object bloom_filter)
199 /* this function can GC */
202 Lisp_Object name = Qnil;
203 Lisp_Object fullname = Qnil;
204 Lisp_Object resname = Qnil;
207 char *statnam = NULL;
208 struct gcpro gcpro1, gcpro2, gcpro3;
210 GCPRO3(name, fullname, resname);
212 if (!DIRENTRY_NONEMPTY(res) ||
213 (TRIVIAL_DIRECTORY_ENTRY(res->d_name) &&
214 !(NILP(Vdirectory_files_no_trivial_p) && opts->maxdepth == 0))) {
220 resname = make_ext_string(res->d_name, len, Qfile_name);
222 FAST_CONCAT(fullname, fulldir, resname);
223 FAST_CONCAT(name, dir, resname);
225 /* we want full file names? */
232 /* check if we have to recur, i.e. if res was a
233 directory, otherwise we assume name to be a
234 file and cons it to the result */
235 #if defined(_DIRENT_HAVE_D_TYPE) && USE_D_TYPE
236 if (res->d_type == DT_DIR) {
238 } else if (res->d_type == DT_LNK && !opts->symlink_file_p) {
239 char *canon_name = NULL;
241 statnam = (char*)XSTRING_DATA(fullname);
243 /* ugly things may happen when a link
244 * points back to a directory in our recurring
245 * area, ln -s . foo is a candidate
246 * now, we canonicalise the filename, i.e.
247 * resolve all symlinks and afterwards we
248 * store it to our companion bloom filter
250 canon_name = CANONICALISE_FILENAME(statnam);
252 /* now, recycle full name */
253 fullname = make_ext_string(
254 canon_name, strlen(canon_name), Qfile_name);
256 fullname = fname_as_directory(fullname);
258 /* now stat statnam */
259 if (sxemacs_stat(statnam, &st) == 0 &&
260 (st.st_mode & S_IFMT) == S_IFDIR &&
262 !(bloom_owns_p(XBLOOM(compbf), fullname))) {
270 #else /* defined(_DIRENT_HAVE_D_TYPE) && USE_D_TYPE */
271 statnam = (char*)XSTRING_DATA(fullname);
272 if (lstat(statnam, &st) == 0) {
273 if ((st.st_mode & S_IFMT) == S_IFDIR) {
275 } else if ((st.st_mode & S_IFMT) == S_IFLNK && !opts->symlink_file_p) {
276 char *canon_name = NULL;
278 /* ugly things may happen when a link
279 * points back to a directory in our recurring
280 * area, ln -s . foo is a candidate
281 * now, we canonicalise the filename, i.e.
282 * resolve all symlinks and afterwards we
283 * store it to our companion bloom filter
284 * The ugly things are even worse than in the
285 * case of D_TYPE, since we !always! have to
286 * check against the bloom filter.
288 canon_name = CANONICALISE_FILENAME(statnam);
291 /* now, recycle full name */
292 fullname = make_ext_string(
293 canon_name, strlen(canon_name),
296 fullname = fname_as_directory(fullname);
298 /* now stat statnam */
299 if (sxemacs_stat(statnam, &st) == 0 &&
300 (st.st_mode & S_IFMT) == S_IFDIR &&
301 /* does the bloom know about the dir? */
303 !(bloom_owns_p(XBLOOM(compbf), fullname))) {
313 #endif /* defined(_DIRENT_HAVE_D_TYPE) && USE_D_TYPE */
315 /* argh, here is a design flaw!
316 these operations are not commutable, and it's a
317 hard-coded how `match' is interpreted.
318 * There are two possibilites:
319 * (1) check pathname against `match'
320 if nil, do not process further
321 if a directory, recur
322 if non-nil, add to result according to files_only
323 * (2) if a directory, recur
324 check pathname against `match'
325 if nil, do not add to result
326 if non-nil, add to result according to files_only
328 * Hm, I think I'd choose the latter variant, it is
329 not that performant, but it avoids two problems:
331 - With the former variant it is NOT possible to have
332 the trivial filenames on the result list, since a
333 match against "^[.]$" would exclude everything, while
334 actually it was likely meant to _solely_ exclude "."
336 - Furthermore, we _MUST_ traverse in preorder,
337 otherwise there is the possibility that pathnames are
338 on the file list already which turn out later to be
340 * Anyone wants to help brainstorming?
343 /* check if we put it on the list of matches */
344 if (NILP(files_only)) {
346 } else if (EQ(files_only, Qt) && !dir_p) {
348 } else if (!EQ(files_only, Qt) && dir_p) {
354 if (curdepth >= opts->maxdepth) {
359 dired_stack_item_t dsi;
360 dsi = xnew_and_zero(struct dired_stack_item_s);
362 dsi->depth = 1+curdepth;
363 dired_stack_push(ds, dsi);
366 if (result_p && !NILP(match) && !pathname_matches_p(name, match, bufp)) {
371 dllist_append(XDLLIST(result), (void*)resname);
372 /* add the result to the companion bloom-f */
373 /* hm, for large trees this yields a bf which
374 owns everything :( ... we need far better and
375 faster bloom techniques for it -hroptatyr */
376 if (!NILP(bloom_filter)) {
377 bloom_add(XBLOOM(bloom_filter), resname);
386 dfr_outer(Lisp_Object directory, dirent_t *ent,
387 Lisp_Object compbf, dfr_options_t opts,
388 Lisp_Object files_only, dired_stack_t ds, Lisp_Object match,
389 struct re_pattern_buffer *bufp, Lisp_Object result,
390 Lisp_Object bloom_filter)
392 dired_stack_item_t dir_dpt = dired_stack_pop(ds);
393 Lisp_Object dir = dir_dpt->dir;
394 unsigned int dpt = dir_dpt->depth;
395 Lisp_Object fulldir = Fexpand_file_name(dir, directory);
397 dirent_t *res = NULL;
398 struct gcpro gcpro1, gcpro2;
400 GCPRO2(dir, fulldir);
404 dir = fname_as_directory(dir);
405 fulldir = fname_as_directory(fulldir);
407 /* add the full directory name to the companion bloom filter */
409 bloom_add(XBLOOM(compbf), fulldir);
411 /* external format conversion is done in the encapsulation of
412 * opendir in sysdep.c
414 d = opendir((char*)XSTRING_DATA(fulldir));
416 /* why should we want this? I think spitting a warning
422 report_file_error("Opening directory", list1(fulldir));
427 warn_when_safe(Qfile, Qwarning,
428 "Opening directory `%s' failed",
429 (char*)XSTRING_DATA(fulldir));
435 record_unwind_protect(close_directory_unwind,
436 make_opaque_ptr((void *)d));
438 while (DFR_READDIR(d, ent, &res) == 0 && res != NULL) {
439 dfr_inner(res, fulldir, dir,
441 files_only, dpt, ds, match, bufp,
442 result, bloom_filter);
449 dired_stack_mark(Lisp_Object obj)
451 dired_stack_t ds = get_dynacat(obj);
452 WITH_DLLIST_TRAVERSE(
454 dired_stack_item_t dsi = dllist_item;
455 mark_object(dsi->dir));
461 dired_stack_fini(Lisp_Object obj)
463 dired_stack_t ds = get_dynacat(obj);
464 free_dired_stack(ds);
470 directory_files_magic(Lisp_Object directory, Lisp_Object match,
471 Lisp_Object files_only, Lisp_Object bloom_filter,
474 /* This function can GC */
475 Lisp_Object result = wrap_dllist(make_dllist());
476 Lisp_Object lds = Qnil;
477 dired_stack_t ds = NULL;
478 dired_stack_item_t ds_item = NULL;
479 /* this is a companion bloom filter,
480 * we register processed directories in here and hence avoid
481 * processing an entry twice */
482 Lisp_Object compbf = Qnil;
483 int speccount = specpdl_depth();
484 struct re_pattern_buffer *bufp = NULL;
485 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
487 ds = new_dired_stack();
488 lds = make_dynacat(ds);
489 set_dynacat_marker(lds, dired_stack_mark);
490 set_dynacat_finaliser(lds, (dynacat_finaliser_f)dired_stack_fini);
491 GCPRO5(directory, result, compbf, bloom_filter, lds);
493 /* SXEmacs: this should come after Ffile_name_as_directory() to avoid
494 potential regexp cache smashage. It comes before the opendir()
495 because it might signal an error. */
497 if (STRINGP(match)) {
499 /* MATCH might be a flawed regular expression. Rather
500 than catching and signalling our own errors, we just
501 call compile_pattern to do the work for us. */
502 bufp = compile_pattern(match, 0, Qnil, 0, ERROR_ME);
503 /* Now *bufp is the compiled form of MATCH; don't call
504 anything which might compile a new regexp until we
505 are done with the loop! */
507 } else if (!NILP(Ffunctionp(match))) {
510 return wrong_type_argument(Qstringp, match);
514 regex_match_object = Qnil;
515 regex_emacs_buffer = current_buffer;
517 if (opts->maxdepth > 0) {
518 compbf = make_bloom(8192, 8);
521 /* set up the directories queue */
522 ds_item = xnew_and_zero(struct dired_stack_item_s);
523 ds_item->dir = make_string((Bufbyte*)"", 0);
525 dired_stack_push(ds, ds_item);
527 /* alloc the directory entry pointer */
529 dirent_t _ent, *ent = &_ent;
532 memset(ent, 0, sizeof(dirent_t));
534 while (dired_stack_size(ds) > 0) {
535 dfr_outer(directory, ent, compbf,
536 opts, files_only, ds, match,
537 bufp, result, bloom_filter);
538 /* This will close the dir */
539 unbind_to(speccount, Qnil);
544 /* save the companion bloom filter */
545 Fput(result, Qcompanion_bf, compbf);
552 directory_files_canonicalise_dn(Lisp_Object directory)
557 /* expand the directory argument and canonicalise */
558 directory = Fexpand_file_name(directory, Qnil);
559 directory = fname_as_directory(directory);
561 RETURN_UNGCPRO(directory);
565 directory_files_resultify(Lisp_Object result, Lisp_Object result_type)
567 /* This function can GC */
568 Lisp_Object final_result = Qnil;
569 struct gcpro gcpro1, gcpro2, gcpro3;
570 GCPRO3(result, result_type, final_result);
572 /* see if the user requested a dllist */
573 if (EQ(result_type, Qdllist)) {
574 final_result = result;
575 } else if (NILP(result_type) || EQ(result_type, Qsorted_list)) {
576 final_result = Fdllist_to_list_reversed(result);
577 final_result = Fsort(final_result, Qstring_lessp);
578 } else if (EQ(result_type, Qdesc_sorted_list)) {
579 final_result = Fdllist_to_list(result);
580 final_result = Fsort(final_result, Qstring_greaterp);
581 } else if (!NILP(result_type) || EQ(result_type, Qlist)) {
582 final_result = Fdllist_to_list(result);
590 call9(Lisp_Object fn,
591 Lisp_Object arg0, Lisp_Object arg1, Lisp_Object arg2,
592 Lisp_Object arg3, Lisp_Object arg4, Lisp_Object arg5,
593 Lisp_Object arg6, Lisp_Object arg7, Lisp_Object arg8)
595 /* This function can GC */
597 Lisp_Object res, args[10] = {fn, arg0, arg1, arg2, arg3,
598 arg4, arg5, arg6, arg7, arg8};
600 GCPROn(args, countof(args));
601 res = Ffuncall(10, args);
608 EXFUN(Fdirectory_files_recur, 8);
610 DEFUN("directory-files", Fdirectory_files, 1, 7, 0, /*
611 Return a list of names of files in DIRECTORY.
612 Args are DIRECTORY &optional FULL MATCH RESULT-TYPE FILES_ONLY SYMLINK_IS_FILE BLOOM_FILTER
614 There are four optional arguments:
615 If FULL is non-nil, absolute pathnames of the files are returned.
617 If MATCH is non-nil, it may be a string indicating a regular
618 expression which pathnames must meet in order to be returned.
619 Moreover, a predicate function can be specified which is called with
620 one argument, the pathname in question. On non-nil return value,
621 the pathname is considered in the final result, otherwise it is
624 Optional argument RESULT-TYPE can be one of:
625 - sorted-list (default) to return a list, sorted in alphabetically
627 - desc-sorted-list to return a list, sorted in alphabetically
629 - list to return an unsorted list
630 - dllist to return an unsorted dllist
631 The two latter types can be useful if you plan to sort the result
632 yourself, or want to feed the result to further processing.
634 For compatibility with XEmacs' NOSORT argument to this function,
635 RESULT-TYPE can also be any non-nil value. In that case it will
636 return an unsorted list. (https://issues.sxemacs.org/show_bug.cgi?id=163)
638 Optional argument FILES-ONLY can be one of:
639 - t to return only files and symlinks in DIRECTORY
640 - nil (default) to return all entries (files, symlinks, and
641 subdirectories) in DIRECTORY
642 - subdir to return only subdirectories -- but *NOT* symlinks to
643 directories -- in DIRECTORY
645 Optional argument SYMLINK-IS-FILE specifies whether symlinks
646 should be resolved \(which is the default behaviour\) or whether
647 they are treated as ordinary files \(non-nil\), in the latter
648 case symlinks to directories are not recurred.
650 Optional argument BLOOM-FILTER specifies a bloom filter where
651 to put results in addition to the ordinary result list.
653 (directory, full, match, result_type, files_only,
654 symlink_is_file, bloom_filter))
656 Lisp_Object handler = Qnil;
657 Lisp_Object result = Qnil;
658 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
659 /* just a convenience array for gc pro'ing */
660 Lisp_Object args[8] = {
661 directory, match, result_type, files_only,
662 symlink_is_file, bloom_filter, handler, result};
664 struct dfr_options_s opts = {
666 .fullp = !NILP(full),
667 .symlink_file_p = !NILP(symlink_is_file),
671 /* argument checks */
672 CHECK_STRING(directory);
674 GCPROn(args, countof(args));
676 directory = directory_files_canonicalise_dn(directory);
678 /* If the file name has special constructs in it,
679 call the corresponding file handler. */
680 handler = Ffind_file_name_handler(directory, Qdirectory_files);
681 if (!NILP(handler)) {
683 return call8(handler, Qdirectory_files,
684 directory, full, match, result_type, files_only,
685 symlink_is_file, bloom_filter);
688 result = directory_files_magic(directory, match,
689 files_only, bloom_filter,
693 return directory_files_resultify(result, result_type);
696 DEFUN("directory-files-recur", Fdirectory_files_recur, 1, 8, 0, /*
697 Like `directory-files' but recursive and much faster.
698 Args are DIRECTORY &optional FULL MATCH RESULT_TYPE FILES-ONLY MAXDEPTH
699 SYMLINK_IS_FILE BLOOM_FILTER
701 If FULL is non-nil, absolute pathnames of the files are returned.
703 If MATCH is non-nil, it may be a string indicating a regular
704 expression which pathnames must meet in order to be returned.
705 Moreover, a predicate function can be specified which is called with
706 one argument, the pathname in question. On non-nil return value,
707 the pathname is considered in the final result, otherwise it is
710 Optional argument RESULT-TYPE can be one of:
711 - sorted-list (default) to return a list, sorted in alphabetically
713 - desc-sorted-list to return a list, sorted in alphabetically
715 - list to return an unsorted list
716 - dllist to return an unsorted dllist
717 The two latter types can be useful if you plan to sort the result
718 yourself, or want to feed the result to further processing.
720 Optional argument FILES-ONLY can be one of:
721 - t to return only files and symlinks in DIRECTORY
722 - nil (default) to return all entries (files, symlinks, and
723 subdirectories) in DIRECTORY
724 - subdir to return only subdirectories -- but *NOT* symlinks to
725 directories -- in DIRECTORY
727 Optional argument MAXDEPTH \(a positive integer\) specifies the
728 maximal recursion depth, use 0 to emulate old `directory-files'.
730 Optional argument SYMLINK-IS-FILE specifies whether symlinks
731 should be resolved \(which is the default behaviour\) or whether
732 they are treated as ordinary files \(non-nil\), in the latter
733 case symlinks to directories are not recurred.
735 Optional argument BLOOM-FILTER specifies a bloom filter where
736 to put results in addition to the ordinary result list.
738 (directory, full, match, result_type, files_only, maxdepth,
739 symlink_is_file, bloom_filter))
741 Lisp_Object handler = Qnil, result = Qnil;
742 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
743 /* just a convenience array for gc pro'ing */
744 Lisp_Object args[8] = {
745 directory, match, result_type, files_only,
746 symlink_is_file, bloom_filter, handler, result};
748 struct dfr_options_s opts = {
750 .fullp = !NILP(full),
751 .symlink_file_p = !NILP(symlink_is_file),
755 /* argument checks */
756 CHECK_STRING(directory);
757 if (!NILP(maxdepth)) {
758 CHECK_NATNUM(maxdepth);
759 opts.maxdepth = XUINT(maxdepth);
762 GCPROn(args, countof(args));
764 directory = directory_files_canonicalise_dn(directory);
766 /* If the file name has special constructs in it,
767 call the corresponding file handler. */
768 handler = Ffind_file_name_handler(directory, Qdirectory_files_recur);
769 if (!NILP(handler)) {
772 res = call9(handler, Qdirectory_files_recur,
773 directory, full, match, result_type, files_only,
774 maxdepth, symlink_is_file, bloom_filter);
779 result = directory_files_magic(directory, match,
780 files_only, bloom_filter,
782 /* convert to final result type */
783 result = directory_files_resultify(result, result_type);
789 static Lisp_Object file_name_completion(Lisp_Object file,
790 Lisp_Object directory,
791 int all_flag, int ver_flag);
793 DEFUN("file-name-completion", Ffile_name_completion, 2, 2, 0, /*
794 Complete file name PARTIAL-FILENAME in directory DIRECTORY.
795 Return the longest prefix common to all file names in DIRECTORY
796 that start with PARTIAL-FILENAME.
797 If there is only one and PARTIAL-FILENAME matches it exactly, return t.
798 Return nil if DIRECTORY contains no name starting with PARTIAL-FILENAME.
800 File names which end with any member of `completion-ignored-extensions'
801 are not considered as possible completions for PARTIAL-FILENAME unless
802 there is no other possible completion. `completion-ignored-extensions'
803 is not applied to the names of directories.
805 (partial_filename, directory))
807 /* This function can GC. GC checked 1996.04.06. */
810 /* If the directory name has special constructs in it,
811 call the corresponding file handler. */
812 handler = Ffind_file_name_handler(directory, Qfile_name_completion);
814 return call3(handler, Qfile_name_completion, partial_filename,
817 /* If the file name has special constructs in it,
818 call the corresponding file handler. */
820 Ffind_file_name_handler(partial_filename, Qfile_name_completion);
822 return call3(handler, Qfile_name_completion, partial_filename,
825 return file_name_completion(partial_filename, directory, 0, 0);
828 DEFUN("file-name-all-completions", Ffile_name_all_completions, 2, 2, 0, /*
829 Return a list of all completions of PARTIAL-FILENAME in DIRECTORY.
830 These are all file names in DIRECTORY which begin with PARTIAL-FILENAME.
832 (partial_filename, directory))
834 /* This function can GC. GC checked 1997.06.04. */
839 directory = Fexpand_file_name(directory, Qnil);
840 /* If the file name has special constructs in it,
841 call the corresponding file handler. */
843 Ffind_file_name_handler(directory, Qfile_name_all_completions);
846 return call3(handler, Qfile_name_all_completions,
847 partial_filename, directory);
849 return file_name_completion(partial_filename, directory, 1, 0);
853 file_name_completion_stat(Lisp_Object directory, DIRENTRY * dp,
854 struct stat *st_addr)
856 Bytecount len = NAMLEN(dp);
857 Bytecount pos = XSTRING_LENGTH(directory);
859 char *fullname = (char *)alloca(len + pos + 2);
861 memcpy(fullname, XSTRING_DATA(directory), pos);
862 if (!IS_DIRECTORY_SEP(fullname[pos - 1]))
863 fullname[pos++] = DIRECTORY_SEP;
865 memcpy(fullname + pos, dp->d_name, len);
866 fullname[pos + len] = 0;
869 /* We want to return success if a link points to a nonexistent file,
870 but we want to return the status for what the link points to,
871 in case it is a directory. */
872 value = lstat(fullname, st_addr);
873 if (S_ISLNK(st_addr->st_mode))
874 (void)sxemacs_stat(fullname, st_addr);
876 value = sxemacs_stat(fullname, st_addr);
881 static Lisp_Object file_name_completion_unwind(Lisp_Object locative)
884 Lisp_Object obj = XCAR(locative);
887 d = (DIR *) get_opaque_ptr(obj);
889 free_opaque_ptr(obj);
891 free_cons(XCONS(locative));
896 file_name_completion(Lisp_Object file, Lisp_Object directory, int all_flag,
899 /* This function can GC */
902 Lisp_Object bestmatch = Qnil;
903 Charcount bestmatchsize = 0;
906 int speccount = specpdl_depth();
907 Charcount file_name_length;
908 Lisp_Object locative;
909 struct gcpro gcpro1, gcpro2, gcpro3;
911 GCPRO3(file, directory, bestmatch);
915 #ifdef FILE_SYSTEM_CASE
916 file = FILE_SYSTEM_CASE(file);
918 directory = Fexpand_file_name(directory, Qnil);
919 file_name_length = XSTRING_CHAR_LENGTH(file);
921 /* With passcount = 0, ignore files that end in an ignored extension.
922 If nothing found then try again with passcount = 1, don't ignore them.
923 If looking for all completions, start with passcount = 1,
924 so always take even the ignored ones.
926 ** It would not actually be helpful to the user to ignore any possible
927 completions when making a list of them.** */
929 /* We cannot use close_directory_unwind() because we change the
930 directory. The old code used to just avoid signaling errors, and
931 call closedir, but it was wrong, because it made sane handling of
932 QUIT impossible and, besides, various utility functions like
933 regexp_ignore_completion_p can signal errors. */
934 locative = noseeum_cons(Qnil, Qnil);
935 record_unwind_protect(file_name_completion_unwind, locative);
937 for (passcount = !!all_flag; NILP(bestmatch) && passcount < 2;
939 Lisp_Object tmp_dfn = Fdirectory_file_name(directory);
940 d = opendir((char *)XSTRING_DATA(tmp_dfn));
942 report_file_error("Opening directory",
945 XCAR(locative) = make_opaque_ptr((void *)d);
947 /* Loop reading blocks */
951 /* scmp() works in characters, not bytes, so we have to compute
955 int ignored_extension_p = 0;
962 /* Cast to Bufbyte* is OK, as readdir() Mule-encapsulates. */
963 d_name = (Bufbyte *) dp->d_name;
965 cclen = bytecount_to_charcount(d_name, len);
969 if (!DIRENTRY_NONEMPTY(dp)
970 || cclen < file_name_length
971 || 0 <= scmp(d_name, XSTRING_DATA(file),
975 if (file_name_completion_stat(directory, dp, &st) < 0)
978 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR);
980 /* "." and ".." are never interesting as completions, but are
981 actually in the way in a directory containing only one file. */
983 && TRIVIAL_DIRECTORY_ENTRY(dp->d_name))
986 /* Compare extensions-to-be-ignored against end of this file name */
987 /* if name is not an exact match against specified string. */
988 if (!passcount && cclen > file_name_length) {
990 /* and exit this for loop if a match is found */
991 EXTERNAL_LIST_LOOP(tem,
992 Vcompletion_ignored_extensions)
994 Lisp_Object elt = XCAR(tem);
1001 XSTRING_CHAR_LENGTH(elt);
1011 ignored_extension_p = 1;
1018 /* If an ignored-extensions match was found,
1019 don't process this name as a completion. */
1020 if (!passcount && ignored_extension_p)
1024 && regexp_ignore_completion_p(d_name, Qnil, 0,
1028 /* Update computation of how much all possible completions match */
1031 if (all_flag || NILP(bestmatch)) {
1032 Lisp_Object name = Qnil;
1033 struct gcpro ngcpro1;
1035 /* This is a possible completion */
1036 name = make_string(d_name, len);
1037 if (directoryp) /* Completion is a directory; end it with '/' */
1038 name = Ffile_name_as_directory(name);
1040 bestmatch = Fcons(name, bestmatch);
1044 XSTRING_CHAR_LENGTH(name);
1048 Charcount compare = min(bestmatchsize, cclen);
1049 Bufbyte *p1 = XSTRING_DATA(bestmatch);
1050 Bufbyte *p2 = d_name;
1051 Charcount matchsize = scmp(p1, p2, compare);
1054 matchsize = compare;
1055 if (completion_ignore_case) {
1056 /* If this is an exact match except for case,
1057 use it as the best match rather than one that is not
1058 an exact match. This way, we get the case pattern
1059 of the actual match. */
1060 if ((matchsize == cclen
1061 && matchsize + !!directoryp
1062 < XSTRING_CHAR_LENGTH(bestmatch))
1064 /* If there is no exact match ignoring case,
1065 prefer a match that does not change the case
1067 (((matchsize == cclen)
1069 (matchsize + !!directoryp
1071 XSTRING_CHAR_LENGTH(bestmatch)))
1072 /* If there is more than one exact match aside from
1073 case, and one of them is exact including case,
1077 file_name_length, 0)
1083 make_string(d_name, len);
1086 Ffile_name_as_directory
1091 /* If this directory all matches,
1092 see if implicit following slash does too. */
1094 && compare == matchsize
1095 && bestmatchsize > matchsize
1097 IS_ANY_SEP(charptr_emchar_n(p1, matchsize)))
1099 bestmatchsize = matchsize;
1103 free_opaque_ptr(XCAR(locative));
1104 XCAR(locative) = Qnil;
1107 unbind_to(speccount, Qnil);
1111 if (all_flag || NILP(bestmatch))
1113 if (matchcount == 1 && bestmatchsize == file_name_length)
1115 return Fsubstring(bestmatch, Qzero, make_int(bestmatchsize));
1118 static Lisp_Object user_name_completion(Lisp_Object user,
1119 int all_flag, int *uniq);
1121 DEFUN("user-name-completion", Fuser_name_completion, 1, 1, 0, /*
1122 Complete user name from PARTIAL-USERNAME.
1123 Return the longest prefix common to all user names starting with
1124 PARTIAL-USERNAME. If there is only one and PARTIAL-USERNAME matches
1125 it exactly, returns t. Return nil if there is no user name starting
1126 with PARTIAL-USERNAME.
1130 return user_name_completion(partial_username, 0, NULL);
1133 DEFUN("user-name-completion-1", Fuser_name_completion_1, 1, 1, 0, /*
1134 Complete user name from PARTIAL-USERNAME.
1136 This function is identical to `user-name-completion', except that
1137 the cons of the completion and an indication of whether the
1138 completion was unique is returned.
1140 The car of the returned value is the longest prefix common to all user
1141 names that start with PARTIAL-USERNAME. If there is only one and
1142 PARTIAL-USERNAME matches it exactly, the car is t. The car is nil if
1143 there is no user name starting with PARTIAL-USERNAME. The cdr of the
1144 result is non-nil if and only if the completion returned in the car
1150 Lisp_Object completed =
1151 user_name_completion(partial_username, 0, &uniq);
1152 return Fcons(completed, uniq ? Qt : Qnil);
1155 DEFUN("user-name-all-completions", Fuser_name_all_completions, 1, 1, 0, /*
1156 Return a list of all user name completions from PARTIAL-USERNAME.
1157 These are all the user names which begin with PARTIAL-USERNAME.
1161 return user_name_completion(partial_username, 1, NULL);
1170 struct user_name *user_names;
1173 EMACS_TIME last_rebuild_time;
1175 static struct user_cache user_cache;
1177 static void free_user_cache(struct user_cache *cache)
1180 for (i = 0; i < cache->length; i++)
1181 xfree(cache->user_names[i].ptr);
1182 xfree(cache->user_names);
1186 static Lisp_Object user_name_completion_unwind(Lisp_Object cache_incomplete_p)
1189 speed_up_interrupts();
1191 if (!NILP(XCAR(cache_incomplete_p)))
1192 free_user_cache(&user_cache);
1194 free_cons(XCONS(cache_incomplete_p));
1199 #define USER_CACHE_TTL (24*60*60) /* Time to live: 1 day, in seconds */
1202 user_name_completion(Lisp_Object user, int all_flag, int *uniq)
1204 /* This function can GC */
1206 Lisp_Object bestmatch = Qnil;
1207 Charcount bestmatchsize = 0;
1208 Charcount user_name_length;
1211 struct gcpro gcpro1, gcpro2;
1213 GCPRO2(user, bestmatch);
1217 user_name_length = XSTRING_CHAR_LENGTH(user);
1219 /* Cache user name lookups because it tends to be quite slow.
1220 * Rebuild the cache occasionally to catch changes */
1222 if (user_cache.user_names &&
1223 (EMACS_SECS(t) - EMACS_SECS(user_cache.last_rebuild_time)
1225 free_user_cache(&user_cache);
1227 if (!user_cache.user_names) {
1229 Lisp_Object cache_incomplete_p = noseeum_cons(Qt, Qnil);
1230 int speccount = specpdl_depth();
1232 slow_down_interrupts();
1234 record_unwind_protect(user_name_completion_unwind,
1235 cache_incomplete_p);
1236 while ((pwd = getpwent())) {
1238 DO_REALLOC(user_cache.user_names, user_cache.size,
1239 user_cache.length + 1, struct user_name);
1240 TO_INTERNAL_FORMAT(C_STRING, pwd->pw_name,
1243 user_names[user_cache.length].ptr,
1244 user_cache.user_names[user_cache.
1247 user_cache.length++;
1249 XCAR(cache_incomplete_p) = Qnil;
1250 unbind_to(speccount, Qnil);
1252 EMACS_GET_TIME(user_cache.last_rebuild_time);
1255 for (i = 0; i < user_cache.length; i++) {
1256 Bufbyte *u_name = user_cache.user_names[i].ptr;
1257 Bytecount len = user_cache.user_names[i].len;
1258 /* scmp() works in chars, not bytes, so we have to compute this: */
1259 Charcount cclen = bytecount_to_charcount(u_name, len);
1263 if (cclen < user_name_length
1264 || 0 <= scmp_1(u_name, XSTRING_DATA(user), user_name_length,
1268 matchcount++; /* count matching completions */
1270 if (all_flag || NILP(bestmatch)) {
1271 Lisp_Object name = Qnil;
1272 struct gcpro ngcpro1;
1274 /* This is a possible completion */
1275 name = make_string(u_name, len);
1277 bestmatch = Fcons(name, bestmatch);
1280 bestmatchsize = XSTRING_CHAR_LENGTH(name);
1284 Charcount compare = min(bestmatchsize, cclen);
1285 Bufbyte *p1 = XSTRING_DATA(bestmatch);
1286 Bufbyte *p2 = u_name;
1287 Charcount matchsize = scmp_1(p1, p2, compare, 0);
1290 matchsize = compare;
1292 bestmatchsize = matchsize;
1299 *uniq = (matchcount == 1);
1301 if (all_flag || NILP(bestmatch))
1303 if (matchcount == 1 && bestmatchsize == user_name_length)
1305 return Fsubstring(bestmatch, Qzero, make_int(bestmatchsize));
1308 Lisp_Object make_directory_hash_table(const char *path)
1311 if ((d = opendir(path))) {
1314 make_lisp_hash_table(20, HASH_TABLE_NON_WEAK,
1317 while ((dp = readdir(d))) {
1318 Bytecount len = NAMLEN(dp);
1319 if (DIRENTRY_NONEMPTY(dp))
1320 /* Cast to Bufbyte* is OK, as readdir() Mule-encapsulates. */
1321 Fputhash(make_string
1322 ((Bufbyte *) dp->d_name, len), Qt,
1332 /* ... never used ... should use list2 directly anyway ... */
1333 /* NOTE: This function can never return a negative value. */
1334 Lisp_Object wasteful_word_to_lisp(unsigned int item)
1336 /* Compatibility: in other versions, file-attributes returns a LIST
1337 of two 16 bit integers... */
1338 Lisp_Object cons = word_to_lisp(item);
1339 XCDR(cons) = Fcons(XCDR(cons), Qnil);
1344 DEFUN("file-attributes", Ffile_attributes, 1, 1, 0, /*
1345 Return a list of attributes of file FILENAME.
1346 Value is nil if specified file cannot be opened.
1347 Otherwise, list elements are:
1348 0. t for directory, string (name linked to) for symbolic link, or nil.
1349 1. Number of links to file.
1352 4. Last access time, as a list of two integers.
1353 First integer has high-order 16 bits of time, second has low 16 bits.
1354 5. Last modification time, likewise.
1355 6. Last status change time, likewise.
1356 7. Size in bytes. (-1, if number is out of range).
1357 8. File modes, as a string of ten letters or dashes as in ls -l.
1358 9. t iff file's gid would change if file were deleted and recreated.
1362 If file does not exist, returns nil.
1366 /* This function can GC. GC checked 1997.06.04. */
1367 Lisp_Object values[12];
1368 #if defined (BSD4_2) || defined (BSD4_3) || \
1369 !defined HAVE_BDWGC || !defined EF_USE_BDWGC
1370 Lisp_Object directory = Qnil;
1371 #endif /* BSD4_2 || BSD4_3 || !BDWGC */
1374 Lisp_Object handler;
1375 struct gcpro gcpro1, gcpro2;
1377 GCPRO2(filename, directory);
1378 filename = Fexpand_file_name(filename, Qnil);
1380 /* If the file name has special constructs in it,
1381 call the corresponding file handler. */
1382 handler = Ffind_file_name_handler(filename, Qfile_attributes);
1383 if (!NILP(handler)) {
1385 return call2(handler, Qfile_attributes, filename);
1388 if (lstat((char *)XSTRING_DATA(filename), &s) < 0) {
1393 directory = Ffile_name_directory(filename);
1396 switch (s.st_mode & S_IFMT) {
1405 values[0] = Ffile_symlink_p(filename);
1409 values[1] = make_int(s.st_nlink);
1410 values[2] = make_int(s.st_uid);
1411 values[3] = make_int(s.st_gid);
1412 values[4] = make_time(s.st_atime);
1413 values[5] = make_time(s.st_mtime);
1414 values[6] = make_time(s.st_ctime);
1415 values[7] = make_int((EMACS_INT) s.st_size);
1416 /* If the size is out of range, give back -1. */
1417 /* #### Fix when Emacs gets bignums! */
1418 if (XINT(values[7]) != s.st_size)
1419 values[7] = make_int(-1);
1420 filemodestring(&s, modes);
1421 values[8] = make_string((Bufbyte *) modes, 10);
1422 #if defined (BSD4_2) || defined (BSD4_3) /* file gid will be dir gid */
1426 if (!NILP(directory)
1427 && sxemacs_stat((char *)XSTRING_DATA(directory), &sdir) == 0)
1428 values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil;
1429 else /* if we can't tell, assume worst */
1432 #else /* file gid will be egid */
1433 values[9] = (s.st_gid != getegid())? Qt : Qnil;
1434 #endif /* BSD4_2 or BSD4_3 */
1435 values[10] = make_int(s.st_ino);
1436 values[11] = make_int(s.st_dev);
1438 return Flist(countof(values), values);
1442 /************************************************************************/
1443 /* initialization */
1444 /************************************************************************/
1446 void syms_of_dired(void)
1448 defsymbol(&Qdirectory_files, "directory-files");
1449 defsymbol(&Qdirectory_files_recur, "directory-files-recur");
1450 defsymbol(&Qfile_name_completion, "file-name-completion");
1451 defsymbol(&Qfile_name_all_completions, "file-name-all-completions");
1452 defsymbol(&Qfile_attributes, "file-attributes");
1454 defsymbol(&Qcompanion_bf, "companion-bf");
1455 defsymbol(&Qsorted_list, "sorted-list");
1456 defsymbol(&Qdesc_sorted_list, "desc-sorted-list");
1457 defsymbol(&Qunsorted_list, "unsorted-list");
1459 DEFSUBR(Fdirectory_files);
1460 DEFSUBR(Fdirectory_files_recur);
1461 DEFSUBR(Ffile_name_completion);
1462 DEFSUBR(Ffile_name_all_completions);
1463 DEFSUBR(Fuser_name_completion);
1464 DEFSUBR(Fuser_name_completion_1);
1465 DEFSUBR(Fuser_name_all_completions);
1466 DEFSUBR(Ffile_attributes);
1469 void vars_of_dired(void)
1471 DEFVAR_LISP("completion-ignored-extensions", &Vcompletion_ignored_extensions /*
1472 *Completion ignores filenames ending in any string in this list.
1473 This variable does not affect lists of possible completions,
1474 but does affect the commands that actually do completions.
1475 It is used by the function `file-name-completion'.
1477 Vcompletion_ignored_extensions = Qnil;
1479 DEFVAR_LISP("directory-files-no-trivial-p",
1480 &Vdirectory_files_no_trivial_p /*
1481 Determine whether to _not_ add the trivial directory entries
1483 ATTENTION: This variable is definitely NOT for users.
1484 For easy temporary circumvention use a let binding.
1486 Vdirectory_files_no_trivial_p = Qnil;