(VALBITS, GCTYPEBITS): Deleted; default is better.
[bpt/emacs.git] / src / process.c
index 70ba93d..526f46f 100644 (file)
@@ -42,6 +42,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <unistd.h>
 #endif
 
+#ifdef WINDOWSNT
+#include <stdlib.h>
+#include <fcntl.h>
+#endif /* not WINDOWSNT */
+
 #ifdef HAVE_SOCKETS    /* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
 #include <netdb.h>
@@ -106,7 +111,7 @@ Lisp_Object Qlast_nonmenu_event;
 #ifdef HAVE_SOCKETS
 static Lisp_Object stream_process;
 
-#define NETCONN_P(p) (XGCTYPE (XPROCESS (p)->childp) == Lisp_String)
+#define NETCONN_P(p) (GC_STRINGP (XPROCESS (p)->childp))
 #else
 #define NETCONN_P(p) 0
 #endif /* HAVE_SOCKETS */
@@ -142,6 +147,7 @@ extern int h_errno;
 #ifndef SYS_SIGLIST_DECLARED
 #ifndef VMS
 #ifndef BSD4_1
+#ifndef WINDOWSNT
 #ifndef LINUX
 extern char *sys_siglist[];
 #endif /* not LINUX */
@@ -175,6 +181,7 @@ char *sys_siglist[] =
     "exceeded CPU time limit",
     "exceeded file size limit"
     };
+#endif /* not WINDOWSNT */
 #endif
 #endif /* VMS */
 #endif /* ! SYS_SIGLIST_DECLARED */
@@ -222,15 +229,19 @@ static int update_tick;
 #define POLL_FOR_INPUT
 #endif
 
-/* Mask of bits indicating the descriptors that we wait for input on */
+/* Mask of bits indicating the descriptors that we wait for input on */
 
 static SELECT_TYPE input_wait_mask;
 
+/* Mask that excludes keyboard input descriptor (s).  */
+
+static SELECT_TYPE non_keyboard_wait_mask;
+
 /* The largest descriptor currently in use for a process object.  */
 static int max_process_desc;
 
-/* Descriptor to use for keyboard input.  */
-static int keyboard_descriptor;
+/* The largest descriptor currently in use for keyboard input.  */
+static int max_keyboard_desc;
 
 /* Nonzero means delete a process right away if it exits.  */
 static int delete_exited_processes;
@@ -247,7 +258,8 @@ Lisp_Object Vprocess_alist;
    output from the process is to read at least one char.
    Always -1 on systems that support FIONREAD.  */
 
-static int proc_buffered_char[MAXDESC];
+/* Don't make static; need to access externally.  */
+int proc_buffered_char[MAXDESC];
 
 static Lisp_Object get_process ();
 
@@ -341,7 +353,8 @@ status_message (status)
       if (code < NSIG)
        {
 #ifndef VMS
-         signame = sys_siglist[code];
+         /* Cast to suppress warning if the table has const char *.  */
+         signame = (char *) sys_siglist[code];
 #else
          signame = sys_errlist[code];
 #endif
@@ -454,27 +467,23 @@ Lisp_Object
 make_process (name)
      Lisp_Object name;
 {
+  struct Lisp_Vector *vec;
   register Lisp_Object val, tem, name1;
   register struct Lisp_Process *p;
   char suffix[10];
   register int i;
 
-  /* size of process structure includes the vector header,
-     so deduct for that.  But struct Lisp_Vector includes the first
-     element, thus deducts too much, so add it back.  */
-  val = Fmake_vector (make_number ((sizeof (struct Lisp_Process)
-                                   - sizeof (struct Lisp_Vector)
-                                   + sizeof (Lisp_Object))
-                                  / sizeof (Lisp_Object)),
-                     Qnil);
-  XSETTYPE (val, Lisp_Process);
-
-  p = XPROCESS (val);
+  vec = allocate_vectorlike ((EMACS_INT) VECSIZE (struct Lisp_Process));
+  for (i = 0; i < VECSIZE (struct Lisp_Process); i++)
+    vec->contents[i] = Qnil;
+  vec->size = VECSIZE (struct Lisp_Process);
+  p = (struct Lisp_Process *)vec;
+
   XSETINT (p->infd, -1);
   XSETINT (p->outfd, -1);
-  XFASTINT (p->pid) = 0;
-  XFASTINT (p->tick) = 0;
-  XFASTINT (p->update_tick) = 0;
+  XSETFASTINT (p->pid, 0);
+  XSETFASTINT (p->tick, 0);
+  XSETFASTINT (p->update_tick, 0);
   p->raw_status_low = Qnil;
   p->raw_status_high = Qnil;
   p->status = Qrun;
@@ -492,6 +501,7 @@ make_process (name)
     }
   name = name1;
   p->name = name;
+  XSETPROCESS (val, p);
   Vprocess_alist = Fcons (Fcons (name, val), Vprocess_alist);
   return val;
 }
