]> code.delx.au - gnu-emacs/blobdiff - src/dired.c
(directory_files_internal): Add missing GCPRO's.
[gnu-emacs] / src / dired.c
index bedda2a7f13233847034e886247d928e6d23acc6..c6466bb967ab19fe6914902b01e662d784978372 100644 (file)
@@ -118,6 +118,16 @@ Lisp_Object Qfile_name_all_completions;
 Lisp_Object Qfile_attributes;
 Lisp_Object Qfile_attributes_lessp;
 \f
+
+Lisp_Object
+directory_files_internal_unwind (dh)
+     Lisp_Object dh;
+{
+  DIR *d = (DIR *) ((XINT (XCAR (dh)) << 16) + XINT (XCDR (dh)));
+  closedir (d);
+  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.  */
@@ -127,22 +137,20 @@ directory_files_internal (directory, full, match, nosort, attrs)
      int attrs;
 {
   DIR *d;
-  int dirnamelen;
-  Lisp_Object list, name, dirfilename;
-  Lisp_Object encoded_directory;
+  int directory_nbytes;
+  Lisp_Object list, dirfilename, encoded_directory;
   Lisp_Object handler;
-  struct re_pattern_buffer *bufp;
+  struct re_pattern_buffer *bufp = NULL;
   int needsep = 0;
-  struct gcpro gcpro1, gcpro2;
+  int count = specpdl_ptr - specpdl;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
 
   /* Because of file name handlers, these functions might call
      Ffuncall, and cause a GC.  */
-  GCPRO1 (match);
+  list = encoded_directory = dirfilename = Qnil;
+  GCPRO5 (match, directory, list, dirfilename, encoded_directory);
   directory = Fexpand_file_name (directory, Qnil);
-  UNGCPRO;
-  GCPRO2 (match, directory);
   dirfilename = Fdirectory_file_name (directory);
-  UNGCPRO;
 
   if (!NILP (match))
     {
@@ -161,8 +169,10 @@ directory_files_internal (directory, full, match, nosort, attrs)
 #endif
     }
 
+  /* Note: ENOCDE_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);
 
   /* Now *bufp is the compiled form of MATCH; don't call anything
@@ -173,62 +183,91 @@ directory_files_internal (directory, full, match, nosort, attrs)
      have to make sure it gets closed, and setting up an
      unwind_protect to do so would be a pain.  */
   d = opendir (XSTRING (dirfilename)->data);
-  if (! d)
+  if (d == NULL)
     report_file_error ("Opening directory", Fcons (directory, Qnil));
 
-  list = Qnil;
-  dirnamelen = STRING_BYTES (XSTRING (directory));
+  /* Unfortunately, we can now invoke expand-file-name and
+     file-attributes on filenames, both of which can throw, so we must
+     do a proper unwind-protect.  */
+  record_unwind_protect (directory_files_internal_unwind,
+                        Fcons (make_number (((unsigned long) d) >> 16),
+                               make_number (((unsigned long) d) & 0xffff)));
+
+  directory_nbytes = STRING_BYTES (XSTRING (directory));
   re_match_object = Qt;
 
   /* Decide whether we need to add a directory separator.  */
 #ifndef VMS
-  if (dirnamelen == 0
-      || !IS_ANY_SEP (XSTRING (directory)->data[dirnamelen - 1]))
+  if (directory_nbytes == 0
+      || !IS_ANY_SEP (XSTRING (directory)->data[directory_nbytes - 1]))
     needsep = 1;
 #endif /* not VMS */
 
-  GCPRO2 (encoded_directory, list);
-
   /* Loop reading blocks */
   while (1)
     {
       DIRENTRY *dp = readdir (d);
 
-      if (!dp) break;
+      if (dp == NULL)
+       break;
+      
       if (DIRENTRY_NONEMPTY (dp))
        {
          int len;
+         int wanted = 0;
+         Lisp_Object name, finalname;
+         struct gcpro gcpro1, gcpro2;
 
          len = NAMLEN (dp);
-         name = DECODE_FILE (make_string (dp->d_name, len));
+         name = finalname = make_string (dp->d_name, len);
+         GCPRO2 (finalname, name);
+         
+         /* Note: ENCODE_FILE can GC; it should protect its argument,
+            though.  */
+         name = DECODE_FILE (name);
          len = STRING_BYTES (XSTRING (name));
 
+         /* 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, XSTRING (name)->data, len, 0, len, 0)))
-           {
-             Lisp_Object finalname;
+           wanted = 1;
 
-             finalname = name;
+         immediate_quit = 0;
+
+         if (wanted)
+           {
              if (!NILP (full))
                {
-                 int afterdirindex = dirnamelen;
-                 int total = len + dirnamelen;
-                 int nchars;
                  Lisp_Object fullname;
+                 int nbytes = len + directory_nbytes + needsep;
+                 int nchars;
 
-                 fullname = make_uninit_multibyte_string (total + needsep,
-                                                          total + needsep);
+                 fullname = make_uninit_multibyte_string (nbytes, nbytes);
                  bcopy (XSTRING (directory)->data, XSTRING (fullname)->data,
-                        dirnamelen);
+                        directory_nbytes);
+                 
                  if (needsep)
-                   XSTRING (fullname)->data[afterdirindex++] = DIRECTORY_SEP;
+                   XSTRING (fullname)->data[directory_nbytes + 1]
+                     = DIRECTORY_SEP;
+                 
                  bcopy (XSTRING (name)->data,
-                        XSTRING (fullname)->data + afterdirindex, len);
-                 nchars = chars_in_text (XSTRING (fullname)->data,
-                                         afterdirindex + len);
+                        XSTRING (fullname)->data + directory_nbytes + needsep,
+                        len);
+                 
+                 nchars = chars_in_text (XSTRING (fullname)->data, nbytes);
+
+                 /* Some bug somewhere.  */
+                 if (nchars > nbytes)
+                   abort ();
+                     
                  XSTRING (fullname)->size = nchars;
-                 if (nchars == STRING_BYTES (XSTRING (fullname)))
+                 if (nchars == nbytes)
                    SET_STRING_BYTES (XSTRING (fullname), -1);
+                 
                  finalname = fullname;
                }
 
@@ -236,29 +275,37 @@ directory_files_internal (directory, full, match, nosort, attrs)
                {
                  /* Construct an expanded filename for the directory entry.
                     Use the decoded names for input to Ffile_attributes.  */
-                 Lisp_Object decoded_fullname;
-                 Lisp_Object fileattrs;
+                 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);
 
                  list = Fcons (Fcons (finalname, fileattrs), list);
+                 UNGCPRO;
                }
              else
-               {
-                 list = Fcons (finalname, list);
-               }
+               list = Fcons (finalname, list);
            }
+
+         UNGCPRO;
        }
     }
+
   closedir (d);
-  UNGCPRO;
-  if (!NILP (nosort))
-    return list;
-  if (attrs)
-    return Fsort (Fnreverse (list), Qfile_attributes_lessp);
-  else
-    return Fsort (Fnreverse (list), Qstring_lessp);
+
+  /* Discard the unwind protect.  */
+  specpdl_ptr = specpdl + count;
+
+  if (NILP (nosort))
+    list = Fsort (Fnreverse (list),
+                 attrs ? Qfile_attributes_lessp : Qstring_lessp);
+  
+  RETURN_UNGCPRO (list);
 }
 
 
@@ -389,7 +436,7 @@ file_name_completion (file, dirname, all_flag, ver_flag)
 {
   DIR *d;
   DIRENTRY *dp;
-  int bestmatchsize, skip;
+  int bestmatchsize = 0, skip;
   register int compare, matchsize;
   unsigned char *p1, *p2;
   int matchcount = 0;
@@ -402,6 +449,8 @@ file_name_completion (file, dirname, all_flag, ver_flag)
   int count = specpdl_ptr - specpdl;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
 
+  elt = Qnil;
+
 #ifdef VMS
   extern DIRENTRY * readdirver ();