use dynwind_begin and dynwind_end
[bpt/emacs.git] / src / callproc.c
index 2a9162c..56bdc7d 100644 (file)
@@ -1,6 +1,7 @@
 /* Synchronous subprocess invocation for GNU Emacs.
-   Copyright (C) 1985-1988, 1993-1995, 1999-2013
-                Free Software Foundation, Inc.
+
+Copyright (C) 1985-1988, 1993-1995, 1999-2014 Free Software Foundation,
+Inc.
 
 This file is part of GNU Emacs.
 
@@ -81,12 +82,7 @@ static Lisp_Object Vtemp_file_name_pattern;
 /* If nonzero, a process-ID that has not been reaped.  */
 static pid_t synch_process_pid;
 
-/* If a string, the name of a temp file that has not been removed.  */
-#ifdef MSDOS
 static Lisp_Object synch_process_tempfile;
-#else
-# define synch_process_tempfile make_number (0)
-#endif
 
 /* Indexes of file descriptors that need closing on call_process_kill.  */
 enum
@@ -102,25 +98,37 @@ enum
     CALLPROC_FDS
   };
 
-static Lisp_Object call_process (ptrdiff_t, Lisp_Object *, int);
+static Lisp_Object call_process (ptrdiff_t, Lisp_Object *, int *, Lisp_Object *);
 \f
-/* Block SIGCHLD.  */
+/* Return the current buffer's working directory, or the home
+   directory if it's unreachable, as a string suitable for a system call.
+   Signal an error if the result would not be an accessible directory.  */
 
-void
-block_child_signal (void)
+Lisp_Object
+encode_current_directory (void)
 {
-  sigset_t blocked;
-  sigemptyset (&blocked);
-  sigaddset (&blocked, SIGCHLD);
-  pthread_sigmask (SIG_BLOCK, &blocked, 0);
-}
+  Lisp_Object dir;
+  struct gcpro gcpro1;
 
-/* Unblock SIGCHLD.  */
+  dir = BVAR (current_buffer, directory);
+  GCPRO1 (dir);
 
-void
-unblock_child_signal (void)
-{
-  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+  dir = Funhandled_file_name_directory (dir);
+
+  /* If the file name handler says that dir is unreachable, use
+     a sensible default. */
+  if (NILP (dir))
+    dir = build_string ("~");
+
+  dir = expand_and_dir_to_file (dir, Qnil);
+
+  if (STRING_MULTIBYTE (dir))
+    dir = ENCODE_FILE (dir);
+  if (! file_accessible_directory_p (SSDATA (dir)))
+    report_file_error ("Setting current directory",
+                      BVAR (current_buffer, directory));
+
+  return dir;
 }
 
 /* If P is reapable, record it as a deleted process and kill it.
@@ -130,7 +138,9 @@ unblock_child_signal (void)
 void
 record_kill_process (struct Lisp_Process *p, Lisp_Object tempfile)
 {
-  block_child_signal ();
+#ifndef MSDOS
+  sigset_t oldset;
+  block_child_signal (&oldset);
 
   if (p->alive)
     {
@@ -139,15 +149,18 @@ record_kill_process (struct Lisp_Process *p, Lisp_Object tempfile)
       kill (- p->pid, SIGKILL);
     }
 
-  unblock_child_signal ();
+  unblock_child_signal (&oldset);
+#endif /* !MSDOS */
 }
 
 /* Clean up files, file descriptors and processes created by Fcall_process.  */
 
 static void
-delete_temp_file (Lisp_Object name)
+delete_temp_file_ptr (Lisp_Object *name_ptr)
 {
-  unlink (SSDATA (name));
+  Lisp_Object name = *name_ptr;
+  if (! NILP (name))
+    unlink (SSDATA (name));
 }
 
 static void
@@ -168,7 +181,7 @@ call_process_kill (void *ptr)
       synch_process_pid = 0;
     }
   else if (STRINGP (synch_process_tempfile))
-    delete_temp_file (synch_process_tempfile);
+    delete_temp_file_ptr (&synch_process_tempfile);
 }
 
 /* Clean up when exiting Fcall_process: restore the buffer, and
@@ -179,6 +192,7 @@ call_process_cleanup (Lisp_Object buffer)
 {
   Fset_buffer (buffer);
 
+#ifndef MSDOS
   if (synch_process_pid)
     {
       kill (-synch_process_pid, SIGINT);
@@ -190,6 +204,7 @@ call_process_cleanup (Lisp_Object buffer)
       immediate_quit = 0;
       message1 ("Waiting for process to die...done");
     }
+#endif /* !MSDOS */
 }
 
 #ifdef DOS_NT
