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 (sxemacs_stat(statnam, &st) == 0 &&
273 (st.st_mode & S_IFMT) == S_IFDIR) {
274 char *canon_name = NULL;
276 /* ugly things may happen when a link
277 * points back to a directory in our recurring
278 * area, ln -s . foo is a candidate
279 * now, we canonicalise the filename, i.e.
280 * resolve all symlinks and afterwards we
281 * store it to our companion bloom filter
282 * The ugly things are even worse than in the
283 * case of D_TYPE, since we !always! have to
284 * check against the bloom filter.
286 canon_name = CANONICALISE_FILENAME(statnam);
289 /* now, recycle full name */
290 fullname = make_ext_string(
291 canon_name, strlen(canon_name),
294 fullname = fname_as_directory(fullname);
296 /* now stat statnam */
297 if (sxemacs_stat(statnam, &st) == 0 &&
298 (st.st_mode & S_IFMT) == S_IFDIR &&
299 /* does the bloom know about the dir? */
301 !(bloom_owns_p(XBLOOM(compbf), fullname))) {
309 #endif /* defined(_DIRENT_HAVE_D_TYPE) && USE_D_TYPE */
311 /* argh, here is a design flaw!
312 these operations are not commutable, and it's a
313 hard-coded how `match' is interpreted.
314 * There are two possibilites:
315 * (1) check pathname against `match'
316 if nil, do not process further
317 if a directory, recur
318 if non-nil, add to result according to files_only
319 * (2) if a directory, recur
320 check pathname against `match'
321 if nil, do not add to result
322 if non-nil, add to result according to files_only
324 * Hm, I think I'd choose the latter variant, it is
325 not that performant, but it avoids two problems:
327 - With the former variant it is NOT possible to have
328 the trivial filenames on the result list, since a
329 match against "^[.]$" would exclude everything, while
330 actually it was likely meant to _solely_ exclude "."
332 - Furthermore, we _MUST_ traverse in preorder,
333 otherwise there is the possibility that pathnames are
334 on the file list already which turn out later to be
336 * Anyone wants to help brainstorming?
339 /* check if we put it on the list of matches */
340 if (NILP(files_only)) {
342 } else if (EQ(files_only, Qt) && !dir_p) {
344 } else if (!EQ(files_only, Qt) && dir_p) {
350 if (curdepth >= opts->maxdepth) {
355 dired_stack_item_t dsi;
356 dsi = xnew_and_zero(struct dired_stack_item_s);
358 dsi->depth = 1+curdepth;
359 dired_stack_push(ds, dsi);
362 if (result_p && !NILP(match) && !pathname_matches_p(name, match, bufp)) {
367 dllist_append(XDLLIST(result), (void*)resname);
368 /* add the result to the companion bloom-f */
369 /* hm, for large trees this yields a bf which
370 owns everything :( ... we need far better and
371 faster bloom techniques for it -hroptatyr */
372 if (!NILP(bloom_filter)) {
373 bloom_add(XBLOOM(bloom_filter), resname);
382 dfr_outer(Lisp_Object directory, dirent_t *ent,
383 Lisp_Object compbf, dfr_options_t opts,
384 Lisp_Object files_only, dired_stack_t ds, Lisp_Object match,
385 struct re_pattern_buffer *bufp, Lisp_Object result,
386 Lisp_Object bloom_filter)
388 dired_stack_item_t dir_dpt = dired_stack_pop(ds);
389 Lisp_Object dir = dir_dpt->dir;
390 unsigned int dpt = dir_dpt->depth;
391 Lisp_Object fulldir = Fexpand_file_name(dir, directory);
393 dirent_t *res = NULL;
394 struct gcpro gcpro1, gcpro2;
396 GCPRO2(dir, fulldir);
400 dir = fname_as_directory(dir);
401 fulldir = fname_as_directory(fulldir);
403 /* add the full directory name to the companion bloom filter */
405 bloom_add(XBLOOM(compbf), fulldir);
407 /* external format conversion is done in the encapsulation of
408 * opendir in sysdep.c
410 d = opendir((char*)XSTRING_DATA(fulldir));
412 /* why should we want this? I think spitting a warning
418 report_file_error("Opening directory", list1(fulldir));
423 warn_when_safe(Qfile, Qwarning,
424 "Opening directory `%s' failed",
425 (char*)XSTRING_DATA(fulldir));
431 record_unwind_protect(close_directory_unwind,
432 make_opaque_ptr((void *)d));
434 while (DFR_READDIR(d, ent, &res) == 0 && res != NULL) {
435 dfr_inner(res, fulldir, dir,
437 files_only, dpt, ds, match, bufp,
438 result, bloom_filter);
445 dired_stack_mark(Lisp_Object obj)
447 dired_stack_t ds = get_dynacat(obj);
448 WITH_DLLIST_TRAVERSE(
450 dired_stack_item_t dsi = dllist_item;
451 mark_object(dsi->dir));
457 dired_stack_fini(Lisp_Object obj)
459 dired_stack_t ds = get_dynacat(obj);
460 free_dired_stack(ds);
466 directory_files_magic(Lisp_Object directory, Lisp_Object match,
467 Lisp_Object files_only, Lisp_Object bloom_filter,
470 /* This function can GC */
471 Lisp_Object result = wrap_dllist(make_dllist());
472 Lisp_Object lds = Qnil;
473 dired_stack_t ds = NULL;
474 dired_stack_item_t ds_item = NULL;
475 /* this is a companion bloom filter,
476 * we register processed directories in here and hence avoid
477 * processing an entry twice */
478 Lisp_Object compbf = Qnil;
479 int speccount = specpdl_depth();
480 struct re_pattern_buffer *bufp = NULL;
481 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
483 ds = new_dired_stack();
484 lds = make_dynacat(ds);
485 set_dynacat_marker(lds, dired_stack_mark);
486 set_dynacat_finaliser(lds, (dynacat_finaliser_f)dired_stack_fini);
487 GCPRO5(directory, result, compbf, bloom_filter, lds);
489 /* SXEmacs: this should come after Ffile_name_as_directory() to avoid
490 potential regexp cache smashage. It comes before the opendir()
491 because it might signal an error. */
493 if (STRINGP(match)) {
495 /* MATCH might be a flawed regular expression. Rather
496 than catching and signalling our own errors, we just
497 call compile_pattern to do the work for us. */
498 bufp = compile_pattern(match, 0, Qnil, 0, ERROR_ME);
499 /* Now *bufp is the compiled form of MATCH; don't call
500 anything which might compile a new regexp until we
501 are done with the loop! */
503 } else if (!NILP(Ffunctionp(match))) {
506 return wrong_type_argument(Qstringp, match);
510 regex_match_object = Qnil;
511 regex_emacs_buffer = current_buffer;
513 if (opts->maxdepth > 0) {
514 compbf = make_bloom(8192, 8);
517 /* set up the directories queue */
518 ds_item = xnew_and_zero(struct dired_stack_item_s);
519 ds_item->dir = make_string((Bufbyte*)"", 0);
521 dired_stack_push(ds, ds_item);
523 /* alloc the directory entry pointer */
525 dirent_t _ent, *ent = &_ent;
528 memset(ent, 0, sizeof(dirent_t));
530 while (dired_stack_size(ds) > 0) {
531 dfr_outer(directory, ent, compbf,
532 opts, files_only, ds, match,
533 bufp, result, bloom_filter);
534 /* This will close the dir */
535 unbind_to(speccount, Qnil);
540 /* save the companion bloom filter */
541 Fput(result, Qcompanion_bf, compbf);
548 directory_files_canonicalise_dn(Lisp_Object directory)
553 /* expand the directory argument and canonicalise */
554 directory = Fexpand_file_name(directory, Qnil);
555 directory = fname_as_directory(directory);
557 RETURN_UNGCPRO(directory);
561 directory_files_resultify(Lisp_Object result, Lisp_Object result_type)
563 /* This function can GC */
564 Lisp_Object final_result = Qnil;
565 struct gcpro gcpro1, gcpro2, gcpro3;
566 GCPRO3(result, result_type, final_result);
568 /* see if the user requested a dllist */
569 if (EQ(result_type, Qdllist)) {
570 final_result = result;
571 } else if (NILP(result_type) || EQ(result_type, Qsorted_list)) {
572 final_result = Fdllist_to_list_reversed(result);
573 final_result = Fsort(final_result, Qstring_lessp);
574 } else if (EQ(result_type, Qdesc_sorted_list)) {
575 final_result = Fdllist_to_list(result);
576 final_result = Fsort(final_result, Qstring_greaterp);
577 } else if (!NILP(result_type) || EQ(result_type, Qlist)) {
578 final_result = Fdllist_to_list(result);
586 call9(Lisp_Object fn,
587 Lisp_Object arg0, Lisp_Object arg1, Lisp_Object arg2,
588 Lisp_Object arg3, Lisp_Object arg4, Lisp_Object arg5,
589 Lisp_Object arg6, Lisp_Object arg7, Lisp_Object arg8)
591 /* This function can GC */
593 Lisp_Object res, args[10] = {fn, arg0, arg1, arg2, arg3,
594 arg4, arg5, arg6, arg7, arg8};
596 GCPROn(args, countof(args));
597 res = Ffuncall(10, args);
604 EXFUN(Fdirectory_files_recur, 8);
606 DEFUN("directory-files", Fdirectory_files, 1, 5, 0, /*
607 Return a list of names of files in DIRECTORY.
608 Args are DIRECTORY &optional FULL MATCH RESULT-TYPE FILES_ONLY.
610 There are four optional arguments:
611 If FULL is non-nil, absolute pathnames of the files are returned.
613 If MATCH is non-nil, it may be a string indicating a regular
614 expression which pathnames must meet in order to be returned.
615 Moreover, a predicate function can be specified which is called with
616 one argument, the pathname in question. On non-nil return value,
617 the pathname is considered in the final result, otherwise it is
620 Optional argument RESULT-TYPE can be one of:
621 - sorted-list (default) to return a list, sorted in alphabetically
623 - desc-sorted-list to return a list, sorted in alphabetically
625 - list to return an unsorted list
626 - dllist to return an unsorted dllist
627 The two latter types can be useful if you plan to sort the result
628 yourself, or want to feed the result to further processing.
630 For compatibility with XEmacs' NOSORT argument to this function,
631 RESULT-TYPE can also be any non-nil value. In that case it will
632 return an unsorted list. (https://issues.sxemacs.org/show_bug.cgi?id=163)
634 Optional argument FILES-ONLY can be one of:
635 - t to return only files and symlinks in DIRECTORY
636 - nil (default) to return all entries (files, symlinks, and
637 subdirectories) in DIRECTORY
638 - subdir to return only subdirectories -- but *NOT* symlinks to
639 directories -- in DIRECTORY
641 (directory, full, match, result_type, files_only))
644 Lisp_Object result = Qnil;
645 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
646 struct dfr_options_s opts = {
648 .fullp = !NILP(full),
652 /* argument checks */
653 CHECK_STRING(directory);
655 GCPRO6(directory, full, match, result_type, files_only, result);
657 directory = directory_files_canonicalise_dn(directory);
659 /* If the file name has special constructs in it,
660 call the corresponding file handler. */
661 handler = Ffind_file_name_handler(directory, Qdirectory_files);
662 if (!NILP(handler)) {
664 return call6(handler, Qdirectory_files,
665 directory, full, match, result_type, files_only);
668 result = directory_files_magic(directory, match,
669 files_only, /* bloom filter */Qnil,
673 return directory_files_resultify(result, result_type);
676 DEFUN("directory-files-recur", Fdirectory_files_recur, 1, 8, 0, /*
677 Like `directory-files' but recursive and much faster.
678 Args are DIRECTORY &optional FULL MATCH RESULT_TYPE FILES-ONLY MAXDEPTH
679 SYMLINK_IS_FILE BLOOM_FILTER
681 If FULL is non-nil, absolute pathnames of the files are returned.
683 If MATCH is non-nil, it may be a string indicating a regular
684 expression which pathnames must meet in order to be returned.
685 Moreover, a predicate function can be specified which is called with
686 one argument, the pathname in question. On non-nil return value,
687 the pathname is considered in the final result, otherwise it is
690 Optional argument RESULT-TYPE can be one of:
691 - sorted-list (default) to return a list, sorted in alphabetically
693 - desc-sorted-list to return a list, sorted in alphabetically
695 - list to return an unsorted list
696 - dllist to return an unsorted dllist
697 The two latter types can be useful if you plan to sort the result
698 yourself, or want to feed the result to further processing.
700 Optional argument FILES-ONLY can be one of:
701 - t to return only files and symlinks in DIRECTORY
702 - nil (default) to return all entries (files, symlinks, and
703 subdirectories) in DIRECTORY
704 - subdir to return only subdirectories -- but *NOT* symlinks to
705 directories -- in DIRECTORY
707 Optional argument MAXDEPTH \(a positive integer\) specifies the
708 maximal recursion depth, use 0 to emulate old `directory-files'.
710 Optional argument SYMLINK-IS-FILE specifies whether symlinks
711 should be resolved \(which is the default behaviour\) or whether
712 they are treated as ordinary files \(non-nil\), in the latter
713 case symlinks to directories are not recurred.
715 Optional argument BLOOM-FILTER specifies a bloom filter where
716 to put results in addition to the ordinary result list.
718 (directory, full, match, result_type, files_only, maxdepth,
719 symlink_is_file, bloom_filter))
721 (int nargs, Lisp_Object *args))
724 Lisp_Object handler = Qnil, result = Qnil;
725 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
726 /* just a convenience array for gc pro'ing */
727 Lisp_Object args[8] = {
728 directory, match, result_type, files_only,
729 symlink_is_file, bloom_filter, handler, result};
731 struct dfr_options_s opts = {
733 .fullp = !NILP(full),
734 .symlink_file_p = !NILP(symlink_is_file),
738 /* argument checks */
739 CHECK_STRING(directory);
740 if (!NILP(maxdepth)) {
741 CHECK_NATNUM(maxdepth);
742 opts.maxdepth = XUINT(maxdepth);
745 GCPROn(args, countof(args));
747 directory = directory_files_canonicalise_dn(directory);
749 /* If the file name has special constructs in it,
750 call the corresponding file handler. */
751 handler = Ffind_file_name_handler(directory, Qdirectory_files_recur);
752 if (!NILP(handler)) {
755 res = call9(handler, Qdirectory_files_recur,
756 directory, full, match, result_type, files_only,
757 maxdepth, symlink_is_file, bloom_filter);
762 result = directory_files_magic(directory, match,
763 files_only, bloom_filter,
765 /* convert to final result type */
766 result = directory_files_resultify(result, result_type);
772 static Lisp_Object file_name_completion(Lisp_Object file,
773 Lisp_Object directory,
774 int all_flag, int ver_flag);
776 DEFUN("file-name-completion", Ffile_name_completion, 2, 2, 0, /*
777 Complete file name PARTIAL-FILENAME in directory DIRECTORY.
778 Return the longest prefix common to all file names in DIRECTORY
779 that start with PARTIAL-FILENAME.
780 If there is only one and PARTIAL-FILENAME matches it exactly, return t.
781 Return nil if DIRECTORY contains no name starting with PARTIAL-FILENAME.
783 File names which end with any member of `completion-ignored-extensions'
784 are not considered as possible completions for PARTIAL-FILENAME unless
785 there is no other possible completion. `completion-ignored-extensions'
786 is not applied to the names of directories.
788 (partial_filename, directory))
790 /* This function can GC. GC checked 1996.04.06. */
793 /* If the directory name has special constructs in it,
794 call the corresponding file handler. */
795 handler = Ffind_file_name_handler(directory, Qfile_name_completion);
797 return call3(handler, Qfile_name_completion, partial_filename,
800 /* If the file name has special constructs in it,
801 call the corresponding file handler. */
803 Ffind_file_name_handler(partial_filename, Qfile_name_completion);
805 return call3(handler, Qfile_name_completion, partial_filename,
808 return file_name_completion(partial_filename, directory, 0, 0);
811 DEFUN("file-name-all-completions", Ffile_name_all_completions, 2, 2, 0, /*
812 Return a list of all completions of PARTIAL-FILENAME in DIRECTORY.
813 These are all file names in DIRECTORY which begin with PARTIAL-FILENAME.
815 (partial_filename, directory))
817 /* This function can GC. GC checked 1997.06.04. */
822 directory = Fexpand_file_name(directory, Qnil);
823 /* If the file name has special constructs in it,
824 call the corresponding file handler. */
826 Ffind_file_name_handler(directory, Qfile_name_all_completions);
829 return call3(handler, Qfile_name_all_completions,
830 partial_filename, directory);
832 return file_name_completion(partial_filename, directory, 1, 0);
836 file_name_completion_stat(Lisp_Object directory, DIRENTRY * dp,
837 struct stat *st_addr)
839 Bytecount len = NAMLEN(dp);
840 Bytecount pos = XSTRING_LENGTH(directory);
842 char *fullname = (char *)alloca(len + pos + 2);
844 memcpy(fullname, XSTRING_DATA(directory), pos);
845 if (!IS_DIRECTORY_SEP(fullname[pos - 1]))
846 fullname[pos++] = DIRECTORY_SEP;
848 memcpy(fullname + pos, dp->d_name, len);
849 fullname[pos + len] = 0;
852 /* We want to return success if a link points to a nonexistent file,
853 but we want to return the status for what the link points to,
854 in case it is a directory. */
855 value = lstat(fullname, st_addr);
856 if (S_ISLNK(st_addr->st_mode))
857 (void)sxemacs_stat(fullname, st_addr);
859 value = sxemacs_stat(fullname, st_addr);
864 static Lisp_Object file_name_completion_unwind(Lisp_Object locative)
867 Lisp_Object obj = XCAR(locative);
870 d = (DIR *) get_opaque_ptr(obj);
872 free_opaque_ptr(obj);
874 free_cons(XCONS(locative));
879 file_name_completion(Lisp_Object file, Lisp_Object directory, int all_flag,
882 /* This function can GC */
885 Lisp_Object bestmatch = Qnil;
886 Charcount bestmatchsize = 0;
889 int speccount = specpdl_depth();
890 Charcount file_name_length;
891 Lisp_Object locative;
892 struct gcpro gcpro1, gcpro2, gcpro3;
894 GCPRO3(file, directory, bestmatch);
898 #ifdef FILE_SYSTEM_CASE
899 file = FILE_SYSTEM_CASE(file);
901 directory = Fexpand_file_name(directory, Qnil);
902 file_name_length = XSTRING_CHAR_LENGTH(file);
904 /* With passcount = 0, ignore files that end in an ignored extension.
905 If nothing found then try again with passcount = 1, don't ignore them.
906 If looking for all completions, start with passcount = 1,
907 so always take even the ignored ones.
909 ** It would not actually be helpful to the user to ignore any possible
910 completions when making a list of them.** */
912 /* We cannot use close_directory_unwind() because we change the
913 directory. The old code used to just avoid signaling errors, and
914 call closedir, but it was wrong, because it made sane handling of
915 QUIT impossible and, besides, various utility functions like
916 regexp_ignore_completion_p can signal errors. */
917 locative = noseeum_cons(Qnil, Qnil);
918 record_unwind_protect(file_name_completion_unwind, locative);
920 for (passcount = !!all_flag; NILP(bestmatch) && passcount < 2;
922 Lisp_Object tmp_dfn = Fdirectory_file_name(directory);
923 d = opendir((char *)XSTRING_DATA(tmp_dfn));
925 report_file_error("Opening directory",
928 XCAR(locative) = make_opaque_ptr((void *)d);
930 /* Loop reading blocks */
934 /* scmp() works in characters, not bytes, so we have to compute
938 int ignored_extension_p = 0;
945 /* Cast to Bufbyte* is OK, as readdir() Mule-encapsulates. */
946 d_name = (Bufbyte *) dp->d_name;
948 cclen = bytecount_to_charcount(d_name, len);
952 if (!DIRENTRY_NONEMPTY(dp)
953 || cclen < file_name_length
954 || 0 <= scmp(d_name, XSTRING_DATA(file),
958 if (file_name_completion_stat(directory, dp, &st) < 0)
961 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR);
963 /* "." and ".." are never interesting as completions, but are
964 actually in the way in a directory containing only one file. */
966 && TRIVIAL_DIRECTORY_ENTRY(dp->d_name))
969 /* Compare extensions-to-be-ignored against end of this file name */
970 /* if name is not an exact match against specified string. */
971 if (!passcount && cclen > file_name_length) {
973 /* and exit this for loop if a match is found */
974 EXTERNAL_LIST_LOOP(tem,
975 Vcompletion_ignored_extensions)
977 Lisp_Object elt = XCAR(tem);
984 XSTRING_CHAR_LENGTH(elt);
994 ignored_extension_p = 1;
1001 /* If an ignored-extensions match was found,
1002 don't process this name as a completion. */
1003 if (!passcount && ignored_extension_p)
1007 && regexp_ignore_completion_p(d_name, Qnil, 0,
1011 /* Update computation of how much all possible completions match */
1014 if (all_flag || NILP(bestmatch)) {
1015 Lisp_Object name = Qnil;
1016 struct gcpro ngcpro1;
1018 /* This is a possible completion */
1019 name = make_string(d_name, len);
1020 if (directoryp) /* Completion is a directory; end it with '/' */
1021 name = Ffile_name_as_directory(name);
1023 bestmatch = Fcons(name, bestmatch);
1027 XSTRING_CHAR_LENGTH(name);
1031 Charcount compare = min(bestmatchsize, cclen);
1032 Bufbyte *p1 = XSTRING_DATA(bestmatch);
1033 Bufbyte *p2 = d_name;
1034 Charcount matchsize = scmp(p1, p2, compare);
1037 matchsize = compare;
1038 if (completion_ignore_case) {
1039 /* If this is an exact match except for case,
1040 use it as the best match rather than one that is not
1041 an exact match. This way, we get the case pattern
1042 of the actual match. */
1043 if ((matchsize == cclen
1044 && matchsize + !!directoryp
1045 < XSTRING_CHAR_LENGTH(bestmatch))
1047 /* If there is no exact match ignoring case,
1048 prefer a match that does not change the case
1050 (((matchsize == cclen)
1052 (matchsize + !!directoryp
1054 XSTRING_CHAR_LENGTH(bestmatch)))
1055 /* If there is more than one exact match aside from
1056 case, and one of them is exact including case,
1060 file_name_length, 0)
1066 make_string(d_name, len);
1069 Ffile_name_as_directory
1074 /* If this directory all matches,
1075 see if implicit following slash does too. */
1077 && compare == matchsize
1078 && bestmatchsize > matchsize
1080 IS_ANY_SEP(charptr_emchar_n(p1, matchsize)))
1082 bestmatchsize = matchsize;
1086 free_opaque_ptr(XCAR(locative));
1087 XCAR(locative) = Qnil;
1090 unbind_to(speccount, Qnil);
1094 if (all_flag || NILP(bestmatch))
1096 if (matchcount == 1 && bestmatchsize == file_name_length)
1098 return Fsubstring(bestmatch, Qzero, make_int(bestmatchsize));
1101 static Lisp_Object user_name_completion(Lisp_Object user,
1102 int all_flag, int *uniq);
1104 DEFUN("user-name-completion", Fuser_name_completion, 1, 1, 0, /*
1105 Complete user name from PARTIAL-USERNAME.
1106 Return the longest prefix common to all user names starting with
1107 PARTIAL-USERNAME. If there is only one and PARTIAL-USERNAME matches
1108 it exactly, returns t. Return nil if there is no user name starting
1109 with PARTIAL-USERNAME.
1113 return user_name_completion(partial_username, 0, NULL);
1116 DEFUN("user-name-completion-1", Fuser_name_completion_1, 1, 1, 0, /*
1117 Complete user name from PARTIAL-USERNAME.
1119 This function is identical to `user-name-completion', except that
1120 the cons of the completion and an indication of whether the
1121 completion was unique is returned.
1123 The car of the returned value is the longest prefix common to all user
1124 names that start with PARTIAL-USERNAME. If there is only one and
1125 PARTIAL-USERNAME matches it exactly, the car is t. The car is nil if
1126 there is no user name starting with PARTIAL-USERNAME. The cdr of the
1127 result is non-nil if and only if the completion returned in the car
1133 Lisp_Object completed =
1134 user_name_completion(partial_username, 0, &uniq);
1135 return Fcons(completed, uniq ? Qt : Qnil);
1138 DEFUN("user-name-all-completions", Fuser_name_all_completions, 1, 1, 0, /*
1139 Return a list of all user name completions from PARTIAL-USERNAME.
1140 These are all the user names which begin with PARTIAL-USERNAME.
1144 return user_name_completion(partial_username, 1, NULL);
1153 struct user_name *user_names;
1156 EMACS_TIME last_rebuild_time;
1158 static struct user_cache user_cache;
1160 static void free_user_cache(struct user_cache *cache)
1163 for (i = 0; i < cache->length; i++)
1164 xfree(cache->user_names[i].ptr);
1165 xfree(cache->user_names);
1169 static Lisp_Object user_name_completion_unwind(Lisp_Object cache_incomplete_p)
1172 speed_up_interrupts();
1174 if (!NILP(XCAR(cache_incomplete_p)))
1175 free_user_cache(&user_cache);
1177 free_cons(XCONS(cache_incomplete_p));
1182 #define USER_CACHE_TTL (24*60*60) /* Time to live: 1 day, in seconds */
1185 user_name_completion(Lisp_Object user, int all_flag, int *uniq)
1187 /* This function can GC */
1189 Lisp_Object bestmatch = Qnil;
1190 Charcount bestmatchsize = 0;
1191 Charcount user_name_length;
1194 struct gcpro gcpro1, gcpro2;
1196 GCPRO2(user, bestmatch);
1200 user_name_length = XSTRING_CHAR_LENGTH(user);
1202 /* Cache user name lookups because it tends to be quite slow.
1203 * Rebuild the cache occasionally to catch changes */
1205 if (user_cache.user_names &&
1206 (EMACS_SECS(t) - EMACS_SECS(user_cache.last_rebuild_time)
1208 free_user_cache(&user_cache);
1210 if (!user_cache.user_names) {
1212 Lisp_Object cache_incomplete_p = noseeum_cons(Qt, Qnil);
1213 int speccount = specpdl_depth();
1215 slow_down_interrupts();
1217 record_unwind_protect(user_name_completion_unwind,
1218 cache_incomplete_p);
1219 while ((pwd = getpwent())) {
1221 DO_REALLOC(user_cache.user_names, user_cache.size,
1222 user_cache.length + 1, struct user_name);
1223 TO_INTERNAL_FORMAT(C_STRING, pwd->pw_name,
1226 user_names[user_cache.length].ptr,
1227 user_cache.user_names[user_cache.
1230 user_cache.length++;
1232 XCAR(cache_incomplete_p) = Qnil;
1233 unbind_to(speccount, Qnil);
1235 EMACS_GET_TIME(user_cache.last_rebuild_time);
1238 for (i = 0; i < user_cache.length; i++) {
1239 Bufbyte *u_name = user_cache.user_names[i].ptr;
1240 Bytecount len = user_cache.user_names[i].len;
1241 /* scmp() works in chars, not bytes, so we have to compute this: */
1242 Charcount cclen = bytecount_to_charcount(u_name, len);
1246 if (cclen < user_name_length
1247 || 0 <= scmp_1(u_name, XSTRING_DATA(user), user_name_length,
1251 matchcount++; /* count matching completions */
1253 if (all_flag || NILP(bestmatch)) {
1254 Lisp_Object name = Qnil;
1255 struct gcpro ngcpro1;
1257 /* This is a possible completion */
1258 name = make_string(u_name, len);
1260 bestmatch = Fcons(name, bestmatch);
1263 bestmatchsize = XSTRING_CHAR_LENGTH(name);
1267 Charcount compare = min(bestmatchsize, cclen);
1268 Bufbyte *p1 = XSTRING_DATA(bestmatch);
1269 Bufbyte *p2 = u_name;
1270 Charcount matchsize = scmp_1(p1, p2, compare, 0);
1273 matchsize = compare;
1275 bestmatchsize = matchsize;
1282 *uniq = (matchcount == 1);
1284 if (all_flag || NILP(bestmatch))
1286 if (matchcount == 1 && bestmatchsize == user_name_length)
1288 return Fsubstring(bestmatch, Qzero, make_int(bestmatchsize));
1291 Lisp_Object make_directory_hash_table(const char *path)
1294 if ((d = opendir(path))) {
1297 make_lisp_hash_table(20, HASH_TABLE_NON_WEAK,
1300 while ((dp = readdir(d))) {
1301 Bytecount len = NAMLEN(dp);
1302 if (DIRENTRY_NONEMPTY(dp))
1303 /* Cast to Bufbyte* is OK, as readdir() Mule-encapsulates. */
1304 Fputhash(make_string
1305 ((Bufbyte *) dp->d_name, len), Qt,
1315 /* ... never used ... should use list2 directly anyway ... */
1316 /* NOTE: This function can never return a negative value. */
1317 Lisp_Object wasteful_word_to_lisp(unsigned int item)
1319 /* Compatibility: in other versions, file-attributes returns a LIST
1320 of two 16 bit integers... */
1321 Lisp_Object cons = word_to_lisp(item);
1322 XCDR(cons) = Fcons(XCDR(cons), Qnil);
1327 DEFUN("file-attributes", Ffile_attributes, 1, 1, 0, /*
1328 Return a list of attributes of file FILENAME.
1329 Value is nil if specified file cannot be opened.
1330 Otherwise, list elements are:
1331 0. t for directory, string (name linked to) for symbolic link, or nil.
1332 1. Number of links to file.
1335 4. Last access time, as a list of two integers.
1336 First integer has high-order 16 bits of time, second has low 16 bits.
1337 5. Last modification time, likewise.
1338 6. Last status change time, likewise.
1339 7. Size in bytes. (-1, if number is out of range).
1340 8. File modes, as a string of ten letters or dashes as in ls -l.
1341 9. t iff file's gid would change if file were deleted and recreated.
1345 If file does not exist, returns nil.
1349 /* This function can GC. GC checked 1997.06.04. */
1350 Lisp_Object values[12];
1351 #if defined (BSD4_2) || defined (BSD4_3) || \
1352 !defined HAVE_BDWGC || !defined EF_USE_BDWGC
1353 Lisp_Object directory = Qnil;
1354 #endif /* BSD4_2 || BSD4_3 || !BDWGC */
1357 Lisp_Object handler;
1358 struct gcpro gcpro1, gcpro2;
1360 GCPRO2(filename, directory);
1361 filename = Fexpand_file_name(filename, Qnil);
1363 /* If the file name has special constructs in it,
1364 call the corresponding file handler. */
1365 handler = Ffind_file_name_handler(filename, Qfile_attributes);
1366 if (!NILP(handler)) {
1368 return call2(handler, Qfile_attributes, filename);
1371 if (lstat((char *)XSTRING_DATA(filename), &s) < 0) {
1376 directory = Ffile_name_directory(filename);
1379 switch (s.st_mode & S_IFMT) {
1388 values[0] = Ffile_symlink_p(filename);
1392 values[1] = make_int(s.st_nlink);
1393 values[2] = make_int(s.st_uid);
1394 values[3] = make_int(s.st_gid);
1395 values[4] = make_time(s.st_atime);
1396 values[5] = make_time(s.st_mtime);
1397 values[6] = make_time(s.st_ctime);
1398 values[7] = make_int((EMACS_INT) s.st_size);
1399 /* If the size is out of range, give back -1. */
1400 /* #### Fix when Emacs gets bignums! */
1401 if (XINT(values[7]) != s.st_size)
1402 values[7] = make_int(-1);
1403 filemodestring(&s, modes);
1404 values[8] = make_string((Bufbyte *) modes, 10);
1405 #if defined (BSD4_2) || defined (BSD4_3) /* file gid will be dir gid */
1409 if (!NILP(directory)
1410 && sxemacs_stat((char *)XSTRING_DATA(directory), &sdir) == 0)
1411 values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil;
1412 else /* if we can't tell, assume worst */
1415 #else /* file gid will be egid */
1416 values[9] = (s.st_gid != getegid())? Qt : Qnil;
1417 #endif /* BSD4_2 or BSD4_3 */
1418 values[10] = make_int(s.st_ino);
1419 values[11] = make_int(s.st_dev);
1421 return Flist(countof(values), values);
1425 /************************************************************************/
1426 /* initialization */
1427 /************************************************************************/
1429 void syms_of_dired(void)
1431 defsymbol(&Qdirectory_files, "directory-files");
1432 defsymbol(&Qdirectory_files_recur, "directory-files-recur");
1433 defsymbol(&Qfile_name_completion, "file-name-completion");
1434 defsymbol(&Qfile_name_all_completions, "file-name-all-completions");
1435 defsymbol(&Qfile_attributes, "file-attributes");
1437 defsymbol(&Qcompanion_bf, "companion-bf");
1438 defsymbol(&Qsorted_list, "sorted-list");
1439 defsymbol(&Qdesc_sorted_list, "desc-sorted-list");
1440 defsymbol(&Qunsorted_list, "unsorted-list");
1442 DEFSUBR(Fdirectory_files);
1443 DEFSUBR(Fdirectory_files_recur);
1444 DEFSUBR(Ffile_name_completion);
1445 DEFSUBR(Ffile_name_all_completions);
1446 DEFSUBR(Fuser_name_completion);
1447 DEFSUBR(Fuser_name_completion_1);
1448 DEFSUBR(Fuser_name_all_completions);
1449 DEFSUBR(Ffile_attributes);
1452 void vars_of_dired(void)
1454 DEFVAR_LISP("completion-ignored-extensions", &Vcompletion_ignored_extensions /*
1455 *Completion ignores filenames ending in any string in this list.
1456 This variable does not affect lists of possible completions,
1457 but does affect the commands that actually do completions.
1458 It is used by the function `file-name-completion'.
1460 Vcompletion_ignored_extensions = Qnil;
1462 DEFVAR_LISP("directory-files-no-trivial-p",
1463 &Vdirectory_files_no_trivial_p /*
1464 Determine whether to _not_ add the trivial directory entries
1466 ATTENTION: This variable is definitely NOT for users.
1467 For easy temporary circumvention use a let binding.
1469 Vdirectory_files_no_trivial_p = Qnil;