/* 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.
/* 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
CALLPROC_FDS
};
-static Lisp_Object call_process (ptrdiff_t, Lisp_Object *, int, ptrdiff_t);
+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.
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)
{
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
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
{
Fset_buffer (buffer);
+#ifndef MSDOS
if (synch_process_pid)
{
kill (-synch_process_pid, SIGINT);
immediate_quit = 0;
message1 ("Waiting for process to die...done");
}
+#endif /* !MSDOS */
}
#ifdef DOS_NT
Lisp_Object infile, encoded_infile;
int filefd;
struct gcpro gcpro1;
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
if (nargs >= 2 && ! NILP (args[1]))
{
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, -1));
+ 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.
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,
- ptrdiff_t tempfile_index)
+call_process (ptrdiff_t nargs, Lisp_Object *args, int *filefd, Lisp_Object *tempfile_ptr)
{
Lisp_Object buffer, current_dir, path;
bool display_p;
int callproc_fd[CALLPROC_FDS];
int status;
ptrdiff_t i;
- ptrdiff_t count = SPECPDL_INDEX ();
USE_SAFE_ALLOCA;
char **new_argv;
char *tempfile = NULL;
int pid;
#else
+ sigset_t oldset;
pid_t pid;
#endif
int child_errno;
Lisp_Object coding_systems;
bool discard_output;
+ dynwind_begin ();
+
if (synch_process_pid)
error ("call-process invoked recursively");
{
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))
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]);
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);
#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)),
emacs_close (callproc_fd[i]);
callproc_fd[i] = -1;
}
- emacs_close (filefd);
- clear_unwind_protect (count - 1);
+ emacs_close (*filefd);
+ *filefd = -1;
if (tempfile)
{
#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. */
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++)
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++)
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 */
if (INTEGERP (buffer))
{
- if (tempfile_index < 0)
- record_deleted_pid (pid, Qnil);
- else
- {
- eassert (1 < nargs);
- record_deleted_pid (pid, args[1]);
- clear_unwind_protect (tempfile_index);
- }
+ if (tempfile_ptr)
+ {
+ record_deleted_pid (pid, *tempfile_ptr);
+ *tempfile_ptr = Qnil;
+ }
+ else
+ {
+ record_deleted_pid (pid, Qnil);
+ }
synch_process_pid = 0;
}
}
- unblock_child_signal ();
+ unblock_child_signal (&oldset);
unblock_input ();
-#endif /* not MSDOS */
-
if (pid < 0)
report_file_errno ("Doing vfork", Qnil, child_errno);
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);
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;
/* 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
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))
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
synch_process_pid = 0;
SAFE_FREE ();
- unbind_to (count, Qnil);
+ dynwind_end ();
if (WIFSIGNALED (status))
{
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;
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];
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
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)
/* 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,
{
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;
}
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);
}
GCPRO1 (infile);
}
args[1] = infile;
- val = call_process (nargs, args, fd, empty_input ? -1 : count);
- RETURN_UNGCPRO (unbind_to (count, val));
+ val = call_process (nargs, args, &fd, &infile);
+ dynwind_end ();
+ return val;
}
\f
#ifndef WINDOWSNT
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
#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
#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. */
#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);
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;
#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
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.
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.
See `setenv' and `getenv'. */);
Vprocess_environment = Qnil;
-
- defsubr (&Scall_process);
- defsubr (&Sgetenv_internal);
- defsubr (&Scall_process_region);
}