@@ -230,7 +245,7 @@ usage: (call-process PROGRAM &optional INFILE DESTINATION DISPLAY &rest ARGS)  *
   Lisp_Object infile, encoded_infile;
   int filefd;
   struct gcpro gcpro1;
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
 
   if (nargs >= 2 && ! NILP (args[1]))
     {
@@ -246,16 +261,23 @@ usage: (call-process PROGRAM &optional INFILE DESTINATION DISPLAY &rest ARGS)  *
   filefd = emacs_open (SSDATA (encoded_infile), O_RDONLY, 0);
   if (filefd < 0)
     report_file_error ("Opening process input file", infile);
-  record_unwind_protect_int (close_file_unwind, filefd);
+  record_unwind_protect_ptr (close_file_ptr_unwind, &filefd);
   UNGCPRO;
-  return unbind_to (count, call_process (nargs, args, filefd));
+  Lisp_Object tem0 = call_process (nargs, args, &filefd, NULL);
+  dynwind_end ();
+  return tem0;
 }
 
 /* Like Fcall_process (NARGS, ARGS), except use FILEFD as the input file.
+
+   If TEMPFILE_INDEX is nonnegative, it is the specpdl index of an
+   unwinder that is intended to remove the input temporary file; in
+   this case NARGS must be at least 2 and ARGS[1] is the file's name.
+
    At entry, the specpdl stack top entry must be close_file_unwind (FILEFD).  */
 
 static Lisp_Object
-call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
+call_process (ptrdiff_t nargs, Lisp_Object *args, int *filefd, Lisp_Object *tempfile_ptr)
 {
   Lisp_Object buffer, current_dir, path;
   bool display_p;
@@ -263,7 +285,6 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
   int callproc_fd[CALLPROC_FDS];
   int status;
   ptrdiff_t i;
-  ptrdiff_t count = SPECPDL_INDEX ();
   USE_SAFE_ALLOCA;
 
   char **new_argv;
@@ -275,6 +296,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
   char *tempfile = NULL;
   int pid;
 #else
+  sigset_t oldset;
   pid_t pid;
 #endif
   int child_errno;
@@ -285,6 +307,8 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
   Lisp_Object coding_systems;
   bool discard_output;
 
+  dynwind_begin ();
+
   if (synch_process_pid)
     error ("call-process invoked recursively");
 
@@ -402,24 +426,10 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
   {
     struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
 
-    current_dir = BVAR (current_buffer, directory);
+    current_dir = encode_current_directory ();
 
     GCPRO4 (buffer, current_dir, error_file, output_file);
 
-    current_dir = Funhandled_file_name_directory (current_dir);
-    if (NILP (current_dir))
-      /* If the file name handler says that current_dir is unreachable, use
-        a sensible default. */
-      current_dir = build_string ("~/");
-    current_dir = expand_and_dir_to_file (current_dir, Qnil);
-    current_dir = Ffile_name_as_directory (current_dir);
-
-    if (NILP (Ffile_accessible_directory_p (current_dir)))
-      report_file_error ("Setting current directory",
-                        BVAR (current_buffer, directory));
-
-    if (STRING_MULTIBYTE (current_dir))
-      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))
@@ -442,7 +452,8 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
     int ok;
 
     GCPRO3 (buffer, current_dir, error_file);
-    ok = openp (Vexec_path, args[0], Vexec_suffixes, &path, make_number (X_OK));
+    ok = openp (Vexec_path, args[0], Vexec_suffixes, &path,
+               make_number (X_OK), false);
     UNGCPRO;
     if (ok < 0)
       report_file_error ("Searching for program", args[0]);
@@ -493,10 +504,10 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
       char const *outf = tmpdir ? tmpdir : "";
       tempfile = alloca (strlen (outf) + 20);
       strcpy (tempfile, outf);
-      dostounix_filename (tempfile, 0);
+      dostounix_filename (tempfile);
       if (*tempfile == '\0' || tempfile[strlen (tempfile) - 1] != '/')
        strcat (tempfile, "/");
-      strcat (tempfile, "detmp.XXX");
+      strcat (tempfile, "emXXXXXX");
       mktemp (tempfile);
       if (!*tempfile)
        report_file_error ("Opening process output file", Qnil);
@@ -558,12 +569,12 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
 #ifdef MSDOS /* MW, July 1993 */
   /* Note that on MSDOS `child_setup' actually returns the child process
      exit status, not its PID, so assign it to status below.  */
-  pid = child_setup (filefd, fd_output, fd_error, new_argv, 0, current_dir);
+  pid = child_setup (*filefd, fd_output, fd_error, new_argv, 0, current_dir);
 
   if (pid < 0)
     {
       child_errno = errno;
-      unbind_to (count, Qnil);
+      dynwind_end ();
       synchronize_system_messages_locale ();
       return
        code_convert_string_norecord (build_string (strerror (child_errno)),
@@ -577,8 +588,8 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
        emacs_close (callproc_fd[i]);
        callproc_fd[i] = -1;
       }
-  emacs_close (filefd);
-  clear_unwind_protect (count - 1);
+  emacs_close (*filefd);
+  *filefd = -1;
 
   if (tempfile)
     {
@@ -604,10 +615,10 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
 #ifndef MSDOS
 
   block_input ();
-  block_child_signal ();
+  block_child_signal (&oldset);
 
 #ifdef WINDOWSNT
-  pid = child_setup (filefd, fd_output, fd_error, new_argv, 0, current_dir);
+  pid = child_setup (*filefd, fd_output, fd_error, new_argv, 0, current_dir);
 #else  /* not WINDOWSNT */
 
   /* vfork, and prevent local vars from being clobbered by the vfork.  */
@@ -616,11 +627,8 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
     Lisp_Object volatile coding_systems_volatile = coding_systems;
     Lisp_Object volatile current_dir_volatile = current_dir;
     bool volatile display_p_volatile = display_p;
-    bool volatile sa_must_free_volatile = sa_must_free;
     int volatile fd_error_volatile = fd_error;
-    int volatile filefd_volatile = filefd;
-    ptrdiff_t volatile count_volatile = count;
-    ptrdiff_t volatile sa_count_volatile = sa_count;
+    int *volatile filefd_volatile = filefd;
     char **volatile new_argv_volatile = new_argv;
     int volatile callproc_fd_volatile[CALLPROC_FDS];
     for (i = 0; i < CALLPROC_FDS; i++)
@@ -632,11 +640,8 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
     coding_systems = coding_systems_volatile;
     current_dir = current_dir_volatile;
     display_p = display_p_volatile;
-    sa_must_free = sa_must_free_volatile;
     fd_error = fd_error_volatile;
     filefd = filefd_volatile;
-    count = count_volatile;
-    sa_count = sa_count_volatile;
     new_argv = new_argv_volatile;
 
     for (i = 0; i < CALLPROC_FDS; i++)
@@ -646,14 +651,18 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
 
   if (pid == 0)
     {
-      unblock_child_signal ();
+      unblock_child_signal (&oldset);
 
       setsid ();
 
       /* Emacs ignores SIGPIPE, but the child should not.  */
       signal (SIGPIPE, SIG_DFL);
+      /* Likewise for SIGPROF.  */
+#ifdef SIGPROF
+      signal (SIGPROF, SIG_DFL);
+#endif
 
-      child_setup (filefd, fd_output, fd_error, new_argv, 0, current_dir);
+      child_setup (*filefd, fd_output, fd_error, new_argv, 0, current_dir);
     }
 
 #endif /* not WINDOWSNT */
@@ -661,12 +670,26 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
   child_errno = errno;
 
   if (pid > 0)
-    synch_process_pid = pid;
+    {
+      synch_process_pid = pid;
 
-  unblock_child_signal ();
-  unblock_input ();
+      if (INTEGERP (buffer))
+       {
+          if (tempfile_ptr)
+            {
+              record_deleted_pid (pid, *tempfile_ptr);
+              *tempfile_ptr = Qnil;
+            }
+          else
+            {
+              record_deleted_pid (pid, Qnil);
+            }
+         synch_process_pid = 0;
+       }
+    }
 
-#endif /* not MSDOS */
+  unblock_child_signal (&oldset);
+  unblock_input ();
 
   if (pid < 0)
     report_file_errno ("Doing vfork", Qnil, child_errno);
@@ -679,11 +702,16 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
        emacs_close (callproc_fd[i]);
        callproc_fd[i] = -1;
       }
-  emacs_close (filefd);
-  clear_unwind_protect (count - 1);
+  emacs_close (*filefd);
+  *filefd = -1;
+
+#endif /* not MSDOS */
 
   if (INTEGERP (buffer))
-    return unbind_to (count, Qnil);
+    {
+      dynwind_end ();
+      return Qnil;
+    }
 
   if (BUFFERP (buffer))
     Fset_buffer (buffer);
@@ -739,7 +767,6 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
       char buf[CALLPROC_BUFFER_SIZE_MAX];
       int bufsize = CALLPROC_BUFFER_SIZE_MIN;
       int nread;
-      bool first = 1;
       EMACS_INT total_read = 0;
       int carryover = 0;
       bool display_on_the_fly = display_p;
@@ -775,15 +802,19 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
          /* Now NREAD is the total amount of data in the buffer.  */
          immediate_quit = 0;
 
-         if (NILP (BVAR (current_buffer, enable_multibyte_characters))
-             && ! CODING_MAY_REQUIRE_DECODING (&process_coding))
+         if (!nread)
+           ;
+         else 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;
-             ptrdiff_t count1 = SPECPDL_INDEX ();
 
+              dynwind_begin ();
              XSETBUFFER (curbuf, current_buffer);
+             /* FIXME: Call signal_after_change!  */
+             prepare_to_modify_buffer (PT, PT, NULL);
              /* We cannot allow after-change-functions be run
                 during decoding, because that might modify the
                 buffer, while we rely on process_coding.produced to
@@ -792,7 +823,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
              specbind (Qinhibit_modification_hooks, Qt);
              decode_coding_c_string (&process_coding,
                                      (unsigned char *) buf, nread, curbuf);
-             unbind_to (count1, Qnil);
+              dynwind_end ();
              if (display_on_the_fly
                  && CODING_REQUIRE_DETECTION (&saved_coding)
                  && ! CODING_REQUIRE_DETECTION (&process_coding))
@@ -836,9 +867,6 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
 
          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, set it back to 1 because
@@ -870,7 +898,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
   synch_process_pid = 0;
 
   SAFE_FREE ();
-  unbind_to (count, Qnil);
+  dynwind_end ();
 
   if (WIFSIGNALED (status))
     {
@@ -897,9 +925,9 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd)
    Unwind-protect the file, so that the file descriptor will be closed
    and the file removed when the caller unwinds the specpdl stack.  */
 
-static int
+static void
 create_temp_file (ptrdiff_t nargs, Lisp_Object *args,
-                 Lisp_Object *filename_string_ptr)
+                 Lisp_Object *filename_string_ptr, int *fdp)
 {
   int fd;
   struct gcpro gcpro1;
@@ -949,14 +977,14 @@ create_temp_file (ptrdiff_t nargs, Lisp_Object *args,
     GCPRO1 (filename_string);
     tempfile = SSDATA (filename_string);
 
-    count = SPECPDL_INDEX ();
-    record_unwind_protect_nothing ();
     fd = mkostemp (tempfile, O_CLOEXEC);
     if (fd < 0)
       report_file_error ("Failed to open temporary file using pattern",
                         pattern);
-    set_unwind_protect (count, delete_temp_file, filename_string);
-    record_unwind_protect_int (close_file_unwind, fd);
+    *fdp = fd;
+    *filename_string_ptr = filename_string;
+    record_unwind_protect (delete_temp_file_ptr, filename_string_ptr);
+    record_unwind_protect_ptr (close_file_ptr_unwind, fdp);
   }
 
   start = args[0];
@@ -981,7 +1009,7 @@ create_temp_file (ptrdiff_t nargs, Lisp_Object *args,
   val = complement_process_encoding_system (val);
 
   {
-    ptrdiff_t count1 = SPECPDL_INDEX ();
+    dynwind_begin ();
 
     specbind (intern ("coding-system-for-write"), val);
     /* POSIX lets mk[s]temp use "."; don't invoke jka-compr if we
@@ -989,7 +1017,7 @@ create_temp_file (ptrdiff_t nargs, Lisp_Object *args,
     specbind (intern ("file-name-handler-alist"), Qnil);
     write_region (start, end, filename_string, Qnil, Qlambda, Qnil, Qnil, fd);
 
-    unbind_to (count1, Qnil);
+    dynwind_end ();
   }
 
   if (lseek (fd, 0, SEEK_SET) < 0)
@@ -998,9 +1026,7 @@ create_temp_file (ptrdiff_t nargs, Lisp_Object *args,
   /* Note that Fcall_process takes care of binding
      coding-system-for-read.  */
 
-  *filename_string_ptr = filename_string;
   UNGCPRO;
-  return fd;
 }
 
 DEFUN ("call-process-region", Fcall_process_region, Scall_process_region,
@@ -1030,9 +1056,9 @@ 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)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
-  struct gcpro gcpro1, gcpro2;
+  struct gcpro gcpro1;
   Lisp_Object infile, val;
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   Lisp_Object start = args[0];
   Lisp_Object end = args[1];
   bool empty_input;
@@ -1051,18 +1077,17 @@ usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &r
     }
 
   if (!empty_input)
-    fd = create_temp_file (nargs, args, &infile);
+    create_temp_file (nargs, args, &infile, &fd);
   else
     {
       infile = Qnil;
       fd = emacs_open (NULL_DEVICE, O_RDONLY, 0);
       if (fd < 0)
        report_file_error ("Opening null device", Qnil);
-      record_unwind_protect_int (close_file_unwind, fd);
+      record_unwind_protect_ptr (close_file_ptr_unwind, &fd);
     }
 
-  val = infile;
-  GCPRO2 (infile, val);
+  GCPRO1 (infile);
 
   if (nargs > 3 && !NILP (args[3]))
     Fdelete_region (start, end);
@@ -1079,17 +1104,9 @@ usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &r
     }
   args[1] = infile;
 
-  val = call_process (nargs, args, fd);
-
-  if (!empty_input && 4 < nargs
-      && (INTEGERP (CONSP (args[4]) ? XCAR (args[4]) : args[4])))
-    {
-      record_deleted_pid (synch_process_pid, infile);
-      synch_process_pid = 0;
-      clear_unwind_protect (count);
-    }
-
-  RETURN_UNGCPRO (unbind_to (count, val));
+  val = call_process (nargs, args, &fd, &infile);
+  dynwind_end ();
+  return val;
 }
 \f
 #ifndef WINDOWSNT
@@ -1165,23 +1182,21 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
      static variables as if the superior had done alloca and will be
      cleaned up in the usual way. */
   {
-    register char *temp;
-    size_t i; /* size_t, because ptrdiff_t might overflow here!  */
+    char *temp;
+    ptrdiff_t i;
 
     i = SBYTES (current_dir);
 #ifdef MSDOS
     /* MSDOS must have all environment variables malloc'ed, because
        low-level libc functions that launch subsidiary processes rely
        on that.  */
-    pwd_var = xmalloc (i + 6);
+    pwd_var = xmalloc (i + 5);
 #else
-    pwd_var = alloca (i + 6);
+    pwd_var = alloca (i + 5);
 #endif
     temp = pwd_var + 4;
     memcpy (pwd_var, "PWD=", 4);
-    memcpy (temp, SDATA (current_dir), i);
-    if (!IS_DIRECTORY_SEP (temp[i - 1])) temp[i++] = DIRECTORY_SEP;
-    temp[i] = 0;
+    strcpy (temp, SSDATA (current_dir));
 
 #ifndef DOS_NT
     /* We can't signal an Elisp error here; we're in a vfork.  Since
@@ -1497,14 +1512,14 @@ init_callproc_1 (void)
 #ifdef HAVE_NS
                                              etc_dir ? etc_dir :
 #endif
-                                             PATH_DATA);
+                                             PATH_DATA, 0);
   Vdata_directory = Ffile_name_as_directory (Fcar (Vdata_directory));
 
   Vdoc_directory = decode_env_path ("EMACSDOC",
 #ifdef HAVE_NS
                                              etc_dir ? etc_dir :
 #endif
-                                             PATH_DOC);
+                                             PATH_DOC, 0);
   Vdoc_directory = Ffile_name_as_directory (Fcar (Vdoc_directory));
 
   /* Check the EMACSPATH environment variable, defaulting to the
@@ -1513,10 +1528,10 @@ init_callproc_1 (void)
 #ifdef HAVE_NS
                                 path_exec ? path_exec :
 #endif
-                                PATH_EXEC);
+                                PATH_EXEC, 0);
   Vexec_directory = Ffile_name_as_directory (Fcar (Vexec_path));
   /* FIXME?  For ns, path_exec should go at the front?  */
-  Vexec_path = nconc2 (decode_env_path ("PATH", ""), Vexec_path);
+  Vexec_path = nconc2 (decode_env_path ("PATH", "", 0), Vexec_path);
 }
 
 /* This is run after init_cmdargs, when Vinstallation_directory is valid.  */
