changeset 83529:0d9e16eab053

Rework environment variable support. (Reported by Kalle Olavi Niemitalo and Noah Friedman.) * src/callproc.c (Vglobal_environment, Vlocal_environment_variables): Remove. (getenv_internal, child_setup): Don't look at global-environment or local-environment-variables. (Fgetenv_internal): Update docs. (set_initial_environment): Rename from set_global_environment. Store Emacs environment in initial frame parameter. (syms_of_callproc): Remove obsolete defvars. Update docs. * lisp/env.el (read-envvar-name): Remove reference to global-environment. (setenv-internal): New function. (setenv): Use it. Always set process-environment. Update docs. (getenv): Update docs. (environment): Rewrite for the new environment design. Update docs. * lisp/frame.el (frame-initialize): Copy the environment from the initial frame. * src/emacs.c (main): Call set_initial_environment, not set_global_environment. git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-569
author Karoly Lorentey <lorentey@elte.hu>
date Fri, 26 May 2006 17:37:25 +0000
parents a43b5a268ea1
children 46b1096093f5
files README.multi-tty lisp/env.el lisp/frame.el src/callproc.c src/emacs.c
diffstat 5 files changed, 149 insertions(+), 256 deletions(-) [+]
line wrap: on
line diff
--- a/README.multi-tty	Wed May 24 12:14:26 2006 +0000
+++ b/README.multi-tty	Fri May 26 17:37:25 2006 +0000
@@ -40,6 +40,7 @@
 Robert J. Chassell <bob@rattlesnake.com>
 Romain Francoise <romain@orebokech.com>
 Ami Fischman <ami@fischman.org>
+Noah Friedman <friedman@splode.com>
 Friedrich Delgado Friedrichs <friedel@nomaden.org>
 IRIE Tetsuya <irie@t.email.ne.jp>
 Yoshiaki Kasahara <kasahara@nc.kyushu-u.ac.jp>
--- a/lisp/env.el	Wed May 24 12:14:26 2006 +0000
+++ b/lisp/env.el	Fri May 26 17:37:25 2006 +0000
@@ -55,8 +55,7 @@
 				     (substring enventry 0
 						(string-match "=" enventry)))))
 			   (append process-environment
-				   (frame-parameter (frame-with-environment) 'environment)
-				   global-environment))
+				   (frame-parameter (frame-with-environment) 'environment)))
 		   nil mustmatch nil 'read-envvar-name-history))
 
 ;; History list for VALUE argument to setenv.
@@ -92,6 +91,40 @@
 		   start (+ (match-beginning 0) 1)))))
     string))
 
