changeset 104257:a577041a0370

(create_pty): New function. (Fstart_process): Use it to allow Emacs to just associate a pty with the buffer. See associated change in gdb-mi.el. (list_processes_1): Deal with no program name. (start_process_unwind): Use pid == -2 to mean no process.
author Nick Roberts <nickrob@snap.net.nz>
date Thu, 13 Aug 2009 13:22:55 +0000
parents fdb28981838b
children 81cbeb1f6df1
files src/process.c
diffstat 1 files changed, 162 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/src/process.c	Thu Aug 13 13:22:11 2009 +0000
+++ b/src/process.c	Thu Aug 13 13:22:55 2009 +0000
@@ -284,6 +284,7 @@
 static void deactivate_process P_ ((Lisp_Object));
 static void status_notify P_ ((struct Lisp_Process *));
 static int read_process_output P_ ((Lisp_Object, int));
+static void create_pty P_ ((Lisp_Object));
 
 /* If we support a window system, turn on the code to poll periodically
    to detect C-g.  It isn't actually used when doing interrupt input.  */
@@ -1530,6 +1531,8 @@
 	  while (1)
 	    {
 	      tem1 = Fcar (tem);
+	      if (NILP (tem1))
+		break;
 	      Finsert (1, &tem1);
 	      tem = Fcdr (tem);
 	      if (NILP (tem))
@@ -1579,8 +1582,9 @@
 function to handle the output.  BUFFER may also be nil, meaning that
 this process is not associated with any buffer.
 
-PROGRAM is the program file name.  It is searched for in PATH.
-Remaining arguments are strings to give program as arguments.
+PROGRAM is the program file name.  It is searched for in PATH.  If
+nil, just associate a pty with the buffer.  Remaining arguments are
+strings to give program as arguments.
 
 If you want to separate standard output from standard error, invoke
 the command through a shell and redirect one of them using the shell
@@ -1634,7 +1638,8 @@
 
   program = args[2];
 
-  CHECK_STRING (program);
+  if (!NILP (program))
+    CHECK_STRING (program);
 
   proc = make_process (name);
   /* If an error occurs and we can't start the process, we want to
@@ -1680,7 +1685,8 @@
 	args2[0] = Qstart_process;
 	for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
 	GCPRO2 (proc, current_dir);
-	coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
+	if (!NILP (program))
+	  coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
 	UNGCPRO;
 	if (CONSP (coding_systems))
 	  val = XCAR (coding_systems);
@@ -1698,7 +1704,8 @@
 	    args2[0] = Qstart_process;
 	    for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
 	    GCPRO2 (proc, current_dir);
-	    coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
+	    if (!NILP (program))
+	      coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
 	    UNGCPRO;
 	  }
 	if (CONSP (coding_systems))
@@ -1709,71 +1716,6 @@
     XPROCESS (proc)->encode_coding_system = val;
   }
 
-  /* If program file name is not absolute, search our path for it.
-     Put the name we will really use in TEM.  */
-  if (!IS_DIRECTORY_SEP (SREF (program, 0))
-      && !(SCHARS (program) > 1
-	   && IS_DEVICE_SEP (SREF (program, 1))))
-    {
-      struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
-
-      tem = Qnil;
-      GCPRO4 (name, program, buffer, current_dir);
-      openp (Vexec_path, program, Vexec_suffixes, &tem, make_number (X_OK));
-      UNGCPRO;
-      if (NILP (tem))
-	report_file_error ("Searching for program", Fcons (program, Qnil));
-      tem = Fexpand_file_name (tem, Qnil);
-    }
-  else
-    {
-      if (!NILP (Ffile_directory_p (program)))
-	error ("Specified program for new process is a directory");
-      tem = program;
-    }
-
-  /* If program file name starts with /: for quoting a magic name,
-     discard that.  */
-  if (SBYTES (tem) > 2 && SREF (tem, 0) == '/'
-      && SREF (tem, 1) == ':')
-    tem = Fsubstring (tem, make_number (2), Qnil);
-
-  {
-    struct gcpro gcpro1;
-    GCPRO1 (tem);
-
-    /* Encode the file name and put it in NEW_ARGV.
-       That's where the child will use it to execute the program.  */
-    tem = Fcons (ENCODE_FILE (tem), Qnil);
-
-    /* Here we encode arguments by the coding system used for sending
-       data to the process.  We don't support using different coding
-       systems for encoding arguments and for encoding data sent to the
-       process.  */
-
-    for (i = 3; i < nargs; i++)
-      {
-	tem = Fcons (args[i], tem);
-	CHECK_STRING (XCAR (tem));
-	if (STRING_MULTIBYTE (XCAR (tem)))
-	  XSETCAR (tem,
-		   code_convert_string_norecord
-		   (XCAR (tem), XPROCESS (proc)->encode_coding_system, 1));
-      }
-
-    UNGCPRO;
-  }
-
-  /* Now that everything is encoded we can collect the strings into
-     NEW_ARGV.  */
-  new_argv = (unsigned char **) alloca ((nargs - 1) * sizeof (char *));
-  new_argv[nargs - 2] = 0;
-
-  for (i = nargs - 3; i >= 0; i--)
-    {
-      new_argv[i] = SDATA (XCAR (tem));
-      tem = XCDR (tem);
-    }
 
   XPROCESS (proc)->decoding_buf = make_uninit_string (0);
   XPROCESS (proc)->decoding_carryover = 0;
@@ -1782,7 +1724,78 @@
   XPROCESS (proc)->inherit_coding_system_flag
     = !(NILP (buffer) || !inherit_process_coding_system);
 
-  create_process (proc, (char **) new_argv, current_dir);
+  if (!NILP (program))
+    {
+      /* If program file name is not absolute, search our path for it.
+	 Put the name we will really use in TEM.  */
+      if (!IS_DIRECTORY_SEP (SREF (program, 0))
+	  && !(SCHARS (program) > 1
+	       && IS_DEVICE_SEP (SREF (program, 1))))
+	{
+	  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+
+	  tem = Qnil;
+	  GCPRO4 (name, program, buffer, current_dir);
+	  openp (Vexec_path, program, Vexec_suffixes, &tem, make_number (X_OK));
+	  UNGCPRO;
+	  if (NILP (tem))
+	    report_file_error ("Searching for program", Fcons (program, Qnil));
+	  tem = Fexpand_file_name (tem, Qnil);
+	}
+      else
+	{
+	  if (!NILP (Ffile_directory_p (program)))
+	    error ("Specified program for new process is a directory");
+	  tem = program;
+	}
+
+      /* If program file name starts with /: for quoting a magic name,
+	 discard that.  */
+      if (SBYTES (tem) > 2 && SREF (tem, 0) == '/'
+	  && SREF (tem, 1) == ':')
+	tem = Fsubstring (tem, make_number (2), Qnil);
+
+      {
+	struct gcpro gcpro1;
+	GCPRO1 (tem);
+
+	/* Encode the file name and put it in NEW_ARGV.
+	   That's where the child will use it to execute the program.  */
+	tem = Fcons (ENCODE_FILE (tem), Qnil);
+
+	/* Here we encode arguments by the coding system used for sending
+	   data to the process.  We don't support using different coding
+	   systems for encoding arguments and for encoding data sent to the
+	   process.  */
+
+	for (i = 3; i < nargs; i++)
+	  {
+	    tem = Fcons (args[i], tem);
+	    CHECK_STRING (XCAR (tem));
+	    if (STRING_MULTIBYTE (XCAR (tem)))
+	      XSETCAR (tem,
+		       code_convert_string_norecord
+		       (XCAR (tem), XPROCESS (proc)->encode_coding_system, 1));
+	  }
+
+	UNGCPRO;
+      }
+
+      /* Now that everything is encoded we can collect the strings into
+	 NEW_ARGV.  */
+      new_argv = (unsigned char **) alloca ((nargs - 1) * sizeof (char *));
+      new_argv[nargs - 2] = 0;
+
+      for (i = nargs - 3; i >= 0; i--)
+	{
+	  new_argv[i] = SDATA (XCAR (tem));
+	  tem = XCDR (tem);
+	}
+
+      create_process (proc, (char **) new_argv, current_dir);
+    }
+  else
+    create_pty (proc);
 
   return unbind_to (count, proc);
 }
