(detect_coding_iso2022): Do not exclude posibility of
[bpt/emacs.git] / src / fileio.c
index e81893c..9ad7a42 100644 (file)
@@ -1,5 +1,5 @@
 /* File IO for GNU Emacs.
-   Copyright (C) 1985,86,87,88,93,94,95,96 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,88,93,94,95,96,1997 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA.  */
 #include <fcntl.h>
 #endif
 
+#include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
@@ -197,6 +198,8 @@ extern Lisp_Object Vuser_login_name;
 
 extern int minibuf_level;
 
+extern int minibuffer_auto_raise;
+
 /* These variables describe handlers that have "already" had a chance
    to handle the current operation.
 
@@ -2776,9 +2779,7 @@ Otherwise returns nil.")
 }
 
 DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
-  "Return t if file FILENAME is the name of a directory as a file.\n\
-A directory name spec may be given instead; then the value is t\n\
-if the directory so specified exists and really is a directory.")
+  "Return t if FILENAME names an existing directory.")
   (filename)
      Lisp_Object filename;
 {
@@ -3016,8 +3017,9 @@ and (2) it puts less data in the undo list.\n\
 When REPLACE is non-nil, the value is the number of characters actually read,\n\
 which is often less than the number of characters to be read.\n\
 This does code conversion according to the value of\n\
-  `coding-system-for-read' or `coding-system-alist', and sets the variable\n\
-  `last-coding-system-used' to the coding system actually used.")
+  `coding-system-for-read' or `file-coding-system-alist',\n\
+  and sets the variable `last-coding-system-used' to the coding system\n\
+  actually used.")
   (filename, visit, beg, end, replace)
      Lisp_Object filename, visit, beg, end, replace;
 {
@@ -3063,21 +3065,34 @@ This does code conversion according to the value of\n\
 
   /* Decide the coding-system of the file.  */
   {
-    Lisp_Object val = Vcoding_system_for_read;
-    if (NILP (current_buffer->enable_multibyte_characters))
-      val = Qnil;
-    else if (NILP (val))
+    Lisp_Object val;
+
+    if (!NILP (Vcoding_system_for_read))
+      val = Vcoding_system_for_read;
+    else if (NILP (current_buffer->enable_multibyte_characters))
+      val = Qemacs_mule;
+    else
       {
        Lisp_Object args[6], coding_systems;
 
        args[0] = Qinsert_file_contents, args[1] = filename, args[2] = visit,
          args[3] = beg, args[4] = end, args[5] = replace;
-       coding_systems = Ffind_coding_system (6, args);
+       coding_systems = Ffind_operation_coding_system (6, args);
        val = CONSP (coding_systems) ? XCONS (coding_systems)->car : Qnil;
       }
     setup_coding_system (Fcheck_coding_system (val), &coding);
   }
 
+#ifdef DOS_NT
+  /* Use the conversion type to determine buffer-file-type
+     (find-buffer-file-type is now used to help determine the
+     conversion).  */
+  if (coding.type == coding_type_no_conversion)
+    current_buffer->buffer_file_type = Qt;
+  else
+    current_buffer->buffer_file_type = Qnil;
+#endif
+
   fd = -1;
 
 #ifndef APOLLO
@@ -3164,11 +3179,7 @@ This does code conversion according to the value of\n\
      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)
