diff src/dired.c @ 398:74fd4e045ea6 r21-2-29

Import from CVS: tag r21-2-29
author cvs
date Mon, 13 Aug 2007 11:13:30 +0200
parents 6719134a07c2
children 2f8bb876ab1d
line wrap: on
line diff
--- a/src/dired.c	Mon Aug 13 11:12:06 2007 +0200
+++ b/src/dired.c	Mon Aug 13 11:13:30 2007 +0200
@@ -31,6 +31,7 @@
 #include "sysfile.h"
 #include "sysdir.h"
 #include "systime.h"
+#include "sysdep.h"
 #include "syspwd.h"
 
 Lisp_Object Vcompletion_ignored_extensions;
@@ -139,38 +140,15 @@
 	{
 	  if (!NILP (files_only))
 	    {
-	      int dir_p;
 	      struct stat st;
-	      char *cur_statbuf = statbuf;
-	      char *cur_statbuf_tail = statbuf_tail;
-
-	      /* #### I don't think the code under `if' is necessary
-		 anymore.  The crashes in this function were reported
-		 because MAXNAMLEN was used to remember the *whole*
-		 statbuf, instead of using MAXPATHLEN.  This should be
-		 tested after 21.0 is released.  */
+	      int dir_p = 0;
 
-	      /* We normally use the buffer created by alloca.
-		 However, if the file name we get too big, we'll use a
-		 malloced buffer, and free it.  It is undefined how
-		 stat() will react to this, but we avoid a buffer
-		 overrun.  */
-	      if (len > MAXNAMLEN)
-		{
-		  cur_statbuf = (char *)xmalloc (directorylen + len + 1);
-		  memcpy (cur_statbuf, statbuf, directorylen);
-		  cur_statbuf_tail = cur_statbuf + directorylen;
-		}
-	      memcpy (cur_statbuf_tail, dp->d_name, len);
-	      cur_statbuf_tail[len] = 0;
+	      memcpy (statbuf_tail, dp->d_name, len);
+	      statbuf_tail[len] = 0;
 
-	      if (stat (cur_statbuf, &st) < 0)
-		dir_p = 0;
-	      else
-		dir_p = ((st.st_mode & S_IFMT) == S_IFDIR);
-
-	      if (cur_statbuf != statbuf)
-		xfree (cur_statbuf);
+	      if (stat (statbuf, &st) == 0
+		  && (st.st_mode & S_IFMT) == S_IFDIR)
+		dir_p = 1;
 
 	      if (EQ (files_only, Qt) && dir_p)
 		continue;
@@ -564,9 +542,7 @@
        (user))
 {
   int uniq;
-  Lisp_Object completed;
-
-  completed = user_name_completion (user, 0, &uniq);
+  Lisp_Object completed = user_name_completion (user, 0, &uniq);
   return Fcons (completed, uniq ? Qt : Qnil);
 }
 
@@ -579,54 +555,57 @@
   return user_name_completion (user, 1, NULL);
 }
 
-static Lisp_Object
-user_name_completion_unwind (Lisp_Object locative)
+struct user_name
 {
-  Lisp_Object obj1 = XCAR (locative);
-  Lisp_Object obj2 = XCDR (locative);
-  char **cache;
-  int clen, i;
+  Bufbyte *ptr;
+  size_t len;
+};
 
+struct user_cache
+{
+  struct user_name *user_names;
+  int length;
+  int size;
+  EMACS_TIME last_rebuild_time;
+};
+static struct user_cache user_cache;
 
-  if (!NILP (obj1) && !NILP (obj2))
-    {
-      /* clean up if interrupted building cache */
-      cache = *(char ***)get_opaque_ptr (obj1);
-      clen  = *(int *)get_opaque_ptr (obj2);
-      free_opaque_ptr (obj1);
-      free_opaque_ptr (obj2);
-      for (i = 0; i < clen; i++)
-        free (cache[i]);
-      free (cache);
-    }
+static void
+free_user_cache (struct user_cache *cache)
+{
+  int i;
+  for (i = 0; i < cache->length; i++)
+    xfree (cache->user_names[i].ptr);
+  xfree (cache->user_names);
+  xzero (*cache);
+}
 
