]> code.delx.au - gnu-emacs/blobdiff - src/dired.c
Merge from emacs--devo--0
[gnu-emacs] / src / dired.c
index 4725644ee33d4a85bcaccdb866509702bfb6d730..3283d38eb4b95ad35e061f6eeb4f3df6bc93c2f9 100644 (file)
@@ -1,6 +1,6 @@
 /* Lisp functions for making directory listings.
    Copyright (C) 1985, 1986, 1993, 1994, 1999, 2000, 2001, 2002, 2003,
-                 2004, 2005 Free Software Foundation, Inc.
+                 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -33,7 +33,6 @@ Boston, MA 02110-1301, USA.  */
 #include <grp.h>
 #endif
 
-#include "systime.h"
 #include <errno.h>
 
 #ifdef VMS
@@ -86,19 +85,22 @@ extern struct direct *readdir ();
 #endif /* not MSDOS */
 #endif /* not SYSV_SYSTEM_DIR */
 
-#ifdef MSDOS
+/* Some versions of Cygwin don't have d_ino in `struct dirent'.  */
+#if defined(MSDOS) || defined(__CYGWIN__)
 #define DIRENTRY_NONEMPTY(p) ((p)->d_name[0] != 0)
 #else
 #define DIRENTRY_NONEMPTY(p) ((p)->d_ino)
 #endif
 
 #include "lisp.h"
+#include "systime.h"
 #include "buffer.h"
 #include "commands.h"
 #include "character.h"
 #include "charset.h"
 #include "coding.h"
 #include "regex.h"
+#include "blockinput.h"
 
 /* Returns a search buffer, with a fastmap allocated and ready to go.  */
 extern struct re_pattern_buffer *compile_pattern ();
@@ -133,7 +135,9 @@ directory_files_internal_unwind (dh)
      Lisp_Object dh;
 {
   DIR *d = (DIR *) XSAVE_VALUE (dh)->pointer;
+  BLOCK_INPUT;
   closedir (d);
+  UNBLOCK_INPUT;
   return Qnil;
 }
 
@@ -175,9 +179,15 @@ directory_files_internal (directory, full, match, nosort, attrs, id_format)
 #ifdef VMS
       bufp = compile_pattern (match, 0,
                              buffer_defaults.downcase_table, 0, 1);
-#else
+#else  /* !VMS */
+# ifdef WINDOWSNT
+      /* Windows users want case-insensitive wildcards.  */
+      bufp = compile_pattern (match, 0,
+                             buffer_defaults.case_canon_table, 0, 1);
+# else /* !WINDOWSNT */
       bufp = compile_pattern (match, 0, Qnil, 0, 1);
-#endif
+# endif         /* !WINDOWSNT */
+#endif  /* !VMS */
     }
 
   /* Note: ENCODE_FILE and DECODE_FILE can GC because they can run
@@ -189,7 +199,9 @@ directory_files_internal (directory, full, match, nosort, attrs, id_format)
   /* Now *bufp is the compiled form of MATCH; don't call anything
      which might compile a new regexp until we're done with the loop!  */
 
+  BLOCK_INPUT;
   d = opendir (SDATA (dirfilename));
+  UNBLOCK_INPUT;
   if (d == NULL)
     report_file_error ("Opening directory", Fcons (directory, Qnil));
 
@@ -314,7 +326,9 @@ directory_files_internal (directory, full, match, nosort, attrs, id_format)
        }
     }
 
+  BLOCK_INPUT;
   closedir (d);
+  UNBLOCK_INPUT;
 
   /* Discard the unwind protect.  */
   specpdl_ptr = specpdl + count;
