* lisp/isearch.el (isearch-mode-map): Bind `C-x 8 RET' to
[bpt/emacs.git] / src / dired.c
index 2c634b9..1fda9e8 100644 (file)
@@ -22,7 +22,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <setjmp.h>
 
 #ifdef HAVE_PWD_H
 #include <pwd.h>
 
 #ifdef HAVE_PWD_H
 #include <pwd.h>
@@ -32,48 +31,15 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <errno.h>
 #include <unistd.h>
 
 #include <errno.h>
 #include <unistd.h>
 
-/* The d_nameln member of a struct dirent includes the '\0' character
-   on some systems, but not on others.  What's worse, you can't tell
-   at compile-time which one it will be, since it really depends on
-   the sort of system providing the filesystem you're reading from,
-   not the system you are running on.  Paul Eggert
-   <eggert@bi.twinsun.com> says this occurs when Emacs is running on a
-   SunOS 4.1.2 host, reading a directory that is remote-mounted from a
-   Solaris 2.1 host and is in a native Solaris 2.1 filesystem.
-
-   Since applying strlen to the name always works, we'll just do that.  */
-#define NAMLEN(p) strlen (p->d_name)
-
-#ifdef HAVE_DIRENT_H
-
 #include <dirent.h>
 #include <dirent.h>
-#define DIRENTRY struct dirent
-
-#else /* not HAVE_DIRENT_H */
-
-#include <sys/dir.h>
-#include <sys/stat.h>
-
-#define DIRENTRY struct direct
-
-extern DIR *opendir (char *);
-extern struct direct *readdir (DIR *);
-
-#endif /* HAVE_DIRENT_H */
-
 #include <filemode.h>
 #include <filemode.h>
-
-#ifdef MSDOS
-#define DIRENTRY_NONEMPTY(p) ((p)->d_name[0] != 0)
-#else
-#define DIRENTRY_NONEMPTY(p) ((p)->d_ino)
-#endif
+#include <stat-time.h>
 
 #include "lisp.h"
 #include "systime.h"
 
 #include "lisp.h"
 #include "systime.h"
+#include "character.h"
 #include "buffer.h"
 #include "commands.h"
 #include "buffer.h"
 #include "commands.h"
-#include "character.h"
 #include "charset.h"
 #include "coding.h"
 #include "regex.h"
 #include "charset.h"
 #include "coding.h"
 #include "regex.h"
@@ -86,9 +52,19 @@ static Lisp_Object Qfile_name_all_completions;
 static Lisp_Object Qfile_attributes;
 static Lisp_Object Qfile_attributes_lessp;
 
 static Lisp_Object Qfile_attributes;
 static Lisp_Object Qfile_attributes_lessp;
 
-static int scmp (const char *, const char *, int);
-static Lisp_Object Ffile_attributes (Lisp_Object, Lisp_Object);
+static ptrdiff_t scmp (const char *, const char *, ptrdiff_t);
 \f
 \f
+/* Return the number of bytes in DP's name.  */
+static ptrdiff_t
+dirent_namelen (struct dirent *dp)
+{
+#ifdef _D_EXACT_NAMLEN
+  return _D_EXACT_NAMLEN (dp);
+#else
+  return strlen (dp->d_name);
+#endif
+}
+
 #ifdef WINDOWSNT
 Lisp_Object
 directory_files_internal_w32_unwind (Lisp_Object arg)
 #ifdef WINDOWSNT
 Lisp_Object
 directory_files_internal_w32_unwind (Lisp_Object arg)
@@ -102,28 +78,30 @@ static Lisp_Object
 directory_files_internal_unwind (Lisp_Object dh)
 {
   DIR *d = (DIR *) XSAVE_VALUE (dh)->pointer;
 directory_files_internal_unwind (Lisp_Object dh)
 {
   DIR *d = (DIR *) XSAVE_VALUE (dh)->pointer;
-  BLOCK_INPUT;
+  block_input ();
   closedir (d);
   closedir (d);
-  UNBLOCK_INPUT;
+  unblock_input ();
   return Qnil;
 }
 
 /* Function shared by Fdirectory_files and Fdirectory_files_and_attributes.
   return Qnil;
 }
 
 /* Function shared by Fdirectory_files and Fdirectory_files_and_attributes.
-   When ATTRS is zero, return a list of directory filenames; when
-   non-zero, return a list of directory filenames and their attributes.
+   If not ATTRS, return a list of directory filenames;
+   if ATTRS, return a list of directory filenames and their attributes.
    In the latter case, ID_FORMAT is passed to Ffile_attributes.  */
 
 Lisp_Object
    In the latter case, ID_FORMAT is passed to Ffile_attributes.  */
 
 Lisp_Object
-directory_files_internal (Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort, int attrs, Lisp_Object id_format)
+directory_files_internal (Lisp_Object directory, Lisp_Object full,
+                         Lisp_Object match, Lisp_Object nosort, bool attrs,
+                         Lisp_Object id_format)
 {
   DIR *d;
 {
   DIR *d;
-  int directory_nbytes;
+  ptrdiff_t directory_nbytes;
   Lisp_Object list, dirfilename, encoded_directory;
   struct re_pattern_buffer *bufp = NULL;
   Lisp_Object list, dirfilename, encoded_directory;
   struct re_pattern_buffer *bufp = NULL;
-  int needsep = 0;
-  int count = SPECPDL_INDEX ();
+  bool needsep = 0;
+  ptrdiff_t count = SPECPDL_INDEX ();
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
-  DIRENTRY *dp;
+  struct dirent *dp;
 #ifdef WINDOWSNT
   Lisp_Object w32_save = Qnil;
 #endif
 #ifdef WINDOWSNT
   Lisp_Object w32_save = Qnil;
 #endif
@@ -163,9 +141,9 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, Lisp_Object m
   /* 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!  */
 
   /* 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;
+  block_input ();
   d = opendir (SSDATA (dirfilename));
   d = opendir (SSDATA (dirfilename));
-  UNBLOCK_INPUT;
+  unblock_input ();
   if (d == NULL)
     report_file_error ("Opening directory", Fcons (directory, Qnil));
 
   if (d == NULL)
     report_file_error ("Opening directory", Fcons (directory, Qnil));
 
@@ -208,110 +186,103 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, Lisp_Object m
   /* Loop reading blocks until EOF or error.  */
   for (;;)
     {
   /* Loop reading blocks until EOF or error.  */
   for (;;)
     {
+      ptrdiff_t len;
+      bool wanted = 0;
+      Lisp_Object name, finalname;
+      struct gcpro gcpro1, gcpro2;
+
       errno = 0;
       dp = readdir (d);
       errno = 0;
       dp = readdir (d);
+      if (!dp)
+       {
+         if (errno == EAGAIN || errno == EINTR)
+           {
+             QUIT;
+             continue;
+           }
+         break;
+       }
 
 
-      if (dp == NULL && (0
-#ifdef EAGAIN
-                        || errno == EAGAIN
-#endif
-#ifdef EINTR
-                        || errno == EINTR
-#endif
-                        ))
-       { QUIT; continue; }
+      len = dirent_namelen (dp);
+      name = finalname = make_unibyte_string (dp->d_name, len);
+      GCPRO2 (finalname, name);
+
+      /* Note: DECODE_FILE can GC; it should protect its argument,
+        though.  */
+      name = DECODE_FILE (name);
+      len = SBYTES (name);
 
 
-      if (dp == NULL)
-       break;
+      /* Now that we have unwind_protect in place, we might as well
+        allow matching to be interrupted.  */
+      immediate_quit = 1;
+      QUIT;
+
+      if (NILP (match)
+         || (0 <= re_search (bufp, SSDATA (name), len, 0, len, 0)))
+       wanted = 1;
 
 
-      if (DIRENTRY_NONEMPTY (dp))
+      immediate_quit = 0;
+
+      if (wanted)
        {
        {
-         int len;
-         int wanted = 0;
-         Lisp_Object name, finalname;
-         struct gcpro gcpro1, gcpro2;
+         if (!NILP (full))
+           {
+             Lisp_Object fullname;
+             ptrdiff_t nbytes = len + directory_nbytes + needsep;
+             ptrdiff_t nchars;
 
 
-         len = NAMLEN (dp);
-         name = finalname = make_unibyte_string (dp->d_name, len);
-         GCPRO2 (finalname, name);
+             fullname = make_uninit_multibyte_string (nbytes, nbytes);
+             memcpy (SDATA (fullname), SDATA (directory),
+                     directory_nbytes);
 
 
-         /* Note: DECODE_FILE can GC; it should protect its argument,
-            though.  */
-         name = DECODE_FILE (name);
-         len = SBYTES (name);
+             if (needsep)
+               SSET (fullname, directory_nbytes, DIRECTORY_SEP);
 
 
-         /* Now that we have unwind_protect in place, we might as well
-             allow matching to be interrupted.  */
-         immediate_quit = 1;
-         QUIT;
+             memcpy (SDATA (fullname) + directory_nbytes + needsep,
+                     SDATA (name), len);
 
 
-         if (NILP (match)
-             || (0 <= re_search (bufp, SSDATA (name), len, 0, len, 0)))
-           wanted = 1;
+             nchars = chars_in_text (SDATA (fullname), nbytes);
 
 
-         immediate_quit = 0;
+             /* Some bug somewhere.  */
+             if (nchars > nbytes)
+               emacs_abort ();
 
 
-         if (wanted)
-           {
-             if (!NILP (full))
-               {
-                 Lisp_Object fullname;
-                 int nbytes = len + directory_nbytes + needsep;
-                 int nchars;
-
-                 fullname = make_uninit_multibyte_string (nbytes, nbytes);
-                 memcpy (SDATA (fullname), SDATA (directory),
-                         directory_nbytes);
-
-                 if (needsep)
-                   SSET (fullname, directory_nbytes, DIRECTORY_SEP);
-
-                 memcpy (SDATA (fullname) + directory_nbytes + needsep,
-                         SDATA (name), len);
-
-                 nchars = chars_in_text (SDATA (fullname), nbytes);
-
-                 /* Some bug somewhere.  */
-                 if (nchars > nbytes)
-                   abort ();
-
-                 STRING_SET_CHARS (fullname, nchars);
-                 if (nchars == nbytes)
-                   STRING_SET_UNIBYTE (fullname);
-
-                 finalname = fullname;
-               }
-             else
-               finalname = name;
-
-             if (attrs)
-               {
-                 /* Construct an expanded filename for the directory entry.
-                    Use the decoded names for input to Ffile_attributes.  */
-                 Lisp_Object decoded_fullname, fileattrs;
-                 struct gcpro gcpro1, gcpro2;
-
-                 decoded_fullname = fileattrs = Qnil;
-                 GCPRO2 (decoded_fullname, fileattrs);
-
-                 /* Both Fexpand_file_name and Ffile_attributes can GC.  */
-                 decoded_fullname = Fexpand_file_name (name, directory);
-                 fileattrs = Ffile_attributes (decoded_fullname, id_format);
-
-                 list = Fcons (Fcons (finalname, fileattrs), list);
-                 UNGCPRO;
-               }
-             else
-               list = Fcons (finalname, list);
+             STRING_SET_CHARS (fullname, nchars);
+             if (nchars == nbytes)
+               STRING_SET_UNIBYTE (fullname);
+
+             finalname = fullname;
            }
            }
+         else
+           finalname = name;
 
 
-         UNGCPRO;
+         if (attrs)
+           {
+             /* Construct an expanded filename for the directory entry.
+                Use the decoded names for input to Ffile_attributes.  */
+             Lisp_Object decoded_fullname, fileattrs;
+             struct gcpro gcpro1, gcpro2;
+
+             decoded_fullname = fileattrs = Qnil;
+             GCPRO2 (decoded_fullname, fileattrs);
+
+             /* Both Fexpand_file_name and Ffile_attributes can GC.  */
+             decoded_fullname = Fexpand_file_name (name, directory);
+             fileattrs = Ffile_attributes (decoded_fullname, id_format);
+
+             list = Fcons (Fcons (finalname, fileattrs), list);
+             UNGCPRO;
+           }
+         else
+           list = Fcons (finalname, list);
        }
        }
+
+      UNGCPRO;
     }
 
     }
 
-  BLOCK_INPUT;
+  block_input ();
   closedir (d);
   closedir (d);
-  UNBLOCK_INPUT;
+  unblock_input ();
 #ifdef WINDOWSNT
   if (attrs)
     Vw32_get_true_file_attributes = w32_save;
 #ifdef WINDOWSNT
   if (attrs)
     Vw32_get_true_file_attributes = w32_save;
@@ -381,9 +352,8 @@ which see.  */)
 }
 
 \f
 }
 
 \f
-static Lisp_Object file_name_completion
-  (Lisp_Object file, Lisp_Object dirname, int all_flag, int ver_flag,
-   Lisp_Object predicate);
+static Lisp_Object file_name_completion (Lisp_Object, Lisp_Object, bool,
+                                        Lisp_Object);
 
 DEFUN ("file-name-completion", Ffile_name_completion, Sfile_name_completion,
        2, 3, 0,
 
 DEFUN ("file-name-completion", Ffile_name_completion, Sfile_name_completion,
        2, 3, 0,
@@ -415,7 +385,7 @@ determined by the variable `completion-ignored-extensions', which see.  */)
   if (!NILP (handler))
     return call4 (handler, Qfile_name_completion, file, directory, predicate);
 
   if (!NILP (handler))
     return call4 (handler, Qfile_name_completion, file, directory, predicate);
 
