Add match-full option to directory-files{,-recur}
[sxemacs] / src / dired.c
index 981edaf..bcc6994 100644 (file)
@@ -53,6 +53,7 @@ Lisp_Object Qfile_attributes;
 
 Lisp_Object Qcompanion_bf;
 Lisp_Object Qsorted_list, Qdesc_sorted_list, Qunsorted_list;
+Lisp_Object Qmatch_full;
 Lisp_Object Qnoncyclic_directory, Qcyclic_directory;
 Lisp_Object Qsymlink, Qalive_symlink, Qdead_symlink;
 Lisp_Object Qwhiteout;
@@ -101,6 +102,7 @@ struct dfr_options_s {
        long unsigned int maxdepth;
        _Bool fullp:1;
        _Bool symlink_file_p:1;
+       _Bool matchfullp:1;
 };
 
 static Lisp_Object fname_as_directory(Lisp_Object);
@@ -269,43 +271,47 @@ dfr_inner(dirent_t *res,
        }
 #else  /* defined(_DIRENT_HAVE_D_TYPE) && USE_D_TYPE */
        statnam = (char*)XSTRING_DATA(fullname);
-       if (sxemacs_stat(statnam, &st) == 0 &&
-           (st.st_mode & S_IFMT) == S_IFDIR) {
-               char *canon_name = NULL;
-
-               /* ugly things may happen when a link
-                * points back to a directory in our recurring
-                * area, ln -s . foo  is a candidate
-                * now, we canonicalise the filename, i.e.
-                * resolve all symlinks and afterwards we
-                * store it to our companion bloom filter
-                * The ugly things are even worse than in the
-                * case of D_TYPE, since we !always! have to
-                * check against the bloom filter.
-                */
-               canon_name = CANONICALISE_FILENAME(statnam);
-
-               if (canon_name) {
-                       /* now, recycle full name */
-                       fullname = make_ext_string(
-                               canon_name, strlen(canon_name),
-                               Qfile_name);
-               }
-               fullname = fname_as_directory(fullname);
-
-               /* now stat statnam */
-               if (sxemacs_stat(statnam, &st) == 0 &&
-                   (st.st_mode & S_IFMT) == S_IFDIR &&
-                   /* does the bloom know about the dir? */
-                   !NILP(compbf) &&
-                   !(bloom_owns_p(XBLOOM(compbf), fullname))) {
+       if (lstat(statnam, &st) == 0) {
+               if ((st.st_mode & S_IFMT) == S_IFDIR) {
                        dir_p = 1;
-               }
+               } else if ((st.st_mode & S_IFMT) == S_IFLNK && !opts->symlink_file_p) {
+                       char *canon_name = NULL;
+
+                       /* ugly things may happen when a link
+                        * points back to a directory in our recurring
+                        * area, ln -s . foo  is a candidate
+                        * now, we canonicalise the filename, i.e.
+                        * resolve all symlinks and afterwards we
+                        * store it to our companion bloom filter
+                        * The ugly things are even worse than in the
+                        * case of D_TYPE, since we !always! have to
+                        * check against the bloom filter.
+                        */
+                       canon_name = CANONICALISE_FILENAME(statnam);
+
+                       if (canon_name) {
+                               /* now, recycle full name */
+                               fullname = make_ext_string(
+                                       canon_name, strlen(canon_name),
+                                       Qfile_name);
+                       }
+                       fullname = fname_as_directory(fullname);
+
+                       /* now stat statnam */
+                       if (sxemacs_stat(statnam, &st) == 0 &&
+                           (st.st_mode & S_IFMT) == S_IFDIR &&
+                           /* does the bloom know about the dir? */
+                           !NILP(compbf) &&
+                           !(bloom_owns_p(XBLOOM(compbf), fullname))) {
+                               dir_p = 1;
+                       }
 
-               if (canon_name) {
-                       xfree(canon_name);
+                       if (canon_name) {
+                               xfree(canon_name);
+                       }
                }
        }
+
 #endif /* defined(_DIRENT_HAVE_D_TYPE) && USE_D_TYPE */
 
        /* argh, here is a design flaw!
@@ -359,7 +365,9 @@ dfr_inner(dirent_t *res,
                dired_stack_push(ds, dsi);
        }
 
-       if (result_p && !NILP(match) && !pathname_matches_p(name, match, bufp)) {
+       if (result_p && !NILP(match)
+           && !pathname_matches_p((opts->matchfullp?fullname:name),
+                                  match, bufp)) {
                result_p = 0;
        }
 
@@ -603,19 +611,24 @@ call9(Lisp_Object fn,
 \f
 EXFUN(Fdirectory_files_recur, 8);
 
-DEFUN("directory-files", Fdirectory_files, 1, 5, 0,    /*
+DEFUN("directory-files", Fdirectory_files, 1, 7, 0,    /*
 Return a list of names of files in DIRECTORY.
-Args are DIRECTORY &optional FULL MATCH RESULT-TYPE FILES_ONLY.
+Args are DIRECTORY &optional FULL MATCH RESULT-TYPE FILES_ONLY
+SYMLINK_IS_FILE BLOOM_FILTER
 
 There are four optional arguments:
-If FULL is non-nil, absolute pathnames of the files are returned.
+FULL can be one of:
+- t to return absolute pathnames of the files.
+- match-full to return and match on absolute pathnames of the files.
+- nil to return relative filenames.
 
 If MATCH is non-nil, it may be a string indicating a regular
 expression which pathnames must meet in order to be returned.
 Moreover, a predicate function can be specified which is called with
-one argument, the pathname in question.  On non-nil return value,
-the pathname is considered in the final result, otherwise it is
-ignored.
+one argument, the pathname in question.  On non-nil return value, the
+pathname is considered in the final result, otherwise it is ignored.
+Note that FULL affects whether the match is done on the filename of
+the full pathname.
 
 Optional argument RESULT-TYPE can be one of:
 - sorted-list (default)  to return a list, sorted in alphabetically
@@ -637,22 +650,38 @@ Optional argument FILES-ONLY can be one of:
   subdirectories) in DIRECTORY
 - subdir  to return only subdirectories -- but *NOT* symlinks to
   directories -- in DIRECTORY
+
+Optional argument SYMLINK-IS-FILE specifies whether symlinks
+should be resolved \(which is the default behaviour\) or whether
+they are treated as ordinary files \(non-nil\), in the latter
+case symlinks to directories are not recurred.
+
+Optional argument BLOOM-FILTER specifies a bloom filter where
+to put results in addition to the ordinary result list.
 */
-      (directory, full, match, result_type, files_only))
+      (directory, full, match, result_type, files_only,
+       symlink_is_file, bloom_filter))
 {
-       Lisp_Object handler;
+       Lisp_Object handler = Qnil;
        Lisp_Object result = Qnil;
-       struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
+#if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
+       /* just a convenience array for gc pro'ing */
+       Lisp_Object args[8] = {
+               directory, match, result_type, files_only,
+               symlink_is_file, bloom_filter, handler, result};
+#endif /* !BDWGC */
        struct dfr_options_s opts = {
                .maxdepth = 0,
                .fullp = !NILP(full),
-               .symlink_file_p = 0,
+               .symlink_file_p = !NILP(symlink_is_file),
+               .matchfullp = EQ(full,Qmatch_full),
        };
+       struct gcpro gcpro1;
 
        /* argument checks */
        CHECK_STRING(directory);
 
-       GCPRO6(directory, full, match, result_type, files_only, result);
+       GCPROn(args, countof(args));
 
        directory = directory_files_canonicalise_dn(directory);
 
@@ -661,12 +690,13 @@ Optional argument FILES-ONLY can be one of:
        handler = Ffind_file_name_handler(directory, Qdirectory_files);
        if (!NILP(handler)) {
                UNGCPRO;
-               return call6(handler, Qdirectory_files,
-                            directory, full, match, result_type, files_only);
+               return call8(handler, Qdirectory_files,
+                            directory, full, match, result_type, files_only,
+                            symlink_is_file, bloom_filter);
        }
 
        result = directory_files_magic(directory, match,
-                                      files_only, /* bloom filter */Qnil,
+                                      files_only, bloom_filter,
                                       &opts);
 
        UNGCPRO;
@@ -678,14 +708,18 @@ Like `directory-files' but recursive and much faster.
 Args are DIRECTORY &optional FULL MATCH RESULT_TYPE FILES-ONLY MAXDEPTH
 SYMLINK_IS_FILE BLOOM_FILTER
 
-If FULL is non-nil, absolute pathnames of the files are returned.
+FULL can be one of:
+- t to return absolute pathnames of the files.
+- match-full to return and match on absolute pathnames of the files.
+- nil to return relative filenames.
 
 If MATCH is non-nil, it may be a string indicating a regular
 expression which pathnames must meet in order to be returned.
 Moreover, a predicate function can be specified which is called with
-one argument, the pathname in question.  On non-nil return value,
-the pathname is considered in the final result, otherwise it is
-ignored.
+one argument, the pathname in question.  On non-nil return value, the
+pathname is considered in the final result, otherwise it is ignored.
+Note that FULL affects whether the match is done on the filename of
+the full pathname.
 
 Optional argument RESULT-TYPE can be one of:
 - sorted-list (default)  to return a list, sorted in alphabetically
@@ -717,9 +751,6 @@ to put results in addition to the ordinary result list.
 */
       (directory, full, match, result_type, files_only, maxdepth,
        symlink_is_file, bloom_filter))
-#if 0
-      (int nargs, Lisp_Object *args))
-#endif
 {
        Lisp_Object handler = Qnil, result = Qnil;
 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
@@ -732,6 +763,7 @@ to put results in addition to the ordinary result list.
                .maxdepth = 64,
                .fullp = !NILP(full),
                .symlink_file_p = !NILP(symlink_is_file),
+               .matchfullp = EQ(full, Qmatch_full),
        };
        struct gcpro gcpro1;
 
@@ -1438,6 +1470,7 @@ void syms_of_dired(void)
        defsymbol(&Qsorted_list, "sorted-list");
        defsymbol(&Qdesc_sorted_list, "desc-sorted-list");
        defsymbol(&Qunsorted_list, "unsorted-list");
+       defsymbol(&Qmatch_full, "match-full");
 
        DEFSUBR(Fdirectory_files);
        DEFSUBR(Fdirectory_files_recur);