(set_auto_coding_unwind): New function.
[bpt/emacs.git] / src / fileio.c
index 66ac958..742c7ad 100644 (file)
@@ -3246,6 +3246,26 @@ Lisp_Object Qfind_buffer_file_type;
 #define READ_BUF_SIZE (64 << 10)
 #endif
 
+/* This function is called when a function bound to
+   Vset_auto_coding_function causes some error.  At that time, a text
+   of a file has already been inserted in the current buffer, but,
+   markers has not yet been adjusted.  Thus we must adjust markers
+   here.  We are sure that the buffer was empty before the text of the
+   file was inserted.  */
+
+static Lisp_Object
+set_auto_coding_unwind (multibyte)
+     Lisp_Object multibyte;
+{
+  int inserted = Z_BYTE - BEG_BYTE;
+
+  if (!NILP (multibyte))
+    inserted = multibyte_chars_in_text (GPT_ADDR - inserted, inserted);
+  adjust_after_insert (PT, PT_BYTE, Z, Z_BYTE, inserted);
+
+  return Qnil;
+}
+
 DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
   1, 5, 0,
   "Insert contents of file FILENAME after point.\n\
@@ -3290,6 +3310,7 @@ actually used.")
   unsigned char buffer[1 << 14];
   int replace_handled = 0;
   int set_coding_system = 0;
+  int coding_system_decided = 0;
 
   if (current_buffer->base_buffer && ! NILP (visit))
     error ("Cannot do file visiting in an indirect buffer");
@@ -3392,161 +3413,107 @@ actually used.")
        }
     }
 
