callproc.c (Fcall_process): Set the member dst_multibyte of process_coding.
[bpt/emacs.git] / src / callproc.c
index eb2a226..01772ef 100644 (file)
@@ -1,6 +1,6 @@
 /* Synchronous subprocess invocation for GNU Emacs.
    Copyright (C) 1985-1988, 1993-1995, 1999-2011
-                 Free Software Foundation, Inc.
+                Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -29,6 +29,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <sys/file.h>
 #include <fcntl.h>
 
+#include "lisp.h"
+
 #ifdef WINDOWSNT
 #define NOMINMAX
 #include <windows.h>
@@ -41,7 +43,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <sys/param.h>
 #endif /* MSDOS */
 
-#include "lisp.h"
 #include "commands.h"
 #include "buffer.h"
 #include "character.h"
@@ -96,7 +97,7 @@ int synch_process_retcode;
 /* Nonzero if this is termination due to exit.  */
 static int call_process_exited;
 
-EXFUN (Fgetenv_internal, 2);
+static Lisp_Object Fgetenv_internal (Lisp_Object, Lisp_Object);
 
 static Lisp_Object
 call_process_kill (Lisp_Object fdpid)
@@ -113,6 +114,7 @@ call_process_cleanup (Lisp_Object arg)
   Lisp_Object fdpid = Fcdr (arg);
 #if defined (MSDOS)
   Lisp_Object file;
+  int fd;
 #else
   int pid;
 #endif
@@ -121,9 +123,13 @@ call_process_cleanup (Lisp_Object arg)
 
 #if defined (MSDOS)
   /* for MSDOS fdpid is really (fd . tempfile)  */
+  fd = XFASTINT (Fcar (fdpid));
   file = Fcdr (fdpid);
-  emacs_close (XFASTINT (Fcar (fdpid)));
-  if (strcmp (SDATA (file), NULL_DEVICE) != 0)
+  /* FD is -1 and FILE is "" when we didn't actually create a
+     temporary file in call-process.  */
+  if (fd >= 0)
+    emacs_close (fd);
+  if (!(strcmp (SDATA (file), NULL_DEVICE) == 0 || SREF (file, 0) == '\0'))
     unlink (SDATA (file));
 #else /* not MSDOS */
   pid = XFASTINT (Fcdr (fdpid));