@@ -764,9 +774,15 @@ If the process has a filter, its buffer is not used for output.")
 {
   CHECK_PROCESS (proc, 0);
   if (EQ (filter, Qt))
-    FD_CLR (XINT (XPROCESS (proc)->infd), &input_wait_mask);
+    {
+      FD_CLR (XINT (XPROCESS (proc)->infd), &input_wait_mask);
+      FD_CLR (XINT (XPROCESS (proc)->infd), &non_keyboard_wait_mask);
+    }
   else if (EQ (XPROCESS (proc)->filter, Qt))
-    FD_SET (XINT (XPROCESS (proc)->infd), &input_wait_mask);
+    {
+      FD_SET (XINT (XPROCESS (proc)->infd), &input_wait_mask);
+      FD_SET (XINT (XPROCESS (proc)->infd), &non_keyboard_wait_mask);
+    }
   XPROCESS (proc)->filter = filter;
   return filter;
 }
@@ -862,7 +878,7 @@ list_processes_1 ()
   register int state;
   char tembuf[80];
 
-  XFASTINT (minspace) = 1;
+  XSETFASTINT (minspace, 1);
 
   set_buffer_internal (XBUFFER (Vstandard_output));
   Fbuffer_disable_undo (Vstandard_output);
@@ -870,8 +886,8 @@ list_processes_1 ()
   current_buffer->truncate_lines = Qt;
 
   write_string ("\
-Proc         Status   Buffer         Command\n\
-----         ------   ------         -------\n", -1);
+Proc         Status   Buffer         Tty         Command\n\
+----         ------   ------         ---         -------\n", -1);
 
   for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
     {
@@ -939,6 +955,13 @@ Proc         Status   Buffer         Command\n\
 
       Findent_to (make_number (37), minspace);
 
+      if (STRINGP (p->tty_name))
+       Finsert (1, &p->tty_name);
+      else
+       insert_string ("(none)");
+
+      Findent_to (make_number (49), minspace);
+
       if (NETCONN_P (proc))
         {
          sprintf (tembuf, "(network stream connection to %s)\n",
@@ -1072,7 +1095,9 @@ Remaining arguments are strings to give program as arguments.")
   new_argv = (unsigned char **) alloca ((nargs - 1) * sizeof (char *));
 
   /* If program file name is not absolute, search our path for it */
-  if (XSTRING (program)->data[0] != '/')
+  if (!IS_DIRECTORY_SEP (XSTRING (program)->data[0])
+      && !(XSTRING (program)->size > 1
+          && IS_DEVICE_SEP (XSTRING (program)->data[1])))
     {
       struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
 
@@ -1214,12 +1239,22 @@ create_process (process, new_argv, current_dir)
     }
 #else /* not SKTPAIR */
     {
+#ifdef WINDOWSNT
+      pipe_with_inherited_out (sv);
+      inchannel = sv[0];
+      forkout = sv[1];
+
+      pipe_with_inherited_in (sv);
+      forkin = sv[0];
+      outchannel = sv[1];
+#else /* not WINDOWSNT */
       pipe (sv);
       inchannel = sv[0];
       forkout = sv[1];
       pipe (sv);
       outchannel = sv[1];
       forkin = sv[0];
+#endif /* not WINDOWSNT */
     }
 #endif /* not SKTPAIR */
 
@@ -1255,7 +1290,7 @@ create_process (process, new_argv, current_dir)
   if (forkin < 0)
     XPROCESS (process)->subtty = Qnil;
   else
-    XFASTINT (XPROCESS (process)->subtty) = forkin;
+    XSETFASTINT (XPROCESS (process)->subtty, forkin);
   XPROCESS (process)->pty_flag = (pty_flag ? Qt : Qnil);
   XPROCESS (process)->status = Qrun;
 
@@ -1277,6 +1312,7 @@ create_process (process, new_argv, current_dir)
 #endif /* SIGCHLD */
 
   FD_SET (inchannel, &input_wait_mask);
+  FD_SET (inchannel, &non_keyboard_wait_mask);
   if (inchannel > max_process_desc)
     max_process_desc = inchannel;
 
@@ -1293,8 +1329,10 @@ create_process (process, new_argv, current_dir)
        Protect it from permanent change.  */
     char **save_environ = environ;
 
+#ifndef WINDOWSNT
     pid = vfork ();
     if (pid == 0)
+#endif /* not WINDOWSNT */
       {
        int xforkin = forkin;
        int xforkout = forkout;
@@ -1362,7 +1400,11 @@ create_process (process, new_argv, current_dir)
            /* In order to get a controlling terminal on some versions
               of BSD, it is necessary to put the process in pgrp 0
               before it opens the terminal.  */
+#ifdef OSF1
+           setpgid (0, 0);
+#else
            setpgrp (0, 0);
+#endif
 #endif
          }
 #endif /* TIOCNOTTY */
@@ -1425,8 +1467,13 @@ create_process (process, new_argv, current_dir)
 
        if (pty_flag)
          child_setup_tty (xforkout);
+#ifdef WINDOWSNT
+       pid = child_setup (xforkin, xforkout, xforkout,
+                          new_argv, 1, current_dir);
+#else  /* not WINDOWSNT */     
        child_setup (xforkin, xforkout, xforkout,
                     new_argv, 1, current_dir);
+#endif /* not WINDOWSNT */
       }
     environ = save_environ;
   }
@@ -1440,7 +1487,11 @@ create_process (process, new_argv, current_dir)
       report_file_error ("Doing vfork", Qnil);
     }
   