@@ -1799,7 +1812,7 @@
     abort ();
 
   /* Was PROC started successfully?  */
-  if (XPROCESS (proc)->pid <= 0)
+  if (XPROCESS (proc)->pid == -1)
     remove_process (proc);
 
   return Qnil;
@@ -2268,6 +2281,83 @@
     report_file_error ("Doing vfork", Qnil);
 }
 
+void
+create_pty (process)
+     Lisp_Object process;
+{
+  int inchannel, outchannel;
+
+  /* Use volatile to protect variables from being clobbered by longjmp.  */
+  volatile int forkin, forkout;
+  volatile int pty_flag = 0;
+
+  inchannel = outchannel = -1;
+
+#ifdef HAVE_PTYS
+  if (!NILP (Vprocess_connection_type))
+    outchannel = inchannel = allocate_pty ();
+
+  if (inchannel >= 0)
+    {
+#if ! defined (USG) || defined (USG_SUBTTY_WORKS)
+      /* On most USG systems it does not work to open the pty's tty here,
+	 then close it and reopen it in the child.  */
+#ifdef O_NOCTTY
+      /* Don't let this terminal become our controlling terminal
+	 (in case we don't have one).  */
+      forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
+#else
+      forkout = forkin = emacs_open (pty_name, O_RDWR, 0);
+#endif
+      if (forkin < 0)
+	report_file_error ("Opening pty", Qnil);
+#if defined (RTU) || defined (UNIPLUS) || defined (DONT_REOPEN_PTY)
+      /* In the case that vfork is defined as fork, the parent process
+	 (Emacs) may send some data before the child process completes
+	 tty options setup.  So we setup tty before forking.  */
+      child_setup_tty (forkout);
+#endif /* RTU or UNIPLUS or DONT_REOPEN_PTY */
+#else
+      forkin = forkout = -1;
+#endif /* not USG, or USG_SUBTTY_WORKS */
+      pty_flag = 1;
+    }
+#endif /* HAVE_PTYS */
+
+#ifdef O_NONBLOCK
+  fcntl (inchannel, F_SETFL, O_NONBLOCK);
+  fcntl (outchannel, F_SETFL, O_NONBLOCK);
+#else
+#ifdef O_NDELAY
+  fcntl (inchannel, F_SETFL, O_NDELAY);
+  fcntl (outchannel, F_SETFL, O_NDELAY);
+#endif
+#endif
+
+  /* Record this as an active process, with its channels.
+     As a result, child_setup will close Emacs's side of the pipes.  */
+  chan_process[inchannel] = process;
+  XPROCESS (process)->infd = inchannel;
+  XPROCESS (process)->outfd = outchannel;
+
+  /* Previously we recorded the tty descriptor used in the subprocess.
+     It was only used for getting the foreground tty process, so now
+     we just reopen the device (see emacs_get_tty_pgrp) as this is
+     more portable (see USG_SUBTTY_WORKS above).  */
+
+  XPROCESS (process)->pty_flag = pty_flag;
+  XPROCESS (process)->status = Qrun;
+  setup_process_coding_systems (process);
+
+  FD_SET (inchannel, &input_wait_mask);
+  FD_SET (inchannel, &non_keyboard_wait_mask);
+  if (inchannel > max_process_desc)
+    max_process_desc = inchannel;
+
+  XPROCESS (process)->pid = -2;
+  XPROCESS (process)->tty_name = build_string (pty_name);
+}
+
 
 #ifdef HAVE_SOCKETS