-  /* Decide the coding-system of the file.  */
-  {
-    Lisp_Object val;
-    val = Qnil;
-
-    if (!NILP (Vcoding_system_for_read))
-      val = Vcoding_system_for_read;
-    else if (! NILP (replace))
-      /* In REPLACE mode, we can use the same coding system
-        that was used to visit the file.  */
-      val = current_buffer->buffer_file_coding_system;
-    else if (! not_regular)
-      {
-       /* Don't try looking inside a file for a coding system specification
-          if it is not seekable.  */
-       if (! NILP (Vset_auto_coding_function))
-         {
-           /* Find a coding system specified in the heading two lines
-              or in the tailing several lines of the file.  We assume
-              that the 1K-byte and 3K-byte for heading and tailing
-              respectively are sufficient fot this purpose.  */
-           int nread;
-           int beginning_of_end, end_of_beginning;
-
-           if (st.st_size <= (1024 * 4))
-             {
-               nread = read (fd, read_buf, 1024 * 4);
-               end_of_beginning = nread;
-               beginning_of_end = 0;
-             }
-           else
-             {
-               nread = read (fd, read_buf, 1024);
-               end_of_beginning = nread;
-               beginning_of_end = nread;
-               if (nread >= 0)
-                 {
-                   if (lseek (fd, st.st_size - (1024 * 3), 0) < 0)
-                     report_file_error ("Setting file position",
-                                        Fcons (orig_filename, Qnil));
-                   nread += read (fd, read_buf + nread, 1024 * 3);
-                 }
-             }
+  if (BEG < Z)
+    {
+      /* Decide the coding system to use for reading the file now
+         because we can't use an optimized method for handling
+         `coding:' tag if the current buffer is not empty.  */
+      Lisp_Object val;
+      val = Qnil;
 
-           if (nread < 0)
-             error ("IO error reading %s: %s",
-                    XSTRING (orig_filename)->data, strerror (errno));
-           else if (nread > 0)
-             {
-               int i;
-               int possible_spec = 0;
-               unsigned char *p, *p1;
-               Lisp_Object tem;
-               unsigned char *copy = (unsigned char *) alloca (nread + 1);
-
-               /* Make a copy of the contents of read_buf in COPY, 
-                  and convert it to lower case so we can compare
-                  more efficiently.  */
-               bcopy (read_buf, copy, nread);
-               for (i = 0; i < nread; i++)
-                 copy[i] = DOWNCASE (copy[i]);
-               /* Ensure various comparisons fail at end of data.  */
-               copy[nread] = 0;
-
-               /* Now test quickly whether the file contains a -*- line.  */
-               p = copy;
-               while (*p != '\n' && p - copy < end_of_beginning)
-                 p++;
-               if (copy[0] == '#' && copy[1] == '!')
-                 while (*p != '\n' && p - copy < end_of_beginning)
-                   p++;
-               p1 = copy;
-               while (p - p1 >= 3)
-                 {
-                   if (p1[0] == '-' && p1[1] == '*' && p1[2] == '-')
-                     {
-                       while (p - p1 >= 7)
-                         {
-                           if (! bcmp ("coding:", p1, 7))
-                             {
-                               possible_spec = 1;
-                               goto win;
-                             }
-                           p1++;
-                         }
-                       break;
-                     }
-                   p1++;
-                 }
+      if (!NILP (Vcoding_system_for_read))
+       val = Vcoding_system_for_read;
+      else if (! NILP (replace))
+       /* In REPLACE mode, we can use the same coding system
+          that was used to visit the file.  */
+       val = current_buffer->buffer_file_coding_system;
+      else
+       {
+         /* Don't try looking inside a file for a coding system
+            specification if it is not seekable.  */
+         if (! not_regular && ! NILP (Vset_auto_coding_function))
+           {
+             /* Find a coding system specified in the heading two
+                lines or in the tailing several lines of the file.
+                We assume that the 1K-byte and 3K-byte for heading
+                and tailing respectively are sufficient fot this
+                purpose.  */
+             int how_many, nread;
+
+             if (st.st_size <= (1024 * 4))
+               nread = read (fd, read_buf, 1024 * 4);
+             else
+               {
+                 nread = read (fd, read_buf, 1024);
+                 if (nread >= 0)
+                   {
+                     if (lseek (fd, st.st_size - (1024 * 3), 0) < 0)
+                       report_file_error ("Setting file position",
+                                          Fcons (orig_filename, Qnil));
+                     nread += read (fd, read_buf + nread, 1024 * 3);
+                   }
+               }
 
-               /* Test quickly whether the file
-                  contains a local variables list.  */
-               p = &copy[nread - 1];
-               p1 = &copy[beginning_of_end];
-               while (p > p1)
-                 {
-                   if (p[0] == '\n' && p[1] == '\f')
-                     break;
-                   p--;
-                 }
-               p1 = &copy[nread];
-               while (p1 - p >= 16)
-                 {
-                   if (! bcmp ("local variables:", p, 16))
-                     {
-                       possible_spec = 1;
-                       break;
-                     }
-                   p++;
-                 }
-             win:
+             if (nread < 0)
+               error ("IO error reading %s: %s",
+                      XSTRING (orig_filename)->data, strerror (errno));
+             else if (nread > 0)
+               {
+                 int count = specpdl_ptr - specpdl;
+                 struct buffer *prev = current_buffer;
+
+                 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+                 temp_output_buffer_setup (" *code-converting-work*");
+                 set_buffer_internal (XBUFFER (Vstandard_output));
+                 current_buffer->enable_multibyte_characters = Qnil;
+                 insert_1_both (read_buf, nread, nread, 0, 0, 0);
+                 TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
+                 val = call1 (Vset_auto_coding_function, make_number (nread));
+                 set_buffer_internal (prev);
+                 /* Discard the unwind protect for recovering the
+                     current buffer.  */
+                 specpdl_ptr--;
+
+                 /* Rewind the file for the actual read done later.  */
+                 if (lseek (fd, 0, 0) < 0)
+                   report_file_error ("Setting file position",
+                                      Fcons (orig_filename, Qnil));
+               }
+           }
 
-               if (possible_spec)
-                 {
-                   /* Always make this a unibyte string
-                      because we have not yet decoded it.  */ 
-                   tem = make_unibyte_string (read_buf, nread);
-                   val = call1 (Vset_auto_coding_function, tem);
-                 }
+         if (NILP (val))
+           {
+             /* If we have not yet decided a coding system, check
+                 file-coding-system-alist.  */
+             Lisp_Object args[6], coding_systems;
+
+             args[0] = Qinsert_file_contents, args[1] = orig_filename;
+             args[2] = visit, args[3] = beg, args[4] = end, args[5] = replace;
+             coding_systems = Ffind_operation_coding_system (6, args);
+             if (CONSP (coding_systems))
+               val = XCONS (coding_systems)->car;
+           }
+       }
 
-               /* Rewind the file for the actual read done later.  */
-               if (lseek (fd, 0, 0) < 0)
-                 report_file_error ("Setting file position",
-                                    Fcons (orig_filename, Qnil));
-             }
-         }
-       if (NILP (val))
-         {
-           Lisp_Object args[6], coding_systems;
+      setup_coding_system (Fcheck_coding_system (val), &coding);
 
-           args[0] = Qinsert_file_contents, args[1] = orig_filename;
-           args[2] = visit, args[3] = beg, args[4] = end, args[5] = replace;
-           coding_systems = Ffind_operation_coding_system (6, args);
-           if (CONSP (coding_systems))
-             val = XCONS (coding_systems)->car;
-         }
-      }
+      if (NILP (Vcoding_system_for_read)
+         && NILP (current_buffer->enable_multibyte_characters))
+       {
+         /* We must suppress all text conversion except for end-of-line
+            conversion.  */
+         int eol_type;
 
-    if (NILP (Vcoding_system_for_read)
-       && NILP (current_buffer->enable_multibyte_characters))
-      {
-       /* We must suppress all text conversion except for end-of-line
-          conversion.  */
-       struct coding_system coding_temp;
+         eol_type = coding.eol_type;
+         setup_coding_system (Qraw_text, &coding);
+         coding.eol_type = eol_type;
+       }
 
-       setup_coding_system (Fcheck_coding_system (val), &coding_temp);
-       setup_coding_system (Qraw_text, &coding);
-       coding.eol_type = coding_temp.eol_type;
-      }
-    else
-      setup_coding_system (Fcheck_coding_system (val), &coding);
+      coding_system_decided = 1;
+    }
 
-    /* Ensure we always set Vlast_coding_system_used.  */
-    set_coding_system = 1;
-  }
+  /* Ensure we always set Vlast_coding_system_used.  */
+  set_coding_system = 1;
 
   /* If requested, replace the accessible part of the buffer
      with the file contents.  Avoid replacing text at the
@@ -3563,6 +3530,7 @@ actually used.")
      But if we discover the need for conversion, we give up on this method
      and let the following if-statement handle the replace job.  */
   if (!NILP (replace)
+      && BEGV < ZV
       && ! CODING_REQUIRE_DECODING (&coding)
       && (coding.eol_type == CODING_EOL_UNDECIDED
          || coding.eol_type == CODING_EOL_LF))