-  return file_name_completion (file, directory, 0, 0, predicate);
+  return file_name_completion (file, directory, 0, predicate);
 }
 
 DEFUN ("file-name-all-completions", Ffile_name_all_completions,
 }
 
 DEFUN ("file-name-all-completions", Ffile_name_all_completions,
@@ -439,17 +409,19 @@ These are all file names in directory DIRECTORY which begin with FILE.  */)
   if (!NILP (handler))
     return call3 (handler, Qfile_name_all_completions, file, directory);
 
   if (!NILP (handler))
     return call3 (handler, Qfile_name_all_completions, file, directory);
 
-  return file_name_completion (file, directory, 1, 0, Qnil);
+  return file_name_completion (file, directory, 1, Qnil);
 }
 
 }
 
-static int file_name_completion_stat (Lisp_Object dirname, DIRENTRY *dp, struct stat *st_addr);
+static int file_name_completion_stat (Lisp_Object dirname, struct dirent *dp,
+                                     struct stat *st_addr);
 static Lisp_Object Qdefault_directory;
 
 static Lisp_Object
 static Lisp_Object Qdefault_directory;
 
 static Lisp_Object
-file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int ver_flag, Lisp_Object predicate)
+file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag,
+                     Lisp_Object predicate)
 {
   DIR *d;
 {
   DIR *d;
-  int bestmatchsize = 0;
+  ptrdiff_t bestmatchsize = 0;
   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
   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
@@ -458,21 +430,18 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v
   Lisp_Object encoded_file;
   Lisp_Object encoded_dir;
   struct stat st;
   Lisp_Object encoded_file;
   Lisp_Object encoded_dir;
   struct stat st;
-  int directoryp;
-  /* If includeall is zero, exclude files in completion-ignored-extensions as
+  bool directoryp;
+  /* If not INCLUDEALL, exclude files in completion-ignored-extensions as
      well as "." and "..".  Until shown otherwise, assume we can't exclude
      anything.  */
      well as "." and "..".  Until shown otherwise, assume we can't exclude
      anything.  */
-  int includeall = 1;
-  int count = SPECPDL_INDEX ();
+  bool includeall = 1;
+  ptrdiff_t count = SPECPDL_INDEX ();
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
 
   elt = Qnil;
 
   CHECK_STRING (file);
 
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
 
   elt = Qnil;
 
   CHECK_STRING (file);
 
-#ifdef FILE_SYSTEM_CASE
-  file = FILE_SYSTEM_CASE (file);
-#endif
   bestmatch = Qnil;
   encoded_file = encoded_dir = Qnil;
   GCPRO5 (file, dirname, bestmatch, encoded_file, encoded_dir);
   bestmatch = Qnil;
   encoded_file = encoded_dir = Qnil;
   GCPRO5 (file, dirname, bestmatch, encoded_file, encoded_dir);
@@ -488,9 +457,9 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v
 
   encoded_dir = ENCODE_FILE (dirname);
 
 
   encoded_dir = ENCODE_FILE (dirname);
 
-  BLOCK_INPUT;
+  block_input ();
   d = opendir (SSDATA (Fdirectory_file_name (encoded_dir)));
   d = opendir (SSDATA (Fdirectory_file_name (encoded_dir)));
-  UNBLOCK_INPUT;
+  unblock_input ();
   if (!d)
     report_file_error ("Opening directory", Fcons (dirname, Qnil));
 
   if (!d)
     report_file_error ("Opening directory", Fcons (dirname, Qnil));
 
@@ -501,29 +470,26 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v
   /* (att3b compiler bug requires do a null comparison this way) */
   while (1)
     {
   /* (att3b compiler bug requires do a null comparison this way) */
   while (1)
     {
-      DIRENTRY *dp;
-      int len;
-      int canexclude = 0;
+      struct dirent *dp;
+      ptrdiff_t len;
+      bool canexclude = 0;
 
       errno = 0;
       dp = readdir (d);
 
       errno = 0;
       dp = readdir (d);
-      if (dp == NULL && (0
-# ifdef EAGAIN
-                        || errno == EAGAIN
-# endif
-# ifdef EINTR
-                        || errno == EINTR
-# endif
-                        ))
-       { QUIT; continue; }
-
-      if (!dp) break;
+      if (!dp)
+       {
+         if (errno == EAGAIN || errno == EINTR)
+           {
+             QUIT;
+             continue;
+           }
+         break;
+       }
 
 
-      len = NAMLEN (dp);
+      len = dirent_namelen (dp);
 
       QUIT;
 
       QUIT;
-      if (! DIRENTRY_NONEMPTY (dp)
-         || len < SCHARS (encoded_file)
+      if (len < SCHARS (encoded_file)
          || 0 <= scmp (dp->d_name, SSDATA (encoded_file),
                        SCHARS (encoded_file)))
        continue;
          || 0 <= scmp (dp->d_name, SSDATA (encoded_file),
                        SCHARS (encoded_file)))
        continue;
@@ -531,14 +497,14 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v
       if (file_name_completion_stat (encoded_dir, dp, &st) < 0)
        continue;
 
       if (file_name_completion_stat (encoded_dir, dp, &st) < 0)
        continue;
 
-      directoryp = S_ISDIR (st.st_mode);
+      directoryp = S_ISDIR (st.st_mode) != 0;
       tem = Qnil;
       /* If all_flag is set, always include all.
         It would not actually be helpful to the user to ignore any possible
         completions when making a list of them.  */
       if (!all_flag)
        {
       tem = Qnil;
       /* If all_flag is set, always include all.
         It would not actually be helpful to the user to ignore any possible
         completions when making a list of them.  */
       if (!all_flag)
        {
-         int skip;
+         ptrdiff_t skip;
 
 #if 0 /* FIXME: The `scmp' call compares an encoded and a decoded string. */
          /* If this entry matches the current bestmatch, the only
 
 #if 0 /* FIXME: The `scmp' call compares an encoded and a decoded string. */
          /* If this entry matches the current bestmatch, the only
@@ -568,7 +534,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v
                for (tem = Vcompletion_ignored_extensions;
                     CONSP (tem); tem = XCDR (tem))
                  {
                for (tem = Vcompletion_ignored_extensions;
                     CONSP (tem); tem = XCDR (tem))
                  {
-                   int elt_len;
+                   ptrdiff_t elt_len;
                    char *p1;
 
                    elt = XCAR (tem);
                    char *p1;
 
                    elt = XCAR (tem);
@@ -685,7 +651,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v
 
       /* Suitably record this match.  */
 
 
       /* Suitably record this match.  */
 
-      matchcount++;
+      matchcount += matchcount <= 1;
 
       if (all_flag)
        bestmatch = Fcons (name, bestmatch);
 
       if (all_flag)
        bestmatch = Fcons (name, bestmatch);
@@ -698,14 +664,14 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v
        {
          Lisp_Object zero = make_number (0);
          /* FIXME: This is a copy of the code in Ftry_completion.  */
        {
          Lisp_Object zero = make_number (0);
          /* FIXME: This is a copy of the code in Ftry_completion.  */
-         int compare = min (bestmatchsize, SCHARS (name));
+         ptrdiff_t compare = min (bestmatchsize, SCHARS (name));
          Lisp_Object cmp
            = Fcompare_strings (bestmatch, zero,
                                make_number (compare),
                                name, zero,
                                make_number (compare),
                                completion_ignore_case ? Qt : Qnil);
          Lisp_Object cmp
            = Fcompare_strings (bestmatch, zero,
                                make_number (compare),
                                name, zero,
                                make_number (compare),
                                completion_ignore_case ? Qt : Qnil);
-         int matchsize
+         ptrdiff_t matchsize
            = (EQ (cmp, Qt)     ? compare
               : XINT (cmp) < 0 ? - XINT (cmp) - 1
               :                  XINT (cmp) - 1);
            = (EQ (cmp, Qt)     ? compare
               : XINT (cmp) < 0 ? - XINT (cmp) - 1
               :                  XINT (cmp) - 1);
@@ -719,7 +685,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v
              /* This tests that the current file is an exact match
                 but BESTMATCH is not (it is too long).  */
              if ((matchsize == SCHARS (name)
              /* 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
                  ||
                  /* If there is no exact match ignoring case,
                     prefer a match that does not change the case
@@ -731,7 +697,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v
                     either both or neither are exact.  */
                  (((matchsize == SCHARS (name))
                    ==
                     either both or neither are exact.  */
                  (((matchsize == SCHARS (name))
                    ==
-                   (matchsize + !!directoryp == SCHARS (bestmatch)))
+                   (matchsize + directoryp == SCHARS (bestmatch)))
                   && (cmp = Fcompare_strings (name, zero,
                                               make_number (SCHARS (file)),
                                               file, zero,
                   && (cmp = Fcompare_strings (name, zero,
                                               make_number (SCHARS (file)),
                                               file, zero,
@@ -784,10 +750,10 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v
    Return -1 if strings match,
    else number of chars that match at the beginning.  */
 
    Return -1 if strings match,
    else number of chars that match at the beginning.  */
 
-static int
-scmp (const char *s1, const char *s2, int len)
+static ptrdiff_t
+scmp (const char *s1, const char *s2, ptrdiff_t len)
 {
 {
-  register int l = len;
+  register ptrdiff_t l = len;
 
   if (completion_ignore_case)
     {
 
   if (completion_ignore_case)
     {
@@ -808,12 +774,14 @@ scmp (const char *s1, const char *s2, int len)
 }
 
 static int
 }
 
 static int
-file_name_completion_stat (Lisp_Object dirname, DIRENTRY *dp, struct stat *st_addr)
+file_name_completion_stat (Lisp_Object dirname, struct dirent *dp,
+                          struct stat *st_addr)
 {
 {
-  int len = NAMLEN (dp);
-  int pos = SCHARS (dirname);
+  ptrdiff_t len = dirent_namelen (dp);
+  ptrdiff_t pos = SCHARS (dirname);
   int value;
   int value;
-  char *fullname = (char *) alloca (len + pos + 2);
+  USE_SAFE_ALLOCA;
+  char *fullname = SAFE_ALLOCA (len + pos + 2);
 
 #ifdef MSDOS
   /* Some fields of struct stat are *very* expensive to compute on MS-DOS,
 
 #ifdef MSDOS
   /* Some fields of struct stat are *very* expensive to compute on MS-DOS,
@@ -842,6 +810,7 @@ file_name_completion_stat (Lisp_Object dirname, DIRENTRY *dp, struct stat *st_ad
 #ifdef MSDOS
   _djstat_flags = save_djstat_flags;
 #endif /* MSDOS */
 #ifdef MSDOS
   _djstat_flags = save_djstat_flags;
 #endif /* MSDOS */
+  SAFE_FREE ();
   return value;
 }
 \f
   return value;
 }
 \f
@@ -851,7 +820,7 @@ stat_uname (struct stat *st)
 #ifdef WINDOWSNT
   return st->st_uname;
 #else
 #ifdef WINDOWSNT
   return st->st_uname;
 #else
-  struct passwd *pw = (struct passwd *) getpwuid (st->st_uid);
+  struct passwd *pw = getpwuid (st->st_uid);
 
   if (pw)
     return pw->pw_name;
 
   if (pw)
     return pw->pw_name;
@@ -866,7 +835,7 @@ stat_gname (struct stat *st)
 #ifdef WINDOWSNT
   return st->st_gname;
 #else
 #ifdef WINDOWSNT
   return st->st_gname;
 #else
-  struct group *gr = (struct group *) getgrgid (st->st_gid);
+  struct group *gr = getgrgid (st->st_gid);
 
   if (gr)
     return gr->gr_name;
 
   if (gr)
     return gr->gr_name;
@@ -890,8 +859,8 @@ Elements of the attribute list are:
  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.
  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.
+ 4. Last access time, as a list of integers (HIGH LOW USEC PSEC) in the
+  same style as (current-time).
   (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.
   (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.
@@ -900,7 +869,7 @@ Elements of the attribute list are:
  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.
  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.
+ 9. An unspecified value, present only for backward compatibility.
 10. inode number.  If it is larger than what an Emacs integer can hold,
   this is of the form (HIGH . LOW): first the high bits, then the low 16 bits.
   If even HIGH is too large for an Emacs integer, this is instead of the form
 10. inode number.  If it is larger than what an Emacs integer can hold,
   this is of the form (HIGH . LOW): first the high bits, then the low 16 bits.
   If even HIGH is too large for an Emacs integer, this is instead of the form
@@ -922,10 +891,7 @@ so last access time will always be midnight of that day.  */)
   Lisp_Object values[12];
   Lisp_Object encoded;
   struct stat s;
   Lisp_Object values[12];
   Lisp_Object encoded;
   struct stat s;
-#ifdef BSD4_2
-  Lisp_Object dirname;
-  struct stat sdir;
-#endif /* BSD4_2 */
+  int lstat_result;
 
   /* An array to hold the mode string generated by filemodestring,
      including its terminating space and null byte.  */
 
   /* An array to hold the mode string generated by filemodestring,
      including its terminating space and null byte.  */
@@ -953,7 +919,21 @@ so last access time will always be midnight of that day.  */)
   encoded = ENCODE_FILE (filename);
   UNGCPRO;
 
   encoded = ENCODE_FILE (filename);
   UNGCPRO;
 
-  if (lstat (SSDATA (encoded), &s) < 0)
+#ifdef WINDOWSNT
+  /* We usually don't request accurate owner and group info, because
+     it can be very expensive on Windows to get that, and most callers
+     of 'lstat' don't need that.  But here we do want that information
+     to be accurate.  */
+  w32_stat_get_owner_group = 1;
+#endif
+
+  lstat_result = lstat (SSDATA (encoded), &s);
+
+#ifdef WINDOWSNT
+  w32_stat_get_owner_group = 0;
+#endif
+
+  if (lstat_result < 0)
     return Qnil;
 
   values[0] = (S_ISLNK (s.st_mode) ? Ffile_symlink_p (filename)
     return Qnil;
 
   values[0] = (S_ISLNK (s.st_mode) ? Ffile_symlink_p (filename)
@@ -962,10 +942,10 @@ so last access time will always be midnight of that day.  */)
 
   if (!(NILP (id_format) || EQ (id_format, Qinteger)))
     {
 
   if (!(NILP (id_format) || EQ (id_format, Qinteger)))
     {
-      BLOCK_INPUT;
+      block_input ();
       uname = stat_uname (&s);
       gname = stat_gname (&s);
       uname = stat_uname (&s);
       gname = stat_gname (&s);
-      UNBLOCK_INPUT;
+      unblock_input ();
     }
   if (uname)
     values[2] = DECODE_SYSTEM (build_string (uname));
     }
   if (uname)
     values[2] = DECODE_SYSTEM (build_string (uname));
@@ -976,9 +956,9 @@ so last access time will always be midnight of that day.  */)
   else
     values[3] = make_fixnum_or_float (s.st_gid);
 
   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[4] = make_lisp_time (get_stat_atime (&s));
+  values[5] = make_lisp_time (get_stat_mtime (&s));
+  values[6] = make_lisp_time (get_stat_ctime (&s));
 
   /* If the file size is a 4-byte type, assume that files of sizes in
      the 2-4 GiB range wrap around to negative values, as this is a
 
   /* If the file size is a 4-byte type, assume that files of sizes in
      the 2-4 GiB range wrap around to negative values, as this is a
@@ -990,17 +970,7 @@ so last access time will always be midnight of that day.  */)
 
   filemodestring (&s, modes);
   values[8] = make_string (modes, 10);
 
   filemodestring (&s, modes);
   values[8] = make_string (modes, 10);
-#ifdef BSD4_2 /* file gid will be dir gid */
-  dirname = Ffile_name_directory (filename);
-  if (! NILP (dirname))
-    encoded = ENCODE_FILE (dirname);
-  if (! NILP (dirname) && stat (SDATA (encoded), &sdir) == 0)
-    values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil;
-  else                                 /* if we can't tell, assume worst */
-    values[9] = Qt;
-#else                                  /* file gid will be egid */
-  values[9] = (s.st_gid != getegid ()) ? Qt : Qnil;
-#endif /* not BSD4_2 */
+  values[9] = Qt;
   values[10] = INTEGER_TO_CONS (s.st_ino);
   values[11] = INTEGER_TO_CONS (s.st_dev);
 
   values[10] = INTEGER_TO_CONS (s.st_ino);
   values[11] = INTEGER_TO_CONS (s.st_dev);
 
@@ -1018,11 +988,12 @@ Comparison is in lexicographic order and case is significant.  */)
 
 DEFUN ("system-users", Fsystem_users, Ssystem_users, 0, 0, 0,
        doc: /* Return a list of user names currently registered in the system.
 
 DEFUN ("system-users", Fsystem_users, Ssystem_users, 0, 0, 0,
        doc: /* Return a list of user names currently registered in the system.
-The value may be nil if not supported on this platform.  */)
+If we don't know how to determine that on this platform, just
+return a list with one element, taken from `user-real-login-name'.  */)
      (void)
 {
   Lisp_Object users = Qnil;
      (void)
 {
   Lisp_Object users = Qnil;
-#if defined(HAVE_GETPWENT) && defined(HAVE_ENDPWENT)
+#if defined HAVE_GETPWENT && defined HAVE_ENDPWENT
   struct passwd *pw;
 
   while ((pw = getpwent ()))
   struct passwd *pw;
 
   while ((pw = getpwent ()))
@@ -1042,9 +1013,8 @@ The value may be nil if not supported on this platform.  */)
      (void)
 {
   Lisp_Object groups = Qnil;
      (void)
 {
   Lisp_Object groups = Qnil;
-#if defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT)
+#if defined HAVE_GETGRENT && defined HAVE_ENDGRENT
   struct group *gr;
   struct group *gr;
-  int length;
 
   while ((gr = getgrent ()))
     groups = Fcons (DECODE_SYSTEM (build_string (gr->gr_name)), groups);
 
   while ((gr = getgrent ()))
     groups = Fcons (DECODE_SYSTEM (build_string (gr->gr_name)), groups);