(syms_of_ntproc) <w32-get-true-file-attributes>: Doc fix.
[bpt/emacs.git] / src / dired.c
index a576c9d..7b4c916 100644 (file)
@@ -1,12 +1,12 @@
 /* Lisp functions for making directory listings.
    Copyright (C) 1985, 1986, 1993, 1994, 1999, 2000, 2001, 2002, 2003,
-                 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+                 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -116,10 +116,10 @@ extern void filemodestring P_ ((struct stat *, char *));
 #endif
 
 extern int completion_ignore_case;
+extern Lisp_Object Qcompletion_ignore_case;
 extern Lisp_Object Vcompletion_regexp_list;
 
 Lisp_Object Vcompletion_ignored_extensions;
-Lisp_Object Qcompletion_ignore_case;
 Lisp_Object Qdirectory_files;
 Lisp_Object Qdirectory_files_and_attributes;
 Lisp_Object Qfile_name_completion;
@@ -193,8 +193,10 @@ directory_files_internal (directory, full, match, nosort, attrs, id_format)
   /* Note: ENCODE_FILE and DECODE_FILE can GC because they can run
      run_pre_post_conversion_on_str which calls Lisp directly and
      indirectly.  */
-  dirfilename = ENCODE_FILE (dirfilename);
-  encoded_directory = ENCODE_FILE (directory);
+  if (STRING_MULTIBYTE (dirfilename))
+    dirfilename = ENCODE_FILE (dirfilename);
+  encoded_directory = (STRING_MULTIBYTE (directory)
+                      ? ENCODE_FILE (directory) : directory);
 
   /* 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!  */
@@ -251,7 +253,7 @@ directory_files_internal (directory, full, match, nosort, attrs, id_format)
          name = finalname = make_unibyte_string (dp->d_name, len);
          GCPRO2 (finalname, name);
 
-         /* Note: ENCODE_FILE can GC; it should protect its argument,
+         /* Note: DECODE_FILE can GC; it should protect its argument,
             though.  */
          name = DECODE_FILE (name);
          len = SBYTES (name);
