diff options
Diffstat (limited to 'src/callproc.c')
-rw-r--r-- | src/callproc.c | 221 |
1 files changed, 161 insertions, 60 deletions
diff --git a/src/callproc.c b/src/callproc.c index 7b8ba8fea21..2f0e569d0c8 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -84,6 +84,8 @@ extern int errno; #include "syssignal.h" #include "systty.h" #include "blockinput.h" +#include "frame.h" +#include "termhooks.h" #ifdef MSDOS #include "msdos.h" @@ -130,6 +132,7 @@ int synch_process_termsig; /* If synch_process_death is zero, this is exit code of synchronous subprocess. */ int synch_process_retcode; + /* Clean up when exiting Fcall_process. On MSDOS, delete the temporary file on any kind of termination. @@ -1177,6 +1180,40 @@ usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &r static int relocate_fd (); +static char ** +add_env (char **env, char **new_env, char *string) +{ + char **ep; + int ok = 1; + if (string == NULL) + return new_env; + + /* See if this string duplicates any string already in the env. + If so, don't put it in. + When an env var has multiple definitions, + we keep the definition that comes first in process-environment. */ + for (ep = env; ok && ep != new_env; ep++) + { + char *p = *ep, *q = string; + while (ok) + { + if (*q != *p) + break; + if (*q == 0) + /* The string is a lone variable name; keep it for now, we + will remove it later. It is a placeholder for a + variable that is not to be included in the environment. */ + break; + if (*q == '=') + ok = 0; + p++, q++; + } + } + if (ok) + *new_env++ = string; + return new_env; +} + /* This is the last thing run in a newly forked inferior either synchronous or asynchronous. Copy descriptors IN, OUT and ERR as descriptors 0, 1 and 2. @@ -1278,14 +1315,23 @@ child_setup (in, out, err, new_argv, set_pgrp, current_dir) temp[--i] = 0; } - /* Set `env' to a vector of the strings in Vprocess_environment. */ + /* Set `env' to a vector of the strings in the environment. */ { register Lisp_Object tem; register char **new_env; + char **p, **q; register int new_length; + Lisp_Object local = get_frame_param (XFRAME (Fframe_with_environment (selected_frame)), + Qenvironment); new_length = 0; + for (tem = Vprocess_environment; + CONSP (tem) && STRINGP (XCAR (tem)); + tem = XCDR (tem)) + new_length++; + + for (tem = local; CONSP (tem) && STRINGP (XCAR (tem)); tem = XCDR (tem)) new_length++; @@ -1295,39 +1341,33 @@ child_setup (in, out, err, new_argv, set_pgrp, current_dir) /* If we have a PWD envvar, pass one down, but with corrected value. */ - if (getenv ("PWD")) + if (egetenv ("PWD")) *new_env++ = pwd_var; - - /* Copy the Vprocess_environment strings into new_env. */ + + /* Overrides. */ for (tem = Vprocess_environment; CONSP (tem) && STRINGP (XCAR (tem)); tem = XCDR (tem)) + new_env = add_env (env, new_env, SDATA (XCAR (tem))); + + /* Local part of environment. */ + for (tem = local; + CONSP (tem) && STRINGP (XCAR (tem)); + tem = XCDR (tem)) + new_env = add_env (env, new_env, SDATA (XCAR (tem))); + + *new_env = 0; + + /* Remove variable names without values. */ + p = q = env; + while (*p != 0) { - char **ep = env; - char *string = (char *) SDATA (XCAR (tem)); - /* See if this string duplicates any string already in the env. - If so, don't put it in. - When an env var has multiple definitions, - we keep the definition that comes first in process-environment. */ - for (; ep != new_env; ep++) - { - char *p = *ep, *q = string; - while (1) - { - if (*q == 0) - /* The string is malformed; might as well drop it. */ - goto duplicate; - if (*q != *p) - break; - if (*q == '=') - goto duplicate; - p++, q++; - } - } - *new_env++ = string; - duplicate: ; + while (*q != 0 && strchr (*q, '=') == NULL) + *q++; + *p = *q++; + if (*p != 0) + p++; } - *new_env = 0; } #ifdef WINDOWSNT prepare_standard_handles (in, out, err, handles); @@ -1442,29 +1482,69 @@ relocate_fd (fd, minfd) } static int -getenv_internal (var, varlen, value, valuelen) +getenv_internal (var, varlen, value, valuelen, frame) char *var; int varlen; char **value; int *valuelen; + Lisp_Object frame; { Lisp_Object scan; - for (scan = Vprocess_environment; CONSP (scan); scan = XCDR (scan)) + if (NILP (frame)) + { + /* Try to find VAR in Vprocess_environment first. */ + for (scan = Vprocess_environment; CONSP (scan); scan = XCDR (scan)) + { + Lisp_Object entry = XCAR (scan); + if (STRINGP (entry) + && SBYTES (entry) >= varlen +#ifdef WINDOWSNT + /* NT environment variables are case insensitive. */ + && ! strnicmp (SDATA (entry), var, varlen) +#else /* not WINDOWSNT */ + && ! bcmp (SDATA (entry), var, varlen) +#endif /* not WINDOWSNT */ + ) + { + if (SBYTES (entry) > varlen && SREF (entry, varlen) == '=') + { + *value = (char *) SDATA (entry) + (varlen + 1); + *valuelen = SBYTES (entry) - (varlen + 1); + return 1; + } + else if (SBYTES (entry) == varlen) + { + /* Lone variable names in Vprocess_environment mean that + variable should be removed from the environment. */ + return 0; + } + } + } + frame = selected_frame; + } + + /* Find the environment in which to search the variable. */ + CHECK_FRAME (frame); + frame = Fframe_with_environment (frame); + + for (scan = get_frame_param (XFRAME (frame), Qenvironment); + CONSP (scan); + scan = XCDR (scan)) { Lisp_Object entry; entry = XCAR (scan); if (STRINGP (entry) - && SBYTES (entry) > varlen - && SREF (entry, varlen) == '=' + && SBYTES (entry) > varlen + && SREF (entry, varlen) == '=' #ifdef WINDOWSNT - /* NT environment variables are case insensitive. */ - && ! strnicmp (SDATA (entry), var, varlen) + /* NT environment variables are case insensitive. */ + && ! strnicmp (SDATA (entry), var, varlen) #else /* not WINDOWSNT */ - && ! bcmp (SDATA (entry), var, varlen) + && ! bcmp (SDATA (entry), var, varlen) #endif /* not WINDOWSNT */ - ) + ) { *value = (char *) SDATA (entry) + (varlen + 1); *valuelen = SBYTES (entry) - (varlen + 1); @@ -1475,26 +1555,34 @@ getenv_internal (var, varlen, value, valuelen) return 0; } -DEFUN ("getenv-internal", Fgetenv_internal, Sgetenv_internal, 1, 1, 0, - doc: /* Return the value of environment variable VAR, as a string. -VAR should be a string. Value is nil if VAR is undefined in the environment. -This function consults the variable ``process-environment'' for its value. */) - (var) - Lisp_Object var; +DEFUN ("getenv-internal", Fgetenv_internal, Sgetenv_internal, 1, 2, 0, + doc: /* Get the value of environment variable VARIABLE. +VARIABLE should be a string. Value is nil if VARIABLE is undefined in +the environment. Otherwise, value is a string. + +This function searches `process-environment' for VARIABLE. If it is +not found there, then it continues the search in the environment list +of the selected frame. + +If optional parameter FRAME is non-nil, then this function will ignore +`process-environment' and will simply look up the variable in that +frame's environment. */) + (variable, frame) + Lisp_Object variable, frame; { char *value; int valuelen; - CHECK_STRING (var); - if (getenv_internal (SDATA (var), SBYTES (var), - &value, &valuelen)) + CHECK_STRING (variable); + if (getenv_internal (SDATA (variable), SBYTES (variable), + &value, &valuelen, frame)) return make_string (value, valuelen); else return Qnil; } -/* A version of getenv that consults process_environment, easily - callable from C. */ +/* A version of getenv that consults the Lisp environment lists, + easily callable from C. */ char * egetenv (var) char *var; @@ -1502,7 +1590,7 @@ egetenv (var) char *value; int valuelen; - if (getenv_internal (var, strlen (var), &value, &valuelen)) + if (getenv_internal (var, strlen (var), &value, &valuelen, Qnil)) return value; else return 0; @@ -1625,8 +1713,8 @@ init_callproc () { char *dir = getenv ("TMPDIR"); Vtemp_file_name_pattern - = Fexpand_file_name (build_string ("emacsXXXXXX"), - build_string (dir)); + = Fexpand_file_name (build_string ("emacsXXXXXX"), + build_string (dir)); } else Vtemp_file_name_pattern = build_string ("/tmp/emacsXXXXXX"); @@ -1642,17 +1730,18 @@ init_callproc () } void -set_process_environment () +set_initial_environment () { register char **envp; - - Vprocess_environment = Qnil; + Lisp_Object env = Qnil; #ifndef CANNOT_DUMP if (initialized) #endif - for (envp = environ; *envp; envp++) - Vprocess_environment = Fcons (build_string (*envp), - Vprocess_environment); + { + for (envp = environ; *envp; envp++) + env = Fcons (build_string (*envp), env); + store_frame_param (SELECTED_FRAME(), Qenvironment, env); + } } void @@ -1711,15 +1800,27 @@ This is used by `call-process-region'. */); /* This variable is initialized in init_callproc. */ DEFVAR_LISP ("process-environment", &Vprocess_environment, - doc: /* List of environment variables for subprocesses to inherit. + doc: /* List of overridden environment variables for subprocesses to inherit. Each element should be a string of the form ENVVARNAME=VALUE. + +Entries in this list take precedence to those in the frame-local +environments. Therefore, let-binding `process-environment' is an easy +way to temporarily change the value of an environment variable, +irrespective of where it comes from. To use `process-environment' to +remove an environment variable, include only its name in the list, +without "=VALUE". + +This variable is set to nil when Emacs starts. + If multiple entries define the same variable, the first one always takes precedence. -The environment which Emacs inherits is placed in this variable -when Emacs starts. + Non-ASCII characters are encoded according to the initial value of -`locale-coding-system', i.e. the elements must normally be decoded for use. +`locale-coding-system', i.e. the elements must normally be decoded for +use. + See `setenv' and `getenv'. */); + Vprocess_environment = Qnil; #ifndef VMS defsubr (&Scall_process); |