@@ -156,8 +162,9 @@ DEFUN ("call-process", Fcall_process, Scall_process, 1, MANY, 0,
        doc: /* Call PROGRAM synchronously in separate process.
 The remaining arguments are optional.
 The program's input comes from file INFILE (nil means `/dev/null').
-Insert output in BUFFER before point; t means current buffer;
- nil for BUFFER means discard it; 0 means discard and don't wait.
+Insert output in BUFFER before point; t means current buffer; nil for BUFFER
+ means discard it; 0 means discard and don't wait; and `(:file FILE)', where
+ FILE is a file name string, means that it should be written to that file.
 BUFFER can also have the form (REAL-BUFFER STDERR-FILE); in that case,
 REAL-BUFFER says what to do with standard output, as above,
 while STDERR-FILE says what to do with standard error in the child.
@@ -177,7 +184,7 @@ and returns a numeric exit status or a signal description string.
 If you quit, the process is killed with SIGINT, or SIGKILL if you quit again.
 
 usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
-  (size_t nargs, register Lisp_Object *args)
+  (ptrdiff_t nargs, Lisp_Object *args)
 {
   Lisp_Object infile, buffer, current_dir, path;
   volatile int display_p_volatile;
@@ -191,19 +198,21 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
   int count = SPECPDL_INDEX ();
   volatile USE_SAFE_ALLOCA;
 
-  const unsigned char **volatile new_argv_volatile;
   register const unsigned char **new_argv;
   /* File to use for stderr in the child.
      t means use same as standard output.  */
   Lisp_Object error_file;
+  Lisp_Object output_file = Qnil;
 #ifdef MSDOS   /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */
-  char *outf, *tempfile;
+  char *outf, *tempfile = NULL;
   int outfilefd;
 #endif
+  int fd_output = -1;
   struct coding_system process_coding; /* coding-system of process output */
   struct coding_system argument_coding;        /* coding-system of arguments */
   /* Set to the return value of Ffind_operation_coding_system.  */
   Lisp_Object coding_systems;
+  int output_to_buffer = 1;
 
   /* Qt denotes that Ffind_operation_coding_system is not yet called.  */
   coding_systems = Qt;
@@ -222,7 +231,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
   /* Decide the coding-system for giving arguments.  */
   {
     Lisp_Object val, *args2;
-    size_t i;
+    ptrdiff_t i;
 
     /* If arguments are supplied, we may have to encode them.  */
     if (nargs >= 5)
@@ -243,7 +252,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
          val = Qraw_text;
        else
          {
-           SAFE_ALLOCA (args2, Lisp_Object *, (nargs + 1) * sizeof *args2);
+           SAFE_NALLOCA (args2, 1, nargs + 1);
            args2[0] = Qcall_process;
            for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
            coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
@@ -273,9 +282,12 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
     {
       buffer = args[2];
 
-      /* If BUFFER is a list, its meaning is
-        (BUFFER-FOR-STDOUT FILE-FOR-STDERR).  */
-      if (CONSP (buffer))
+      /* If BUFFER is a list, its meaning is (BUFFER-FOR-STDOUT
+        FILE-FOR-STDERR), unless the first element is :file, in which case see
+        the next paragraph. */
+      if (CONSP (buffer)
+         && (! SYMBOLP (XCAR (buffer))
+             || strcmp (SSDATA (SYMBOL_NAME (XCAR (buffer))), ":file")))
        {
          if (CONSP (XCDR (buffer)))
            {
@@ -291,6 +303,17 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
          buffer = XCAR (buffer);
        }
 
+      /* If the buffer is (still) a list, it might be a (:file "file") spec. */
+      if (CONSP (buffer)
+         && SYMBOLP (XCAR (buffer))
+         && ! strcmp (SSDATA (SYMBOL_NAME (XCAR (buffer))), ":file"))
+       {
+         output_file = Fexpand_file_name (XCAR (XCDR (buffer)),
+                                          BVAR (current_buffer, directory));
+         CHECK_STRING (output_file);
+         buffer = Qnil;
+       }
+
       if (!(EQ (buffer, Qnil)
            || EQ (buffer, Qt)
            || INTEGERP (buffer)))
@@ -318,11 +341,11 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
      protected by the caller, so all we really have to worry about is
      buffer.  */
   {
-    struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+    struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
 
     current_dir = BVAR (current_buffer, directory);
 
-    GCPRO4 (infile, buffer, current_dir, error_file);
+    GCPRO5 (infile, buffer, current_dir, error_file, output_file);
 
     current_dir = Funhandled_file_name_directory (current_dir);
     if (NILP (current_dir))
@@ -342,6 +365,8 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
       current_dir = ENCODE_FILE (current_dir);
     if (STRINGP (error_file) && STRING_MULTIBYTE (error_file))
       error_file = ENCODE_FILE (error_file);
+    if (STRINGP (output_file) && STRING_MULTIBYTE (output_file))
+      output_file = ENCODE_FILE (output_file);
     UNGCPRO;
   }
 
@@ -353,6 +378,26 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
       infile = DECODE_FILE (infile);
       report_file_error ("Opening process input file", Fcons (infile, Qnil));
     }
+
+  if (STRINGP (output_file))
+    {
+#ifdef DOS_NT
+      fd_output = emacs_open (SSDATA (output_file),
+                             O_WRONLY | O_TRUNC | O_CREAT | O_TEXT,
+                             S_IREAD | S_IWRITE);
+#else  /* not DOS_NT */
+      fd_output = creat (SSDATA (output_file), 0666);
+#endif /* not DOS_NT */
+      if (fd_output < 0)
+       {
+         output_file = DECODE_FILE (output_file);
+         report_file_error ("Opening process output file",
+                            Fcons (output_file, Qnil));
+       }
+      if (STRINGP (error_file) || NILP (error_file))
+       output_to_buffer = 0;
+    }
+
   /* Search for program; barf if not found.  */
   {
     struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
@@ -375,10 +420,9 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
 
   SAFE_ALLOCA (new_argv, const unsigned char **,
               (nargs > 4 ? nargs - 2 : 2) * sizeof *new_argv);
-  new_argv_volatile = new_argv;
   if (nargs > 4)
     {
-      register size_t i;
+      ptrdiff_t i;
       struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
 
       GCPRO5 (infile, buffer, current_dir, path, error_file);
@@ -400,26 +444,32 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
   new_argv[0] = SDATA (path);
 
 #ifdef MSDOS /* MW, July 1993 */
-  if ((outf = egetenv ("TMPDIR")))
-    strcpy (tempfile = alloca (strlen (outf) + 20), outf);
-  else
-    {
-      tempfile = alloca (20);
-      *tempfile = '\0';
-    }
-  dostounix_filename (tempfile);
-  if (*tempfile == '\0' || tempfile[strlen (tempfile) - 1] != '/')
-    strcat (tempfile, "/");
-  strcat (tempfile, "detmp.XXX");
-  mktemp (tempfile);
-
-  outfilefd = creat (tempfile, S_IREAD | S_IWRITE);
-  if (outfilefd < 0)
+
+  /* If we're redirecting STDOUT to a file, that file is already open
+     on fd_output.  */
+  if (fd_output < 0)
     {
-      emacs_close (filefd);
-      report_file_error ("Opening process output file",
-                        Fcons (build_string (tempfile), Qnil));
+      if ((outf = egetenv ("TMPDIR")))
+       strcpy (tempfile = alloca (strlen (outf) + 20), outf);
+      else
+       {
+         tempfile = alloca (20);
+         *tempfile = '\0';
+       }
+      dostounix_filename (tempfile);
+      if (*tempfile == '\0' || tempfile[strlen (tempfile) - 1] != '/')
+       strcat (tempfile, "/");
+      strcat (tempfile, "detmp.XXX");
+      mktemp (tempfile);
+      outfilefd = creat (tempfile, S_IREAD | S_IWRITE);
+      if (outfilefd < 0) {
+       emacs_close (filefd);
+       report_file_error ("Opening process output file",
+                          Fcons (build_string (tempfile), Qnil));
+      }
     }
+  else
+    outfilefd = fd_output;
   fd[0] = filefd;
   fd[1] = outfilefd;
 #endif /* MSDOS */
@@ -450,6 +500,8 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
     struct sigaction sigpipe_action;
 #endif
 
+    if (fd_output >= 0)
+      fd1 = fd_output;
 #if 0  /* Some systems don't have sigblock.  */
     mask = sigblock (sigmask (SIGCHLD));
 #endif
@@ -515,15 +567,21 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
     if (fd_error != outfilefd)
       emacs_close (fd_error);
     fd1 = -1; /* No harm in closing that one!  */
-    /* Since CRLF is converted to LF within `decode_coding', we can
-       always open a file with binary mode.  */
-    fd[0] = emacs_open (tempfile, O_RDONLY | O_BINARY, 0);
-    if (fd[0] < 0)
+    if (tempfile)
       {
-       unlink (tempfile);
-       emacs_close (filefd);
-       report_file_error ("Cannot re-open temporary file", Qnil);
+       /* Since CRLF is converted to LF within `decode_coding', we
+          can always open a file with binary mode.  */
+       fd[0] = emacs_open (tempfile, O_RDONLY | O_BINARY, 0);
+       if (fd[0] < 0)
+         {
+           unlink (tempfile);
+           emacs_close (filefd);
+           report_file_error ("Cannot re-open temporary file",
+                              Fcons (build_string (tempfile), Qnil));
+         }
       }
+    else
+      fd[0] = -1; /* We are not going to read from tempfile.   */
 #else /* not MSDOS */
 #ifdef WINDOWSNT
     pid = child_setup (filefd, fd1, fd_error, (char **) new_argv,
@@ -538,33 +596,52 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
     sigemptyset (&blocked);
     sigaddset (&blocked, SIGPIPE);
     sigaction (SIGPIPE, 0, &sigpipe_action);
-    sigprocmask (SIG_BLOCK, &blocked, &procmask);
+    pthread_sigmask (SIG_BLOCK, &blocked, &procmask);
 #endif
 
     BLOCK_INPUT;
 
-    pid = vfork ();
-
-    new_argv = new_argv_volatile;
+    /* vfork, and prevent local vars from being clobbered by the vfork.  */
+    {
+      Lisp_Object volatile buffer_volatile = buffer;
+      Lisp_Object volatile coding_systems_volatile = coding_systems;
+      Lisp_Object volatile current_dir_volatile = current_dir;
+      int volatile fd1_volatile = fd1;
+      int volatile fd_error_volatile = fd_error;
+      int volatile fd_output_volatile = fd_output;
+      int volatile output_to_buffer_volatile = output_to_buffer;
+      unsigned char const **volatile new_argv_volatile = new_argv;
+
+      pid = vfork ();
+
+      buffer = buffer_volatile;
+      coding_systems = coding_systems_volatile;
+      current_dir = current_dir_volatile;
+      fd1 = fd1_volatile;
+      fd_error = fd_error_volatile;
+      fd_output = fd_output_volatile;
+      output_to_buffer = output_to_buffer_volatile;
+      new_argv = new_argv_volatile;
+    }
 
     if (pid == 0)
       {
        if (fd[0] >= 0)
          emacs_close (fd[0]);
 #ifdef HAVE_SETSID
-        setsid ();
+       setsid ();
 #endif
 #if defined (USG)
-        setpgrp ();
+       setpgrp ();
 #else
-        setpgrp (pid, pid);
+       setpgrp (pid, pid);
 #endif /* USG */
 
        /* GConf causes us to ignore SIGPIPE, make sure it is restored
           in the child.  */
        //signal (SIGPIPE, SIG_DFL);
 #ifdef HAVE_WORKING_VFORK
-       sigprocmask (SIG_SETMASK, &procmask, 0);
+       pthread_sigmask (SIG_SETMASK, &procmask, 0);
 #endif
 
        child_setup (filefd, fd1, fd_error, (char **) new_argv,
@@ -576,7 +653,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
 #ifdef HAVE_WORKING_VFORK
     /* Restore the signal state.  */
     sigaction (SIGPIPE, &sigpipe_action, 0);
-    sigprocmask (SIG_SETMASK, &procmask, 0);
+    pthread_sigmask (SIG_SETMASK, &procmask, 0);
 #endif
 
 #endif /* not WINDOWSNT */
@@ -591,6 +668,8 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
     /* Close most of our fd's, but not fd[0]
        since we will use that to read input from.  */
     emacs_close (filefd);
+    if (fd_output >= 0)
+      emacs_close (fd_output);
     if (fd1 >= 0 && fd1 != fd_error)
       emacs_close (fd1);
   }
@@ -612,12 +691,12 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
   /* Enable sending signal if user quits below.  */
   call_process_exited = 0;
 
-#if defined(MSDOS)
+#if defined (MSDOS)
   /* MSDOS needs different cleanup information.  */
   record_unwind_protect (call_process_cleanup,
                         Fcons (Fcurrent_buffer (),
                                Fcons (make_number (fd[0]),
-                                      build_string (tempfile))));
+                                      build_string (tempfile ? tempfile : ""))));
 #else
   record_unwind_protect (call_process_cleanup,
                         Fcons (Fcurrent_buffer (),
@@ -633,6 +712,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
       /* If BUFFER is nil, we must read process output once and then
         discard it, so setup coding system but with nil.  */
       setup_coding_system (Qnil, &process_coding);
+      process_coding.dst_multibyte = 0;
     }
   else
     {
@@ -645,9 +725,9 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
        {
          if (EQ (coding_systems, Qt))
            {
-             size_t i;
+             ptrdiff_t i;
 
-             SAFE_ALLOCA (args2, Lisp_Object *, (nargs + 1) * sizeof *args2);
+             SAFE_NALLOCA (args2, 1, nargs + 1);
              args2[0] = Qcall_process;
              for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
              coding_systems
@@ -668,141 +748,148 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
          && !NILP (val))
        val = raw_text_coding_system (val);
       setup_coding_system (val, &process_coding);
+      process_coding.dst_multibyte
+       = ! NILP (BVAR (current_buffer, enable_multibyte_characters));
     }
+  process_coding.src_multibyte = 0;
 
   immediate_quit = 1;
   QUIT;
 
-  {
-    register EMACS_INT nread;
-    int first = 1;
-    EMACS_INT total_read = 0;
-    int carryover = 0;
-    int display_p = display_p_volatile;
-    int display_on_the_fly = display_p;
-    struct coding_system saved_coding;
-
-    saved_coding = process_coding;
-    while (1)
-      {
-       /* Repeatedly read until we've filled as much as possible
-          of the buffer size we have.  But don't read
-          less than 1024--save that for the next bufferful.  */
-       nread = carryover;
-       while (nread < bufsize - 1024)
-         {
-           int this_read = emacs_read (fd[0], buf + nread,
-                                       bufsize - nread);
+  if (output_to_buffer)
+    {
+      register EMACS_INT nread;
+      int first = 1;
+      EMACS_INT total_read = 0;
+      int carryover = 0;
+      int display_p = display_p_volatile;
+      int display_on_the_fly = display_p;
+      struct coding_system saved_coding;
+
+      saved_coding = process_coding;
+      while (1)
+       {
+         /* Repeatedly read until we've filled as much as possible
+            of the buffer size we have.  But don't read
+            less than 1024--save that for the next bufferful.  */
+         nread = carryover;
+         while (nread < bufsize - 1024)
+           {
+             int this_read = emacs_read (fd[0], buf + nread,
+                                         bufsize - nread);
 
-           if (this_read < 0)
-             goto give_up;
+             if (this_read < 0)
+               goto give_up;
 
-           if (this_read == 0)
-             {
-               process_coding.mode |= CODING_MODE_LAST_BLOCK;
-               break;
-             }
+             if (this_read == 0)
+               {
+                 process_coding.mode |= CODING_MODE_LAST_BLOCK;
+                 break;
+               }
 
-           nread += this_read;
-           total_read += this_read;
+             nread += this_read;
+             total_read += this_read;
 
-           if (display_on_the_fly)
-             break;
-         }
+             if (display_on_the_fly)
+               break;
+           }
 
-       /* Now NREAD is the total amount of data in the buffer.  */
-       immediate_quit = 0;
+         /* Now NREAD is the total amount of data in the buffer.  */
+         immediate_quit = 0;
 
-       if (!NILP (buffer))
-         {
-           if (NILP (BVAR (current_buffer, enable_multibyte_characters))
-               && ! CODING_MAY_REQUIRE_DECODING (&process_coding))
-             insert_1_both (buf, nread, nread, 0, 1, 0);
-           else
-             {                 /* We have to decode the input.  */
-               Lisp_Object curbuf;
-               int count1 = SPECPDL_INDEX ();
-
-               XSETBUFFER (curbuf, current_buffer);
-               /* We cannot allow after-change-functions be run
-                  during decoding, because that might modify the
-                  buffer, while we rely on process_coding.produced to
-                  faithfully reflect inserted text until we
-                  TEMP_SET_PT_BOTH below.  */
-               specbind (Qinhibit_modification_hooks, Qt);
-               decode_coding_c_string (&process_coding, (unsigned char *) buf,
-                                       nread, curbuf);
-               unbind_to (count1, Qnil);
-               if (display_on_the_fly
-                   && CODING_REQUIRE_DETECTION (&saved_coding)
-                   && ! CODING_REQUIRE_DETECTION (&process_coding))
-                 {
-                   /* We have detected some coding system.  But,
-                      there's a possibility that the detection was
-                      done by insufficient data.  So, we give up
-                      displaying on the fly.  */
-                   if (process_coding.produced > 0)
-                     del_range_2 (process_coding.dst_pos,
-                                  process_coding.dst_pos_byte,
-                                  process_coding.dst_pos
-                                  + process_coding.produced_char,
-                                  process_coding.dst_pos_byte
-                                  + process_coding.produced, 0);
-                   display_on_the_fly = 0;
-                   process_coding = saved_coding;
-                   carryover = nread;
-                   /* This is to make the above condition always
-                      fails in the future.  */
-                   saved_coding.common_flags
-                     &= ~CODING_REQUIRE_DETECTION_MASK;
-                   continue;
-                 }
-
-               TEMP_SET_PT_BOTH (PT + process_coding.produced_char,
-                                 PT_BYTE + process_coding.produced);
-               carryover = process_coding.carryover_bytes;
-               if (carryover > 0)
-                 memcpy (buf, process_coding.carryover,
-                         process_coding.carryover_bytes);
-             }
-         }
+         if (!NILP (buffer))
+           {
+             if (NILP (BVAR (current_buffer, enable_multibyte_characters))
+                 && ! CODING_MAY_REQUIRE_DECODING (&process_coding))
+               insert_1_both (buf, nread, nread, 0, 1, 0);
+             else
+               {                       /* We have to decode the input.  */
+                 Lisp_Object curbuf;
+                 int count1 = SPECPDL_INDEX ();
+
+                 XSETBUFFER (curbuf, current_buffer);
+                 /* We cannot allow after-change-functions be run
+                    during decoding, because that might modify the
+                    buffer, while we rely on process_coding.produced to
+                    faithfully reflect inserted text until we
+                    TEMP_SET_PT_BOTH below.  */
+                 specbind (Qinhibit_modification_hooks, Qt);
+                 decode_coding_c_string (&process_coding,
+                                         (unsigned char *) buf, nread, curbuf);
+                 unbind_to (count1, Qnil);
+                 if (display_on_the_fly
+                     && CODING_REQUIRE_DETECTION (&saved_coding)
+                     && ! CODING_REQUIRE_DETECTION (&process_coding))
+                   {
+                     /* We have detected some coding system.  But,
+                        there's a possibility that the detection was
+                        done by insufficient data.  So, we give up
+                        displaying on the fly.  */
+                     if (process_coding.produced > 0)
+                       del_range_2 (process_coding.dst_pos,
+                                    process_coding.dst_pos_byte,
+                                    process_coding.dst_pos
+                                    + process_coding.produced_char,
+                                    process_coding.dst_pos_byte
+                                    + process_coding.produced, 0);
+                     display_on_the_fly = 0;
+                     process_coding = saved_coding;
+                     carryover = nread;
+                     /* This is to make the above condition always
+                        fails in the future.  */
+                     saved_coding.common_flags
+                       &= ~CODING_REQUIRE_DETECTION_MASK;
+                     continue;
+                   }
+
+                 TEMP_SET_PT_BOTH (PT + process_coding.produced_char,
+                                   PT_BYTE + process_coding.produced);
+                 carryover = process_coding.carryover_bytes;
+                 if (carryover > 0)
+                   memcpy (buf, process_coding.carryover,
+                           process_coding.carryover_bytes);
+               }
+           }
 
-       if (process_coding.mode & CODING_MODE_LAST_BLOCK)
-         break;
+         if (process_coding.mode & CODING_MODE_LAST_BLOCK)
+           break;
 
-       /* Make the buffer bigger as we continue to read more data,
-          but not past CALLPROC_BUFFER_SIZE_MAX.  */
-       if (bufsize < CALLPROC_BUFFER_SIZE_MAX && total_read > 32 * bufsize)
-         if ((bufsize *= 2) > CALLPROC_BUFFER_SIZE_MAX)
-           bufsize = CALLPROC_BUFFER_SIZE_MAX;
+         /* Make the buffer bigger as we continue to read more data,
+            but not past CALLPROC_BUFFER_SIZE_MAX.  */
+         if (bufsize < CALLPROC_BUFFER_SIZE_MAX && total_read > 32 * bufsize)
+           if ((bufsize *= 2) > CALLPROC_BUFFER_SIZE_MAX)
+             bufsize = CALLPROC_BUFFER_SIZE_MAX;
 
-       if (display_p)
-         {
-           if (first)
-             prepare_menu_bars ();
-           first = 0;
-           redisplay_preserve_echo_area (1);
-           /* This variable might have been set to 0 for code
-              detection.  In that case, we set it back to 1 because
-              we should have already detected a coding system.  */
-           display_on_the_fly = 1;
-         }
-       immediate_quit = 1;
-       QUIT;
-      }
-  give_up: ;
-
-    Vlast_coding_system_used = CODING_ID_NAME (process_coding.id);
-    /* If the caller required, let the buffer inherit the
-       coding-system used to decode the process output.  */
-    if (inherit_process_coding_system)
-      call1 (intern ("after-insert-file-set-buffer-file-coding-system"),
-            make_number (total_read));
-  }
+         if (display_p)
+           {
+             if (first)
+               prepare_menu_bars ();
+             first = 0;
+             redisplay_preserve_echo_area (1);
+             /* This variable might have been set to 0 for code
+                detection.  In that case, we set it back to 1 because
+                we should have already detected a coding system.  */
+             display_on_the_fly = 1;
+           }
+         immediate_quit = 1;
+         QUIT;
+       }
+    give_up: ;
+
+      Vlast_coding_system_used = CODING_ID_NAME (process_coding.id);
+      /* If the caller required, let the buffer inherit the
+        coding-system used to decode the process output.  */
+      if (inherit_process_coding_system)
+       call1 (intern ("after-insert-file-set-buffer-file-coding-system"),
+              make_number (total_read));
+    }
 
 #ifndef MSDOS
   /* Wait for it to terminate, unless it already has.  */
-  wait_for_termination (pid);
+  if (output_to_buffer)
+    wait_for_termination (pid);
+  else
+    interruptible_wait_for_termination (pid);
 #endif
 
   immediate_quit = 0;
@@ -822,7 +909,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
       signame = strsignal (synch_process_termsig);
 
       if (signame == 0)
-        signame = "unknown";
+       signame = "unknown";
 
       synch_process_death = signame;
     }
@@ -850,8 +937,10 @@ DEFUN ("call-process-region", Fcall_process_region, Scall_process_region,
 The remaining arguments are optional.
 Delete the text if fourth arg DELETE is non-nil.
 
-Insert output in BUFFER before point; t means current buffer;
- nil for BUFFER means discard it; 0 means discard and don't wait.
+Insert output in BUFFER before point; t means current buffer; nil for
+ BUFFER means discard it; 0 means discard and don't wait; and `(:file
+ FILE)', where FILE is a file name string, means that it should be
+ written to that file.
 BUFFER can also have the form (REAL-BUFFER STDERR-FILE); in that case,
 REAL-BUFFER says what to do with standard output, as above,
 while STDERR-FILE says what to do with standard error in the child.
@@ -867,7 +956,7 @@ and returns a numeric exit status or a signal description string.
 If you quit, the process is killed with SIGINT, or SIGKILL if you quit again.
 
 usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &rest ARGS)  */)
-  (size_t nargs, register Lisp_Object *args)
+  (ptrdiff_t nargs, Lisp_Object *args)
 {
   struct gcpro gcpro1;
   Lisp_Object filename_string;
@@ -876,7 +965,7 @@ usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &r
   /* Qt denotes we have not yet called Ffind_operation_coding_system.  */
   Lisp_Object coding_systems;
   Lisp_Object val, *args2;
-  size_t i;
+  ptrdiff_t i;
   char *tempfile;
   Lisp_Object tmpdir, pattern;
 
@@ -939,7 +1028,7 @@ usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &r
   else
     {
       USE_SAFE_ALLOCA;
-      SAFE_ALLOCA (args2, Lisp_Object *, (nargs + 1) * sizeof *args2);
+      SAFE_NALLOCA (args2, 1, nargs + 1);
       args2[0] = Qcall_process_region;
       for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
       coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
@@ -1003,18 +1092,18 @@ add_env (char **env, char **new_env, char *string)
     {
       char *p = *ep, *q = string;
       while (ok)
-        {
-          if (*q != *p)
-            break;
-          if (*q == 0)
-            /* The string is a lone variable name; keep it for now, we
-               will remove it later.  It is a placeholder for a
-               variable that is not to be included in the environment.  */
-            break;
-          if (*q == '=')
-            ok = 0;
-          p++, q++;
-        }
+       {
+         if (*q != *p)
+           break;
+         if (*q == 0)
+           /* The string is a lone variable name; keep it for now, we
+              will remove it later.  It is a placeholder for a
+              variable that is not to be included in the environment.  */
+           break;
+         if (*q == '=')
+           ok = 0;
+         p++, q++;
+       }
     }
   if (ok)
     *new_env++ = string;
@@ -1068,7 +1157,7 @@ child_setup (int in, int out, int err, register char **new_argv, int set_pgrp, L
      cleaned up in the usual way. */
   {
     register char *temp;
-    register int i;
+    size_t i; /* size_t, because ptrdiff_t might overflow here!  */
 
     i = SBYTES (current_dir);
 #ifdef MSDOS
@@ -1118,8 +1207,8 @@ child_setup (int in, int out, int err, register char **new_argv, int set_pgrp, L
     new_length = 0;
 
     for (tem = Vprocess_environment;
-         CONSP (tem) && STRINGP (XCAR (tem));
-         tem = XCDR (tem))
+        CONSP (tem) && STRINGP (XCAR (tem));
+        tem = XCDR (tem))
       {
        if (strncmp (SSDATA (XCAR (tem)), "DISPLAY", 7) == 0
            && (SDATA (XCAR (tem)) [7] == '\0'
@@ -1153,8 +1242,7 @@ child_setup (int in, int out, int err, register char **new_argv, int set_pgrp, L
 
     if (STRINGP (display))
       {
-       int vlen = strlen ("DISPLAY=") + strlen (SSDATA (display)) + 1;
-       char *vdata = (char *) alloca (vlen);
+       char *vdata = (char *) alloca (sizeof "DISPLAY=" + SBYTES (display));
        strcpy (vdata, "DISPLAY=");
        strcat (vdata, SSDATA (display));
        new_env = add_env (env, new_env, vdata);
@@ -1172,11 +1260,11 @@ child_setup (int in, int out, int err, register char **new_argv, int set_pgrp, L
     p = q = env;
     while (*p != 0)
       {
-        while (*q != 0 && strchr (*q, '=') == NULL)
-          q++;
-        *p = *q++;
-        if (*p != 0)
-          p++;
+       while (*q != 0 && strchr (*q, '=') == NULL)
+         q++;
+       *p = *q++;
+       if (*p != 0)
+         p++;
       }
   }
 
@@ -1231,7 +1319,7 @@ child_setup (int in, int out, int err, register char **new_argv, int set_pgrp, L
   if (err != in && err != out)
     emacs_close (err);
 
-#if defined(USG)
+#if defined (USG)
 #ifndef SETPGRP_RELEASES_CTTY
   setpgrp ();                  /* No arguments but equivalent in this case */
 #endif
@@ -1301,8 +1389,8 @@ relocate_fd (int fd, int minfd)
 #endif /* not WINDOWSNT */
 
 static int
-getenv_internal_1 (const char *var, int varlen, char **value, int *valuelen,
-                  Lisp_Object env)
+getenv_internal_1 (const char *var, ptrdiff_t varlen, char **value,
+                  ptrdiff_t *valuelen, Lisp_Object env)
 {
   for (; CONSP (env); env = XCDR (env))
     {
@@ -1336,8 +1424,8 @@ getenv_internal_1 (const char *var, int varlen, char **value, int *valuelen,
 }
 
 static int
-getenv_internal (const char *var, int varlen, char **value, int *valuelen,
-                Lisp_Object frame)
+getenv_internal (const char *var, ptrdiff_t varlen, char **value,
+                ptrdiff_t *valuelen, Lisp_Object frame)
 {
   /* Try to find VAR in Vprocess_environment first.  */
   if (getenv_internal_1 (var, varlen, value, valuelen,
@@ -1377,7 +1465,7 @@ If optional parameter ENV is a list, then search this list instead of
   (Lisp_Object variable, Lisp_Object env)
 {
   char *value;
-  int valuelen;
+  ptrdiff_t valuelen;
 
   CHECK_STRING (variable);
   if (CONSP (env))
@@ -1401,7 +1489,7 @@ char *
 egetenv (const char *var)
 {
   char *value;
-  int valuelen;
+  ptrdiff_t valuelen;
 
   if (getenv_internal (var, strlen (var), &value, &valuelen, Qnil))
     return value;
@@ -1526,20 +1614,13 @@ init_callproc (void)
 void
 set_initial_environment (void)
 {
-  register char **envp;
-#ifdef CANNOT_DUMP
-  Vprocess_environment = Qnil;
-#else
-  if (initialized)
-#endif
-    {
-      for (envp = environ; *envp; envp++)
-       Vprocess_environment = Fcons (build_string (*envp),
-                                     Vprocess_environment);
-      /* Ideally, the `copy' shouldn't be necessary, but it seems it's frequent
-        to use `delete' and friends on process-environment.  */
-      Vinitial_environment = Fcopy_sequence (Vprocess_environment);
-    }
+  char **envp;
+  for (envp = environ; *envp; envp++)
+    Vprocess_environment = Fcons (build_string (*envp),
+                                 Vprocess_environment);
+  /* Ideally, the `copy' shouldn't be necessary, but it seems it's frequent
+     to use `delete' and friends on process-environment.  */
+  Vinitial_environment = Fcopy_sequence (Vprocess_environment);
 }
 
 void