diff src/dired.c @ 195:a2f645c6b9f8 r20-3b24

Import from CVS: tag r20-3b24
author cvs
date Mon, 13 Aug 2007 09:59:05 +0200
parents 3d6bfa290dbd
children 41ff10fd062f
line wrap: on
line diff
--- a/src/dired.c	Mon Aug 13 09:58:32 2007 +0200
+++ b/src/dired.c	Mon Aug 13 09:59:05 2007 +0200
@@ -27,6 +27,7 @@
 #include "commands.h"
 #include "elhash.h"
 #include "regex.h"
+#include "opaque.h"
 
 #include "sysfile.h"
 #include "sysdir.h"
@@ -38,6 +39,15 @@
 Lisp_Object Qfile_name_all_completions;
 Lisp_Object Qfile_attributes;
 
+static Lisp_Object
+close_directory_fd (Lisp_Object unwind_obj)
+{
+  DIR *d = (DIR *)get_opaque_ptr (unwind_obj);
+  closedir (d);
+  free_opaque_ptr (unwind_obj);
+  return Qnil;
+}
+
 DEFUN ("directory-files", Fdirectory_files, 1, 5, 0, /*
 Return a list of names of files in DIRECTORY.
 There are four optional arguments:
@@ -55,19 +65,16 @@
 {
   /* This function can GC.  GC checked 1997.04.06. */
   DIR *d;
-  Bytecount dirname_length;
+  Bytecount name_as_dir_length;
   Lisp_Object list, name, dirfilename = Qnil;
   Lisp_Object handler;
   struct re_pattern_buffer *bufp = NULL;
+  Lisp_Object name_as_dir = Qnil;
+  int speccount = specpdl_depth ();
+  char *statbuf, *statbuf_tail;
 
-  char statbuf [MAXNAMLEN+2];
-  char *statbuf_tail;
-  Lisp_Object tail_cons = Qnil;
-  char slashfilename[MAXNAMLEN+2];
-  char *filename = slashfilename;
-
-  struct gcpro gcpro1, gcpro2, gcpro3;
-  GCPRO3 (dirname, dirfilename, tail_cons);
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+  GCPRO4 (dirname, name_as_dir, dirfilename, list);
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
@@ -87,20 +94,16 @@
      but earlier everywhere else? */
   dirname = Fexpand_file_name (dirname, Qnil);
   dirfilename = Fdirectory_file_name (dirname);
+  name_as_dir = Ffile_name_as_directory (dirname);
 
-  {
-    /* XEmacs: this should come before the opendir() because it might error. */
-    Lisp_Object name_as_dir = Ffile_name_as_directory (dirname);
-    CHECK_STRING (name_as_dir);
-    memcpy (statbuf, ((char *) XSTRING_DATA (name_as_dir)),
-           XSTRING_LENGTH (name_as_dir));
-    statbuf_tail = statbuf + XSTRING_LENGTH (name_as_dir);
-  }
+  name_as_dir_length = XSTRING_LENGTH (name_as_dir);
+  statbuf = alloca (name_as_dir_length + MAXNAMLEN + 1);
+  memcpy (statbuf, XSTRING_DATA (name_as_dir), name_as_dir_length);
+  statbuf_tail = statbuf + name_as_dir_length;
 
   /* XEmacs: this should come after Ffile_name_as_directory() to avoid
-     potential regexp cache smashage.  This should come before the
-     opendir() because it might signal an error.
-   */
+     potential regexp cache smashage.  It comes before the opendir()
+     because it might signal an error.  */
   if (!NILP (match))
     {
       CHECK_STRING (match);
@@ -108,38 +111,22 @@
       /* MATCH might be a flawed regular expression.  Rather than
 	 catching and signalling our own errors, we just call
 	 compile_pattern to do the work for us.  */
-#ifdef VMS
-      bufp =
-	compile_pattern (match, 0,
-			 (char *) MIRROR_DOWNCASE_TABLE_AS_STRING
-			 (XBUFFER (Vbuffer_defaults)), 0, ERROR_ME);
-#else
       bufp = compile_pattern (match, 0, 0, 0, ERROR_ME);
-#endif
     }
 
   /* 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!  */
 
-  /* Do this opendir after anything which might signal an error; if
-     an error is signalled while the directory stream is open, we
-     have to make sure it gets closed, and setting up an
-     unwind_protect to do so would be a pain.  */
+  /* Do this opendir after anything which might signal an error;
+     previosly, there was no unwind-protection in case of error, but
+     now there is.  */
   d = opendir ((char *) XSTRING_DATA (dirfilename));
   if (! d)
     report_file_error ("Opening directory", list1 (dirname));
 
+  record_unwind_protect (close_directory_fd, make_opaque_ptr ((void *)d));
+
   list = Qnil;
-  tail_cons = Qnil;
-  dirname_length = XSTRING_LENGTH (dirname);
-#ifndef VMS
-  if (dirname_length == 0
-      || !IS_ANY_SEP (XSTRING_BYTE (dirname, dirname_length - 1)))
-  {
-    *filename++ = DIRECTORY_SEP;
-    dirname_length++;
-  }
-#endif /* VMS */
 
   /* Loop reading blocks */
   while (1)
@@ -152,30 +139,39 @@
       if (DIRENTRY_NONEMPTY (dp))
 	{
 	  int result;
-	  Lisp_Object oinhibit_quit = Vinhibit_quit;
-	  strncpy (filename, dp->d_name, len);
-	  filename[len] = 0;
-	  /* re_search can now QUIT, so prevent it to avoid
-	     filedesc lossage */
-	  Vinhibit_quit = Qt;
 	  result = (NILP (match)
-	      || (0 <= re_search (bufp, filename, len, 0, len, 0)));
-          Vinhibit_quit = oinhibit_quit;
+	      || (0 <= re_search (bufp, dp->d_name, len, 0, len, 0)));
           if (result)
 	    {
 	      if (!NILP (files_only))
 		{
 		  int dir_p;
 		  struct stat st;
+		  char *cur_statbuf = statbuf;
+		  char *cur_statbuf_tail = statbuf_tail;
 
-		  memcpy (statbuf_tail, filename, len);
-		  statbuf_tail [len] = 0;
+		  /* A trick: we normally use the buffer created by
+                     alloca.  However, if the filename is too big
+                     (meaning MAXNAMLEN lies on the system), we'll use
+                     a malloced buffer, and free it. */
+		  if (len > MAXNAMLEN)
+		    {
+		      cur_statbuf = (char *) xmalloc (name_as_dir_length
+						      + len + 1);
+		      memcpy (cur_statbuf, statbuf, name_as_dir_length);
+		      cur_statbuf_tail = cur_statbuf + name_as_dir_length;
+		    }
+		  memcpy (cur_statbuf_tail, dp->d_name, len);
+		  cur_statbuf_tail [len] = 0;
 
-		  if (stat (statbuf, &st) < 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 (EQ (files_only, Qt) && dir_p)
 		    continue;
 		  else if (!EQ (files_only, Qt) && !dir_p)
@@ -183,28 +179,20 @@
 		}
 
 	      if (!NILP (full))
-		name = concat2 (dirname, build_string (slashfilename));
+		name = concat2 (name_as_dir,
+				make_string ((Bufbyte *)dp->d_name, len));
 	      else
-		name = make_string ((Bufbyte *) filename, len);
+		name = make_string ((Bufbyte *)dp->d_name, len);
 
-	      if (NILP (tail_cons))
-		{
-		  list = list1 (name);
-		  tail_cons = list;
-		}
-	      else
-		{
-		  XCDR (tail_cons) = list1 (name);
-		  tail_cons = XCDR (tail_cons);
-		}
+	      list = Fcons (name, list);
 	    }
 	}
     }
-  closedir (d);
-  UNGCPRO;
+  unbind_to (speccount, Qnil);	/* This will close the dir */
   if (!NILP (nosort))
-    return list;
-  return Fsort (Fnreverse (list), Qstring_lessp);
+    RETURN_UNGCPRO (list);
+  else
+    RETURN_UNGCPRO (Fsort (Fnreverse (list), Qstring_lessp));
 }
 
 static Lisp_Object file_name_completion (Lisp_Object file,