-  XFASTINT (XPROCESS (process)->pid) = pid;
+  XSETFASTINT (XPROCESS (process)->pid, pid);
+
+#ifdef WINDOWSNT
+  register_child (pid, inchannel);
+#endif /* WINDOWSNT */
 
   /* If the subfork execv fails, and it exits,
      this close hangs.  I don't know why.
@@ -1663,6 +1714,7 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
   XSETINT (XPROCESS (proc)->outfd, outch);
   XPROCESS (proc)->status = Qrun;
   FD_SET (inch, &input_wait_mask);
+  FD_SET (inch, &non_keyboard_wait_mask);
   if (inch > max_process_desc)
     max_process_desc = inch;
 
@@ -1702,6 +1754,7 @@ deactivate_process (proc)
       XSETINT (p->outfd, -1);
       chan_process[inchannel] = Qnil;
       FD_CLR (inchannel, &input_wait_mask);
+      FD_CLR (inchannel, &non_keyboard_wait_mask);
       if (inchannel == max_process_desc)
        {
          int i;
@@ -1721,6 +1774,7 @@ deactivate_process (proc)
 
 close_process_descs ()
 {
+#ifndef WINDOWSNT
   int i;
   for (i = 0; i < MAXDESC; i++)
     {
@@ -1736,6 +1790,7 @@ close_process_descs ()
            close (out);
        }
     }
+#endif
 }
 \f
 DEFUN ("accept-process-output", Faccept_process_output, Saccept_process_output,
@@ -1796,7 +1851,7 @@ Return non-nil iff we received any output before the timeout expired.")
     }
 
   if (NILP (proc))
-    XFASTINT (proc) = 0;
+    XSETFASTINT (proc, 0);
 
   return
     (wait_reading_process_input (seconds, useconds, proc, 0)
@@ -1870,14 +1925,14 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
     {
       wait_proc = XPROCESS (read_kbd);
       wait_channel = XINT (wait_proc->infd);
-      XFASTINT (read_kbd) = 0;
+      XSETFASTINT (read_kbd, 0);
     }
 
   /* If waiting for non-nil in a cell, record where.  */
   if (CONSP (read_kbd))
     {
       wait_for_cell = &XCONS (read_kbd)->car;
-      XFASTINT (read_kbd) = 0;
+      XSETFASTINT (read_kbd, 0);
     }
 
   waiting_for_user_input_p = XINT (read_kbd);