-      && (! CODING_REQUIRE_CONVERSION (&coding)
-         || (coding.type == coding_type_automatic
-             && ! CODING_REQUIRE_EOL_CONVERSION (&coding))
-         || (coding.eol_type == CODING_EOL_AUTOMATIC
-             && ! CODING_REQUIRE_TEXT_CONVERSION (&coding))))
+      && CODING_MAY_REQUIRE_NO_CONVERSION (&coding))
     {
       int same_at_start = BEGV;
       int same_at_end = ZV;
@@ -3200,9 +3211,11 @@ This does code conversion according to the value of\n\
          else if (nread == 0)
            break;
 
-         if (coding.type == coding_type_automatic)
+         if (coding.type == coding_type_undecided)
            detect_coding (&coding, buffer, nread);
-         if (CODING_REQUIRE_TEXT_CONVERSION (&coding))
+         if (coding.type != coding_type_undecided
+             && coding.type != coding_type_no_conversion
+             && coding.type != coding_type_emacs_mule)
            /* We found that the file should be decoded somehow.
                Let's give up here.  */
            {
@@ -3210,9 +3223,10 @@ This does code conversion according to the value of\n\
              break;
            }
 
-         if (coding.eol_type == CODING_EOL_AUTOMATIC)
+         if (coding.eol_type == CODING_EOL_UNDECIDED)
            detect_eol (&coding, buffer, nread);
-         if (CODING_REQUIRE_EOL_CONVERSION (&coding))
+         if (coding.eol_type != CODING_EOL_UNDECIDED
+             && coding.eol_type != CODING_EOL_LF)
            /* We found that the format of eol should be decoded.
                Let's give up here.  */
            {
@@ -3286,7 +3300,8 @@ This does code conversion according to the value of\n\
                 we cannot use this method; giveup and try the other.  */
              if (same_at_end > same_at_start
                  && FETCH_BYTE (same_at_end - 1) >= 0200
-                 && ! NILP (current_buffer->enable_multibyte_characters))
+                 && ! NILP (current_buffer->enable_multibyte_characters)
+                 && ! CODING_REQUIRE_NO_CONVERSION (&coding))
                giveup_match_end = 1;
              break;
            }