@@ -382,17 +396,20 @@ ID-FORMAT specifies the preferred format of attributes uid and gid, see
 Lisp_Object file_name_completion ();
 
 DEFUN ("file-name-completion", Ffile_name_completion, Sfile_name_completion,
-       2, 2, 0,
+       2, 3, 0,
        doc: /* Complete file name FILE in directory DIRECTORY.
 Returns the longest string
 common to all file names in DIRECTORY that start with FILE.
 If there is only one and FILE matches it exactly, returns t.
 Returns nil if DIRECTORY contains no name starting with FILE.
 
+If PREDICATE is non-nil, call PREDICATE with each possible
+completion (in absolute form) and ignore it if PREDICATE returns nil.
+
 This function ignores some of the possible completions as
 determined by the variable `completion-ignored-extensions', which see.  */)
-     (file, directory)
-     Lisp_Object file, directory;
+     (file, directory, predicate)
+     Lisp_Object file, directory, predicate;
 {
   Lisp_Object handler;
 
@@ -400,15 +417,15 @@ determined by the variable `completion-ignored-extensions', which see.  */)
      call the corresponding file handler.  */
   handler = Ffind_file_name_handler (directory, Qfile_name_completion);
   if (!NILP (handler))
-    return call3 (handler, Qfile_name_completion, file, directory);
+    return call4 (handler, Qfile_name_completion, file, directory, predicate);
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
   handler = Ffind_file_name_handler (file, Qfile_name_completion);
   if (!NILP (handler))
-    return call3 (handler, Qfile_name_completion, file, directory);
+    return call4 (handler, Qfile_name_completion, file, directory, predicate);
 
-  return file_name_completion (file, directory, 0, 0);
+  return file_name_completion (file, directory, 0, 0, predicate);
 }
 
 DEFUN ("file-name-all-completions", Ffile_name_all_completions,
@@ -432,21 +449,25 @@ These are all file names in directory DIRECTORY which begin with FILE.  */)
   if (!NILP (handler))
     return call3 (handler, Qfile_name_all_completions, file, directory);
 
-  return file_name_completion (file, directory, 1, 0);
+  return file_name_completion (file, directory, 1, 0, Qnil);
 }
 
 static int file_name_completion_stat ();
 
 Lisp_Object
-file_name_completion (file, dirname, all_flag, ver_flag)
+file_name_completion (file, dirname, all_flag, ver_flag, predicate)
      Lisp_Object file, dirname;
      int all_flag, ver_flag;
+     Lisp_Object predicate;
 {
   DIR *d;
   int bestmatchsize = 0, skip;
   register int compare, matchsize;
   unsigned char *p1, *p2;
   int matchcount = 0;
+  /* If ALL_FLAG is 1, BESTMATCH is the list of all matches, decoded.
+     If ALL_FLAG is 0, BESTMATCH is either nil
+     or the best match so far, not decoded.  */
   Lisp_Object bestmatch, tem, elt, name;
   Lisp_Object encoded_file;
   Lisp_Object encoded_dir;
@@ -501,7 +522,9 @@ file_name_completion (file, dirname, all_flag, ver_flag)
     {
       int inner_count = SPECPDL_INDEX ();
 
+      BLOCK_INPUT;
       d = opendir (SDATA (Fdirectory_file_name (encoded_dir)));
+      UNBLOCK_INPUT;
       if (!d)
        report_file_error ("Opening directory", Fcons (dirname, Qnil));
 
@@ -552,8 +575,8 @@ file_name_completion (file, dirname, all_flag, ver_flag)
 #ifndef TRIVIAL_DIRECTORY_ENTRY
 #define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, ".."))
 #endif
-             /* "." and ".." are never interesting as completions, but are
-                actually in the way in a directory contains only one file.  */
+             /* "." and ".." are never interesting as completions, and are
+                actually in the way in a directory with only one file.  */
              if (!passcount && TRIVIAL_DIRECTORY_ENTRY (dp->d_name))
                continue;
              if (!passcount && len > SCHARS (encoded_file))
@@ -634,30 +657,38 @@ file_name_completion (file, dirname, all_flag, ver_flag)
                continue;
            }
 
-         /* Update computation of how much all possible completions match */
+         /* This is a possible completion */
+         if (directoryp)
+           {
+             /* This completion is a directory; make it end with '/' */
+             name = Ffile_name_as_directory (make_string (dp->d_name, len));
+           }
+         else
+           name = make_string (dp->d_name, len);
+
+         /* Test the predicate, if any.  */
+
+         if (!NILP (predicate))
+           {
+             Lisp_Object decoded;
+             decoded = Fexpand_file_name (DECODE_FILE (name), dirname);
+             if (NILP (call1 (predicate, decoded)))
+               continue;
+           }
+
+         /* Suitably record this match.  */
 
          matchcount++;
 
-         if (all_flag || NILP (bestmatch))
+         if (all_flag)
            {
-             /* This is a possible completion */
-             if (directoryp)
-               {
-                 /* This completion is a directory; make it end with '/' */
-                 name = Ffile_name_as_directory (make_string (dp->d_name, len));
-               }
-             else
-               name = make_string (dp->d_name, len);
-             if (all_flag)
-               {
-                 name = DECODE_FILE (name);
-                 bestmatch = Fcons (name, bestmatch);
-               }
-             else
-               {
-                 bestmatch = name;
-                 bestmatchsize = SCHARS (name);
-               }
+             name = DECODE_FILE (name);
+             bestmatch = Fcons (name, bestmatch);
+           }
+         else if (NILP (bestmatch))
+           {
+             bestmatch = name;
+             bestmatchsize = SCHARS (name);
            }
          else
            {
@@ -693,11 +724,7 @@ file_name_completion (file, dirname, all_flag, ver_flag)
                         == SCHARS (bestmatch)))
                       && !bcmp (p2, SDATA (encoded_file), SCHARS (encoded_file))
                       && bcmp (p1, SDATA (encoded_file), SCHARS (encoded_file))))
-                   {
-                     bestmatch = make_string (dp->d_name, len);
-                     if (directoryp)
-                       bestmatch = Ffile_name_as_directory (bestmatch);
-                   }
+                   bestmatch = name;
                }
 
              /* If this dirname all matches, see if implicit following
@@ -820,7 +847,7 @@ DEFUN ("file-name-all-versions", Ffile_name_all_versions,
      (file, directory)
      Lisp_Object file, directory;
 {
-  return file_name_completion (file, directory, 1, 1);
+  return file_name_completion (file, directory, 1, 1, Qnil);
 }
 
 DEFUN ("file-version-limit", Ffile_version_limit, Sfile_version_limit, 1, 1, 0,
@@ -945,10 +972,12 @@ Elements of the attribute list are:
     }
   else
     {
+      BLOCK_INPUT;
       pw = (struct passwd *) getpwuid (s.st_uid);
       values[2] = (pw ? build_string (pw->pw_name) : make_number (s.st_uid));
       gr = (struct group *) getgrgid (s.st_gid);
       values[3] = (gr ? build_string (gr->gr_name) : make_number (s.st_gid));
+      UNBLOCK_INPUT;
     }
   values[4] = make_time (s.st_atime);
   values[5] = make_time (s.st_mtime);
@@ -1037,11 +1066,11 @@ syms_of_dired ()
 #endif /* VMS */
 
   DEFVAR_LISP ("completion-ignored-extensions", &Vcompletion_ignored_extensions,
-              doc: /* *Completion ignores filenames ending in any string in this list.
-Directories are ignored if they match any string in this list which
-ends in a slash.
-This variable does not affect lists of possible completions,
-but does affect the commands that actually do completions.  */);
+              doc: /* Completion ignores file names ending in any string in this list.
+It does not ignore them if all possible completions end in one of
+these strings or when displaying a list of completions.
+It ignores directory names if they match any string in this list which
+ends in a slash.  */);
   Vcompletion_ignored_extensions = Qnil;
 }