@@ -463,7 +465,6 @@ file_name_completion (file, dirname, all_flag, ver_flag, 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
@@ -506,7 +507,10 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
   /* Do completion on the encoded file name
      because the other names in the directory are (we presume)
      encoded likewise.  We decode the completed string at the end.  */
-  encoded_file = ENCODE_FILE (file);
+  /* Actually, this is not quite true any more: we do most of the completion
+     work with decoded file names, but we still do some filtering based
+     on the encoded file name.  */
+  encoded_file = STRING_MULTIBYTE (file) ? ENCODE_FILE (file) : file;
 
   encoded_dir = ENCODE_FILE (dirname);
 
@@ -586,6 +590,7 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
                     CONSP (tem); tem = XCDR (tem))
                  {
                    int elt_len;
+                   unsigned char *p1;
 
                    elt = XCAR (tem);
                    if (!STRINGP (elt))
@@ -638,6 +643,11 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
          if (!passcount && CONSP (tem))
            continue;
 
+         /* FIXME: If we move this `decode' earlier we can eliminate
+            the repeated ENCODE_FILE on Vcompletion_ignored_extensions.  */
+         name = make_unibyte_string (dp->d_name, len);
+         name = DECODE_FILE (name);
+
          if (!passcount)
            {
              Lisp_Object regexps;
@@ -647,12 +657,8 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
              /* Ignore this element if it fails to match all the regexps.  */
              for (regexps = Vcompletion_regexp_list; CONSP (regexps);
                   regexps = XCDR (regexps))
-               {
-                 tem = Fstring_match (XCAR (regexps),
-                                      make_string (dp->d_name, len), zero);
-                 if (NILP (tem))
-                   break;
-               }
+               if (fast_string_match (XCAR (regexps), name) < 0)
+                 break;
              if (CONSP (regexps))
                continue;
            }
@@ -661,10 +667,8 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
          if (directoryp)
            {
              /* This completion is a directory; make it end with '/' */
-             name = Ffile_name_as_directory (make_string (dp->d_name, len));
+             name = Ffile_name_as_directory (name);
            }
-         else
-           name = make_string (dp->d_name, len);
 
          /* Test the predicate, if any.  */
 
@@ -675,7 +679,7 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
              struct gcpro gcpro1;
 
              GCPRO1 (name);
-             decoded = Fexpand_file_name (DECODE_FILE (name), dirname);
+             decoded = Fexpand_file_name (name, dirname);
              val = call1 (predicate, decoded);
              UNGCPRO;
 
@@ -688,10 +692,7 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
          matchcount++;
 
          if (all_flag)
-           {
-             name = DECODE_FILE (name);
-             bestmatch = Fcons (name, bestmatch);
-           }
+           bestmatch = Fcons (name, bestmatch);
          else if (NILP (bestmatch))
            {
              bestmatch = name;
@@ -699,12 +700,21 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
            }
          else
            {
-             compare = min (bestmatchsize, len);
-             p1 = SDATA (bestmatch);
-             p2 = (unsigned char *) dp->d_name;
-             matchsize = scmp (p1, p2, compare);
-             if (matchsize < 0)
+             Lisp_Object zero = make_number (0);
+             /* FIXME: This is a copy of the code in Ftry_completion.  */
+             compare = min (bestmatchsize, SCHARS (name));
+             tem = Fcompare_strings (bestmatch, zero,
+                                     make_number (compare),
+                                     name, zero,
+                                     make_number (compare),
+                                     completion_ignore_case ? Qt : Qnil);
+             if (EQ (tem, Qt))
                matchsize = compare;
+             else if (XINT (tem) < 0)
+               matchsize = - XINT (tem) - 1;
+             else
+               matchsize = XINT (tem) - 1;
+
              if (completion_ignore_case)
                {
                  /* If this is an exact match except for case,
@@ -713,9 +723,9 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
                     of the actual match.  */
                  /* This tests that the current file is an exact match
                     but BESTMATCH is not (it is too long).  */
-                 if ((matchsize == len
+                 if ((matchsize == SCHARS (name)
                       && matchsize + !!directoryp
-                         < SCHARS (bestmatch))
+                         < SCHARS (bestmatch))
                      ||
                      /* If there is no exact match ignoring case,
                         prefer a match that does not change the case
@@ -725,22 +735,23 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
                         prefer that one.  */
                      /* This == checks that, of current file and BESTMATCH,
                         either both or neither are exact.  */
-                     (((matchsize == len)
+                     (((matchsize == SCHARS (name))
                        ==
-                       (matchsize + !!directoryp
-                        == SCHARS (bestmatch)))
-                      && !bcmp (p2, SDATA (encoded_file), SCHARS (encoded_file))
-                      && bcmp (p1, SDATA (encoded_file), SCHARS (encoded_file))))
+                       (matchsize + !!directoryp == SCHARS (bestmatch)))
+                      && (tem = Fcompare_strings (name, zero,
+                                                  make_number (SCHARS (file)),
+                                                  file, zero,
+                                                  Qnil,
+                                                  Qnil),
+                          EQ (Qt, tem))
+                      && (tem = Fcompare_strings (bestmatch, zero,
+                                                  make_number (SCHARS (file)),
+                                                  file, zero,
+                                                  Qnil,
+                                                  Qnil),
+                          ! EQ (Qt, tem))))
                    bestmatch = name;
                }
-
-             /* If this dirname all matches, see if implicit following
-                slash does too.  */
-             if (directoryp
-                 && compare == matchsize
-                 && bestmatchsize > matchsize
-                 && IS_ANY_SEP (p1[matchsize]))
-               matchsize++;
              bestmatchsize = matchsize;
            }
        }
@@ -752,18 +763,11 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
   bestmatch = unbind_to (count, bestmatch);
 
   if (all_flag || NILP (bestmatch))
-    {
-      if (STRINGP (bestmatch))
-       bestmatch = DECODE_FILE (bestmatch);
-      return bestmatch;
-    }
+    return bestmatch;
   if (matchcount == 1 && bestmatchsize == SCHARS (file))
     return Qt;
   bestmatch = Fsubstring (bestmatch, make_number (0),
                          make_number (bestmatchsize));
-  /* Now that we got the right initial segment of BESTMATCH,
-     decode it from the coding system in use.  */
-  bestmatch = DECODE_FILE (bestmatch);
   return bestmatch;
 }
 
@@ -895,6 +899,36 @@ make_time (time)
                Fcons (make_number (time & 0177777), Qnil));
 }
 
+static char *
+stat_uname (struct stat *st)
+{
+#ifdef WINDOWSNT
+  return st->st_uname;
+#else
+  struct passwd *pw = (struct passwd *) getpwuid (st->st_uid);
+
+  if (pw)
+    return pw->pw_name;
+  else
+    return NULL;
+#endif
+}
+
+static char *
+stat_gname (struct stat *st)
+{
+#ifdef WINDOWSNT
+  return st->st_gname;
+#else
+  struct group *gr = (struct group *) getgrgid (st->st_gid);
+
+  if (gr)
+    return gr->gr_name;
+  else
+    return NULL;
+#endif
+}
+
 DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 2, 0,
        doc: /* Return a list of attributes of file FILENAME.
 Value is nil if specified file cannot be opened.
@@ -917,10 +951,12 @@ 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.
- 9. t iff file's gid would change if file were deleted and recreated.
+ 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,
-  this is a cons cell containing two integers: first the high part,
-  then the low 16 bits.
+  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.  */)
      (filename, id_format)