@@ -3741,7 +3709,7 @@ actually used.")
      is needed, in a simple way that needs a lot of memory.
      The preceding if-statement handles the case of no conversion
      in a more optimized way.  */
-  if (!NILP (replace) && ! replace_handled)
+  if (!NILP (replace) && ! replace_handled && BEGV < ZV)
     {
       int same_at_start = BEGV_BYTE;
       int same_at_end = ZV_BYTE;
@@ -3993,6 +3961,69 @@ actually used.")
 
   if (inserted > 0)
     {
+      if (! coding_system_decided)
+       {
+         /* The coding system is not yet decided.  Decide it by an
+            optimized method for handling `coding:' tag.  */
+         Lisp_Object val;
+         val = Qnil;
+
+         if (!NILP (Vcoding_system_for_read))
+           val = Vcoding_system_for_read;
+         else
+           {
+             if (! NILP (Vset_auto_coding_function))
+               {
+                 /* Since we are sure that the current buffer was
+                    empty before the insertion, we can toggle
+                    enable-multibyte-characters directly here without
+                    taking care of marker adjustment and byte
+                    combining problem.  */
+                 Lisp_Object prev_multibyte;
+                 int count = specpdl_ptr - specpdl;
+
+                 prev_multibyte = current_buffer->enable_multibyte_characters;
+                 current_buffer->enable_multibyte_characters = Qnil;
+                 record_unwind_protect (set_auto_coding_unwind,
+                                        prev_multibyte);
+                 val = call1 (Vset_auto_coding_function,
+                              make_number (inserted));
+                 /* Discard the unwind protect for recovering the
+                    error of Vset_auto_coding_function.  */
+                 specpdl_ptr--;
+                 current_buffer->enable_multibyte_characters = prev_multibyte;
+                 TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
+               }
+
+             if (NILP (val))
+               {
+                 /* If the coding system is not yet decided, check
+                    file-coding-system-alist.  */
+                 Lisp_Object args[6], coding_systems;
+
+                 args[0] = Qinsert_file_contents, args[1] = orig_filename;
+                 args[2] = visit, args[3] = beg, args[4] = end, args[5] = Qnil;
+                 coding_systems = Ffind_operation_coding_system (6, args);
+                 if (CONSP (coding_systems))
+                   val = XCONS (coding_systems)->car;
+               }
+           }
+
+         setup_coding_system (Fcheck_coding_system (val), &coding);
+
+         if (NILP (Vcoding_system_for_read)
+             && NILP (current_buffer->enable_multibyte_characters))
+           {
+             /* We must suppress all text conversion except for
+                end-of-line conversion.  */
+             int eol_type;
+
+             eol_type = coding.eol_type;
+             setup_coding_system (Qraw_text, &coding);
+             coding.eol_type = eol_type;
+           }
+       }
+
       if (CODING_MAY_REQUIRE_DECODING (&coding))
        {
          /* Here, we don't have to consider byte combining (see the
@@ -4763,13 +4794,22 @@ e_write (desc, addr, nbytes, coding)
      now it is handled within encode_coding.  */
   while (1)
     {
-      encode_coding (coding, addr, buf, nbytes, WRITE_BUF_SIZE);
+      int result;
+
+      result = encode_coding (coding, addr, buf, nbytes, WRITE_BUF_SIZE);
       nbytes -= coding->consumed, addr += coding->consumed;
       if (coding->produced > 0)
        {
          coding->produced -= write (desc, buf, coding->produced);
          if (coding->produced) return -1;
        }
+      if (result == CODING_FINISH_INSUFFICIENT_SRC)
+       {
+         /* The source text ends by an incomplete multibyte form.
+             There's no way other than write it out as is.  */
+         nbytes -= write (desc, addr, nbytes);
+         if (nbytes) return -1;
+       }
       if (nbytes <= 0)
        break;
     }