Mercurial > hg > xemacs-beta
comparison lisp/process.el @ 5533:11da5b828d10
shell-command and shell-command-on-region API compliant with FSF 23.3.1
author | Mats Lidell <mats.lidell@cag.se> |
---|---|
date | Sun, 31 Jul 2011 01:29:09 +0200 |
parents | 308d34e9f07d |
children | a39cd9dc92ba |
comparison
equal
deleted
inserted
replaced
5531:1b054bc2ac40 | 5533:11da5b828d10 |
---|---|
1 ;;; process.el --- commands for subprocesses; split out of simple.el | 1 ;;; process.el --- commands for subprocesses; split out of simple.el |
2 | 2 |
3 ;; Copyright (C) 1985-7, 1993,4, 1997 Free Software Foundation, Inc. | 3 ;; Copyright (C) 1985-7, 1993,4, 1997, 2011 Free Software Foundation, Inc. |
4 ;; Copyright (C) 1995, 2000, 2001, 2002 Ben Wing. | 4 ;; Copyright (C) 1995, 2000, 2001, 2002 Ben Wing. |
5 | 5 |
6 ;; Author: Ben Wing | 6 ;; Author: Ben Wing |
7 ;; Maintainer: XEmacs Development Team | 7 ;; Maintainer: XEmacs Development Team |
8 ;; Keywords: internal, processes, dumped | 8 ;; Keywords: internal, processes, dumped |
22 ;; You should have received a copy of the GNU General Public License | 22 ;; You should have received a copy of the GNU General Public License |
23 ;; along with XEmacs. If not, see <http://www.gnu.org/licenses/>. | 23 ;; along with XEmacs. If not, see <http://www.gnu.org/licenses/>. |
24 | 24 |
25 ;;; Synched up with: FSF 19.30, except for setenv/getenv (synched with FSF | 25 ;;; Synched up with: FSF 19.30, except for setenv/getenv (synched with FSF |
26 ;;; 21.2.1). | 26 ;;; 21.2.1). |
27 ;;; shell-command and shell-command-on-region synced with FSF 23.3.1. | |
27 | 28 |
28 ;;; Authorship: | 29 ;;; Authorship: |
29 | 30 |
30 ;; Created 1995 by Ben Wing during Mule work -- some commands split out | 31 ;; Created 1995 by Ben Wing during Mule work -- some commands split out |
31 ;; of simple.el and wrappers of *-internal functions created so they could | 32 ;; of simple.el and wrappers of *-internal functions created so they could |
54 | 55 |
55 ;; This may be changed to "/c" in win32-native.el. | 56 ;; This may be changed to "/c" in win32-native.el. |
56 | 57 |
57 (defvar shell-command-switch "-c" | 58 (defvar shell-command-switch "-c" |
58 "Switch used to have the shell execute its command line argument.") | 59 "Switch used to have the shell execute its command line argument.") |
60 | |
61 (defvar shell-command-default-error-buffer nil | |
62 "*Buffer name for `shell-command' and `shell-command-on-region' error output. | |
63 This buffer is used when `shell-command' or `shell-command-on-region' | |
64 is run interactively. A value of nil means that output to stderr and | |
65 stdout will be intermixed in the output stream.") | |
59 | 66 |
60 (defun start-process-shell-command (name buffer &rest args) | 67 (defun start-process-shell-command (name buffer &rest args) |
61 "Start a program in a subprocess. Return the process object for it. | 68 "Start a program in a subprocess. Return the process object for it. |
62 NAME is name for process. It is modified if necessary to make it unique. | 69 NAME is name for process. It is modified if necessary to make it unique. |
63 BUFFER is the buffer or (buffer-name) to associate with the process. | 70 BUFFER is the buffer or (buffer-name) to associate with the process. |
314 (condition-case nil | 321 (condition-case nil |
315 (if (and proc (process-live-p proc)) (kill-process proc)) | 322 (if (and proc (process-live-p proc)) (kill-process proc)) |
316 (error nil))))) | 323 (error nil))))) |
317 | 324 |
318 | 325 |
319 (defun shell-command (command &optional output-buffer) | 326 (defun shell-command (command &optional output-buffer error-buffer) |
320 "Execute string COMMAND in inferior shell; display output, if any. | 327 "Execute string COMMAND in inferior shell; display output, if any. |
321 | 328 |
322 If COMMAND ends in ampersand, execute it asynchronously. | 329 If COMMAND ends in ampersand, execute it asynchronously. The command |
323 The output appears in the buffer `*Async Shell Command*'. | 330 is executed using the background package. See `background' for |
324 That buffer is in shell mode. | 331 details. |
325 | 332 |
326 Otherwise, COMMAND is executed synchronously. The output appears in the | 333 Otherwise, COMMAND is executed synchronously. The output appears in the |
327 buffer `*Shell Command Output*'. | 334 buffer `*Shell Command Output*'. |
328 If the output is one line, it is displayed in the echo area *as well*, | 335 If the output is one line, it is displayed in the echo area *as well*, |
329 but it is nonetheless available in buffer `*Shell Command Output*', | 336 but it is nonetheless available in buffer `*Shell Command Output*', |
334 The optional second argument OUTPUT-BUFFER, if non-nil, | 341 The optional second argument OUTPUT-BUFFER, if non-nil, |
335 says to put the output in some other buffer. | 342 says to put the output in some other buffer. |
336 If OUTPUT-BUFFER is a buffer or buffer name, put the output there. | 343 If OUTPUT-BUFFER is a buffer or buffer name, put the output there. |
337 If OUTPUT-BUFFER is not a buffer and not nil, | 344 If OUTPUT-BUFFER is not a buffer and not nil, |
338 insert output in current buffer. (This cannot be done asynchronously.) | 345 insert output in current buffer. (This cannot be done asynchronously.) |
339 In either case, the output is inserted after point (leaving mark after it)." | 346 In either case, the output is inserted after point (leaving mark after it). |
347 | |
348 If the optional third argument ERROR-BUFFER is non-nil, it is a buffer | |
349 or buffer name to which to direct the command's standard error output. | |
350 If it is nil, error output is mingled with regular output. In an | |
351 interactive call, the variable `shell-command-default-error-buffer' | |
352 specifies the value of ERROR-BUFFER." | |
340 (interactive (list (read-shell-command "Shell command: ") | 353 (interactive (list (read-shell-command "Shell command: ") |
341 current-prefix-arg)) | 354 current-prefix-arg |
355 shell-command-default-error-buffer)) | |
342 (if (and output-buffer | 356 (if (and output-buffer |
343 (not (or (bufferp output-buffer) (stringp output-buffer)))) | 357 (not (or (bufferp output-buffer) (stringp output-buffer)))) |
344 (progn (barf-if-buffer-read-only) | 358 (progn (barf-if-buffer-read-only) |
345 (push-mark nil (not (interactive-p))) | 359 (push-mark nil (not (interactive-p))) |
346 ;; We do not use -f for csh; we will not support broken use of | 360 ;; We do not use -f for csh; we will not support broken use of |
361 output-buffer) | 375 output-buffer) |
362 (error | 376 (error |
363 'unimplemented | 377 'unimplemented |
364 "backgrounding a shell command requires package `background'"))) | 378 "backgrounding a shell command requires package `background'"))) |
365 | 379 |
366 (shell-command-on-region (point) (point) command output-buffer))))) | 380 (shell-command-on-region (point) (point) command output-buffer nil error-buffer))))) |
367 | 381 |
368 ;; We have a sentinel to prevent insertion of a termination message | 382 ;; We have a sentinel to prevent insertion of a termination message |
369 ;; in the buffer itself. | 383 ;; in the buffer itself. |
370 (defun shell-command-sentinel (process signal) | 384 (defun shell-command-sentinel (process signal) |
371 (if (memq (process-status process) '(exit signal)) | 385 (if (memq (process-status process) '(exit signal)) |
372 (message "%s: %s." | 386 (message "%s: %s." |
373 (car (cdr (cdr (process-command process)))) | 387 (car (cdr (cdr (process-command process)))) |
374 (substring signal 0 -1)))) | 388 (substring signal 0 -1)))) |
375 | 389 |
376 (defun shell-command-on-region (start end command | 390 (defun shell-command-on-region (start end command |
377 &optional output-buffer replace) | 391 &optional output-buffer replace |
392 error-buffer display-error-buffer) | |
378 "Execute string COMMAND in inferior shell with region as input. | 393 "Execute string COMMAND in inferior shell with region as input. |
379 Normally display output (if any) in temp buffer `*Shell Command Output*'; | 394 Normally display output (if any) in temp buffer `*Shell Command Output*'; |
380 Prefix arg means replace the region with it. | 395 Prefix arg means replace the region with it. |
381 | 396 |
382 The noninteractive arguments are START, END, COMMAND, OUTPUT-BUFFER, REPLACE. | 397 The noninteractive arguments are START, END, COMMAND, OUTPUT-BUFFER, REPLACE. |
392 If the optional fourth argument OUTPUT-BUFFER is non-nil, | 407 If the optional fourth argument OUTPUT-BUFFER is non-nil, |
393 that says to put the output in some other buffer. | 408 that says to put the output in some other buffer. |
394 If OUTPUT-BUFFER is a buffer or buffer name, put the output there. | 409 If OUTPUT-BUFFER is a buffer or buffer name, put the output there. |
395 If OUTPUT-BUFFER is not a buffer and not nil, | 410 If OUTPUT-BUFFER is not a buffer and not nil, |
396 insert output in the current buffer. | 411 insert output in the current buffer. |
397 In either case, the output is inserted after point (leaving mark after it)." | 412 In either case, the output is inserted after point (leaving mark after it). |
413 | |
414 If optional sixth argument ERROR-BUFFER is non-nil, it is a buffer | |
415 or buffer name to which to direct the command's standard error output. | |
416 If it is nil, error output is mingled with regular output. | |
417 If DISPLAY-ERROR-BUFFER is non-nil, display the error buffer if there | |
418 were any errors. (This is always t, interactively.) | |
419 In an interactive call, the variable `shell-command-default-error-buffer' | |
420 specifies the value of ERROR-BUFFER." | |
398 (interactive (let ((string | 421 (interactive (let ((string |
399 ;; Do this before calling region-beginning | 422 ;; Do this before calling region-beginning |
400 ;; and region-end, in case subprocess output | 423 ;; and region-end, in case subprocess output |
401 ;; relocates them while we are in the minibuffer. | 424 ;; relocates them while we are in the minibuffer. |
402 (read-shell-command "Shell command on region: "))) | 425 (read-shell-command "Shell command on region: "))) |
403 ;; call-interactively recognizes region-beginning and | 426 ;; call-interactively recognizes region-beginning and |
404 ;; region-end specially, leaving them in the history. | 427 ;; region-end specially, leaving them in the history. |
405 (list (region-beginning) (region-end) | 428 (list (region-beginning) (region-end) |
406 string | 429 string |
407 current-prefix-arg | 430 current-prefix-arg |
408 current-prefix-arg))) | 431 current-prefix-arg |
409 (if (or replace | 432 shell-command-default-error-buffer |
410 (and output-buffer | 433 t))) |
411 (not (or (bufferp output-buffer) (stringp output-buffer))))) | 434 (let ((error-file |
412 ;; Replace specified region with output from command. | 435 (if error-buffer |
413 (let ((swap (and replace (< start end)))) | 436 (make-temp-file |
414 ;; Don't muck with mark unless REPLACE says we should. | 437 (expand-file-name "scor" |
415 (goto-char start) | 438 (or small-temporary-file-directory |
416 (and replace (push-mark)) | 439 (temp-directory)))) |
417 (call-process-region start end shell-file-name t t nil | 440 nil)) |
418 shell-command-switch command) | 441 (exit-status nil)) |
419 (let ((shell-buffer (get-buffer "*Shell Command Output*"))) | 442 (if (or replace |
420 (and shell-buffer (not (eq shell-buffer (current-buffer))) | 443 (and output-buffer |
421 (kill-buffer shell-buffer))) | 444 (not (or (bufferp output-buffer) (stringp output-buffer))))) |
422 ;; Don't muck with mark unless REPLACE says we should. | 445 ;; Replace specified region with output from command. |
423 (and replace swap (exchange-point-and-mark t))) | 446 (let ((swap (and replace (< start end)))) |
447 ;; Don't muck with mark unless REPLACE says we should. | |
448 (goto-char start) | |
449 (and replace (push-mark)) | |
450 (setq exit-status (call-process-region start end shell-file-name t | |
451 (if error-file | |
452 (list t error-file) | |
453 t) | |
454 nil shell-command-switch command)) | |
455 (let ((shell-buffer (get-buffer "*Shell Command Output*"))) | |
456 (and shell-buffer (nnot (eq shell-buffer (current-buffer))) | |
457 (kill-buffer shell-buffer))) | |
458 ;; Don't muck with mark unless REPLACE says we should. | |
459 (and replace swap (exchange-point-and-mark t))) | |
424 ;; No prefix argument: put the output in a temp buffer, | 460 ;; No prefix argument: put the output in a temp buffer, |
425 ;; replacing its entire contents. | 461 ;; replacing its entire contents. |
426 (let ((buffer (get-buffer-create | 462 (let ((buffer (get-buffer-create |
427 (or output-buffer "*Shell Command Output*"))) | 463 (or output-buffer "*Shell Command Output*"))) |
428 (success nil) | 464 (directory default-directory)) |
429 (exit-status nil) | 465 (unwind-protect |
430 (directory default-directory)) | 466 (if (eq buffer (current-buffer)) |
431 (unwind-protect | 467 ;; If the input is the same buffer as the output, |
432 (if (eq buffer (current-buffer)) | 468 ;; delete everything but the specified region, |
433 ;; If the input is the same buffer as the output, | 469 ;; then replace that region with the output. |
434 ;; delete everything but the specified region, | 470 (progn (setq buffer-read-only nil) |
435 ;; then replace that region with the output. | 471 (delete-region (max start end) (point-max)) |
436 (progn (setq buffer-read-only nil) | 472 (delete-region (point-min) (min start end)) |
437 (delete-region (max start end) (point-max)) | 473 (setq exit-status |
438 (delete-region (point-min) (min start end)) | 474 (call-process-region (point-min) (point-max) |
439 (setq exit-status | 475 shell-file-name t |
440 (call-process-region (point-min) (point-max) | 476 (if error-file |
441 shell-file-name t t nil | 477 (list t error-file) |
442 shell-command-switch command)) | 478 t) |
443 (setq success t)) | 479 nil shell-command-switch |
444 ;; Clear the output buffer, | 480 command))) |
445 ;; then run the command with output there. | 481 ;; Clear the output buffer, |
446 (save-excursion | 482 ;; then run the command with output there. |
447 (set-buffer buffer) | 483 (save-excursion |
448 (setq buffer-read-only nil) | 484 (set-buffer buffer) |
449 ;; XEmacs change | 485 (setq buffer-read-only nil) |
450 (setq default-directory directory) | 486 ;; XEmacs change |
451 (erase-buffer)) | 487 (setq default-directory directory) |
452 (setq exit-status | 488 (erase-buffer)) |
453 (call-process-region start end shell-file-name | 489 (setq exit-status |
454 nil buffer nil | 490 (call-process-region start end shell-file-name |
455 shell-command-switch command)) | 491 nil |
456 (setq success t)) | 492 (if error-file |
457 ;; Report the amount of output. | 493 (list buffer error-file) |
458 (let ((lines (save-excursion | 494 buffer) |
459 (set-buffer buffer) | 495 nil shell-command-switch command))) |
460 (if (= (buffer-size) 0) | 496 |
461 0 | 497 ;; Report the output. |
462 (count-lines (point-min) (point-max)))))) | 498 (with-current-buffer buffer |
463 (cond ((= lines 0) | 499 (setq modeline-process |
464 (if success | 500 (cond ((null exit-status) |
465 (display-message | 501 " - Error") |
466 'command | 502 ((stringp exit-status) |
467 (if (eql exit-status 0) | 503 (format " - Signal [%s]" exit-status)) |
468 "(Shell command succeeded with no output)" | 504 ((not (equal 0 exit-status)) |
469 "(Shell command failed with no output)"))) | 505 (format " - Exit [%d]" exit-status))))) |
470 (kill-buffer buffer)) | 506 (if (with-current-buffer buffer (> (point-max) (point-min))) |
471 ((and success (= lines 1)) | 507 ;; There's some output, display it |
472 (message "%s" | 508 (let ((lines (save-excursion |
473 (save-excursion | 509 (set-buffer buffer) |
474 (set-buffer buffer) | 510 (if (= (buffer-size) 0) |
475 (goto-char (point-min)) | 511 0 |
476 (buffer-substring (point) | 512 (count-lines (point-min) (point-max)))))) |
477 (progn (end-of-line) | 513 (cond ((= lines 0) |
478 (point)))))) | 514 (display-message |
479 (t | 515 'command |
480 (set-window-start (display-buffer buffer) 1)))))))) | 516 (if (eql exit-status 0) |
517 "(Shell command succeeded with no output)" | |
518 "(Shell command failed with no output)")) | |
519 (kill-buffer buffer)) | |
520 ((= lines 1) | |
521 (message "%s" | |
522 (save-excursion | |
523 (set-buffer buffer) | |
524 (goto-char (point-min)) | |
525 (buffer-substring (point) | |
526 (progn (end-of-line) | |
527 (point)))))) | |
528 (t | |
529 (set-window-start (display-buffer buffer) 1)))) | |
530 ;; No output; error? | |
531 (let ((output | |
532 (if (and error-file | |
533 (< 0 (nth 7 (file-attributes error-file)))) | |
534 "some error output" | |
535 "no output"))) | |
536 (cond ((null exit-status) | |
537 (message "(Shell command failed with error)")) | |
538 ((equal 0 exit-status) | |
539 (message "(Shell command succeeded with %s)" | |
540 output)) | |
541 ((stringp exit-status) | |
542 (message "(Shell command killed by signal %s)" | |
543 exit-status)) | |
544 (t | |
545 (message "(Shell command failed with code %d and %s)" | |
546 exit-status output)))) | |
547 ;; Don't kill: there might be useful info in the undo-log. | |
548 ;; (kill-buffer buffer) | |
549 )))) | |
550 | |
551 (when (and error-file (file-exists-p error-file)) | |
552 (if (< 0 (nth 7 (file-attributes error-file))) | |
553 (with-current-buffer (get-buffer-create error-buffer) | |
554 (let ((pos-from-end (- (point-max) (point)))) | |
555 (or (bobp) | |
556 (insert "\f\n")) | |
557 ;; Do no formatting while reading error file, | |
558 ;; because that can run a shell command, and we | |
559 ;; don't want that to cause an infinite recursion. | |
560 (format-insert-file error-file nil) | |
561 ;; Put point after the inserted errors. | |
562 (goto-char (- (point-max) pos-from-end))) | |
563 (and display-error-buffer | |
564 (display-buffer (current-buffer))))) | |
565 (delete-file error-file)) | |
566 exit-status)) | |
481 | 567 |
482 (defun shell-quote-argument (argument) | 568 (defun shell-quote-argument (argument) |
483 "Quote an argument for passing as argument to an inferior shell." | 569 "Quote an argument for passing as argument to an inferior shell." |
484 (if (and (eq system-type 'windows-nt) | 570 (if (and (eq system-type 'windows-nt) |
485 (let ((progname (downcase (file-name-nondirectory | 571 (let ((progname (downcase (file-name-nondirectory |