@@ -929,8 +965,6 @@ Elements of the attribute list are:
   Lisp_Object values[12];
   Lisp_Object encoded;
   struct stat s;
-  struct passwd *pw;
-  struct group *gr;
 #if defined (BSD4_2) || defined (BSD4_3)
   Lisp_Object dirname;
   struct stat sdir;
@@ -938,7 +972,8 @@ Elements of the attribute list are:
   char modes[10];
   Lisp_Object handler;
   struct gcpro gcpro1;
-  EMACS_INT uid, gid, ino;
+  EMACS_INT ino;
+  char *uname, *gname;
 
   filename = Fexpand_file_name (filename, Qnil);
 
@@ -973,26 +1008,20 @@ Elements of the attribute list are:
 #endif
     }
   values[1] = make_number (s.st_nlink);
-  /* When make_fixnum_or_float is called below with types that are
-     shorter than an int (e.g., `short'), GCC whines about comparison
-     being always false due to limited range of data type.  Fix by
-     copying s.st_uid and s.st_gid into int variables.  */
-  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);
+      values[2] = make_fixnum_or_float (s.st_uid);
+      values[3] = make_fixnum_or_float (s.st_gid);
     }
   else
     {
       BLOCK_INPUT;
-      pw = (struct passwd *) getpwuid (uid);
-      values[2] = (pw ? build_string (pw->pw_name)
-                  : make_fixnum_or_float (uid));
-      gr = (struct group *) getgrgid (gid);
-      values[3] = (gr ? build_string (gr->gr_name)
-                  : make_fixnum_or_float (gid));
+      uname = stat_uname (&s);
+      values[2] = (uname ? build_string (uname)
+                  : make_fixnum_or_float (s.st_uid));
+      gname = stat_gname (&s);
+      values[3] = (gname ? build_string (gname)
+                  : make_fixnum_or_float (s.st_gid));
       UNBLOCK_INPUT;
     }
   values[4] = make_time (s.st_atime);
@@ -1014,25 +1043,45 @@ Elements of the attribute list are:
   if (! NILP (dirname))
     encoded = ENCODE_FILE (dirname);
   if (! NILP (dirname) && stat (SDATA (encoded), &sdir) == 0)
-    values[9] = (sdir.st_gid != gid) ? Qt : Qnil;
+    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] = (gid != getegid ()) ? Qt : Qnil;
+  values[9] = (s.st_gid != getegid ()) ? Qt : Qnil;
 #endif /* BSD4_2 (or BSD4_3) */
   /* Shut up GCC warnings in FIXNUM_OVERFLOW_P below.  */
-  ino = s.st_ino;
-  if (FIXNUM_OVERFLOW_P (ino))
+  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))
+    /* 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)
     /* To allow inode numbers larger than VALBITS, separate the bottom
        16 bits.  */
-    values[10] = Fcons (make_number (ino >> 16),
-                       make_number (ino & 0xffff));
+    values[10] = Fcons (make_number ((EMACS_INT)(s.st_ino >> 16)),
+                       make_number ((EMACS_INT)(s.st_ino & 0xffff)));
   else
-    /* But keep the most common cases as integers.  */
-    values[10] = make_number (ino);
+    {
+      /* To allow inode numbers beyond 32 bits, separate into 2 24-bit
+        high parts and a 16-bit bottom part.  */
+      EMACS_INT high_ino = s.st_ino >> 32;
+      EMACS_INT low_ino  = s.st_ino & 0xffffffff;
+
+      values[10] = Fcons (make_number (high_ino >> 8),
+                         Fcons (make_number (((high_ino & 0xff) << 16)
+                                             + (low_ino >> 16)),
+                                make_number (low_ino & 0xffff)));
+    }
 
-  /* Likewise for device.  */
-  if (FIXNUM_OVERFLOW_P (s.st_dev))
+  /* 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)
     values[11] = Fcons (make_number (s.st_dev >> 16),
                        make_number (s.st_dev & 0xffff));
   else
@@ -1078,11 +1127,6 @@ syms_of_dired ()
   defsubr (&Sfile_attributes);
   defsubr (&Sfile_attributes_lessp);
 
-#ifdef VMS
-  Qcompletion_ignore_case = intern ("completion-ignore-case");
-  staticpro (&Qcompletion_ignore_case);
-#endif /* VMS */
-
   DEFVAR_LISP ("completion-ignored-extensions", &Vcompletion_ignored_extensions,
               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