Mercurial > emacs
comparison lisp/env.el @ 83425:c82829d08b89
Fix semantics of let-binding `process-environment'.
* lisp/env.el: Require cl for byte compilation. (For `block' and `return'.)
(read-envvar-name): Update for rename. Include `process-environment'
as well.
(setenv): Update for rename also handle `process-environment'. Update doc.
(getenv): Update doc.
(environment): New function.
(let-environment): New macro.
* lisp/font-lock.el (lisp-font-lock-keywords-2): Add `let-environment'.
* src/callproc.c (Vglobal_environment): New variable, taking over the
previous role of `Vprocess_environment', which is now something else.
(add_env): New function.
(child_setup): Use it.
(child_setup, getenv_internal): Rename Vprocess_environment to
Vglobal_environment. Handle the new Vprocess_environment.
(Fgetenv_internal, egetenv): Update doc.
(set_process_environment): Rename to `set_global_environment'. Rename
Vprocess_environment to Vglobal_environment.
(syms_of_callproc): Rename process-environment to global-environment,
add new process-environment, update docs.
* src/emacs.c (main): Call set_global_environment instead of
set_process_environment.
* fileio.c (Fread_file_name): Update comment.
git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-465
author | Karoly Lorentey <lorentey@elte.hu> |
---|---|
date | Thu, 29 Dec 2005 01:28:33 +0000 |
parents | bb2edc915032 |
children | 2afc49c9f0c0 |
comparison
equal
deleted
inserted
replaced
83424:e5cd70e447a8 | 83425:c82829d08b89 |
---|---|
33 ;; Note that the environment string `process-environment' is not | 33 ;; Note that the environment string `process-environment' is not |
34 ;; decoded, but the args of `setenv' and `getenv' are normally | 34 ;; decoded, but the args of `setenv' and `getenv' are normally |
35 ;; multibyte text and get coding conversion. | 35 ;; multibyte text and get coding conversion. |
36 | 36 |
37 ;;; Code: | 37 ;;; Code: |
38 | |
39 (eval-when-compile (require 'cl)) | |
38 | 40 |
39 ;; History list for environment variable names. | 41 ;; History list for environment variable names. |
40 (defvar read-envvar-name-history nil) | 42 (defvar read-envvar-name-history nil) |
41 | 43 |
42 (defun read-envvar-name (prompt &optional mustmatch) | 44 (defun read-envvar-name (prompt &optional mustmatch) |
50 (substring enventry 0 | 52 (substring enventry 0 |
51 (string-match "=" enventry)) | 53 (string-match "=" enventry)) |
52 locale-coding-system t) | 54 locale-coding-system t) |
53 (substring enventry 0 | 55 (substring enventry 0 |
54 (string-match "=" enventry))))) | 56 (string-match "=" enventry))))) |
55 (append (terminal-parameter nil 'environment) | 57 (append process-environment |
56 process-environment)) | 58 (terminal-parameter nil 'environment) |
59 global-environment)) | |
57 nil mustmatch nil 'read-envvar-name-history)) | 60 nil mustmatch nil 'read-envvar-name-history)) |
58 | 61 |
59 ;; History list for VALUE argument to setenv. | 62 ;; History list for VALUE argument to setenv. |
60 (defvar setenv-history nil) | 63 (defvar setenv-history nil) |
61 | 64 |
87 (t | 90 (t |
88 (setq string (replace-match "$" t t string) | 91 (setq string (replace-match "$" t t string) |
89 start (+ (match-beginning 0) 1))))) | 92 start (+ (match-beginning 0) 1))))) |
90 string)) | 93 string)) |
91 | 94 |
92 ;; Fixme: Should `process-environment' be recoded if LC_CTYPE &c is set? | 95 ;; Fixme: Should the environment be recoded if LC_CTYPE &c is set? |
93 | 96 |
94 (defun setenv (variable &optional value unset substitute-env-vars terminal) | 97 (defun setenv (variable &optional value unset substitute-env-vars terminal) |
95 "Set the value of the environment variable named VARIABLE to VALUE. | 98 "Set the value of the environment variable named VARIABLE to VALUE. |
96 VARIABLE should be a string. VALUE is optional; if not provided or | 99 VARIABLE should be a string. VALUE is optional; if not provided or |
97 nil, the environment variable VARIABLE will be removed. UNSET | 100 nil, the environment variable VARIABLE will be removed. UNSET |
104 Interactively, a prefix argument means to unset the variable. | 107 Interactively, a prefix argument means to unset the variable. |
105 Interactively, the current value (if any) of the variable | 108 Interactively, the current value (if any) of the variable |
106 appears at the front of the history list when you type in the new value. | 109 appears at the front of the history list when you type in the new value. |
107 Interactively, always replace environment variables in the new value. | 110 Interactively, always replace environment variables in the new value. |
108 | 111 |
112 If VARIABLE is set in `process-environment', then this function | |
113 modifies its value there. Otherwise, this function works by | |
114 modifying either `global-environment' or the environment | |
115 belonging to the terminal device of the selected frame, depending | |
116 on the value of `local-environment-variables'. | |
117 | |
109 If optional parameter TERMINAL is non-nil, then it should be a | 118 If optional parameter TERMINAL is non-nil, then it should be a |
110 terminal id or a frame. If the specified terminal device has its own | 119 terminal id or a frame. If the specified terminal device has its own |
111 set of environment variables, this function will modify VAR in it. | 120 set of environment variables, this function will modify VAR in it. |
112 | |
113 Otherwise, this function works by modifying either | |
114 `process-environment' or the environment belonging to the | |
115 terminal device of the selected frame, depending on the value of | |
116 `local-environment-variables'. | |
117 | 121 |
118 As a special case, setting variable `TZ' calls `set-time-zone-rule' as | 122 As a special case, setting variable `TZ' calls `set-time-zone-rule' as |
119 a side-effect." | 123 a side-effect." |
120 (interactive | 124 (interactive |
121 (if current-prefix-arg | 125 (if current-prefix-arg |
145 (setq variable (encode-coding-string variable locale-coding-system))) | 149 (setq variable (encode-coding-string variable locale-coding-system))) |
146 (if (and value (multibyte-string-p value)) | 150 (if (and value (multibyte-string-p value)) |
147 (setq value (encode-coding-string value locale-coding-system))) | 151 (setq value (encode-coding-string value locale-coding-system))) |
148 (if (string-match "=" variable) | 152 (if (string-match "=" variable) |
149 (error "Environment variable name `%s' contains `='" variable)) | 153 (error "Environment variable name `%s' contains `='" variable)) |
150 (let* ((pattern (concat "\\`" (regexp-quote (concat variable "=")))) | 154 (let ((pattern (concat "\\`" (regexp-quote variable) "\\(=\\|\\'\\)")) |
151 (case-fold-search nil) | 155 (case-fold-search nil) |
152 (local-var-p (and (terminal-parameter terminal 'environment) | 156 (terminal-env (terminal-parameter terminal 'environment)) |
153 (or terminal | 157 (scan process-environment) |
154 (eq t local-environment-variables) | 158 found) |
155 (member variable local-environment-variables)))) | |
156 (scan (if local-var-p | |
157 (terminal-parameter terminal 'environment) | |
158 process-environment)) | |
159 found) | |
160 (if (string-equal "TZ" variable) | 159 (if (string-equal "TZ" variable) |
161 (set-time-zone-rule value)) | 160 (set-time-zone-rule value)) |
162 (while scan | 161 (block nil |
163 (cond ((string-match pattern (car scan)) | 162 ;; Look for an existing entry for VARIABLE; try `process-environment' first. |
164 (setq found t) | 163 (while (and scan (stringp (car scan))) |
165 (if (eq nil value) | 164 (when (string-match pattern (car scan)) |
166 (if local-var-p | 165 (if value |
167 (set-terminal-parameter terminal 'environment | 166 (setcar scan (concat variable "=" value)) |
168 (delq (car scan) | 167 ;; Leave unset variables in `process-environment', |
169 (terminal-parameter terminal 'environment))) | 168 ;; otherwise the overridden value in `global-environment' |
170 (setq process-environment (delq (car scan) | 169 ;; or terminal-env would become unmasked. |
171 process-environment))) | 170 (setcar scan variable)) |
172 (setcar scan (concat variable "=" value))) | 171 (return value)) |
173 (setq scan nil))) | 172 (setq scan (cdr scan))) |
174 (setq scan (cdr scan))) | 173 |
175 (or found | 174 ;; Look in the local or global environment, whichever is relevant. |
175 (let ((local-var-p (and terminal-env | |
176 (or terminal | |
177 (eq t local-environment-variables) | |
178 (member variable local-environment-variables))))) | |
179 (setq scan (if local-var-p | |
180 terminal-env | |
181 global-environment)) | |
182 (while scan | |
183 (when (string-match pattern (car scan)) | |
184 (if value | |
185 (setcar scan (concat variable "=" value)) | |
186 (if local-var-p | |
187 (set-terminal-parameter terminal 'environment | |
188 (delq (car scan) terminal-env)) | |
189 (setq global-environment (delq (car scan) global-environment))) | |
190 (return value))) | |
191 (setq scan (cdr scan))) | |
192 | |
193 ;; VARIABLE is not in any environment list. | |
176 (if value | 194 (if value |
177 (if local-var-p | 195 (if local-var-p |
178 (set-terminal-parameter nil 'environment | 196 (set-terminal-parameter nil 'environment |
179 (cons (concat variable "=" value) | 197 (cons (concat variable "=" value) |
180 (terminal-parameter nil 'environment))) | 198 terminal-env)) |
181 (setq process-environment | 199 (setq global-environment |
182 (cons (concat variable "=" value) | 200 (cons (concat variable "=" value) |
183 process-environment)))))) | 201 global-environment)))) |
184 value) | 202 (return value))))) |
185 | 203 |
186 (defun getenv (variable &optional terminal) | 204 (defun getenv (variable &optional terminal) |
187 "Get the value of environment variable VARIABLE. | 205 "Get the value of environment variable VARIABLE. |
188 VARIABLE should be a string. Value is nil if VARIABLE is undefined in | 206 VARIABLE should be a string. Value is nil if VARIABLE is undefined in |
189 the environment. Otherwise, value is a string. | 207 the environment. Otherwise, value is a string. |
190 | 208 |
191 If optional parameter TERMINAL is non-nil, then it should be a | 209 If optional parameter TERMINAL is non-nil, then it should be a |
192 terminal id or a frame. If the specified terminal device has its own | 210 terminal id or a frame. If the specified terminal device has its own |
193 set of environment variables, this function will look up VAR in it. | 211 set of environment variables, this function will look up VARIABLE in |
194 | 212 it. |
195 Otherwise, if `local-environment-variables' specifies that VAR is a | 213 |
196 local environment variable, then this function consults the | 214 Otherwise, this function searches `process-environment' for VARIABLE. |
197 environment variables belonging to the terminal device of the selected | 215 If it was not found there, then it continues the search in either |
198 frame. | 216 `global-environment' or the local environment list of the current |
199 | 217 terminal device, depending on the value of |
200 Otherwise, the value of VAR will come from `process-environment'." | 218 `local-environment-variables'." |
201 (interactive (list (read-envvar-name "Get environment variable: " t))) | 219 (interactive (list (read-envvar-name "Get environment variable: " t))) |
202 (let ((value (getenv-internal (if (multibyte-string-p variable) | 220 (let ((value (getenv-internal (if (multibyte-string-p variable) |
203 (encode-coding-string | 221 (encode-coding-string |
204 variable locale-coding-system) | 222 variable locale-coding-system) |
205 variable)))) | 223 variable)))) |
207 (setq value (decode-coding-string value locale-coding-system))) | 225 (setq value (decode-coding-string value locale-coding-system))) |
208 (when (interactive-p) | 226 (when (interactive-p) |
209 (message "%s" (if value value "Not set"))) | 227 (message "%s" (if value value "Not set"))) |
210 value)) | 228 value)) |
211 | 229 |
230 (defun environment () | |
231 "Return a list of environment variables with their values. | |
232 Each entry in the list is a string of the form NAME=VALUE. | |
233 | |
234 The returned list can not be used to change environment | |
235 variables, only read them. See `setenv' to do that. | |
236 | |
237 The list is constructed from elements of `process-environment', | |
238 `global-environment' and the local environment list of the | |
239 current terminal, as specified by `local-environment-variables'. | |
240 | |
241 Non-ASCII characters are encoded according to the initial value of | |
242 `locale-coding-system', i.e. the elements must normally be decoded for use. | |
243 See `setenv' and `getenv'." | |
244 (let ((env (cond ((or (not local-environment-variables) | |
245 (not (terminal-parameter nil 'environment))) | |
246 (append process-environment global-environment nil)) | |
247 ((consp local-environment-variables) | |
248 (let ((e (reverse process-environment))) | |
249 (dolist (entry local-environment-variables) | |
250 (setq e (cons (getenv entry) e))) | |
251 (append (nreverse e) global-environment nil))) | |
252 (t | |
253 (append process-environment (terminal-parameter nil 'environment) nil)))) | |
254 scan seen) | |
255 ;; Find the first valid entry in env. | |
256 (while (and env (stringp (car env)) | |
257 (or (not (string-match "=" (car env))) | |
258 (member (substring (car env) 0 (string-match "=" (car env))) seen))) | |
259 (setq seen (cons (car env) seen) | |
260 env (cdr env))) | |
261 (setq scan env) | |
262 (while (and (cdr scan) (stringp (cadr scan))) | |
263 (let* ((match (string-match "=" (cadr scan))) | |
264 (name (substring (cadr scan) 0 match))) | |
265 (cond ((not match) | |
266 ;; Unset variable. | |
267 (setq seen (cons name seen)) | |
268 (setcdr scan (cddr scan))) | |
269 ((member name seen) | |
270 ;; Duplicate variable. | |
271 (setcdr scan (cddr scan))) | |
272 (t | |
273 ;; New variable. | |
274 (setq seen (cons name seen) | |
275 scan (cdr scan)))))) | |
276 env)) | |
277 | |
278 (defmacro let-environment (varlist &rest body) | |
279 "Evaluate BODY with environment variables set according to VARLIST. | |
280 The environment variables are then restored to their previous | |
281 values. | |
282 The value of the last form in BODY is returned. | |
283 | |
284 Each element of VARLIST is either a string (which variable is | |
285 then removed from the environment), or a list (NAME | |
286 VALUEFORM) (which sets NAME to the value of VALUEFORM, a string). | |
287 All the VALUEFORMs are evaluated before any variables are set." | |
288 (declare (indent 2)) | |
289 (let ((old-env (make-symbol "old-env")) | |
290 (name (make-symbol "name")) | |
291 (value (make-symbol "value")) | |
292 (entry (make-symbol "entry")) | |
293 (frame (make-symbol "frame"))) | |
294 `(let ((,frame (selected-frame)) | |
295 ,old-env) | |
296 ;; Evaluate VALUEFORMs and replace them in VARLIST with their values. | |
297 (dolist (,entry ,varlist) | |
298 (unless (stringp ,entry) | |
299 (if (cdr (cdr ,entry)) | |
300 (error "`let-environment' bindings can have only one value-form")) | |
301 (setcdr ,entry (eval (cadr ,entry))))) | |
302 ;; Set the variables. | |
303 (dolist (,entry ,varlist) | |
304 (let ((,name (if (stringp ,entry) ,entry (car ,entry))) | |
305 (,value (if (consp ,entry) (cdr ,entry)))) | |
306 (setq ,old-env (cons (cons ,name (getenv ,name)) ,old-env)) | |
307 (setenv ,name ,value))) | |
308 (unwind-protect | |
309 (progn ,@body) | |
310 ;; Restore old values. | |
311 (with-selected-frame (if (frame-live-p ,frame) | |
312 ,frame | |
313 (selected-frame)) | |
314 (dolist (,entry ,old-env) | |
315 (setenv (car ,entry) (cdr ,entry)))))))) | |
316 | |
212 (provide 'env) | 317 (provide 'env) |
213 | 318 |
214 ;;; arch-tag: b7d6a8f7-bc81-46db-8e39-8d721d4ed0b8 | 319 ;;; arch-tag: b7d6a8f7-bc81-46db-8e39-8d721d4ed0b8 |
215 ;;; env.el ends here | 320 ;;; env.el ends here |