Mercurial > hg > xemacs-beta
annotate lisp/process.el @ 4610:38e8af61f38d
Check if env vars are encodable by native coding system, #'setenv
2009-02-11 Aidan Kehoe <kehoea@parhasard.net>
* process.el (setenv):
Check whether the environment variable and value can be encoded by
the native coding system, error if not, as does GNU Emacs (but our
implementation is different).
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Wed, 11 Feb 2009 12:14:28 +0000 |
parents | 466ad8ad5f13 |
children | 9c97a5a8c241 |
rev | line source |
---|---|
428 | 1 ;;; process.el --- commands for subprocesses; split out of simple.el |
2 | |
3 ;; Copyright (C) 1985-7, 1993,4, 1997 Free Software Foundation, Inc. | |
853 | 4 ;; Copyright (C) 1995, 2000, 2001, 2002 Ben Wing. |
428 | 5 |
6 ;; Author: Ben Wing | |
7 ;; Maintainer: XEmacs Development Team | |
8 ;; Keywords: internal, processes, dumped | |
9 | |
10 ;; This file is part of XEmacs. | |
11 | |
12 ;; XEmacs is free software; you can redistribute it and/or modify it | |
13 ;; under the terms of the GNU General Public License as published by | |
14 ;; the Free Software Foundation; either version 2, or (at your option) | |
15 ;; any later version. | |
16 | |
17 ;; XEmacs is distributed in the hope that it will be useful, but | |
18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
20 ;; General Public License for more details. | |
21 | |
22 ;; You should have received a copy of the GNU General Public License | |
444 | 23 ;; along with XEmacs; see the file COPYING. If not, write to the |
428 | 24 ;; Free Software Foundation, 59 Temple Place - Suite 330, |
25 ;; Boston, MA 02111-1307, USA. | |
26 | |
771 | 27 ;;; Synched up with: FSF 19.30, except for setenv/getenv (synched with FSF |
4327
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
28 ;;; 21.2.1). |
428 | 29 |
442 | 30 ;;; Authorship: |
31 | |
32 ;; Created 1995 by Ben Wing during Mule work -- some commands split out | |
33 ;; of simple.el and wrappers of *-internal functions created so they could | |
34 ;; be redefined in a Mule world. | |
35 ;; Lisp definition of call-process-internal added Mar. 2000 by Ben Wing. | |
36 | |
428 | 37 ;;; Commentary: |
38 | |
39 ;; This file is dumped with XEmacs. | |
40 | |
41 ;;; Code: | |
42 | |
43 | |
44 (defgroup processes nil | |
45 "Process, subshell, compilation, and job control support." | |
46 :group 'external | |
47 :group 'development) | |
48 | |
49 (defgroup processes-basics nil | |
50 "Basic stuff dealing with processes." | |
51 :group 'processes) | |
52 | |
53 (defgroup execute nil | |
54 "Executing external commands." | |
55 :group 'processes) | |
56 | |
611 | 57 ;; This may be changed to "/c" in win32-native.el. |
428 | 58 |
59 (defvar shell-command-switch "-c" | |
60 "Switch used to have the shell execute its command line argument.") | |
61 | |
62 (defun start-process-shell-command (name buffer &rest args) | |
63 "Start a program in a subprocess. Return the process object for it. | |
64 NAME is name for process. It is modified if necessary to make it unique. | |
65 BUFFER is the buffer or (buffer-name) to associate with the process. | |
66 Process output goes at end of that buffer, unless you specify | |
67 an output stream or filter function to handle the output. | |
68 BUFFER may be also nil, meaning that this process is not associated | |
2473 | 69 with any buffer. |
70 Variables `shell-file-name' and `shell-command-switch' are used to | |
71 start the process. | |
428 | 72 Remaining arguments are the arguments for the command. |
73 Wildcards and redirection are handled as usual in the shell." | |
74 ;; We used to use `exec' to replace the shell with the command, | |
75 ;; but that failed to handle (...) and semicolon, etc. | |
76 (start-process name buffer shell-file-name shell-command-switch | |
77 (mapconcat #'identity args " "))) | |
78 | |
862 | 79 (defun process-synchronize-point (proc) |
80 "Set the point(s) in buffer and stderr-buffer according to the process mark." | |
81 ;; We need this because the documentation says to insert *BEFORE* point, | |
82 ;; but we end up inserting after because only the process mark moves | |
83 ;; forward, not point. We synchronize after every place output might | |
84 ;; happen, in sentinels, and in an unwind-protect, to make *SURE* that | |
85 ;; point is correct. (We could do this more easily and perhaps more | |
86 ;; safely using a process filter, but that would create a LOT of garbage | |
87 ;; since all the data would get sent in strings.) We make this a separate | |
88 ;; function, not an flet, due to dynamic binding problems -- the flet may | |
89 ;; not still be in scope when the sentinel is called. | |
90 (let ((pb (process-buffer proc)) | |
91 (pm (process-mark proc))) | |
92 (if (and pb (buffer-live-p pb) (marker-buffer pm)) | |
93 (goto-char pm pb)) | |
94 (if (process-has-separate-stderr-p proc) | |
95 (let ((pseb (process-stderr-buffer proc)) | |
96 (psem (process-stderr-mark proc))) | |
97 (if (and pseb (not (eq pb pseb)) | |
98 (buffer-live-p pseb) | |
99 (marker-buffer psem)) | |
100 (goto-char psem pseb)))))) | |
101 | |
853 | 102 (defun call-process-internal (program &optional infile buffer display |
103 &rest args) | |
104 "Internal function to call PROGRAM synchronously in separate process. | |
105 Lisp callers should use `call-process' or `call-process-region'. | |
106 | |
442 | 107 The program's input comes from file INFILE (nil means `/dev/null'). |
853 | 108 XEmacs feature: INFILE can also be a list of (BUFFER [START [END]]), i.e. |
109 a list of one to three elements, consisting of a buffer and optionally | |
110 a start position or start and end position. In this case, input comes | |
111 from the buffer, starting from START (defaults to the beginning of the | |
112 buffer) and ending at END (defaults to the end of the buffer). | |
113 | |
442 | 114 Insert output in BUFFER before point; t means current buffer; |
115 nil for BUFFER means discard it; 0 means discard and don't wait. | |
853 | 116 If BUFFER is a string, then find or create a buffer with that name, |
117 then insert the output in that buffer, before point. | |
442 | 118 BUFFER can also have the form (REAL-BUFFER STDERR-FILE); in that case, |
119 REAL-BUFFER says what to do with standard output, as above, | |
120 while STDERR-FILE says what to do with standard error in the child. | |
121 STDERR-FILE may be nil (discard standard error output), | |
853 | 122 t (mix it with ordinary output), a file name string, or (XEmacs feature) |
123 a buffer object. If STDERR-FILE is a buffer object (but not the name of | |
124 a buffer, since that would be interpreted as a file), the standard error | |
125 output will be inserted into the buffer before point. | |
442 | 126 |
127 Fourth arg DISPLAY non-nil means redisplay buffer as output is inserted. | |
128 Remaining arguments are strings passed as command arguments to PROGRAM. | |
129 | |
853 | 130 If BUFFER is 0, returns immediately with value nil. |
131 Otherwise waits for PROGRAM to terminate and returns a numeric exit status | |
132 or a signal description string. If you quit, the process is first killed | |
133 with SIGINT, then with SIGKILL if you quit again before the process exits. | |
134 | |
135 Coding systems for the process are the same as for `start-process-internal'." | |
136 (let (proc inbuf errbuf kill-inbuf kill-errbuf no-wait start end) | |
137 ;; first set up an unwind-protect to clean everything up. this will: | |
138 ;; | |
139 ;; -- kill the process. (when we're not waiting for it to finish, we | |
140 ;; set PROC to nil when we're ready to exit so this doesn't happen -- | |
141 ;; if we're interrupted before we're ready to exit, we should still | |
142 ;; kill the process) | |
143 ;; -- kill temporary buffers created to handle I/O to or from a file. | |
144 ;; KILL-INBUF/KILL-ERRBUF tell us if we should do so. | |
145 ;; | |
146 ;; note that we need to be *very* careful in this code to handle C-g | |
147 ;; at any point. | |
148 (unwind-protect | |
149 (progn | |
150 ;; first handle INFILE. | |
151 (cond ((stringp infile) | |
152 (setq infile (expand-file-name infile)) | |
153 (setq kill-inbuf t) | |
154 (setq inbuf (generate-new-buffer "*call-process*")) | |
155 ;; transfer the exact contents of the file to the process. | |
156 ;; we do that by reading in and writing out in | |
157 ;; binary. #### is this even correct? should we be doing | |
158 ;; the same thing with stderr? if so we'd need a way of | |
159 ;; controlling the stderr coding system separate from | |
160 ;; everything else. | |
161 (with-current-buffer inbuf | |
162 ;; Make sure this works with jka-compr | |
163 (let ((file-name-handler-alist nil)) | |
164 (insert-file-contents-internal infile nil nil nil nil | |
165 'binary)) | |
166 (setq start (point-min) end (point-max)))) | |
167 ((consp infile) | |
168 (setq inbuf (get-buffer (car infile))) | |
169 (setq start (or (nth 1 infile) (point-min inbuf))) | |
170 (setq end (or (nth 2 infile) (point-max inbuf)))) | |
171 ((null infile) nil) | |
172 (t | |
173 (error 'wrong-type-argument | |
174 "Must be filename or (BUFFER [START [END]])" | |
175 infile))) | |
176 ;; now handle BUFFER | |
177 (let ((stderr (if (consp buffer) (second buffer) t))) | |
178 (if (consp buffer) (setq buffer (car buffer))) | |
179 (setq buffer | |
180 (cond ((null buffer) nil) | |
181 ((eq buffer t) (current-buffer)) | |
182 ;; use integerp for compatibility with existing | |
183 ;; call-process rmsism. | |
184 ((integerp buffer) (setq no-wait t) nil) | |
185 (t (get-buffer-create buffer)))) | |
186 (when (and stderr (not (eq t stderr))) | |
187 ;; both ERRBUF and STDERR being non-nil indicates to the | |
188 ;; code below that STDERR is a file and we should write | |
189 ;; ERRBUF to it; so clear out STDERR if we don't want this. | |
190 (if (bufferp stderr) (setq errbuf stderr stderr nil) | |
442 | 191 (setq stderr (expand-file-name stderr)) |
853 | 192 (setq kill-errbuf t) |
193 (setq errbuf (generate-new-buffer "*call-process*")))) | |
194 ;; now start process. using a pty causes all sorts of | |
195 ;; weirdness, at least under cygwin, when there's input. #### i | |
196 ;; don't know what's going wrong and whether it's a cygwin-only | |
197 ;; problem. suffice to say that there were NO pty connections | |
198 ;; in the old version. | |
199 (let ((process-connection-type nil)) | |
442 | 200 (setq proc |
201 (apply 'start-process-internal "*call-process*" | |
853 | 202 (if (eq t stderr) buffer (list buffer errbuf)) |
203 program args))) | |
204 ;; see comment above where the data was read from the file. | |
205 (if kill-inbuf | |
206 (set-process-output-coding-system proc 'binary)) | |
207 ;; point mark/stderr-mark at the right place (by default it's | |
208 ;; end of buffer). | |
209 (if buffer | |
210 (set-marker (process-mark proc) (point buffer) buffer)) | |
211 (if errbuf | |
212 (set-marker (process-stderr-mark proc) (point errbuf) errbuf)) | |
859 | 213 ;; now do I/O, very carefully! the unwind-protect makes sure |
214 ;; to clear out the sentinel, since it does a `throw', which | |
215 ;; would have no catch (or writes to a file -- we only want | |
216 ;; this on normal exit) | |
862 | 217 (unwind-protect |
218 ;; if not NO-WAIT, set a sentinel to return the exit | |
219 ;; status. it will throw to this catch so we can exit | |
220 ;; properly. | |
221 (catch 'call-process-done | |
222 (set-process-sentinel | |
223 proc | |
224 (cond | |
225 ((and no-wait errbuf stderr) | |
226 ;; we're trying really really hard to emulate | |
227 ;; the old call-process, which would save the | |
228 ;; stderr to a file even if discarding output. so | |
229 ;; we set a sentinel to save the output when | |
230 ;; we finish. | |
231 ;; | |
232 ;; #### not clear if we should be doing this. | |
233 ;; | |
234 ;; NOTE NOTE NOTE: Due to the total bogosity of | |
235 ;; dynamic scoping, and the lack of closures, we | |
236 ;; have to be careful how we write the first | |
237 ;; sentinel below since it may be executed after | |
238 ;; this function has returned -- thus we fake a | |
239 ;; closure. (This doesn't apply to the second one, | |
240 ;; which only gets executed within the | |
241 ;; unwind-protect.) | |
242 `(lambda (proc status) | |
243 (set-process-sentinel proc nil) | |
244 (process-synchronize-point proc) | |
245 (with-current-buffer ,errbuf | |
246 (write-region-internal | |
247 1 (1+ (buffer-size)) | |
248 ,stderr | |
249 nil 'major-rms-kludge-city nil | |
250 coding-system-for-write)) | |
251 (kill-buffer ,errbuf))) | |
252 (no-wait nil) | |
253 (t | |
254 ;; normal sentinel: maybe write out stderr and return | |
255 ;; status. | |
256 #'(lambda (proc status) | |
257 (process-synchronize-point proc) | |
258 (when (and errbuf stderr) | |
259 (with-current-buffer errbuf | |
260 (write-region-internal | |
261 1 (1+ (buffer-size)) stderr | |
262 nil 'major-rms-kludge-city nil | |
263 coding-system-for-write))) | |
264 (cond ((eq 'exit (process-status proc)) | |
265 (set-process-sentinel proc nil) | |
266 (throw 'call-process-done | |
267 (process-exit-status proc))) | |
268 ((eq 'signal (process-status proc)) | |
269 (set-process-sentinel proc nil) | |
270 (throw 'call-process-done status))))))) | |
271 (if (not no-wait) | |
272 ;; we're waiting. send the input and loop forever, | |
273 ;; handling process output and maybe redisplaying. | |
274 ;; exit happens through the sentinel or C-g. if | |
275 ;; C-g, send SIGINT the first time, EOF if not | |
276 ;; already done so (might make the process exit), | |
277 ;; and keep waiting. Another C-g will exit the | |
278 ;; whole function, and the unwind-protect will | |
279 ;; kill the process. (Hence the documented semantics | |
280 ;; of SIGINT/SIGKILL.) | |
281 (let (eof-sent) | |
282 (condition-case nil | |
283 (progn | |
284 (when inbuf | |
285 (process-send-region proc start end inbuf)) | |
286 (process-send-eof proc) | |
287 (setq eof-sent t) | |
288 (while t | |
289 (accept-process-output proc) | |
290 (process-synchronize-point proc) | |
291 (if display (sit-for 0)))) | |
292 (quit | |
293 (process-send-signal 'SIGINT proc) | |
294 (unless eof-sent | |
295 (process-send-eof proc)) | |
296 (while t | |
297 (accept-process-output proc) | |
298 (process-synchronize-point proc) | |
299 (if display (sit-for 0)))))) | |
300 ;; discard and no wait: send the input, set PROC | |
301 ;; and ERRBUF to nil so that the unwind-protect | |
302 ;; forms don't erase the sentinel, kill the process, | |
303 ;; or kill ERRBUF (the sentinel does that), and exit. | |
304 (when inbuf | |
305 (process-send-region proc start end inbuf)) | |
306 (process-send-eof proc) | |
307 (setq errbuf nil) | |
308 (setq proc nil))) | |
309 ;; inner unwind-protect, once we're ready to do I/O. | |
310 (when proc | |
311 (set-process-sentinel proc nil) | |
312 (process-synchronize-point proc))))) | |
859 | 313 ;; outer unwind-protect forms, to make sure we always clean up. |
853 | 314 (if (and inbuf kill-inbuf) (kill-buffer inbuf)) |
315 (if (and errbuf kill-errbuf) (kill-buffer errbuf)) | |
316 (condition-case nil | |
317 (if (and proc (process-live-p proc)) (kill-process proc)) | |
318 (error nil))))) | |
428 | 319 |
320 | |
321 (defun shell-command (command &optional output-buffer) | |
322 "Execute string COMMAND in inferior shell; display output, if any. | |
323 | |
324 If COMMAND ends in ampersand, execute it asynchronously. | |
325 The output appears in the buffer `*Async Shell Command*'. | |
326 That buffer is in shell mode. | |
327 | |
328 Otherwise, COMMAND is executed synchronously. The output appears in the | |
329 buffer `*Shell Command Output*'. | |
330 If the output is one line, it is displayed in the echo area *as well*, | |
331 but it is nonetheless available in buffer `*Shell Command Output*', | |
332 even though that buffer is not automatically displayed. | |
333 If there is no output, or if output is inserted in the current buffer, | |
334 then `*Shell Command Output*' is deleted. | |
335 | |
336 The optional second argument OUTPUT-BUFFER, if non-nil, | |
337 says to put the output in some other buffer. | |
338 If OUTPUT-BUFFER is a buffer or buffer name, put the output there. | |
339 If OUTPUT-BUFFER is not a buffer and not nil, | |
340 insert output in current buffer. (This cannot be done asynchronously.) | |
341 In either case, the output is inserted after point (leaving mark after it)." | |
342 (interactive (list (read-shell-command "Shell command: ") | |
343 current-prefix-arg)) | |
344 (if (and output-buffer | |
345 (not (or (bufferp output-buffer) (stringp output-buffer)))) | |
346 (progn (barf-if-buffer-read-only) | |
444 | 347 (push-mark nil (not (interactive-p))) |
428 | 348 ;; We do not use -f for csh; we will not support broken use of |
349 ;; .cshrcs. Even the BSD csh manual says to use | |
350 ;; "if ($?prompt) exit" before things which are not useful | |
351 ;; non-interactively. Besides, if someone wants their other | |
352 ;; aliases for shell commands then they can still have them. | |
353 (call-process shell-file-name nil t nil | |
354 shell-command-switch command) | |
355 (exchange-point-and-mark t)) | |
356 ;; Preserve the match data in case called from a program. | |
357 (save-match-data | |
358 (if (string-match "[ \t]*&[ \t]*$" command) | |
359 ;; Command ending with ampersand means asynchronous. | |
360 (progn | |
776 | 361 (if-fboundp 'background |
3491 | 362 (background (substring command 0 (match-beginning 0)) |
363 output-buffer) | |
776 | 364 (error |
365 'unimplemented | |
366 "backgrounding a shell command requires package `background'"))) | |
367 | |
428 | 368 (shell-command-on-region (point) (point) command output-buffer))))) |
369 | |
370 ;; We have a sentinel to prevent insertion of a termination message | |
371 ;; in the buffer itself. | |
372 (defun shell-command-sentinel (process signal) | |
373 (if (memq (process-status process) '(exit signal)) | |
374 (message "%s: %s." | |
375 (car (cdr (cdr (process-command process)))) | |
376 (substring signal 0 -1)))) | |
377 | |
378 (defun shell-command-on-region (start end command | |
379 &optional output-buffer replace) | |
380 "Execute string COMMAND in inferior shell with region as input. | |
381 Normally display output (if any) in temp buffer `*Shell Command Output*'; | |
382 Prefix arg means replace the region with it. | |
383 | |
384 The noninteractive arguments are START, END, COMMAND, OUTPUT-BUFFER, REPLACE. | |
385 If REPLACE is non-nil, that means insert the output | |
386 in place of text from START to END, putting point and mark around it. | |
387 | |
388 If the output is one line, it is displayed in the echo area, | |
389 but it is nonetheless available in buffer `*Shell Command Output*' | |
390 even though that buffer is not automatically displayed. | |
391 If there is no output, or if output is inserted in the current buffer, | |
392 then `*Shell Command Output*' is deleted. | |
393 | |
394 If the optional fourth argument OUTPUT-BUFFER is non-nil, | |
395 that says to put the output in some other buffer. | |
396 If OUTPUT-BUFFER is a buffer or buffer name, put the output there. | |
397 If OUTPUT-BUFFER is not a buffer and not nil, | |
398 insert output in the current buffer. | |
399 In either case, the output is inserted after point (leaving mark after it)." | |
400 (interactive (let ((string | |
401 ;; Do this before calling region-beginning | |
402 ;; and region-end, in case subprocess output | |
403 ;; relocates them while we are in the minibuffer. | |
404 (read-shell-command "Shell command on region: "))) | |
405 ;; call-interactively recognizes region-beginning and | |
406 ;; region-end specially, leaving them in the history. | |
407 (list (region-beginning) (region-end) | |
408 string | |
409 current-prefix-arg | |
410 current-prefix-arg))) | |
411 (if (or replace | |
412 (and output-buffer | |
413 (not (or (bufferp output-buffer) (stringp output-buffer))))) | |
414 ;; Replace specified region with output from command. | |
415 (let ((swap (and replace (< start end)))) | |
416 ;; Don't muck with mark unless REPLACE says we should. | |
417 (goto-char start) | |
418 (and replace (push-mark)) | |
419 (call-process-region start end shell-file-name t t nil | |
420 shell-command-switch command) | |
421 (let ((shell-buffer (get-buffer "*Shell Command Output*"))) | |
422 (and shell-buffer (not (eq shell-buffer (current-buffer))) | |
423 (kill-buffer shell-buffer))) | |
424 ;; Don't muck with mark unless REPLACE says we should. | |
425 (and replace swap (exchange-point-and-mark t))) | |
426 ;; No prefix argument: put the output in a temp buffer, | |
427 ;; replacing its entire contents. | |
428 (let ((buffer (get-buffer-create | |
429 (or output-buffer "*Shell Command Output*"))) | |
430 (success nil) | |
431 (exit-status nil) | |
432 (directory default-directory)) | |
433 (unwind-protect | |
434 (if (eq buffer (current-buffer)) | |
435 ;; If the input is the same buffer as the output, | |
436 ;; delete everything but the specified region, | |
437 ;; then replace that region with the output. | |
438 (progn (setq buffer-read-only nil) | |
439 (delete-region (max start end) (point-max)) | |
921 | 440 (delete-region (point-min) (min start end)) |
428 | 441 (setq exit-status |
442 (call-process-region (point-min) (point-max) | |
443 shell-file-name t t nil | |
444 shell-command-switch command)) | |
445 (setq success t)) | |
446 ;; Clear the output buffer, | |
447 ;; then run the command with output there. | |
448 (save-excursion | |
449 (set-buffer buffer) | |
450 (setq buffer-read-only nil) | |
451 ;; XEmacs change | |
452 (setq default-directory directory) | |
453 (erase-buffer)) | |
454 (setq exit-status | |
455 (call-process-region start end shell-file-name | |
456 nil buffer nil | |
457 shell-command-switch command)) | |
458 (setq success t)) | |
459 ;; Report the amount of output. | |
460 (let ((lines (save-excursion | |
461 (set-buffer buffer) | |
462 (if (= (buffer-size) 0) | |
463 0 | |
464 (count-lines (point-min) (point-max)))))) | |
465 (cond ((= lines 0) | |
466 (if success | |
467 (display-message | |
468 'command | |
469 (if (eql exit-status 0) | |
470 "(Shell command succeeded with no output)" | |
471 "(Shell command failed with no output)"))) | |
472 (kill-buffer buffer)) | |
473 ((and success (= lines 1)) | |
474 (message "%s" | |
475 (save-excursion | |
476 (set-buffer buffer) | |
477 (goto-char (point-min)) | |
478 (buffer-substring (point) | |
479 (progn (end-of-line) | |
480 (point)))))) | |
481 (t | |
482 (set-window-start (display-buffer buffer) 1)))))))) | |
483 | |
484 (defun shell-quote-argument (argument) | |
485 "Quote an argument for passing as argument to an inferior shell." | |
442 | 486 (if (and (eq system-type 'windows-nt) |
487 (let ((progname (downcase (file-name-nondirectory | |
488 shell-file-name)))) | |
489 (or (equal progname "command.com") | |
490 (equal progname "cmd.exe")))) | |
491 ;; the expectation is that you can take the result of | |
492 ;; shell-quote-argument and pass it to as an arg to | |
493 ;; (start-process shell-quote-argument ...) and have it end | |
494 ;; up as-is in the program's argv[] array. to do this, we | |
495 ;; need to protect against both the shell's and the program's | |
496 ;; quoting conventions (and our own conventions in | |
497 ;; mswindows-construct-process-command-line!). Putting quotes | |
498 ;; around shell metachars gets through the last two, and applying | |
499 ;; the normal VC runtime quoting works with practically all apps. | |
776 | 500 (declare-fboundp (mswindows-quote-one-vc-runtime-arg argument t)) |
611 | 501 (if (equal argument "") |
502 "\"\"" | |
503 ;; Quote everything except POSIX filename characters. | |
504 ;; This should be safe enough even for really weird shells. | |
505 (let ((result "") (start 0) end) | |
506 (while (string-match "[^-0-9a-zA-Z_./]" argument start) | |
507 (setq end (match-beginning 0) | |
508 result (concat result (substring argument start end) | |
509 "\\" (substring argument end (1+ end))) | |
510 start (1+ end))) | |
511 (concat result (substring argument start)))))) | |
428 | 512 |
438 | 513 (defun shell-command-to-string (command) |
514 "Execute shell command COMMAND and return its output as a string." | |
428 | 515 (with-output-to-string |
1189 | 516 (with-current-buffer standard-output |
517 (call-process shell-file-name nil t nil shell-command-switch command)))) | |
428 | 518 |
438 | 519 (defalias 'exec-to-string 'shell-command-to-string) |
771 | 520 |
521 | |
522 ;; History list for environment variable names. | |
523 (defvar read-envvar-name-history nil) | |
524 | |
525 (defun read-envvar-name (prompt &optional mustmatch) | |
526 "Read environment variable name, prompting with PROMPT. | |
527 Optional second arg MUSTMATCH, if non-nil, means require existing envvar name. | |
528 If it is also not t, RET does not exit if it does non-null completion." | |
529 (completing-read prompt | |
530 (mapcar (function | |
531 (lambda (enventry) | |
532 (list (substring enventry 0 | |
533 (string-match "=" enventry))))) | |
534 process-environment) | |
535 nil mustmatch nil 'read-envvar-name-history)) | |
536 | |
537 ;; History list for VALUE argument to setenv. | |
538 (defvar setenv-history nil) | |
539 | |
930 | 540 (defun substitute-env-vars (string) |
541 "Substitute environment variables referred to in STRING. | |
542 `$FOO' where FOO is an environment variable name means to substitute | |
543 the value of that variable. The variable name should be terminated | |
544 with a character not a letter, digit or underscore; otherwise, enclose | |
4327
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
545 the entire variable name in braces. For instance, in `ab$cd-x', |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
546 `$cd' is treated as an environment variable. |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
547 |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
548 Use `$$' to insert a single dollar sign." |
930 | 549 (let ((start 0)) |
550 (while (string-match | |
551 ;; XEmacs change - FSF use their rx macro to generate this regexp | |
552 "\\(?:\\$\\(\\(?:[a-zA-Z0-9_]\\)+\\)\\)\\|\\(?:\\${\\(\\(?:.\\|\n\\)*?\\)}\\)\\|\\$\\$" | |
553 string start) | |
554 (cond ((match-beginning 1) | |
555 (let ((value (getenv (match-string 1 string)))) | |
556 (setq string (replace-match (or value "") t t string) | |
557 start (+ (match-beginning 0) (length value))))) | |
558 ((match-beginning 2) | |
559 (let ((value (getenv (match-string 2 string)))) | |
560 (setq string (replace-match (or value "") t t string) | |
561 start (+ (match-beginning 0) (length value))))) | |
562 (t | |
563 (setq string (replace-match "$" t t string) | |
564 start (+ (match-beginning 0) 1))))) | |
565 string)) | |
566 | |
567 (defun setenv (variable &optional value unset substitute-env-vars) | |
771 | 568 "Set the value of the environment variable named VARIABLE to VALUE. |
569 VARIABLE should be a string. VALUE is optional; if not provided or is | |
570 `nil', the environment variable VARIABLE will be removed. | |
571 | |
930 | 572 UNSET, if non-nil, means to remove VARIABLE from the environment. |
573 SUBSTITUTE-ENV-VARS, if non-nil, means to substitute environment | |
574 variables in VALUE using `substitute-env-vars'. | |
575 | |
771 | 576 Interactively, a prefix argument means to unset the variable. |
577 Interactively, the current value (if any) of the variable | |
578 appears at the front of the history list when you type in the new value. | |
579 | |
4327
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
580 This function works by modifying `process-environment'. |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
581 |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
582 As a special case, setting variable `TZ' calls `set-time-zone-rule' as |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
583 a side-effect." |
771 | 584 (interactive |
585 (if current-prefix-arg | |
586 (list (read-envvar-name "Clear environment variable: " 'exact) nil t) | |
4327
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
587 (let* ((var (read-envvar-name "Set environment variable: " nil)) |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
588 (value (getenv var))) |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
589 (when value |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
590 (push value setenv-history)) |
771 | 591 ;; Here finally we specify the args to call setenv with. |
592 (list var (read-from-minibuffer (format "Set %s to value: " var) | |
593 nil nil nil 'setenv-history | |
4327
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
594 ;; XEmacs change; don't specify a |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
595 ;; default. (Nor an abbrev table.) |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
596 ))))) |
930 | 597 (if unset |
598 (setq value nil) | |
599 (if substitute-env-vars | |
600 (setq value (substitute-env-vars value)))) | |
4327
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
601 |
4610
38e8af61f38d
Check if env vars are encodable by native coding system, #'setenv
Aidan Kehoe <kehoea@parhasard.net>
parents:
4327
diff
changeset
|
602 ;; XEmacs change: check whether the environment understands this variable, |
38e8af61f38d
Check if env vars are encodable by native coding system, #'setenv
Aidan Kehoe <kehoea@parhasard.net>
parents:
4327
diff
changeset
|
603 ;; using our function for exactly that, don't use |
38e8af61f38d
Check if env vars are encodable by native coding system, #'setenv
Aidan Kehoe <kehoea@parhasard.net>
parents:
4327
diff
changeset
|
604 ;; #'find-coding-systems-string or trust `undecided' to encode it. |
38e8af61f38d
Check if env vars are encodable by native coding system, #'setenv
Aidan Kehoe <kehoea@parhasard.net>
parents:
4327
diff
changeset
|
605 (query-coding-string (concat variable "=" value) 'native nil t) |
4327
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
606 |
771 | 607 (if (string-match "=" variable) |
608 (error "Environment variable name `%s' contains `='" variable) | |
609 (let ((pattern (concat "\\`" (regexp-quote (concat variable "=")))) | |
610 (case-fold-search nil) | |
611 (scan process-environment) | |
612 found) | |
613 (if (string-equal "TZ" variable) | |
614 (set-time-zone-rule value)) | |
615 (while scan | |
616 (cond ((string-match pattern (car scan)) | |
617 (setq found t) | |
618 (if (eq nil value) | |
619 (setq process-environment (delq (car scan) process-environment)) | |
620 (setcar scan (concat variable "=" value))) | |
621 (setq scan nil))) | |
622 (setq scan (cdr scan))) | |
623 (or found | |
624 (if value | |
625 (setq process-environment | |
626 (cons (concat variable "=" value) | |
627 process-environment))))))) | |
628 | |
629 ;; already in C. Can't move it to Lisp too easily because it's needed | |
630 ;; extremely early in the Lisp loadup sequence. | |
631 | |
632 ; (defun getenv (variable) | |
633 ; "Get the value of environment variable VARIABLE. | |
634 ; VARIABLE should be a string. Value is nil if VARIABLE is undefined in | |
635 ; the environment. Otherwise, value is a string. | |
636 ; | |
637 ; This function consults the variable `process-environment' | |
638 ; for its value." | |
639 ; (interactive (list (read-envvar-name "Get environment variable: " t))) | |
640 ; (let ((value (getenv-internal variable))) | |
641 ; (when (interactive-p) | |
642 ; (message "%s" (if value value "Not set"))) | |
643 ; value)) | |
644 | |
4327
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
645 |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
646 ;; GNU have an #'environment function here, as of 2007-12-14. If someone |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
647 ;; actually uses it in the wild, this would suffice as an implementation: |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
648 |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
649 ; (defun environment (&optional frame) |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
650 ; "Return a list of environment variables with their values. |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
651 ; Each entry in the list is a string of the form NAME=VALUE. |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
652 ; |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
653 ; Optional argument FRAME is ignored, for GNU compatibility. |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
654 ; |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
655 ; Non-ASCII characters look like Mojibake (that is, they are unreadable.)" |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
656 ; (loop |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
657 ; for entry in process-environment |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
658 ; collect (encode-coding-string entry 'native))) |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
659 ; |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
660 |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
661 ;; but we shouldn't encourage that sort of ugliness and needless backwards |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
662 ;; incompatibility. |
466ad8ad5f13
Fix a #'setenv bug, merge other changes from GNU's env.el.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3491
diff
changeset
|
663 |
771 | 664 (provide 'env) ;; Yuck. Formerly the above were in env.el, which did this |
665 ;; provide. | |
428 | 666 |
667 ;;; process.el ends here |