@@ -3297,6 +3312,12 @@ This does code conversion according to the value of\n\
        {
          /* We win!  We can handle REPLACE the optimized way.  */
 
+         /* Extends the end of non-matching text area to multibyte
+             character boundary.  */
+         if (! NILP (current_buffer->enable_multibyte_characters))
+           while (same_at_end < ZV && ! CHAR_HEAD_P (POS_ADDR (same_at_end)))
+             same_at_end++;
+
          /* Don't try to reuse the same piece of text twice.  */
          overlap = same_at_start - BEGV - (same_at_end + st.st_size - ZV);
          if (overlap > 0)
@@ -3374,7 +3395,7 @@ This does code conversion according to the value of\n\
 
          how_much += this;
 
-         if (CODING_REQUIRE_CONVERSION (&coding))
+         if (! CODING_REQUIRE_NO_CONVERSION (&coding))
            {
              int require, produced, consumed;
 
@@ -3386,7 +3407,7 @@ This does code conversion according to the value of\n\
              if (inserted + require + 2 * (total - how_much) > bufsize)
                {
                  bufsize = inserted + require + 2 * (total - how_much);
-                 conversion_buffer = (unsigned char *) realloc (conversion_buffer, bufsize);
+                 conversion_buffer = (unsigned char *) xrealloc (conversion_buffer, bufsize);
                }
 
              /* Convert this batch with results in CONVERSION_BUFFER.  */
@@ -3495,7 +3516,7 @@ This does code conversion according to the value of\n\
     total = READ_BUF_SIZE;
 
   if (NILP (visit) && total > 0)
-    prepare_to_modify_buffer (PT, PT);
+    prepare_to_modify_buffer (PT, PT, NULL);
 
   move_gap (PT);
   if (GAP_SIZE < total)
@@ -3519,9 +3540,9 @@ This does code conversion according to the value of\n\
     {
        /* try is reserved in some compilers (Microsoft C) */
       int trytry = min (total - how_much, READ_BUF_SIZE - unprocessed);
-      char *destination = (CODING_REQUIRE_CONVERSION (&coding)
-                          ? read_buf + unprocessed
-                          : (char *) (POS_ADDR (PT + inserted - 1) + 1));
+      char *destination = (CODING_REQUIRE_NO_CONVERSION (&coding)
+                          ? (char *) (POS_ADDR (PT + inserted - 1) + 1)
+                          : read_buf + unprocessed);
       int this;
 
       /* Allow quitting out of the actual I/O.  */
@@ -3544,7 +3565,7 @@ This does code conversion according to the value of\n\
       if (! not_regular)
        how_much += this;
 
-      if (CODING_REQUIRE_CONVERSION (&coding))
+      if (! CODING_REQUIRE_NO_CONVERSION (&coding))
        {
          int require, produced, consumed;
 
@@ -3724,6 +3745,7 @@ This does code conversion according to the value of\n\
 }
 \f
 static Lisp_Object build_annotations ();
+extern Lisp_Object Ffile_locked_p ();
 
 /* If build_annotations switched buffers, switch back to BUF.
    Kill the temporary buffer that was selected in the meantime.
@@ -3746,8 +3768,8 @@ build_annotations_unwind (buf)
   return Qnil;
 }
 
-DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 7,
-  "r\nFWrite region to file: \ni\ni\ni\nZCoding system: ",
+DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 6,
+  "r\nFWrite region to file: ",
   "Write current region into specified file.\n\
 When called from a program, takes three arguments:\n\
 START, END and FILENAME.  START and END are buffer positions.\n\
@@ -3763,17 +3785,10 @@ If VISIT is neither t nor nil nor a string,\n\
   that means do not print the \"Wrote file\" message.\n\
 The optional sixth arg LOCKNAME, if non-nil, specifies the name to\n\
   use for locking and unlocking, overriding FILENAME and VISIT.\n\
-The optional seventh arg CODING-SYSTEM, if non-nil, specifies the coding\n\
- system to be used for encoding characters.  For interactive use,\n\
- you can specify it by giving a prefix argument.  If no coding system\n\
- is specified, the current region is encoded according to the value of\n\
- `coding-system-for-write' or `coding-system-alist'.  The variable\n\
- `last-coding-system-used' is set the coding system actually used.\n\
 Kludgy feature: if START is a string, then that string is written\n\
 to the file, instead of any buffer contents, and END is ignored.")
-  (start, end, filename, append, visit, lockname, coding_system_symbol)
+  (start, end, filename, append, visit, lockname)
      Lisp_Object start, end, filename, append, visit, lockname;
-     Lisp_Object coding_system_symbol;
 {
   register int desc;
   int failure;
@@ -3793,8 +3808,7 @@ to the file, instead of any buffer contents, and END is ignored.")
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
   struct buffer *given_buffer;
 #ifdef DOS_NT
-  int buffer_file_type
-    = NILP (current_buffer->buffer_file_type) ? O_TEXT : O_BINARY;
+  int buffer_file_type = O_BINARY;
 #endif /* DOS_NT */
   struct coding_system coding;
 
@@ -3804,21 +3818,20 @@ to the file, instead of any buffer contents, and END is ignored.")
   if (!NILP (start) && !STRINGP (start))
     validate_region (&start, &end);
 
-  GCPRO5 (start, filename, visit, lockname, coding_system_symbol);
+  GCPRO4 (start, filename, visit, lockname);
 
   /* Decide the coding-system to be encoded to.  */
   {
     Lisp_Object val;
 
-    if (auto_saving || NILP (current_buffer->enable_multibyte_characters))
+    if (auto_saving)
       val = Qnil;
-    else if (!NILP (coding_system_symbol))
-      val = coding_system_symbol;
     else if (!NILP (Vcoding_system_for_write))
       val = Vcoding_system_for_write;
-    else if (!NILP (Flocal_variable_if_set_p (Qbuffer_file_coding_system,
-                                             Qnil)))
-      val = Fsymbol_value (Qbuffer_file_coding_system);
+    else if (NILP (current_buffer->enable_multibyte_characters))
+      val = (NILP (Flocal_variable_p (Qbuffer_file_coding_system, Qnil))
+            ? Qnil
+            : Fsymbol_value (Qbuffer_file_coding_system));
     else
       {
        Lisp_Object args[7], coding_systems;
@@ -3826,18 +3839,14 @@ to the file, instead of any buffer contents, and END is ignored.")
        args[0] = Qwrite_region, args[1] = start, args[2] = end,
          args[3] = filename, args[4] = append, args[5] = visit,
          args[6] = lockname;
-       coding_systems = Ffind_coding_system (7, args);
-       val = (CONSP (coding_systems)
+       coding_systems = Ffind_operation_coding_system (7, args);
+       val = (CONSP (coding_systems) && !NILP (XCONS (coding_systems)->cdr)
               ? XCONS (coding_systems)->cdr
-              : Fsymbol_value (Qbuffer_file_coding_system));
+              : current_buffer->buffer_file_coding_system);
       }
     setup_coding_system (Fcheck_coding_system (val), &coding); 
     if (!STRINGP (start) && !NILP (current_buffer->selective_display))
       coding.selective = 1;
-#ifdef DOS_NT
-    if (!NILP (current_buffer->buffer_file_type))
-      coding.eol_type = CODING_EOL_LF;
-#endif /* DOS_NT */
   }
 
   filename = Fexpand_file_name (filename, Qnil);
@@ -3894,8 +3903,8 @@ to the file, instead of any buffer contents, and END is ignored.")
   annotations = build_annotations (start, end, coding.pre_write_conversion);
   if (current_buffer != given_buffer)
     {
-      start = BEGV;
-      end = ZV;
+      XSETFASTINT (start, BEGV);
+      XSETFASTINT (end, ZV);
     }
 
 #ifdef CLASH_DETECTION
@@ -3904,7 +3913,7 @@ to the file, instead of any buffer contents, and END is ignored.")
       /* If we've locked this file for some other buffer,
         query before proceeding.  */
       if (!visiting && EQ (Ffile_locked_p (lockname), Qt))
-       call2 (intern ("ask-user-about-lock"), fn, Vuser_login_name);
+       call2 (intern ("ask-user-about-lock"), filename, Vuser_login_name);
 
       lock_file (lockname);
     }
@@ -4067,7 +4076,7 @@ to the file, instead of any buffer contents, and END is ignored.")
       save_errno = errno;
     }
 
-  if (coding.require_flushing)
+  if (coding.require_flushing && !coding.last_block)
     {
       /* We have to flush out a data. */
       coding.last_block = 1;
@@ -4205,8 +4214,8 @@ build_annotations (start, end, pre_write_conversion)
         been dealt with by this function.  */
       if (current_buffer != given_buffer)
        {
-         start = BEGV;
-         end = ZV;
+         XSETFASTINT (start, BEGV);
+         XSETFASTINT (end, ZV);
          annotations = Qnil;
        }
       Flength (res);   /* Check basic validity of return value */
@@ -4227,8 +4236,8 @@ build_annotations (start, end, pre_write_conversion)
                   original_buffer);
       if (current_buffer != given_buffer)
        {
-         start = BEGV;
-         end = ZV;
+         XSETFASTINT (start, BEGV);
+         XSETFASTINT (end, ZV);
          annotations = Qnil;
        }
       Flength (res);
@@ -4457,16 +4466,25 @@ auto_save_1 ()
   return
     Fwrite_region (Qnil, Qnil,
                   current_buffer->auto_save_file_name,
-                  Qnil, Qlambda, Qnil, Qnil);
+                  Qnil, Qlambda, Qnil);
 }
 
 static Lisp_Object
