Commit 850d0752 authored by Nick Roberts's avatar Nick Roberts

(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.
parent 79a1c8a9
......@@ -284,6 +284,7 @@ static int keyboard_bit_set P_ ((SELECT_TYPE *));
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 @@ list_processes_1 (query_only)
while (1)
{
tem1 = Fcar (tem);
if (NILP (tem1))
break;
Finsert (1, &tem1);
tem = Fcdr (tem);
if (NILP (tem))
......@@ -1579,8 +1582,9 @@ at end of BUFFER, unless you specify an output stream or filter
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 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
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 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
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 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
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,80 +1716,86 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
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);
XPROCESS (proc)->decoding_buf = make_uninit_string (0);
XPROCESS (proc)->decoding_carryover = 0;
XPROCESS (proc)->encoding_buf = make_uninit_string (0);
{
struct gcpro gcpro1;
GCPRO1 (tem);
XPROCESS (proc)->inherit_coding_system_flag
= !(NILP (buffer) || !inherit_process_coding_system);
/* 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);
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;
}
/* 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. */
/* 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);
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));
}
struct gcpro gcpro1;
GCPRO1 (tem);
UNGCPRO;
}
/* 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);
/* 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;
/* 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 = nargs - 3; i >= 0; i--)
{
new_argv[i] = SDATA (XCAR (tem));
tem = XCDR (tem);
}
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));
}
XPROCESS (proc)->decoding_buf = make_uninit_string (0);
XPROCESS (proc)->decoding_carryover = 0;
XPROCESS (proc)->encoding_buf = make_uninit_string (0);
UNGCPRO;
}
XPROCESS (proc)->inherit_coding_system_flag
= !(NILP (buffer) || !inherit_process_coding_system);
/* 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;
create_process (proc, (char **) new_argv, current_dir);
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 @@ start_process_unwind (proc)
abort ();
/* Was PROC started successfully? */
if (XPROCESS (proc)->pid <= 0)
if (XPROCESS (proc)->pid == -1)
remove_process (proc);
return Qnil;
......@@ -2268,6 +2281,83 @@ create_process (process, new_argv, current_dir)
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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment