(child_setup): PRIO_PROCESS renamed to SET_EMACS_PRIORITY.
[bpt/emacs.git] / src / callproc.c
index 9b61002..cdf8f1a 100644 (file)
@@ -20,6 +20,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include <signal.h>
 #include <errno.h>
+#include <stdio.h>
 
 #include <config.h>
 
@@ -36,10 +37,12 @@ extern char *strerror ();
 
 #include <sys/file.h>
 #ifdef USG5
+#define INCLUDED_FCNTL
 #include <fcntl.h>
 #endif
 
 #ifdef MSDOS   /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */
+#define INCLUDED_FCNTL
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/param.h>
@@ -71,16 +74,25 @@ extern char **environ;
 #define max(a, b) ((a) > (b) ? (a) : (b))
 
 #ifdef MSDOS
-Lisp_Object Vbinary_process;
+/* When we are starting external processes we need to know whether they
+   take binary input (no conversion) or text input (\n is converted to
+   \r\n).  Similar for output: if newlines are written as \r\n then it's
+   text process output, otherwise it's binary.  */
+Lisp_Object Vbinary_process_input;
+Lisp_Object Vbinary_process_output;
 #endif
 
-Lisp_Object Vexec_path, Vexec_directory, Vdata_directory;
+Lisp_Object Vexec_path, Vexec_directory, Vdata_directory, Vdoc_directory;
 Lisp_Object Vconfigure_info_directory;
 
 Lisp_Object Vshell_file_name;
 
 Lisp_Object Vprocess_environment;
 
+#ifdef MSDOS
+Lisp_Object Qbuffer_file_type;
+#endif
+
 /* True iff we are about to fork off a synchronous process or if we
    are waiting for it.  */
 int synch_process_alive;
@@ -94,6 +106,13 @@ int synch_process_retcode;
 
 extern Lisp_Object Vdoc_file_name;
 \f
+/* Clean up when exiting Fcall_process.
+   On MSDOS, delete the temporary file on any kind of termination.
+   On Unix, kill the process and any children on termination by signal.  */
+
+/* Nonzero if this is termination due to exit.  */
+static int call_process_exited;
+
 #ifndef VMS  /* VMS version is in vmsproc.c.  */
 
 static Lisp_Object
@@ -112,13 +131,21 @@ call_process_cleanup (fdpid)
 {
 #ifdef MSDOS
   /* for MSDOS fdpid is really (fd . tempfile)  */
-  register Lisp_Object file = Fcdr (fdpid);
+  register Lisp_Object file;
+  file = Fcdr (fdpid);
   close (XFASTINT (Fcar (fdpid)));
   if (strcmp (XSTRING (file)-> data, NULL_DEVICE) != 0)
     unlink (XSTRING (file)->data);
 #else /* not MSDOS */
   register int pid = XFASTINT (Fcdr (fdpid));
 
+
+  if (call_process_exited)
+    {
+      close (XFASTINT (Fcar (fdpid)));
+      return Qnil;
+    }
+
   if (EMACS_KILLPG (pid, SIGINT) == 0)
     {
       int count = specpdl_ptr - specpdl;
@@ -217,9 +244,9 @@ If you quit, the process is killed with SIGINT, or SIGKILL if you quit again.")
 
     GCPRO3 (infile, buffer, current_dir);
 
-    current_dir = 
-      expand_and_dir_to_file
-       (Funhandled_file_name_directory (current_dir), Qnil);
+    current_dir
+      = expand_and_dir_to_file (Funhandled_file_name_directory (current_dir),
+                               Qnil);
     if (NILP (Ffile_accessible_directory_p (current_dir)))
       report_file_error ("Setting current directory",
                         Fcons (current_buffer->directory, Qnil));
@@ -229,31 +256,34 @@ If you quit, the process is killed with SIGINT, or SIGKILL if you quit again.")
 
   display = nargs >= 4 ? args[3] : Qnil;
 
-  {
-    register int i;
-    for (i = 4; i < nargs; i++)
-      {
-       CHECK_STRING (args[i], i);
-       new_argv[i - 3] = XSTRING (args[i])->data;
-      }
-    /* Program name is first command arg */
-    new_argv[0] = XSTRING (args[0])->data;
-    new_argv[i - 3] = 0;
-  }
-
   filefd = open (XSTRING (infile)->data, O_RDONLY, 0);
   if (filefd < 0)
     {
       report_file_error ("Opening process input file", Fcons (infile, Qnil));
     }
   /* Search for program; barf if not found.  */
-  openp (Vexec_path, args[0], EXEC_SUFFIXES, &path, 1);
+  {
+    struct gcpro gcpro1;
+
+    GCPRO1 (current_dir);
+    openp (Vexec_path, args[0], EXEC_SUFFIXES, &path, 1);
+    UNGCPRO;
+  }
   if (NILP (path))
     {
       close (filefd);
       report_file_error ("Searching for program", Fcons (args[0], Qnil));
     }
   new_argv[0] = XSTRING (path)->data;
+  {
+    register int i;
+    for (i = 4; i < nargs; i++)
+      {
+       CHECK_STRING (args[i], i);
+       new_argv[i - 3] = XSTRING (args[i])->data;
+      }
+    new_argv[i - 3] = 0;
+  }
 
 #ifdef MSDOS /* MW, July 1993 */
   /* These vars record information from process termination.
@@ -316,13 +346,16 @@ If you quit, the process is killed with SIGINT, or SIGKILL if you quit again.")
     synch_process_retcode = 0;
 
 #ifdef MSDOS /* MW, July 1993 */
+    /* ??? Someone who knows MSDOG needs to check whether this properly
+       closes all descriptors that it opens.  */
     pid = run_msdos_command (new_argv, current_dir, filefd, outfilefd);
     close (outfilefd);
     fd1 = -1; /* No harm in closing that one!  */
-    fd[0] = open (tempfile, NILP (Vbinary_process) ? O_TEXT : O_BINARY);
+    fd[0] = open (tempfile, NILP (Vbinary_process_output) ? O_TEXT : O_BINARY);
     if (fd[0] < 0)
       {
        unlink (tempfile);
+       close (filefd);
        report_file_error ("Cannot re-open temporary file", Qnil);
       }
 #else /* not MSDOS */
@@ -341,15 +374,10 @@ If you quit, the process is killed with SIGINT, or SIGKILL if you quit again.")
       }
 #endif /* not MSDOS */
 
-#if 0
-    /* Tell SIGCHLD handler to look for this pid.  */
-    synch_process_pid = pid;
-    /* Now let SIGCHLD come through.  */
-    sigsetmask (mask);
-#endif
-
     environ = save_environ;
 
+    /* Close most of our fd's, but not fd[0]
+       since we will use that to read input from.  */
     close (filefd);
     if (fd1 >= 0)
       close (fd1);
@@ -357,12 +385,15 @@ If you quit, the process is killed with SIGINT, or SIGKILL if you quit again.")
 
   if (pid < 0)
     {
-      close (fd[0]);
+      if (fd[0] >= 0)
+       close (fd[0]);
       report_file_error ("Doing vfork", Qnil);
     }
 
   if (XTYPE (buffer) == Lisp_Int)
     {
+      if (fd[0] >= 0)
+       close (fd[0]);
 #ifndef subprocesses
       /* If Emacs has been built with asynchronous subprocess support,
         we don't need to do this, I think because it will then have
@@ -372,6 +403,9 @@ If you quit, the process is killed with SIGINT, or SIGKILL if you quit again.")
       return Qnil;
     }
 
+  /* Enable sending signal if user quits below.  */
+  call_process_exited = 0;
+
 #ifdef MSDOS
   /* MSDOS needs different cleanup information.  */
   record_unwind_protect (call_process_cleanup,
@@ -416,6 +450,10 @@ If you quit, the process is killed with SIGINT, or SIGKILL if you quit again.")
 
   set_buffer_internal (old);
 
+  /* Don't kill any children that the subprocess may have left behind
+     when exiting.  */
+  call_process_exited = 1;
+
   unbind_to (count, Qnil);
 
   if (synch_process_death)
@@ -482,7 +520,14 @@ If you quit, the process is killed with SIGINT, or SIGKILL if you quit again.")
   filename_string = build_string (tempfile);
   start = args[0];
   end = args[1];
+#ifdef MSDOS
+  specbind (Qbuffer_file_type, Vbinary_process_input);
+  Fwrite_region (start, end, filename_string, Qnil, Qlambda);
+  unbind_to (count, Qnil);
+#else
   Fwrite_region (start, end, filename_string, Qnil, Qlambda);
+#endif
+
   record_unwind_protect (delete_temp_file, filename_string);
 
   if (!NILP (args[3]))
@@ -529,11 +574,14 @@ child_setup (in, out, err, new_argv, set_pgrp, current_dir)
 
   int pid = getpid ();
 
+#ifdef SET_EMACS_PRIORITY
   {
     extern int emacs_priority;
 
-    nice (- emacs_priority);
+    if (emacs_priority < 0)
+      nice (- emacs_priority);
   }
+#endif
 
 #ifdef subprocesses
   /* Close Emacs's descriptors that this process should not have.  */
@@ -619,8 +667,13 @@ child_setup (in, out, err, new_argv, set_pgrp, current_dir)
      started with its standard in, out, or error closed, as might
      happen under X.  */
   in = relocate_fd (in, 3);
-  out = relocate_fd (out, 3);
-  err = relocate_fd (err, 3);
+  if (out == err)
+    err = out = relocate_fd (out, 3);
+  else
+    {
+      out = relocate_fd (out, 3);
+      err = relocate_fd (err, 3);
+    }
 
   close (0);
   close (1);
@@ -699,8 +752,9 @@ getenv_internal (var, varlen, value, valuelen)
 
   for (scan = Vprocess_environment; CONSP (scan); scan = XCONS (scan)->cdr)
     {
-      Lisp_Object entry = XCONS (scan)->car;
-      
+      Lisp_Object entry;
+
+      entry = XCONS (scan)->car;
       if (XTYPE (entry) == Lisp_String
          && XSTRING (entry)->size > varlen
          && XSTRING (entry)->data[varlen] == '='
@@ -755,10 +809,14 @@ egetenv (var)
 init_callproc_1 ()
 {
   char *data_dir = egetenv ("EMACSDATA");
-    
+  char *doc_dir = egetenv ("EMACSDOC");
+
   Vdata_directory
     = Ffile_name_as_directory (build_string (data_dir ? data_dir 
                                             : PATH_DATA));
+  Vdoc_directory
+    = Ffile_name_as_directory (build_string (doc_dir ? doc_dir
+                                            : PATH_DOC));
 
   /* Check the EMACSPATH environment variable, defaulting to the
      PATH_EXEC path from paths.h.  */
@@ -776,15 +834,14 @@ init_callproc ()
   register char * sh;
   Lisp_Object tempdir;
 
-  if (initialized && !NILP (Vinvocation_directory))
+#ifndef MSDOS
+  if (initialized && !NILP (Vinstallation_directory))
     {
-      /* Add to the path the ../lib-src dir of the Emacs executable,
-        if that dir exists.  */
-      Lisp_Object tem, tem1;
-      tem = Fexpand_file_name (build_string ("../lib-src"),
-                              Vinvocation_directory);
-      tem1 = Ffile_exists_p (tem);
-      if (!NILP (tem1) && NILP (Fmember (tem, Vexec_path)))
+      /* Add to the path the lib-src subdir of the installation dir.  */
+      Lisp_Object tem;
+      tem = Fexpand_file_name (build_string ("lib-src"),
+                              Vinstallation_directory);
+      if (NILP (Fmember (tem, Vexec_path)))
        {
          Vexec_path = nconc2 (Vexec_path, Fcons (tem, Qnil));
          Vexec_directory = Ffile_name_as_directory (tem);
@@ -793,30 +850,53 @@ init_callproc ()
             Do so if ../etc exists and has our DOC-... file in it.  */
          if (data_dir == 0)
            {
-             Lisp_Object tem, tem2, tem3;
-             tem = Fexpand_file_name (build_string ("../etc"),
-                                      Vinvocation_directory);
-             tem2 = Fexpand_file_name (Vdoc_file_name, tem);
-             tem3 = Ffile_exists_p (tem2);
-             if (!NILP (tem3))
-               Vdata_directory = Ffile_name_as_directory (tem);
+             tem = Fexpand_file_name (build_string ("etc"),
+                                      Vinstallation_directory);
+             Vdoc_directory = Ffile_name_as_directory (tem);
            }
        }
     }
 
+  /* Look for the files that should be in etc.  We don't use
+     Vinstallation_directory, because these files are never installed
+     in /bin near the executable, and they are never in the build
+     directory when that's different from the source directory.
+
+     Instead, if these files are not in the nominal place, we try the
+     source directory.  */
+  if (data_dir == 0)
+    {
+      Lisp_Object tem, tem1, newdir;
+
+      tem = Fexpand_file_name (build_string ("GNU"), Vdata_directory);
+      tem1 = Ffile_exists_p (tem);
+      if (NILP (tem1))
+       {
+         newdir = Fexpand_file_name (build_string ("../etc/"),
+                                     build_string (PATH_DUMPLOADSEARCH));
+         tem = Fexpand_file_name (build_string ("GNU"), newdir);
+         tem1 = Ffile_exists_p (tem);
+         if (!NILP (tem1))
+           Vdata_directory = newdir;
+       }
+    }
+#endif
+
   tempdir = Fdirectory_file_name (Vexec_directory);
   if (access (XSTRING (tempdir)->data, 0) < 0)
     {
-      printf ("Warning: arch-dependent data dir (%s) does not exist.\n",
-             XSTRING (Vexec_directory)->data);
+      fprintf (stderr,
+              "Warning: arch-dependent data dir (%s) does not exist.\n",
+              XSTRING (Vexec_directory)->data);
       sleep (2);
     }
 
   tempdir = Fdirectory_file_name (Vdata_directory);
   if (access (XSTRING (tempdir)->data, 0) < 0)
     {
-      printf ("Warning: arch-independent data dir (%s) does not exist.\n",
-             XSTRING (Vdata_directory)->data);
+      fprintf (stderr,
+              "Warning: arch-independent data dir (%s) does not exist.\n",
+              XSTRING (Vdata_directory)->data);
       sleep (2);
     }
 
@@ -844,9 +924,16 @@ set_process_environment ()
 syms_of_callproc ()
 {
 #ifdef MSDOS
-  DEFVAR_LISP ("binary-process", &Vbinary_process,
+  Qbuffer_file_type = intern ("buffer-file-type");
+  staticpro (&Qbuffer_file_type);
+
+  DEFVAR_LISP ("binary-process-input", &Vbinary_process_input,
+    "*If non-nil then new subprocesses are assumed to take binary input.");
+  Vbinary_process_input = Qnil;
+
+  DEFVAR_LISP ("binary-process-output", &Vbinary_process_output,
     "*If non-nil then new subprocesses are assumed to produce binary output.");
-  Vbinary_process = Qnil;
+  Vbinary_process_output = Qnil;
 #endif
 
   DEFVAR_LISP ("shell-file-name", &Vshell_file_name,
@@ -865,6 +952,10 @@ especially executable programs intended for Emacs to invoke.");
     "Directory of architecture-independent files that come with GNU Emacs,\n\
 intended for Emacs to use.");
 
+  DEFVAR_LISP ("doc-directory", &Vdoc_directory,
+    "Directory containing the DOC file that comes with GNU Emacs.\n\
+This is usually the same as data-directory.");
+
   DEFVAR_LISP ("configure-info-directory", &Vconfigure_info_directory,
     "For internal use by the build procedure only.\n\
 This is the name of the directory in which the build procedure installed\n\