Remove support for DJGPP v1.x (bug#5813).
[bpt/emacs.git] / src / dired.c
index 0779fcd..2240f6e 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, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+                 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -23,6 +23,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <setjmp.h>
 
 #ifdef HAVE_PWD_H
 #include <pwd.h>
@@ -104,6 +105,7 @@ extern void filemodestring P_ ((struct stat *, char *));
 extern int completion_ignore_case;
 extern Lisp_Object Qcompletion_ignore_case;
 extern Lisp_Object Vcompletion_regexp_list;
+extern Lisp_Object Vw32_get_true_file_attributes;
 
 Lisp_Object Vcompletion_ignored_extensions;
 Lisp_Object Qdirectory_files;
@@ -115,6 +117,14 @@ Lisp_Object Qfile_attributes_lessp;
 
 static int scmp P_ ((unsigned char *, unsigned char *, int));
 \f
+#ifdef WINDOWSNT
+Lisp_Object
+directory_files_internal_w32_unwind (Lisp_Object arg)
+{
+  Vw32_get_true_file_attributes = arg;
+  return Qnil;
+}
+#endif
 
 Lisp_Object
 directory_files_internal_unwind (dh)
@@ -146,6 +156,9 @@ directory_files_internal (directory, full, match, nosort, attrs, id_format)
   int count = SPECPDL_INDEX ();
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
   DIRENTRY *dp;
+#ifdef WINDOWSNT
+  Lisp_Object w32_save = Qnil;
+#endif
 
   /* Because of file name handlers, these functions might call
      Ffuncall, and cause a GC.  */
@@ -194,6 +207,29 @@ directory_files_internal (directory, full, match, nosort, attrs, id_format)
   record_unwind_protect (directory_files_internal_unwind,
                         make_save_value (d, 0));
 
+#ifdef WINDOWSNT
+  if (attrs)
+    {
+      extern Lisp_Object Qlocal;
+      extern int is_slow_fs (const char *);
+
+      /* Do this only once to avoid doing it (in w32.c:stat) for each
+        file in the directory, when we call Ffile_attributes below.  */
+      record_unwind_protect (directory_files_internal_w32_unwind,
+                            Vw32_get_true_file_attributes);
+      w32_save = Vw32_get_true_file_attributes;
+      if (EQ (Vw32_get_true_file_attributes, Qlocal))
+       {
+         /* w32.c:stat will notice these bindings and avoid calling
+            GetDriveType for each file.  */
+         if (is_slow_fs (SDATA (dirfilename)))
+           Vw32_get_true_file_attributes = Qnil;
+         else
+           Vw32_get_true_file_attributes = Qt;
+       }
+    }
+#endif
+
   directory_nbytes = SBYTES (directory);
   re_match_object = Qt;
 
@@ -310,6 +346,10 @@ directory_files_internal (directory, full, match, nosort, attrs, id_format)
   BLOCK_INPUT;
   closedir (d);
   UNBLOCK_INPUT;
+#ifdef WINDOWSNT
+  if (attrs)
+    Vw32_get_true_file_attributes = w32_save;
+#endif
 
   /* Discard the unwind protect.  */
   specpdl_ptr = specpdl + count;
@@ -329,8 +369,8 @@ If FULL is non-nil, return absolute file names.  Otherwise return names
  that are relative to the specified directory.
 If MATCH is non-nil, mention only file names that match the regexp MATCH.
 If NOSORT is non-nil, the list is not sorted--its order is unpredictable.
 Otherwise, the list returned is sorted with `stringp-lessp'.
 NOSORT is useful if you plan to sort the result yourself.  */)
Otherwise, the list returned is sorted with `string-lessp'.
+ NOSORT is useful if you plan to sort the result yourself.  */)
      (directory, full, match, nosort)
      Lisp_Object directory, full, match, nosort;
 {
@@ -537,6 +577,20 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
       if (!all_flag)
        {
          int skip;
+
+#if 0 /* FIXME: The `scmp' call compares an encoded and a decoded string. */
+         /* If this entry matches the current bestmatch, the only
+            thing it can do is increase matchcount, so don't bother
+            investigating it any further.  */
+         if (!completion_ignore_case
+             /* The return result depends on whether it's the sole match.  */
+             && matchcount > 1
+             && !includeall /* This match may allow includeall to 0.  */
+             && len >= bestmatchsize
+             && 0 > scmp (dp->d_name, SDATA (bestmatch), bestmatchsize))
+           continue;
+#endif
+
          if (directoryp)
            {
 #ifndef TRIVIAL_DIRECTORY_ENTRY
@@ -705,8 +759,7 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
              /* This tests that the current file is an exact match
                 but BESTMATCH is not (it is too long).  */
              if ((matchsize == SCHARS (name)
-                  && matchsize + !!directoryp
-                  < SCHARS (bestmatch))
+                  && matchsize + !!directoryp < SCHARS (bestmatch))
                  ||
                  /* If there is no exact match ignoring case,
                     prefer a match that does not change the case
@@ -734,6 +787,20 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
                bestmatch = name;
            }
          bestmatchsize = matchsize;
+
+         /* If the best completion so far is reduced to the string
+            we're trying to complete, then we already know there's no
+            other completion, so there's no point looking any further.  */
+         if (matchsize <= SCHARS (file)
+             && !includeall /* A future match may allow includeall to 0.  */
+             /* If completion-ignore-case is non-nil, don't
+                short-circuit because we want to find the best
+                possible match *including* case differences.  */
+             && (!completion_ignore_case || matchsize == 0)
+             /* The return value depends on whether it's the sole match.  */
+             && matchcount > 1)
+           break;
+
        }
     }
 
@@ -792,7 +859,6 @@ file_name_completion_stat (dirname, dp, st_addr)
   char *fullname = (char *) alloca (len + pos + 2);
 
 #ifdef MSDOS
-#if __DJGPP__ > 1
   /* Some fields of struct stat are *very* expensive to compute on MS-DOS,
      but aren't required here.  Avoid computing the following fields:
      st_inode, st_size and st_nlink for directories, and the execute bits
@@ -801,7 +867,6 @@ file_name_completion_stat (dirname, dp, st_addr)
   unsigned short save_djstat_flags = _djstat_flags;
 
   _djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
-#endif /* __DJGPP__ > 1 */
 #endif /* MSDOS */
 
   bcopy (SDATA (dirname), fullname, pos);
@@ -821,9 +886,7 @@ file_name_completion_stat (dirname, dp, st_addr)
 #else
   value = stat (fullname, st_addr);
 #ifdef MSDOS
-#if __DJGPP__ > 1
   _djstat_flags = save_djstat_flags;
-#endif /* __DJGPP__ > 1 */
 #endif /* MSDOS */
   return value;
 #endif /* S_IFLNK */
@@ -879,27 +942,37 @@ ID-FORMAT if you use the returned uid or gid.
 Elements of the attribute list are:
  0. t for directory, string (name linked to) for symbolic link, or nil.
  1. Number of links to file.
- 2. File uid as a string or an integer.  If a string value cannot be
-  looked up, the integer value is returned.
+ 2. File uid as a string or a number.  If a string value cannot be
+  looked up, a numeric value, either an integer or a float, is returned.
  3. File gid, likewise.
  4. Last access time, as a list of two integers.
   First integer has high-order 16 bits of time, second has low 16 bits.
- 5. Last modification time, likewise.
- 6. Last status change time, likewise.
+  (See a note below about access time on FAT-based filesystems.)
+ 5. Last modification time, likewise.  This is the time of the last
+  change to the file's contents.
+ 6. Last status change time, likewise.  This is the time of last change
+  to the file's attributes: owner and group, access mode bits, etc.
  7. Size in bytes.
   This is a floating point number if the size is too large for an integer.
  8. File modes, as a string of ten letters or dashes as in ls -l.
  9. t if file's gid would change if file were deleted and recreated.
-10. inode number.  If inode number is larger than the Emacs integer,
-  but still fits into a 32-bit number, this is a cons cell containing two
-  integers: first the high part, then the low 16 bits.  If the inode number
-  is wider than 32 bits, this is a cons cell containing three integers:
-  first the high 24 bits, then middle 24 bits, and finally the low 16 bits.
-11. Device number.  If it is larger than the Emacs integer, this is
-  a cons cell, similar to the inode number.
+10. inode number.  If inode number is larger than what Emacs integer
+  can hold, but still fits into a 32-bit number, this is a cons cell
+  containing two integers: first the high part, then the low 16 bits.
+  If the inode number is wider than 32 bits, this is of the form
+  (HIGH MIDDLE . LOW): first the high 24 bits, then middle 24 bits,
+  and finally the low 16 bits.
+11. Filesystem device number.  If it is larger than what the Emacs
+  integer can hold, this is a cons cell, similar to the inode number.
+
+On most filesystems, the combination of the inode and the device
+number uniquely identifies the file.
 
 On MS-Windows, performance depends on `w32-get-true-file-attributes',
-which see.  */)
+which see.
+
+On some FAT-based filesystems, only the date of last access is recorded,
+so last access time will always be midnight of that day.  */)
      (filename, id_format)
      Lisp_Object filename, id_format;
 {
@@ -913,8 +986,7 @@ which see.  */)
   char modes[10];
   Lisp_Object handler;
   struct gcpro gcpro1;
-  EMACS_INT ino, uid, gid;
-  char *uname, *gname;
+  char *uname = NULL, *gname = NULL;
 
   filename = Fexpand_file_name (filename, Qnil);
 
@@ -949,31 +1021,27 @@ which see.  */)
 #endif
     }
   values[1] = make_number (s.st_nlink);
-  uid = s.st_uid;
-  gid = s.st_gid;
-  if (NILP (id_format) || EQ (id_format, Qinteger))
-    {
-      values[2] = make_fixnum_or_float (uid);
-      values[3] = make_fixnum_or_float (gid);
-    }
-  else
+
+  if (!(NILP (id_format) || EQ (id_format, Qinteger)))
     {
       BLOCK_INPUT;
       uname = stat_uname (&s);
-      values[2] = (uname ? build_string (uname)
-                  : make_fixnum_or_float (uid));
       gname = stat_gname (&s);
-      values[3] = (gname ? build_string (gname)
-                  : make_fixnum_or_float (gid));
       UNBLOCK_INPUT;
     }
+  if (uname)
+    values[2] = DECODE_SYSTEM (build_string (uname));
+  else
+    values[2] = make_fixnum_or_float (s.st_uid);
+  if (gname)
+    values[3] = DECODE_SYSTEM (build_string (gname));
+  else
+    values[3] = make_fixnum_or_float (s.st_gid);
+
   values[4] = make_time (s.st_atime);
   values[5] = make_time (s.st_mtime);
   values[6] = make_time (s.st_ctime);
-  values[7] = make_number (s.st_size);
-  /* If the size is out of range for an integer, return a float.  */
-  if (XINT (values[7]) != s.st_size)
-    values[7] = make_float ((double)s.st_size);
+  values[7] = make_fixnum_or_float (s.st_size);
   /* If the size is negative, and its type is long, convert it back to
      positive.  */
   if (s.st_size < 0 && sizeof (s.st_size) == sizeof (long))
@@ -992,17 +1060,10 @@ which see.  */)
 #else                                  /* file gid will be egid */
   values[9] = (s.st_gid != getegid ()) ? Qt : Qnil;
 #endif /* BSD4_2 (or BSD4_3) */
-  /* Shut up GCC warnings in FIXNUM_OVERFLOW_P below.  */
-  if (sizeof (s.st_ino) > sizeof (ino))
-    ino = (EMACS_INT)(s.st_ino & 0xffffffff);
-  else
-    ino = s.st_ino;
-  if (!FIXNUM_OVERFLOW_P (ino)
-      && (sizeof (s.st_ino) <= sizeof (ino) || (s.st_ino & ~INTMASK) == 0))
+  if (!FIXNUM_OVERFLOW_P (s.st_ino))
     /* Keep the most common cases as integers.  */
-    values[10] = make_number (ino);
-  else if (sizeof (s.st_ino) <= sizeof (ino)
-          || ((s.st_ino >> 16) & ~INTMASK) == 0)
+    values[10] = make_number (s.st_ino);
+  else if (!FIXNUM_OVERFLOW_P (s.st_ino >> 16))
     /* To allow inode numbers larger than VALBITS, separate the bottom
        16 bits.  */
     values[10] = Fcons (make_number ((EMACS_INT)(s.st_ino >> 16)),
@@ -1022,11 +1083,8 @@ which see.  */)
                                 make_number (low_ino & 0xffff)));
     }
 
-  /* Likewise for device, but don't let it become negative.  We used
-     to use FIXNUM_OVERFLOW_P here, but that won't catch large
-     positive numbers such as 0xFFEEDDCC.  */
-  if ((EMACS_INT)s.st_dev < 0
-      || (EMACS_INT)s.st_dev > MOST_POSITIVE_FIXNUM)
+  /* Likewise for device.  */
+  if (FIXNUM_OVERFLOW_P (s.st_dev))
     values[11] = Fcons (make_number (s.st_dev >> 16),
                        make_number (s.st_dev & 0xffff));
   else
@@ -1047,13 +1105,13 @@ Comparison is in lexicographic order and case is significant.  */)
 void
 syms_of_dired ()
 {
-  Qdirectory_files = intern ("directory-files");
-  Qdirectory_files_and_attributes = intern ("directory-files-and-attributes");
-  Qfile_name_completion = intern ("file-name-completion");
-  Qfile_name_all_completions = intern ("file-name-all-completions");
-  Qfile_attributes = intern ("file-attributes");
-  Qfile_attributes_lessp = intern ("file-attributes-lessp");
-  Qdefault_directory = intern ("default-directory");
+  Qdirectory_files = intern_c_string ("directory-files");
+  Qdirectory_files_and_attributes = intern_c_string ("directory-files-and-attributes");
+  Qfile_name_completion = intern_c_string ("file-name-completion");
+  Qfile_name_all_completions = intern_c_string ("file-name-all-completions");
+  Qfile_attributes = intern_c_string ("file-attributes");
+  Qfile_attributes_lessp = intern_c_string ("file-attributes-lessp");
+  Qdefault_directory = intern_c_string ("default-directory");
 
   staticpro (&Qdirectory_files);
   staticpro (&Qdirectory_files_and_attributes);