+
+(defun setenv-internal (env variable value keep-empty)
+  "Set VARIABLE to VALUE in ENV, adding empty entries if KEEP-EMPTY.
+Changes ENV by side-effect, and returns its new value."
+  (let ((pattern (concat "\\`" (regexp-quote variable) "\\(=\\|\\'\\)"))
+	(case-fold-search nil)
+	(scan env)
+	prev found)
+    ;; Handle deletions from the beginning of the list specially.
+    (if (and (null value)
+	     (not keep-empty)
+	     env
+	     (stringp (car env))
+	     (string-match pattern (car env)))
+	(cdr env)
+      ;; Try to find existing entry for VARIABLE in ENV.
+      (while (and scan (stringp (car scan)))
+	(when (string-match pattern (car scan))
+	  (if value
+	      (setcar scan (concat variable "=" value))
+	    (if keep-empty
+		(setcar scan variable)
+	      (setcdr prev (cdr scan))))
+	  (setq found t
+		scan nil))
+	(setq prev scan
+	      scan (cdr scan)))
+      (if (and (not found) (or value keep-empty))
+	  (cons (if value
+		    (concat variable "=" value)
+		  variable)
+		env)
+	env))))
+
 ;; Fixme: Should the environment be recoded if LC_CTYPE &c is set?
 
 (defun setenv (variable &optional value substitute-env-vars frame)
@@ -105,26 +138,23 @@
 This function always replaces environment variables in the new
 value when called interactively.
 
-If VARIABLE is set in `process-environment', then this function
-modifies its value there.  Otherwise, this function works by
-modifying either `global-environment' or the environment
-belonging to the selected frame, depending on the value of
-`local-environment-variables'.
-
 SUBSTITUTE-ENV-VARS, if non-nil, means to substitute environment
 variables in VALUE with `substitute-env-vars', which see.
 This is normally used only for interactive calls.
 
+If optional parameter FRAME is non-nil, this function modifies
+only the frame-local value of VARIABLE on FRAME, ignoring
+`process-environment'.  Note that frames on the same terminal
+device usually share their environment, so calling `setenv' on
+one of them affects the others as well.
+
+If FRAME is nil, `setenv' changes the global value of VARIABLE by
+modifying `process-environment'.  Note that the global value
+overrides any frame-local values.
+
 The return value is the new value of VARIABLE, or nil if
 it was removed from the environment.
 
-If optional parameter FRAME is non-nil, then it should be a a
-frame.  If the specified frame has its own set of environment
-variables, this function will modify VARIABLE in it.  Note that
-frames on the same terminal device usually share their
-environment, so calling `setenv' on one of them affects the
-others as well.
-
 As a special case, setting variable `TZ' calls `set-time-zone-rule' as
 a side-effect."
   (interactive
@@ -155,57 +185,16 @@
       (setq value (encode-coding-string value locale-coding-system)))
   (if (string-match "=" variable)
       (error "Environment variable name `%s' contains `='" variable))
-  (let ((pattern (concat "\\`" (regexp-quote variable) "\\(=\\|\\'\\)"))
-	(case-fold-search nil)
-	(frame-env (frame-parameter (frame-with-environment frame) 'environment))
-	(frame-forced (not frame))
-	(scan process-environment)
-	found)
+  (if (string-equal "TZ" variable)
+      (set-time-zone-rule value))
+  (if (null frame)
+      (setq process-environment (setenv-internal process-environment
+						 variable value t))
     (setq frame (frame-with-environment frame))
-    (if (string-equal "TZ" variable)
-	(set-time-zone-rule value))
-    (block nil
-      ;; Look for an existing entry for VARIABLE; try `process-environment' first.
-      (while (and scan (stringp (car scan)))
-	(when (string-match pattern (car scan))
-	  (if value
-	      (setcar scan (concat variable "=" value))
-	    ;; Leave unset variables in `process-environment',
-	    ;; otherwise the overridden value in `global-environment'
-	    ;; or frame-env would become unmasked.
-	    (setcar scan variable))
-	  (return value))
-	(setq scan (cdr scan)))
-
-      ;; Look in the local or global environment, whichever is relevant.
-      (let ((local-var-p (and frame-env
-			      (or frame-forced
-				  (eq t local-environment-variables)
-				  (member variable local-environment-variables)))))
-	(setq scan (if local-var-p
-		       frame-env
-		     global-environment))
-	(while scan
-	  (when (string-match pattern (car scan))
-	    (if value
-		(setcar scan (concat variable "=" value))
-	      (if local-var-p
-		  (set-frame-parameter frame 'environment
-				       (delq (car scan) frame-env))
-		(setq global-environment (delq (car scan) global-environment))))
-	    (return value))
-	  (setq scan (cdr scan)))
-
-	;; VARIABLE is not in any environment list.
-	(if value
-	    (if local-var-p
-		(set-frame-parameter frame 'environment
-				     (cons (concat variable "=" value)
-					   frame-env))
-	      (setq global-environment
-		    (cons (concat variable "=" value)
-			  global-environment))))
-	(return value)))))
+    (set-frame-parameter frame 'environment
+			 (setenv-internal (frame-parameter frame 'environment)
+					  variable value nil)))
+  value)
 
 (defun getenv (variable &optional frame)
   "Get the value of environment variable VARIABLE.
@@ -213,14 +202,12 @@
 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.
+frame.  This function will look up VARIABLE in its 'environment
+parameter.
 
 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.  If it is not found there, then it continues the search
+in the environment list of the selected frame."
   (interactive (list (read-envvar-name "Get environment variable: " t)))
   (let ((value (getenv-internal (if (multibyte-string-p variable)
 				    (encode-coding-string
@@ -239,47 +226,43 @@
 The returned list can not be used to change environment
 variables, only read them.  See `setenv' to do that.
 
-The list is constructed from elements of `process-environment',
-`global-environment' and the local environment list of the
-selected frame, as specified by `local-environment-variables'.
+The list is constructed by concatenating the elements of
+`process-environment' and the 'environment parameter of the
+selected frame, and removing duplicated and empty values.
 
 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'."
-  (let ((env (let ((local-env (frame-parameter (frame-with-environment)
-					       'environment)))
-	       (cond ((or (not local-environment-variables)
-			  (not local-env))
-		      (append process-environment global-environment nil))
-		     ((consp local-environment-variables)
-		      (let ((e (reverse process-environment)))
-			(dolist (entry local-environment-variables)
-			  (setq e (cons (getenv entry) e)))
-			(append (nreverse e) global-environment nil)))
-		     (t
-		      (append process-environment local-env nil)))))
-	scan seen)
-    ;; Find the first valid entry in env.
-    (while (and env (stringp (car env))
-		(or (not (string-match "=" (car env)))
-		    (member (substring (car env) 0 (string-match "=" (car env))) seen)))
-      (setq seen (cons (car env) seen)
-	    env (cdr env)))
-    (setq scan env)
-    (while (and (cdr scan) (stringp (cadr scan)))
-      (let* ((match (string-match "=" (cadr scan)))
-	     (name (substring (cadr scan) 0 match)))
-	(cond ((not match)
+  (let* ((env (append process-environment
+		      (frame-parameter (frame-with-environment)
+				       'environment)
+		      nil))
+	 (scan env)
+	 prev seen)
+    ;; Remove unset variables from the beginning of the list.
+    (while (and env
+		(or (not (stringp (car env)))
+		    (not (string-match "=" (car env)))))
+      (or (member (car env) seen)
+	  (setq seen (cons (car env) seen)))
+      (setq env (cdr env)
+	    scan env))
+    (let (name)
+      (while scan
+	(cond ((or (not (stringp (car scan)))
+		   (not (string-match "=" (car scan))))
 	       ;; Unset variable.
-	       (setq seen (cons name seen))
-	       (setcdr scan (cddr scan)))
-	      ((member name seen)
-	       ;; Duplicate variable.
-	       (setcdr scan (cddr scan)))
+	       (or (member (car scan) seen)
+		   (setq seen (cons (car scan) seen)))
+	       (setcdr prev (cdr scan)))
+	      ((member (setq name (substring (car scan) 0 (string-match "=" (car scan)))) seen)
+	       ;; Duplicated variable.
+	       (setcdr prev (cdr scan)))
 	      (t
 	       ;; New variable.
-	       (setq seen (cons name seen)
-		     scan (cdr scan))))))
+	       (setq seen (cons name seen))))
+	(setq prev scan
+	      scan (cdr scan))))
     env))
 
 (defmacro let-environment (varlist &rest body)
--- a/lisp/frame.el	Wed May 24 12:14:26 2006 +0000
+++ b/lisp/frame.el	Fri May 26 17:37:25 2006 +0000
@@ -238,6 +238,9 @@
 	      ;; because that would override explicit user resizing.
 	      (setq initial-frame-alist
 		    (frame-remove-geometry-params initial-frame-alist))))
+	;; Copy the environment of the Emacs process into the new frame.
+	(set-frame-parameter frame-initial-frame 'environment
+			     (frame-parameter terminal-frame 'environment))
 	;; At this point, we know that we have a frame open, so we
 	;; can delete the terminal frame.
 	(delete-frame terminal-frame)
--- a/src/callproc.c	Wed May 24 12:14:26 2006 +0000
+++ b/src/callproc.c	Fri May 26 17:37:25 2006 +0000
@@ -113,7 +113,6 @@
 
 Lisp_Object Vshell_file_name;
 
-Lisp_Object Vglobal_environment;
 Lisp_Object Vprocess_environment;
 
 #ifdef DOS_NT
@@ -134,9 +133,6 @@
    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.
@@ -1321,8 +1317,8 @@
     register char **new_env;
     char **p, **q;
     register int new_length;
-    Lisp_Object environment = Vglobal_environment;
-    Lisp_Object local;
+    Lisp_Object local = get_frame_param (XFRAME (Fframe_with_environment (selected_frame)),
+                                         Qenvironment);
 
     new_length = 0;
 
@@ -1331,20 +1327,7 @@
          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;
+    for (tem = local;
 	 CONSP (tem) && STRINGP (XCAR (tem));
 	 tem = XCDR (tem))
       new_length++;
@@ -1354,7 +1337,7 @@
 
     /* If we have a PWD envvar, pass one down,
        but with corrected value.  */
-    if (getenv ("PWD"))
+    if (egetenv ("PWD"))
       *new_env++ = pwd_var;
  
     /* Overrides.  */
@@ -1363,17 +1346,10 @@
 	 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;
+    /* Local part of environment.  */
+    for (tem = local;
          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;
@@ -1510,79 +1486,47 @@
      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))
+  if (NILP (frame))
     {
-      Lisp_Object entry = XCAR (scan);
-      if (STRINGP (entry)
-          && SBYTES (entry) >= varlen
+      /* 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)
+              /* 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 */
-          )
-        {
-          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;
+              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. */
-  if (!NILP (frame))
-    {
-      Lisp_Object local;
+  CHECK_FRAME (frame);
+  frame = Fframe_with_environment (frame);
 
-      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))
+  for (scan = get_frame_param (XFRAME (frame), Qenvironment);
+       CONSP (scan);
+       scan = XCDR (scan))
     {
       Lisp_Object entry;
 
@@ -1612,14 +1556,13 @@
 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.
+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.
 
-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'.  */)
+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;
 {
@@ -1766,8 +1709,8 @@
     {
       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");
@@ -1783,17 +1726,18 @@
 }
 
 void
-set_global_environment ()
+set_initial_environment ()
 {
   register char **envp;
-
-  Vglobal_environment = Qnil;
+  Lisp_Object env = Qnil;
 #ifndef CANNOT_DUMP
   if (initialized)
 #endif
-    for (envp = environ; *envp; envp++)
-      Vglobal_environment = Fcons (build_string (*envp),
-				    Vglobal_environment);
+    {
+      for (envp = environ; *envp; envp++)
+        env = Fcons (build_string (*envp), env);
+      store_frame_param (SELECTED_FRAME(), Qenvironment, env);
+    }
 }
 
 void
@@ -1851,37 +1795,16 @@
 This is used by `call-process-region'.  */);
   /* This variable is initialized in init_callproc.  */
 
-  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.
-
-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".
+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.
 
@@ -1900,23 +1823,6 @@
   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
--- a/src/emacs.c	Wed May 24 12:14:26 2006 +0000
+++ b/src/emacs.c	Fri May 26 17:37:25 2006 +0000
@@ -1518,7 +1518,7 @@
   /* egetenv is a pretty low-level facility, which may get called in
      many circumstances; it seems flimsy to put off initializing it
      until calling init_callproc.  */
-  set_global_environment ();
+  set_initial_environment ();
   /* AIX crashes are reported in system versions 3.2.3 and 3.2.4
      if this is not done.  Do it after set_global_environment so that we
      don't pollute Vglobal_environment.  */