diff options
Diffstat (limited to 'src/callproc.c')
-rw-r--r-- | src/callproc.c | 303 |
1 files changed, 249 insertions, 54 deletions
diff --git a/src/callproc.c b/src/callproc.c index 9f90e9d7537..a6841317e63 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" @@ -111,6 +113,7 @@ Lisp_Object Vtemp_file_name_pattern; Lisp_Object Vshell_file_name; +Lisp_Object Vglobal_environment; Lisp_Object Vprocess_environment; #ifdef DOS_NT @@ -130,6 +133,10 @@ int synch_process_termsig; /* If synch_process_death is zero, this is exit code of synchronous subprocess. */ int synch_process_retcode; + +/* List of environment variables to look up in emacsclient. */ +Lisp_Object Vlocal_environment_variables; + /* Clean up when exiting Fcall_process. On MSDOS, delete the temporary file on any kind of termination. @@ -1169,6 +1176,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. @@ -1270,14 +1311,36 @@ 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 environment = Vglobal_environment; + Lisp_Object local; new_length = 0; + for (tem = Vprocess_environment; + CONSP (tem) && STRINGP (XCAR (tem)); + tem = XCDR (tem)) + new_length++; + + if (!NILP (Vlocal_environment_variables)) + { + local = get_frame_param (XFRAME (Fframe_with_environment (selected_frame)), + Qenvironment); + if (EQ (Vlocal_environment_variables, Qt) + && !NILP (local)) + environment = local; + else if (CONSP (local)) + { + new_length += Fsafe_length (Vlocal_environment_variables); + } + } + + for (tem = environment; CONSP (tem) && STRINGP (XCAR (tem)); tem = XCDR (tem)) new_length++; @@ -1289,37 +1352,38 @@ child_setup (in, out, err, new_argv, set_pgrp, current_dir) but with corrected value. */ if (getenv ("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, if Vlocal_environment_variables is a list. */ + for (tem = Vlocal_environment_variables; + CONSP (tem) && STRINGP (XCAR (tem)); + tem = XCDR (tem)) + new_env = add_env (env, new_env, egetenv (SDATA (XCAR (tem)))); + + /* The rest of the environment (either Vglobal_environment or the + 'environment frame parameter). */ + for (tem = environment; + 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); @@ -1434,29 +1498,101 @@ 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; + Lisp_Object environment = Vglobal_environment; + /* 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; + } + } + } + + /* Find the environment in which to search the variable. */ + if (!NILP (frame)) + { + Lisp_Object local; + + CHECK_FRAME (frame); + frame = Fframe_with_environment (frame); + local = get_frame_param (XFRAME (frame), Qenvironment); + /* Use Vglobal_environment if there is no local environment. */ + if (!NILP (local)) + environment = local; + } + else if (!NILP (Vlocal_environment_variables)) + { + Lisp_Object local = get_frame_param (XFRAME (Fframe_with_environment (selected_frame)), + Qenvironment); + if (EQ (Vlocal_environment_variables, Qt) + && !NILP (local)) + environment = local; + else if (CONSP (local)) + { + for (scan = Vlocal_environment_variables; 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 */ + ) + { + environment = local; + break; + } + } + } + } + + for (scan = environment; 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); @@ -1467,26 +1603,35 @@ 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. + +If optional parameter FRAME is non-nil, then it should be a frame. If +that frame has its own set of environment variables, this function +will look up VARIABLE in there. + +Otherwise, this function searches `process-environment' for VARIABLE. +If it is not found there, then it continues the search in either +`global-environment' or the environment list of the selected frame, +depending on the value of `local-environment-variables'. */) + (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; @@ -1494,7 +1639,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; @@ -1634,17 +1779,17 @@ init_callproc () } void -set_process_environment () +set_global_environment () { register char **envp; - Vprocess_environment = Qnil; + Vglobal_environment = Qnil; #ifndef CANNOT_DUMP if (initialized) #endif for (envp = environ; *envp; envp++) - Vprocess_environment = Fcons (build_string (*envp), - Vprocess_environment); + Vglobal_environment = Fcons (build_string (*envp), + Vglobal_environment); } void @@ -1702,22 +1847,72 @@ If this variable is nil, then Emacs is unable to use a shared directory. */); 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. + DEFVAR_LISP ("global-environment", &Vglobal_environment, + doc: /* Global list of environment variables for subprocesses to inherit. Each element should be a string of the form ENVVARNAME=VALUE. + +The environment which Emacs inherits is placed in this variable when +Emacs starts. + +Some frames may have their own local list of environment variables in +their 'environment parameter, which may override this global list; see +`local-environment-variables' and `frame-with-environment'. See +`process-environment' for a way to modify an environment variable on +all frames. + 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. See `setenv' and `getenv'. */); + DEFVAR_LISP ("process-environment", &Vprocess_environment, + 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 `global-environment' +or the frame-local environments. (See `local-environment-variables' +and `frame-with-environment'.) 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. + +Non-ASCII characters are encoded according to the initial value of +`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); defsubr (&Sgetenv_internal); #endif defsubr (&Scall_process_region); + + DEFVAR_LISP ("local-environment-variables", &Vlocal_environment_variables, + doc: /* Enable or disable frame-local environment variables. +If set to t, `getenv', `setenv' and subprocess creation functions use +the local environment of the selected frame, ignoring +`global-environment'. + +If set to nil, Emacs uses `global-environment' and ignores the +frame-local environment. + +Otherwise, `local-environment-variables' should be a list of variable +names (represented by Lisp strings) to look up in the frame's +environment. The rest will come from `global-environment'. + +The frame-local environment is stored in the 'environment frame +parameter. See `frame-with-environment'. */); + Vlocal_environment_variables = Qt; } /* arch-tag: 769b8045-1df7-4d2b-8968-e3fb49017f95 |