Mercurial > emacs
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 |