comparison lisp/env.el @ 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 1321f6cfb389
children b8d9a391daf3
comparison
equal deleted inserted replaced
83528:a43b5a268ea1 83529:0d9e16eab053
53 (string-match "=" enventry)) 53 (string-match "=" enventry))
54 locale-coding-system t) 54 locale-coding-system t)
55 (substring enventry 0 55 (substring enventry 0
56 (string-match "=" enventry))))) 56 (string-match "=" enventry)))))
57 (append process-environment 57 (append process-environment
58 (frame-parameter (frame-with-environment) 'environment) 58 (frame-parameter (frame-with-environment) 'environment)))
59 global-environment))
60 nil mustmatch nil 'read-envvar-name-history)) 59 nil mustmatch nil 'read-envvar-name-history))
61 60
62 ;; History list for VALUE argument to setenv. 61 ;; History list for VALUE argument to setenv.
63 (defvar setenv-history nil) 62 (defvar setenv-history nil)
64 63
90 (t 89 (t
91 (setq string (replace-match "$" t t string) 90 (setq string (replace-match "$" t t string)
92 start (+ (match-beginning 0) 1))))) 91 start (+ (match-beginning 0) 1)))))
93 string)) 92 string))
94 93
94
95 (defun setenv-internal (env variable value keep-empty)
96 "Set VARIABLE to VALUE in ENV, adding empty entries if KEEP-EMPTY.
97 Changes ENV by side-effect, and returns its new value."
98 (let ((pattern (concat "\\`" (regexp-quote variable) "\\(=\\|\\'\\)"))
99 (case-fold-search nil)
100 (scan env)
101 prev found)
102 ;; Handle deletions from the beginning of the list specially.
103 (if (and (null value)
104 (not keep-empty)
105 env
106 (stringp (car env))
107 (string-match pattern (car env)))
108 (cdr env)
109 ;; Try to find existing entry for VARIABLE in ENV.
110 (while (and scan (stringp (car scan)))
111 (when (string-match pattern (car scan))
112 (if value
113 (setcar scan (concat variable "=" value))
114 (if keep-empty
115 (setcar scan variable)
116 (setcdr prev (cdr scan))))
117 (setq found t
118 scan nil))
119 (setq prev scan
120 scan (cdr scan)))
121 (if (and (not found) (or value keep-empty))
122 (cons (if value
123 (concat variable "=" value)
124 variable)
125 env)
126 env))))
127
95 ;; Fixme: Should the environment be recoded if LC_CTYPE &c is set? 128 ;; Fixme: Should the environment be recoded if LC_CTYPE &c is set?
96 129
97 (defun setenv (variable &optional value substitute-env-vars frame) 130 (defun setenv (variable &optional value substitute-env-vars frame)
98 "Set the value of the environment variable named VARIABLE to VALUE. 131 "Set the value of the environment variable named VARIABLE to VALUE.
99 VARIABLE should be a string. VALUE is optional; if not provided or 132 VARIABLE should be a string. VALUE is optional; if not provided or
103 otherwise the current value (if any) of the variable appears at 136 otherwise the current value (if any) of the variable appears at
104 the front of the history list when you type in the new value. 137 the front of the history list when you type in the new value.
105 This function always replaces environment variables in the new 138 This function always replaces environment variables in the new
106 value when called interactively. 139 value when called interactively.
107 140
108 If VARIABLE is set in `process-environment', then this function
109 modifies its value there. Otherwise, this function works by
110 modifying either `global-environment' or the environment
111 belonging to the selected frame, depending on the value of
112 `local-environment-variables'.
113
114 SUBSTITUTE-ENV-VARS, if non-nil, means to substitute environment 141 SUBSTITUTE-ENV-VARS, if non-nil, means to substitute environment
115 variables in VALUE with `substitute-env-vars', which see. 142 variables in VALUE with `substitute-env-vars', which see.
116 This is normally used only for interactive calls. 143 This is normally used only for interactive calls.
117 144
145 If optional parameter FRAME is non-nil, this function modifies
146 only the frame-local value of VARIABLE on FRAME, ignoring
147 `process-environment'. Note that frames on the same terminal
148 device usually share their environment, so calling `setenv' on
149 one of them affects the others as well.
150
151 If FRAME is nil, `setenv' changes the global value of VARIABLE by
152 modifying `process-environment'. Note that the global value
153 overrides any frame-local values.
154
118 The return value is the new value of VARIABLE, or nil if 155 The return value is the new value of VARIABLE, or nil if
119 it was removed from the environment. 156 it was removed from the environment.
120
121 If optional parameter FRAME is non-nil, then it should be a a
122 frame. If the specified frame has its own set of environment
123 variables, this function will modify VARIABLE in it. Note that
124 frames on the same terminal device usually share their
125 environment, so calling `setenv' on one of them affects the
126 others as well.
127 157
128 As a special case, setting variable `TZ' calls `set-time-zone-rule' as 158 As a special case, setting variable `TZ' calls `set-time-zone-rule' as
129 a side-effect." 159 a side-effect."
130 (interactive 160 (interactive
131 (if current-prefix-arg 161 (if current-prefix-arg
153 (setq variable (encode-coding-string variable locale-coding-system))) 183 (setq variable (encode-coding-string variable locale-coding-system)))
154 (if (and value (multibyte-string-p value)) 184 (if (and value (multibyte-string-p value))
155 (setq value (encode-coding-string value locale-coding-system))) 185 (setq value (encode-coding-string value locale-coding-system)))
156 (if (string-match "=" variable) 186 (if (string-match "=" variable)
157 (error "Environment variable name `%s' contains `='" variable)) 187 (error "Environment variable name `%s' contains `='" variable))
158 (let ((pattern (concat "\\`" (regexp-quote variable) "\\(=\\|\\'\\)")) 188 (if (string-equal "TZ" variable)
159 (case-fold-search nil) 189 (set-time-zone-rule value))
160 (frame-env (frame-parameter (frame-with-environment frame) 'environment)) 190 (if (null frame)
161 (frame-forced (not frame)) 191 (setq process-environment (setenv-internal process-environment
162 (scan process-environment) 192 variable value t))
163 found)
164 (setq frame (frame-with-environment frame)) 193 (setq frame (frame-with-environment frame))
165 (if (string-equal "TZ" variable) 194 (set-frame-parameter frame 'environment
166 (set-time-zone-rule value)) 195 (setenv-internal (frame-parameter frame 'environment)
167 (block nil 196 variable value nil)))
168 ;; Look for an existing entry for VARIABLE; try `process-environment' first. 197 value)
169 (while (and scan (stringp (car scan)))
170 (when (string-match pattern (car scan))
171 (if value
172 (setcar scan (concat variable "=" value))
173 ;; Leave unset variables in `process-environment',
174 ;; otherwise the overridden value in `global-environment'
175 ;; or frame-env would become unmasked.
176 (setcar scan variable))
177 (return value))
178 (setq scan (cdr scan)))
179
180 ;; Look in the local or global environment, whichever is relevant.
181 (let ((local-var-p (and frame-env
182 (or frame-forced
183 (eq t local-environment-variables)
184 (member variable local-environment-variables)))))
185 (setq scan (if local-var-p
186 frame-env
187 global-environment))
188 (while scan
189 (when (string-match pattern (car scan))
190 (if value
191 (setcar scan (concat variable "=" value))
192 (if local-var-p
193 (set-frame-parameter frame 'environment
194 (delq (car scan) frame-env))
195 (setq global-environment (delq (car scan) global-environment))))
196 (return value))
197 (setq scan (cdr scan)))
198
199 ;; VARIABLE is not in any environment list.
200 (if value
201 (if local-var-p
202 (set-frame-parameter frame 'environment
203 (cons (concat variable "=" value)
204 frame-env))
205 (setq global-environment
206 (cons (concat variable "=" value)
207 global-environment))))
208 (return value)))))
209 198
210 (defun getenv (variable &optional frame) 199 (defun getenv (variable &optional frame)
211 "Get the value of environment variable VARIABLE. 200 "Get the value of environment variable VARIABLE.
212 VARIABLE should be a string. Value is nil if VARIABLE is undefined in 201 VARIABLE should be a string. Value is nil if VARIABLE is undefined in
213 the environment. Otherwise, value is a string. 202 the environment. Otherwise, value is a string.
214 203
215 If optional parameter FRAME is non-nil, then it should be a 204 If optional parameter FRAME is non-nil, then it should be a
216 frame. If that frame has its own set of environment variables, 205 frame. This function will look up VARIABLE in its 'environment
217 this function will look up VARIABLE in there. 206 parameter.
218 207
219 Otherwise, this function searches `process-environment' for 208 Otherwise, this function searches `process-environment' for
220 VARIABLE. If it is not found there, then it continues the 209 VARIABLE. If it is not found there, then it continues the search
221 search in either `global-environment' or the environment list of 210 in the environment list of the selected frame."
222 the selected frame, depending on the value of
223 `local-environment-variables'."
224 (interactive (list (read-envvar-name "Get environment variable: " t))) 211 (interactive (list (read-envvar-name "Get environment variable: " t)))
225 (let ((value (getenv-internal (if (multibyte-string-p variable) 212 (let ((value (getenv-internal (if (multibyte-string-p variable)
226 (encode-coding-string 213 (encode-coding-string
227 variable locale-coding-system) 214 variable locale-coding-system)
228 variable)))) 215 variable))))
237 Each entry in the list is a string of the form NAME=VALUE. 224 Each entry in the list is a string of the form NAME=VALUE.
238 225
239 The returned list can not be used to change environment 226 The returned list can not be used to change environment
240 variables, only read them. See `setenv' to do that. 227 variables, only read them. See `setenv' to do that.
241 228
242 The list is constructed from elements of `process-environment', 229 The list is constructed by concatenating the elements of
243 `global-environment' and the local environment list of the 230 `process-environment' and the 'environment parameter of the
244 selected frame, as specified by `local-environment-variables'. 231 selected frame, and removing duplicated and empty values.
245 232
246 Non-ASCII characters are encoded according to the initial value of 233 Non-ASCII characters are encoded according to the initial value of
247 `locale-coding-system', i.e. the elements must normally be decoded for use. 234 `locale-coding-system', i.e. the elements must normally be decoded for use.
248 See `setenv' and `getenv'." 235 See `setenv' and `getenv'."
249 (let ((env (let ((local-env (frame-parameter (frame-with-environment) 236 (let* ((env (append process-environment
250 'environment))) 237 (frame-parameter (frame-with-environment)
251 (cond ((or (not local-environment-variables) 238 'environment)
252 (not local-env)) 239 nil))
253 (append process-environment global-environment nil)) 240 (scan env)
254 ((consp local-environment-variables) 241 prev seen)
255 (let ((e (reverse process-environment))) 242 ;; Remove unset variables from the beginning of the list.
256 (dolist (entry local-environment-variables) 243 (while (and env
257 (setq e (cons (getenv entry) e))) 244 (or (not (stringp (car env)))
258 (append (nreverse e) global-environment nil))) 245 (not (string-match "=" (car env)))))
259 (t 246 (or (member (car env) seen)
260 (append process-environment local-env nil))))) 247 (setq seen (cons (car env) seen)))
261 scan seen) 248 (setq env (cdr env)
262 ;; Find the first valid entry in env. 249 scan env))
263 (while (and env (stringp (car env)) 250 (let (name)
264 (or (not (string-match "=" (car env))) 251 (while scan
265 (member (substring (car env) 0 (string-match "=" (car env))) seen))) 252 (cond ((or (not (stringp (car scan)))
266 (setq seen (cons (car env) seen) 253 (not (string-match "=" (car scan))))
267 env (cdr env)))
268 (setq scan env)
269 (while (and (cdr scan) (stringp (cadr scan)))
270 (let* ((match (string-match "=" (cadr scan)))
271 (name (substring (cadr scan) 0 match)))
272 (cond ((not match)
273 ;; Unset variable. 254 ;; Unset variable.
274 (setq seen (cons name seen)) 255 (or (member (car scan) seen)
275 (setcdr scan (cddr scan))) 256 (setq seen (cons (car scan) seen)))
276 ((member name seen) 257 (setcdr prev (cdr scan)))
277 ;; Duplicate variable. 258 ((member (setq name (substring (car scan) 0 (string-match "=" (car scan)))) seen)
278 (setcdr scan (cddr scan))) 259 ;; Duplicated variable.
260 (setcdr prev (cdr scan)))
279 (t 261 (t
280 ;; New variable. 262 ;; New variable.
281 (setq seen (cons name seen) 263 (setq seen (cons name seen))))
282 scan (cdr scan)))))) 264 (setq prev scan
265 scan (cdr scan))))
283 env)) 266 env))
284 267
285 (defmacro let-environment (varlist &rest body) 268 (defmacro let-environment (varlist &rest body)
286 "Evaluate BODY with environment variables set according to VARLIST. 269 "Evaluate BODY with environment variables set according to VARLIST.
287 The environment variables are then restored to their previous 270 The environment variables are then restored to their previous