@@ -1968,9 +2023,10 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
 
       /* Wait till there is something to do */
 
-      Available = input_wait_mask;
       if (! XINT (read_kbd) && wait_for_cell == 0)
-       FD_CLR (keyboard_descriptor, &Available);
+       Available = non_keyboard_wait_mask;
+      else
+       Available = input_wait_mask;
 
       /* If frame size has changed or the window is newly mapped,
         redisplay now, before we start to wait.  There is a race
@@ -2036,7 +2092,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
            error("select error: %s", strerror (xerrno));
        }
 #if defined(sun) && !defined(USG5_4)
-      else if (nfds > 0 && FD_ISSET (keyboard_descriptor, &Available)
+      else if (nfds > 0 && keyboard_bit_set (&Available)
               && interrupt_input)
        /* System sometimes fails to deliver SIGIO.
 
@@ -2073,7 +2129,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
         but select says there is input.  */
 
       if (XINT (read_kbd) && interrupt_input
-         && (FD_ISSET (keyboard_descriptor, &Available)))
+         && (keyboard_bit_set (&Available)))
        kill (0, SIGIO);
 #endif
 
@@ -2088,10 +2144,10 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       /* Check for data from a process.  */
       /* Really FIRST_PROC_DESC should be 0 on Unix,
         but this is safer in the short run.  */