-do_auto_save_unwind (desc)  /* used as unwind-protect function */
-     Lisp_Object desc;
+do_auto_save_unwind (stream)  /* used as unwind-protect function */
+     Lisp_Object stream;
 {
   auto_saving = 0;
-  if (XINT (desc) >= 0)
-    close (XINT (desc));
+  if (!NILP (stream))
+    fclose ((FILE *) (XFASTINT (XCONS (stream)->car) << 16
+                     | XFASTINT (XCONS (stream)->cdr)));
+  return Qnil;
+}
+
+static Lisp_Object
+do_auto_save_unwind_1 (value)  /* used as unwind-protect function */
+     Lisp_Object value;
+{
+  minibuffer_auto_raise = XINT (value);
   return Qnil;
 }
 
@@ -4490,9 +4508,11 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
   int omessage_length = echo_area_glyphs_length;
   int do_handled_files;
   Lisp_Object oquit;
-  int listdesc;
+  FILE *stream;
+  Lisp_Object lispstream;
   int count = specpdl_ptr - specpdl;
   int *ptr;
+  int orig_minibuffer_auto_raise = minibuffer_auto_raise;
 
   /* Ordinarily don't quit within this function,
      but don't make it impossible to quit (in case we get hung in I/O).  */
@@ -4512,21 +4532,24 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
     {
       Lisp_Object listfile;
       listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil);