@@ -1557,9 +1572,9 @@ init_callproc (void)
 #ifdef HAVE_NS
                                        path_exec ? path_exec :
 #endif
-                                       PATH_EXEC);
+                                       PATH_EXEC, 0);
          Vexec_path = Fcons (tem, Vexec_path);
-         Vexec_path = nconc2 (decode_env_path ("PATH", ""), Vexec_path);
+         Vexec_path = nconc2 (decode_env_path ("PATH", "", 0), Vexec_path);
        }
 
       Vexec_directory = Ffile_name_as_directory (tem);
@@ -1584,17 +1599,17 @@ init_callproc (void)
   if (data_dir == 0)
     {
       Lisp_Object tem, tem1, srcdir;
+      Lisp_Object lispdir = Fcar (decode_env_path (0, PATH_DUMPLOADSEARCH, 0));
+
+      srcdir = Fexpand_file_name (build_string ("../src/"), lispdir);
 
-      srcdir = Fexpand_file_name (build_string ("../src/"),
-                                 build_string (PATH_DUMPLOADSEARCH));
-      tem = Fexpand_file_name (build_string ("GNU"), Vdata_directory);
+      tem = Fexpand_file_name (build_string ("NEWS"), Vdata_directory);
       tem1 = Ffile_exists_p (tem);
       if (!NILP (Fequal (srcdir, Vinvocation_directory)) || NILP (tem1))
        {
          Lisp_Object newdir;
-         newdir = Fexpand_file_name (build_string ("../etc/"),
-                                     build_string (PATH_DUMPLOADSEARCH));
-         tem = Fexpand_file_name (build_string ("GNU"), newdir);
+         newdir = Fexpand_file_name (build_string ("../etc/"), lispdir);
+         tem = Fexpand_file_name (build_string ("NEWS"), newdir);
          tem1 = Ffile_exists_p (tem);
          if (!NILP (tem1))
            Vdata_directory = newdir;
@@ -1620,7 +1635,7 @@ init_callproc (void)
 #ifdef DOS_NT
   Vshared_game_score_directory = Qnil;
 #else
-  Vshared_game_score_directory = build_string (PATH_GAME);
+  Vshared_game_score_directory = build_unibyte_string (PATH_GAME);
   if (NILP (Ffile_accessible_directory_p (Vshared_game_score_directory)))
     Vshared_game_score_directory = Qnil;
 #endif
@@ -1641,19 +1656,17 @@ set_initial_environment (void)
 void
 syms_of_callproc (void)
 {
+#include "callproc.x"
+
 #ifndef DOS_NT
   Vtemp_file_name_pattern = build_string ("emacsXXXXXX");
-#elif defined (WINDOWSNT)
+#else  /* DOS_NT */
   Vtemp_file_name_pattern = build_string ("emXXXXXX");
-#else
-  Vtemp_file_name_pattern = build_string ("detmp.XXX");
 #endif
   staticpro (&Vtemp_file_name_pattern);
 
-#ifdef MSDOS
   synch_process_tempfile = make_number (0);
   staticpro (&synch_process_tempfile);
-#endif
 
   DEFVAR_LISP ("shell-file-name", Vshell_file_name,
               doc: /* File name to load inferior shells from.
@@ -1662,7 +1675,11 @@ default if SHELL is not set.  */);
 
   DEFVAR_LISP ("exec-path", Vexec_path,
               doc: /* List of directories to search programs to run in subprocesses.
-Each element is a string (directory name) or nil (try default directory).  */);
+Each element is a string (directory name) or nil (try default directory).
+
+By default the last element of this list is `exec-directory'. The
+last element is not always used, for example in shell completion
+(`shell-dynamic-complete-command').  */);
 
   DEFVAR_LISP ("exec-suffixes", Vexec_suffixes,
               doc: /* List of suffixes to try to find executable file names.
@@ -1726,8 +1743,4 @@ use.
 
 See `setenv' and `getenv'.  */);
   Vprocess_environment = Qnil;
-
-  defsubr (&Scall_process);
-  defsubr (&Sgetenv_internal);
-  defsubr (&Scall_process_region);
 }