-      for (channel = keyboard_descriptor == 0 ? FIRST_PROC_DESC : 0;
-          channel <= max_process_desc; channel++)
+      for (channel = 0; channel <= max_process_desc; channel++)
        {
-         if (FD_ISSET (channel, &Available))
+         if (FD_ISSET (channel, &Available)
+             && FD_ISSET (channel, &non_keyboard_wait_mask))
            {
              int nread;
 
@@ -2255,12 +2311,20 @@ read_process_output (proc, channel)
 #else /* not VMS */
 
   if (proc_buffered_char[channel] < 0)
+#ifdef WINDOWSNT
+    nchars = read_child_output (channel, chars, sizeof (chars));
+#else
     nchars = read (channel, chars, sizeof chars);
+#endif
   else
     {
       chars[0] = proc_buffered_char[channel];
       proc_buffered_char[channel] = -1;
+#ifdef WINDOWSNT
+      nchars = read_child_output (channel, chars + 1, sizeof (chars) - 1);
+#else
       nchars = read (channel, chars + 1, sizeof chars - 1);
+#endif
       if (nchars < 0)
        nchars = 1;
       else
@@ -2286,13 +2350,17 @@ read_process_output (proc, channel)
       specbind (Qinhibit_quit, Qt);
       specbind (Qlast_nonmenu_event, Qt);
 
+      running_asynch_code = 1;
       internal_condition_case_1 (read_process_output_call,
                                 Fcons (outstream,
                                        Fcons (proc,
-                                              Fcons (make_string (chars, nchars),
+                                              Fcons (make_string (chars,
+                                                                  nchars),
                                                      Qnil))),
                                 !NILP (Vdebug_on_error) ? Qnil : Qerror,
                                 read_process_output_error_handler);
+      running_asynch_code = 0;
+      restore_match_data ();
 
       /* Handling the process output should not deactivate the mark.  */
       Vdeactivate_mark = odeactivate;
@@ -2322,8 +2390,8 @@ read_process_output (proc, channel)
       Fset_buffer (p->buffer);
       opoint = point;
       old_read_only = current_buffer->read_only;
-      XFASTINT (old_begv) = BEGV;
-      XFASTINT (old_zv) = ZV;
+      XSETFASTINT (old_begv, BEGV);
+      XSETFASTINT (old_zv, ZV);
 
       current_buffer->read_only = Qnil;
 
@@ -2347,9 +2415,9 @@ read_process_output (proc, channel)
 
       /* Insert after old_begv, but before old_zv.  */
       if (point < XFASTINT (old_begv))
-       XFASTINT (old_begv) += nchars;
+       XSETFASTINT (old_begv, XFASTINT (old_begv) + nchars);
       if (point <= XFASTINT (old_zv))
-       XFASTINT (old_zv) += nchars;
+       XSETFASTINT (old_zv, XFASTINT (old_zv) + nchars);
 
       /* Insert before markers in case we are inserting where
         the buffer's mark is, and the user's next command is Meta-y.  */
@@ -2511,7 +2579,7 @@ send_process (proc, buf, len, object)
                    else if (STRINGP (object))
                      offset = buf - (char *) XSTRING (object)->data;
 
-                   XFASTINT (zero) = 0;
+                   XSETFASTINT (zero, 0);
                    wait_reading_process_input (1, 0, zero, 0);
 
                    if (BUFFERP (object))
@@ -2887,7 +2955,12 @@ Both PID and CODE are integers.")
 {
   CHECK_NUMBER (pid, 0);
   CHECK_NUMBER (sig, 1);
+#ifdef WINDOWSNT
+  /* Only works for kill-type signals */
+  return make_number (win32_kill_process (XINT (pid), XINT (sig)));
+#else
   return make_number (kill (XINT (pid), XINT (sig)));
+#endif
 }
 
 DEFUN ("process-send-eof", Fprocess_send_eof, Sprocess_send_eof, 0, 1, 0,
@@ -2933,11 +3006,10 @@ kill_buffer_processes (buffer)
 {
   Lisp_Object tail, proc;
 
-  for (tail = Vprocess_alist; XGCTYPE (tail) == Lisp_Cons;
-       tail = XCONS (tail)->cdr)
+  for (tail = Vprocess_alist; GC_CONSP (tail); tail = XCONS (tail)->cdr)
     {
       proc = XCONS (XCONS (tail)->car)->cdr;
-      if (XGCTYPE (proc) == Lisp_Process
+      if (GC_PROCESSP (proc)
          && (NILP (buffer) || EQ (XPROCESS (proc)->buffer, buffer)))
        {
          if (NETCONN_P (proc))
@@ -3049,16 +3121,24 @@ sigchld_handler (signo)
       if (p != 0)
        {
          union { int i; WAITTYPE wt; } u;
+         int clear_desc_flag = 0;
          
          XSETINT (p->tick, ++process_tick);
          u.wt = w;
-         XFASTINT (p->raw_status_low) = u.i & 0xffff;
-         XFASTINT (p->raw_status_high) = u.i >> 16;
+         XSETFASTINT (p->raw_status_low, u.i & 0xffff);
+         XSETFASTINT (p->raw_status_high, u.i >> 16);
          
          /* If process has terminated, stop waiting for its output.  */
-         if (WIFSIGNALED (w) || WIFEXITED (w))
-           if (XINT (p->infd) >= 0)
+         if ((WIFSIGNALED (w) || WIFEXITED (w))
+             && XINT (p->infd) >= 0)
+           clear_desc_flag = 1;
+
+         /* We use clear_desc_flag to avoid a compiler bug in Microsoft C.  */
+         if (clear_desc_flag)
+           {
              FD_CLR (XINT (p->infd), &input_wait_mask);
+             FD_CLR (XINT (p->infd), &non_keyboard_wait_mask);
+           }
 
          /* Tell wait_reading_process_input that it needs to wake up and
             look around.  */
@@ -3083,7 +3163,8 @@ sigchld_handler (signo)
              if (code < NSIG)
                {
 #ifndef VMS
-                 signame = sys_siglist[code];
+                 /* Suppress warning if the table has const char *.  */
+                 signame = (char *) sys_siglist[code];
 #else
                  signame = sys_errlist[code];
 #endif
@@ -3105,7 +3186,7 @@ sigchld_handler (signo)
         get another signal.
         Otherwise (on systems that have WNOHANG), loop around
         to use up all the processes that have something to tell us.  */
-#if defined (USG) && ! (defined (HPUX) && defined (WNOHANG))
+#if defined (USG) && ! (defined (HPUX) && defined (WNOHANG)) || defined (WINDOWSNT)
 #ifdef USG
       signal (signo, sigchld_handler);
 #endif
@@ -3156,11 +3237,14 @@ exec_sentinel (proc, reason)
   specbind (Qinhibit_quit, Qt);
   specbind (Qlast_nonmenu_event, Qt);
 
+  running_asynch_code = 1;
   internal_condition_case_1 (read_process_output_call,
                             Fcons (sentinel,
                                    Fcons (proc, Fcons (reason, Qnil))),
                             !NILP (Vdebug_on_error) ? Qnil : Qerror,
                             exec_sentinel_error_handler);
+  running_asynch_code = 0;
+  restore_match_data ();
 
   Vdeactivate_mark = odeactivate;
   if (! EQ (Fcurrent_buffer (), obuffer))
@@ -3279,6 +3363,60 @@ status_notify ()
   UNGCPRO;
 }
 \f
+/* The first time this is called, assume keyboard input comes from DESC
+   instead of from where we used to expect it.
+   Subsequent calls mean assume input keyboard can come from DESC
+   in addition to other places.  */
+
+static int add_keyboard_wait_descriptor_called_flag;
+
+void
+add_keyboard_wait_descriptor (desc)
+     int desc;
+{
+  if (! add_keyboard_wait_descriptor_called_flag)
+    FD_CLR (0, &input_wait_mask);
+  add_keyboard_wait_descriptor_called_flag = 1;
+  FD_SET (desc, &input_wait_mask);
+  if (desc > max_keyboard_desc)
+    max_keyboard_desc = desc;
+}
+
+/* From now on, do not expect DESC to give keyboard input.  */
+
+void
+delete_keyboard_wait_descriptor (desc)
+     int desc;
+{
+  int fd;
+  int lim = max_keyboard_desc;
+
+  FD_CLR (desc, &input_wait_mask);
+
+  if (desc == max_keyboard_desc)
+    for (fd = 0; fd < lim; fd++)
+      if (FD_ISSET (fd, &input_wait_mask)
+         && !FD_ISSET (fd, &non_keyboard_wait_mask))
+       max_keyboard_desc = fd;
+}
+
+/* Return nonzero if *MASK has a bit set
+   that corresponds to one of the keyboard input descriptors.  */
+
+int
+keyboard_bit_set (mask)
+     SELECT_TYPE *mask;
+{
+  int fd;
+
+  for (fd = 0; fd < max_keyboard_desc; fd++)
+    if (FD_ISSET (fd, mask) && FD_ISSET (fd, &input_wait_mask)
+       && !FD_ISSET (fd, &non_keyboard_wait_mask))
+      return 1;
+
+  return 0;
+}
+\f
 init_process ()
 {
   register int i;
@@ -3291,10 +3429,10 @@ init_process ()
 #endif
 
   FD_ZERO (&input_wait_mask);
+  FD_ZERO (&non_keyboard_wait_mask);
   max_process_desc = 0;
 
-  keyboard_descriptor = 0;
-  FD_SET (keyboard_descriptor, &input_wait_mask);
+  FD_SET (0, &input_wait_mask);
 
   Vprocess_alist = Qnil;
   for (i = 0; i < MAXDESC; i++)
@@ -3304,17 +3442,6 @@ init_process ()
     }
 }
 
-/* From now on, assume keyboard input comes from descriptor DESC.  */
-
-void
-change_keyboard_wait_descriptor (desc)
-     int desc;
-{
-  FD_CLR (keyboard_descriptor, &input_wait_mask);
-  keyboard_descriptor = desc;
-  FD_SET (keyboard_descriptor, &input_wait_mask);
-}
-
 syms_of_process ()
 {
 #ifdef HAVE_SOCKETS