-  free_cons (XCONS (locative));
+static Lisp_Object
+user_name_completion_unwind (Lisp_Object cache_incomplete_p)
+{
   endpwent ();
+  speed_up_interrupts ();
+
+  if (! NILP (XCAR (cache_incomplete_p)))
+    free_user_cache (&user_cache);
+
+  free_cons (XCONS (cache_incomplete_p));
 
   return Qnil;
 }
 
-static char **user_cache;
-static int user_cache_len;
-static int user_cache_max;
-static long user_cache_time;
-
-#define  USER_CACHE_REBUILD  (24*60*60)  /* 1 day, in seconds */
+#define  USER_CACHE_TTL  (24*60*60)  /* Time to live: 1 day, in seconds */
 
 static Lisp_Object
 user_name_completion (Lisp_Object user, int all_flag, int *uniq)
 {
   /* This function can GC */
-  struct passwd *pw;
   int matchcount = 0;
   Lisp_Object bestmatch = Qnil;
   Charcount bestmatchsize = 0;
-  int speccount = specpdl_depth ();
-  int i, cmax, clen;
-  char **cache;
   Charcount user_name_length;
-  Lisp_Object locative;
   EMACS_TIME t;
+  int i;
   struct gcpro gcpro1, gcpro2;
 
   GCPRO2 (user, bestmatch);
@@ -638,67 +617,49 @@
   /* Cache user name lookups because it tends to be quite slow.
    * Rebuild the cache occasionally to catch changes */
   EMACS_GET_TIME (t);
-  if (user_cache  &&
-      EMACS_SECS (t) - user_cache_time > USER_CACHE_REBUILD)
+  if (user_cache.user_names &&
+      (EMACS_SECS (t) - EMACS_SECS (user_cache.last_rebuild_time)
+       > USER_CACHE_TTL))
+    free_user_cache (&user_cache);
+
+  if (!user_cache.user_names)
     {
-      for (i = 0; i < user_cache_len; i++)
-        free (user_cache[i]);
-      free (user_cache);
-      user_cache = NULL;
-      user_cache_len = 0;
-      user_cache_max = 0;
+      struct passwd *pwd;
+      Lisp_Object cache_incomplete_p = noseeum_cons (Qt, Qnil);
+      int speccount = specpdl_depth ();
+
+      slow_down_interrupts ();
+      setpwent ();
+      record_unwind_protect (user_name_completion_unwind, cache_incomplete_p);
+      while ((pwd = getpwent ()))
+        {
+          QUIT;
+	  DO_REALLOC (user_cache.user_names, user_cache.size,
+		      user_cache.length + 1, struct user_name);
+	  TO_INTERNAL_FORMAT (C_STRING, pwd->pw_name,
+			      MALLOC,
+			      (user_cache.user_names[user_cache.length].ptr,
+			       user_cache.user_names[user_cache.length].len),
+			      Qnative);
+	  user_cache.length++;
+        }
+      XCAR (cache_incomplete_p) = Qnil;
+      unbind_to (speccount, Qnil);
+
+      EMACS_GET_TIME (user_cache.last_rebuild_time);
     }
 
-  if (user_cache == NULL || user_cache_max <= 0)
+  for (i = 0; i < user_cache.length; i++)
     {
-      cmax  = 200;
-      clen  = 0;
-      cache = (char **) malloc (cmax*sizeof (char *));
-
-      setpwent ();
-      locative = noseeum_cons (Qnil, Qnil);
-      XCAR (locative) = make_opaque_ptr ((void *) &cache);
-      XCDR (locative) = make_opaque_ptr ((void *) &clen);
-      record_unwind_protect (user_name_completion_unwind, locative);
-      /* #### may need to slow down interrupts around call to getpwent
-       * below.  at least the call to getpwnam in Fuser_full_name
-       * is documented as needing it on irix. */
-      while ((pw = getpwent ()))
-        {
-          if (clen >= cmax)
-            {
-              cmax *= 2;
-              cache = (char **) realloc (cache, cmax*sizeof (char *));
-            }
-
-          QUIT;
-
-          cache[clen++] = strdup (pw->pw_name);
-        }
-      free_opaque_ptr (XCAR (locative));
-      free_opaque_ptr (XCDR (locative));
-      XCAR (locative) = Qnil;
-      XCDR (locative) = Qnil;
-
-      unbind_to (speccount, Qnil); /* free locative cons, endpwent() */
-
-      user_cache_max = cmax;
-      user_cache_len = clen;
-      user_cache = cache;
-      user_cache_time = EMACS_SECS (t);
-    }
-
-  for (i = 0; i < user_cache_len; i++)
-    {
-      Bufbyte *d_name = (Bufbyte *) user_cache[i];
-      Bytecount len = strlen ((char *) d_name);
+      Bufbyte *u_name = user_cache.user_names[i].ptr;
+      Bytecount len   = user_cache.user_names[i].len;
       /* scmp() works in chars, not bytes, so we have to compute this: */
-      Charcount cclen = bytecount_to_charcount (d_name, len);
+      Charcount cclen = bytecount_to_charcount (u_name, len);
 
       QUIT;
 
-      if (cclen < user_name_length   ||
-          0 <= scmp (d_name, XSTRING_DATA (user), user_name_length))
+      if (cclen < user_name_length
+	  || 0 <= scmp_1 (u_name, XSTRING_DATA (user), user_name_length, 0))
         continue;
 
       matchcount++;    /* count matching completions */
@@ -709,7 +670,7 @@
           struct gcpro ngcpro1;
           NGCPRO1 (name);
           /* This is a possible completion */
-          name = make_string (d_name, len);
+          name = make_string (u_name, len);
           if (all_flag)
             {
               bestmatch = Fcons (name, bestmatch);
@@ -725,37 +686,11 @@
         {
           Charcount compare = min (bestmatchsize, cclen);
           Bufbyte *p1 = XSTRING_DATA (bestmatch);
-          Bufbyte *p2 = d_name;
-          Charcount matchsize = scmp (p1, p2, compare);
+          Bufbyte *p2 = u_name;
+          Charcount matchsize = scmp_1 (p1, p2, compare, 0);
 
           if (matchsize < 0)
             matchsize = compare;
-          if (completion_ignore_case)
-            {
-              /* If this is an exact match except for case,
-                 use it as the best match rather than one that is not
-                 an exact match.  This way, we get the case pattern
-                 of the actual match.  */
-              if ((matchsize == cclen
-                   && matchsize < XSTRING_CHAR_LENGTH (bestmatch))
-                  ||
-                  /* If there is no exact match ignoring case,
-                     prefer a match that does not change the case
-                     of the input.  */
-                  (((matchsize == cclen)
-                    ==
-                    (matchsize == XSTRING_CHAR_LENGTH (bestmatch)))
-                   /* If there is more than one exact match aside from
-                      case, and one of them is exact including case,
-                      prefer that one.  */
-                   && 0 > scmp_1 (p2, XSTRING_DATA (user),
-                                  user_name_length, 0)
-                   && 0 <= scmp_1 (p1, XSTRING_DATA (user),
-                                   user_name_length, 0)))
-                {
-                  bestmatch = make_string (d_name, len);
-                }
-            }
 
           bestmatchsize = matchsize;
         }
@@ -776,14 +711,14 @@
 
 
 Lisp_Object
-make_directory_hash_table (CONST char *path)
+make_directory_hash_table (const char *path)
 {
   DIR *d;
-  Lisp_Object hash =
-    make_lisp_hash_table (100, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL);
   if ((d = opendir (path)))
     {
       DIRENTRY *dp;
+      Lisp_Object hash =
+	make_lisp_hash_table (20, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL);
 
       while ((dp = readdir (d)))
 	{
@@ -793,8 +728,10 @@
 	    Fputhash (make_string ((Bufbyte *) dp->d_name, len), Qt, hash);
 	}
       closedir (d);
+      return hash;
     }
-  return hash;
+  else
+    return Qnil;
 }
 
 Lisp_Object
@@ -955,10 +892,4 @@
 `file-name-all-completions'.
 */ );
   Vcompletion_ignored_extensions = Qnil;
-
-#ifndef  WINDOWSNT
-  user_cache = NULL;
-  user_cache_len = 0;
-  user_cache_max = 0;
-#endif
 }