-#ifdef DOS_NT
-      listdesc = open (XSTRING (listfile)->data,
-                      O_WRONLY | O_TRUNC | O_CREAT | O_TEXT,
-                      S_IREAD | S_IWRITE);
-#else  /* not DOS_NT */
-      listdesc = creat (XSTRING (listfile)->data, 0666);
-#endif /* not DOS_NT */
+      stream = fopen (XSTRING (listfile)->data, "w");
+
+      /* Arrange to close that file whether or not we get an error.
+        Also reset auto_saving to 0.  */
+      lispstream = Fcons (Qnil, Qnil);
+      XSETFASTINT (XCONS (lispstream)->car, (EMACS_UINT)stream >> 16);
+      XSETFASTINT (XCONS (lispstream)->cdr, (EMACS_UINT)stream & 0xffff);
     }
   else
-    listdesc = -1;
-
-  /* Arrange to close that file whether or not we get an error.
-     Also reset auto_saving to 0.  */
-  record_unwind_protect (do_auto_save_unwind, make_number (listdesc));
+    {
+      stream = NULL;
+      lispstream = Qnil;
+    }
 
+  record_unwind_protect (do_auto_save_unwind, lispstream);
+  record_unwind_protect (do_auto_save_unwind_1,
+                        make_number (minibuffer_auto_raise));
+  minibuffer_auto_raise = 0;
   auto_saving = 1;
 
   /* First, save all files which don't have handlers.  If Emacs is
@@ -4544,17 +4567,17 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
           in the special file that lists them.  For each of these buffers,
           Record visited name (if any) and auto save name.  */
        if (STRINGP (b->auto_save_file_name)
-           && listdesc >= 0 && do_handled_files == 0)
+           && stream != NULL && do_handled_files == 0)
          {
            if (!NILP (b->filename))
              {
-               write (listdesc, XSTRING (b->filename)->data,
-                      XSTRING (b->filename)->size);
+               fwrite (XSTRING (b->filename)->data, 1,
+                       XSTRING (b->filename)->size, stream);
              }
-           write (listdesc, "\n", 1);
-           write (listdesc, XSTRING (b->auto_save_file_name)->data,
-                  XSTRING (b->auto_save_file_name)->size);
-           write (listdesc, "\n", 1);
+           putc ('\n', stream);
+           fwrite (XSTRING (b->auto_save_file_name)->data, 1,
+                   XSTRING (b->auto_save_file_name)->size, stream);
+           putc ('\n', stream);
          }
 
        if (!NILP (current_only)
@@ -4597,8 +4620,10 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
                && NILP (no_message))
              {
                /* It has shrunk too much; turn off auto-saving here.  */
+               minibuffer_auto_raise = orig_minibuffer_auto_raise;
                message ("Buffer %s has shrunk a lot; auto save turned off there",
                         XSTRING (b->name)->data);
+               minibuffer_auto_raise = 0;
                /* Turn off auto-saving until there's a real save,
                   and prevent any more warnings.  */
                XSETINT (b->save_length, -1);
@@ -4630,7 +4655,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
     {
       if (omessage)
        {
-         sit_for (1, 0, 0, 0);
+         sit_for (1, 0, 0, 0, 0);
          message2 (omessage, omessage_length);
        }
       else
@@ -4845,7 +4870,7 @@ DIR defaults to current buffer's directory default.")
   else if (STRINGP (initial))
     {
       insdef = initial;
-      insdef1 = Fcons (double_dollars (insdef), 0);
+      insdef1 = Fcons (double_dollars (insdef), make_number (0));
     }
   else
     insdef = Qnil, insdef1 = Qnil;
@@ -4859,6 +4884,13 @@ DIR defaults to current buffer's directory default.")
   val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
                          dir, mustmatch, insdef1,
                          Qfile_name_history, default_filename);
+  /* If Fcompleting_read returned the default string itself
+     (rather than a new string with the same contents),
+     it has to mean that the user typed RET with the minibuffer empty.
+     In that case, we really want to return ""
+     so that commands such as set-visited-file-name can distinguish.  */
+  if (EQ (val, default_filename))
+    val = build_string ("");
 
 #ifdef VMS
   unbind_to (count, Qnil);
@@ -5069,7 +5101,7 @@ The value should be either ?/ or ?\\ (any other value is treated as ?\\).\n\
 This variable affects the built-in functions only on Windows,\n\
 on other platforms, it is initialized so that Lisp code can find out\n\
 what the normal separator is.");
-  Vdirectory_sep_char = '/';
+  XSETFASTINT (Vdirectory_sep_char, '/');
 
   DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
     "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\