annotate lisp/eshell/esh-io.el @ 91817:f0b22bbb77fb

;;; smtpmail.el --- simple SMTP protocol (RFC 821) for sending mail ;; Copyright (C) 1995, 1996, 2001, 2002, 2003, 2004, 2005, ;; 2006, 2007, 2008 Free Software Foundation, Inc. ;; Author: Tomoji Kagatani <kagatani@rbc.ncl.omron.co.jp> ;; Maintainer: Simon Josefsson <simon@josefsson.org> ;; w32 Maintainer: Brian D. Carlstrom <bdc@ai.mit.edu> ;; ESMTP support: Simon Leinen <simon@switch.ch> ;; Hacked by Mike Taylor, 11th October 1999 to add support for ;; automatically appending a domain to RCPT TO: addresses. ;; AUTH=LOGIN support: Stephen Cranefield <scranefield@infoscience.otago.ac.nz> ;; Keywords: mail ;; This file is part of GNU Emacs. ;; GNU Emacs is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; Send Mail to smtp host from smtpmail temp buffer. ;; Please add these lines in your .emacs(_emacs) or use customize. ;; ;;(setq send-mail-function 'smtpmail-send-it) ; if you use `mail' ;;(setq message-send-mail-function 'smtpmail-send-it) ; if you use message/Gnus ;;(setq smtpmail-default-smtp-server "YOUR SMTP HOST") ;;(setq smtpmail-local-domain "YOUR DOMAIN NAME") ;;(setq smtpmail-sendto-domain "YOUR DOMAIN NAME") ;;(setq smtpmail-debug-info t) ; only to debug problems ;;(setq smtpmail-auth-credentials ; or use ~/.authinfo ;; '(("YOUR SMTP HOST" 25 "username" "password"))) ;;(setq smtpmail-starttls-credentials ;; '(("YOUR SMTP HOST" 25 "~/.my_smtp_tls.key" "~/.my_smtp_tls.cert"))) ;; Where the 25 equals the value of `smtpmail-smtp-service', it can be an ;; integer or a string, just as long as they match (eq). ;; To queue mail, set smtpmail-queue-mail to t and use ;; smtpmail-send-queued-mail to send. ;; Modified by Stephen Cranefield <scranefield@infoscience.otago.ac.nz>, ;; 22/6/99, to support SMTP Authentication by the AUTH=LOGIN mechanism. ;; See http://help.netscape.com/products/server/messaging/3x/info/smtpauth.html ;; Rewritten by Simon Josefsson to use same credential variable as AUTH ;; support below. ;; Modified by Simon Josefsson <jas@pdc.kth.se>, 22/2/99, to support SMTP ;; Authentication by the AUTH mechanism. ;; See http://www.ietf.org/rfc/rfc2554.txt ;; Modified by Simon Josefsson <simon@josefsson.org>, 2000-10-07, to support ;; STARTTLS. Requires external program ;; ftp://ftp.opaopa.org/pub/elisp/starttls-*.tar.gz. ;; See http://www.ietf.org/rfc/rfc2246.txt, http://www.ietf.org/rfc/rfc2487.txt ;;; Code: (require 'sendmail) (autoload 'starttls-open-stream "starttls") (autoload 'starttls-negotiate "starttls") (autoload 'mail-strip-quoted-names "mail-utils") (autoload 'message-make-date "message") (autoload 'message-make-message-id "message") (autoload 'rfc2104-hash "rfc2104") (autoload 'netrc-parse "netrc") (autoload 'netrc-machine "netrc") (autoload 'netrc-get "netrc") ;;; (defgroup smtpmail nil "SMTP protocol for sending mail." :group 'mail) (defcustom smtpmail-default-smtp-server nil "*Specify default SMTP server. This only has effect if you specify it before loading the smtpmail library." :type '(choice (const nil) string) :group 'smtpmail) (defcustom smtpmail-smtp-server (or (getenv "SMTPSERVER") smtpmail-default-smtp-server) "*The name of the host running SMTP server." :type '(choice (const nil) string) :group 'smtpmail) (defcustom smtpmail-smtp-service 25 "*SMTP service port number. The default value would be \"smtp\" or 25." :type '(choice (integer :tag "Port") (string :tag "Service")) :group 'smtpmail) (defcustom smtpmail-local-domain nil "*Local domain name without a host name. If the function `system-name' returns the full internet address, don't define this value." :type '(choice (const nil) string) :group 'smtpmail) (defcustom smtpmail-sendto-domain nil "*Local domain name without a host name. This is appended (with an @-sign) to any specified recipients which do not include an @-sign, so that each RCPT TO address is fully qualified. \(Some configurations of sendmail require this.) Don't bother to set this unless you have get an error like: Sending failed; SMTP protocol error when sending mail, and the *trace of SMTP session to <somewhere>* buffer includes an exchange like: RCPT TO: <someone> 501 <someone>: recipient address must contain a domain " :type '(choice (const nil) string) :group 'smtpmail) (defcustom smtpmail-debug-info nil "Whether to print info in buffer *trace of SMTP session to <somewhere>*. See also `smtpmail-debug-verb' which determines if the SMTP protocol should be verbose as well." :type 'boolean :group 'smtpmail) (defcustom smtpmail-debug-verb nil "Whether this library sends the SMTP VERB command or not. The commands enables verbose information from the SMTP server." :type 'boolean :group 'smtpmail) (defcustom smtpmail-code-conv-from nil ;; *junet* "*smtpmail code convert from this code to *internal*..for tiny-mime.." :type 'boolean :group 'smtpmail) (defcustom smtpmail-queue-mail nil "*If set, mail is queued; otherwise it is sent immediately. If queued, it is stored in the directory `smtpmail-queue-dir' and sent with `smtpmail-send-queued-mail'." :type 'boolean :group 'smtpmail) (defcustom smtpmail-queue-dir "~/Mail/queued-mail/" "*Directory where `smtpmail.el' stores queued mail." :type 'directory :group 'smtpmail) (defcustom smtpmail-auth-credentials "~/.authinfo" "Specify username and password for servers, directly or via .netrc file. This variable can either be a filename pointing to a file in netrc(5) format, or list of four-element lists that contain, in order, `servername' (a string), `port' (an integer), `user' (a string) and `password' (a string, or nil to query the user when needed). If you need to enter a `realm' too, add it to the user string, so that it looks like `user@realm'." :type '(choice file (repeat (list (string :tag "Server") (integer :tag "Port") (string :tag "Username") (choice (const :tag "Query when needed" nil) (string :tag "Password"))))) :version "22.1" :group 'smtpmail) (defcustom smtpmail-starttls-credentials '(("" 25 "" "")) "Specify STARTTLS keys and certificates for servers. This is a list of four-element list with `servername' (a string), `port' (an integer), `key' (a filename) and `certificate' (a filename). If you do not have a certificate/key pair, leave the `key' and `certificate' fields as `nil'. A key/certificate pair is only needed if you want to use X.509 client authenticated connections." :type '(repeat (list (string :tag "Server") (integer :tag "Port") (file :tag "Key") (file :tag "Certificate"))) :version "21.1" :group 'smtpmail) (defcustom smtpmail-warn-about-unknown-extensions nil "*If set, print warnings about unknown SMTP extensions. This is mainly useful for development purposes, to learn about new SMTP extensions that might be useful to support." :type 'boolean :version "21.1" :group 'smtpmail) (defvar smtpmail-queue-index-file "index" "File name of queued mail index. This is relative to `smtpmail-queue-dir'.") (defvar smtpmail-address-buffer) (defvar smtpmail-recipient-address-list) (defvar smtpmail-queue-counter 0) ;; Buffer-local variable. (defvar smtpmail-read-point) (defvar smtpmail-queue-index (concat smtpmail-queue-dir smtpmail-queue-index-file)) (defconst smtpmail-auth-supported '(cram-md5 plain login) "List of supported SMTP AUTH mechanisms.") ;;; ;;; ;;; (defvar smtpmail-mail-address nil "Value to use for envelope-from address for mail from ambient buffer.") ;;;###autoload (defun smtpmail-send-it () (let ((errbuf (if mail-interactive (generate-new-buffer " smtpmail errors") 0)) (tembuf (generate-new-buffer " smtpmail temp")) (case-fold-search nil) delimline (mailbuf (current-buffer)) ;; Examine this variable now, so that ;; local binding in the mail buffer will take effect. (smtpmail-mail-address (or (and mail-specify-envelope-from (mail-envelope-from)) user-mail-address)) (smtpmail-code-conv-from (if enable-multibyte-characters (let ((sendmail-coding-system smtpmail-code-conv-from)) (select-message-coding-system))))) (unwind-protect (save-excursion (set-buffer tembuf) (erase-buffer) ;; Use the same buffer-file-coding-system as in the mail ;; buffer, otherwise any write-region invocations (e.g., in ;; mail-do-fcc below) will annoy with asking for a suitable ;; encoding. (set-buffer-file-coding-system smtpmail-code-conv-from nil t) (insert-buffer-substring mailbuf) (goto-char (point-max)) ;; require one newline at the end. (or (= (preceding-char) ?\n) (insert ?\n)) ;; Change header-delimiter to be what sendmail expects. (mail-sendmail-undelimit-header) (setq delimline (point-marker)) ;; (sendmail-synch-aliases) (if mail-aliases (expand-mail-aliases (point-min) delimline)) (goto-char (point-min)) ;; ignore any blank lines in the header (while (and (re-search-forward "\n\n\n*" delimline t) (< (point) delimline)) (replace-match "\n")) (let ((case-fold-search t)) ;; We used to process Resent-... headers here, ;; but it was not done properly, and the job ;; is done correctly in smtpmail-deduce-address-list. ;; Don't send out a blank subject line (goto-char (point-min)) (if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t) (replace-match "") ;; This one matches a Subject just before the header delimiter. (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t) (= (match-end 0) delimline)) (replace-match ""))) ;; Put the "From:" field in unless for some odd reason ;; they put one in themselves. (goto-char (point-min)) (if (not (re-search-forward "^From:" delimline t)) (let* ((login smtpmail-mail-address) (fullname (user-full-name))) (cond ((eq mail-from-style 'angles) (insert "From: " fullname) (let ((fullname-start (+ (point-min) 6)) (fullname-end (point-marker))) (goto-char fullname-start) ;; Look for a character that cannot appear unquoted ;; according to RFC 822. (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]" fullname-end 1) (progn ;; Quote fullname, escaping specials. (goto-char fullname-start) (insert "\"") (while (re-search-forward "[\"\\]" fullname-end 1) (replace-match "\\\\\\&" t)) (insert "\"")))) (insert " <" login ">\n")) ((eq mail-from-style 'parens) (insert "From: " login " (") (let ((fullname-start (point))) (insert fullname) (let ((fullname-end (point-marker))) (goto-char fullname-start) ;; RFC 822 says \ and nonmatching parentheses ;; must be escaped in comments. ;; Escape every instance of ()\ ... (while (re-search-forward "[()\\]" fullname-end 1) (replace-match "\\\\\\&" t)) ;; ... then undo escaping of matching parentheses, ;; including matching nested parentheses. (goto-char fullname-start) (while (re-search-forward "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)" fullname-end 1) (replace-match "\\1(\\3)" t) (goto-char fullname-start)))) (insert ")\n")) ((null mail-from-style) (insert "From: " login "\n"))))) ;; Insert a `Message-Id:' field if there isn't one yet. (goto-char (point-min)) (unless (re-search-forward "^Message-Id:" delimline t) (insert "Message-Id: " (message-make-message-id) "\n")) ;; Insert a `Date:' field if there isn't one yet. (goto-char (point-min)) (unless (re-search-forward "^Date:" delimline t) (insert "Date: " (message-make-date) "\n")) ;; Possibly add a MIME header for the current coding system (let (charset) (goto-char (point-min)) (and (eq mail-send-nonascii 'mime) (not (re-search-forward "^MIME-version:" delimline t)) (progn (skip-chars-forward "\0-\177") (/= (point) (point-max))) smtpmail-code-conv-from (setq charset (coding-system-get smtpmail-code-conv-from 'mime-charset)) (goto-char delimline) (insert "MIME-version: 1.0\n" "Content-type: text/plain; charset=" (symbol-name charset) "\nContent-Transfer-Encoding: 8bit\n"))) ;; Insert an extra newline if we need it to work around ;; Sun's bug that swallows newlines. (goto-char (1+ delimline)) (if (eval mail-mailer-swallows-blank-line) (newline)) ;; Find and handle any FCC fields. (goto-char (point-min)) (if (re-search-forward "^FCC:" delimline t) ;; Force mail-do-fcc to use the encoding of the mail ;; buffer to encode outgoing messages on FCC files. (let ((coding-system-for-write smtpmail-code-conv-from)) (mail-do-fcc delimline))) (if mail-interactive (with-current-buffer errbuf (erase-buffer)))) ;; ;; ;; (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*")) (setq smtpmail-recipient-address-list (smtpmail-deduce-address-list tembuf (point-min) delimline)) (kill-buffer smtpmail-address-buffer) (smtpmail-do-bcc delimline) ; Send or queue (if (not smtpmail-queue-mail) (if (not (null smtpmail-recipient-address-list)) (if (not (smtpmail-via-smtp smtpmail-recipient-address-list tembuf)) (error "Sending failed; SMTP protocol error")) (error "Sending failed; no recipients")) (let* ((file-data (expand-file-name (format "%s_%i" (format-time-string "%Y-%m-%d_%H:%M:%S") (setq smtpmail-queue-counter (1+ smtpmail-queue-counter))) smtpmail-queue-dir)) (file-data (convert-standard-filename file-data)) (file-elisp (concat file-data ".el")) (buffer-data (create-file-buffer file-data)) (buffer-elisp (create-file-buffer file-elisp)) (buffer-scratch "*queue-mail*")) (unless (file-exists-p smtpmail-queue-dir) (make-directory smtpmail-queue-dir t)) (with-current-buffer buffer-data (erase-buffer) (set-buffer-file-coding-system smtpmail-code-conv-from nil t) (insert-buffer-substring tembuf) (write-file file-data) (set-buffer buffer-elisp) (erase-buffer) (insert (concat "(setq smtpmail-recipient-address-list '" (prin1-to-string smtpmail-recipient-address-list) ")\n")) (write-file file-elisp) (set-buffer (generate-new-buffer buffer-scratch)) (insert (concat file-data "\n")) (append-to-file (point-min) (point-max) smtpmail-queue-index) ) (kill-buffer buffer-scratch) (kill-buffer buffer-data) (kill-buffer buffer-elisp)))) (kill-buffer tembuf) (if (bufferp errbuf) (kill-buffer errbuf))))) ;;;###autoload (defun smtpmail-send-queued-mail () "Send mail that was queued as a result of setting `smtpmail-queue-mail'." (interactive) (with-temp-buffer ;;; Get index, get first mail, send it, update index, get second ;;; mail, send it, etc... (let ((file-msg "")) (insert-file-contents smtpmail-queue-index) (goto-char (point-min)) (while (not (eobp)) (setq file-msg (buffer-substring (point) (line-end-position))) (load file-msg) ;; Insert the message literally: it is already encoded as per ;; the MIME headers, and code conversions might guess the ;; encoding wrongly. (with-temp-buffer (let ((coding-system-for-read 'no-conversion)) (insert-file-contents file-msg)) (let ((smtpmail-mail-address (or (and mail-specify-envelope-from (mail-envelope-from)) user-mail-address))) (if (not (null smtpmail-recipient-address-list)) (if (not (smtpmail-via-smtp smtpmail-recipient-address-list (current-buffer))) (error "Sending failed; SMTP protocol error")) (error "Sending failed; no recipients")))) (delete-file file-msg) (delete-file (concat file-msg ".el")) (delete-region (point-at-bol) (point-at-bol 2))) (write-region (point-min) (point-max) smtpmail-queue-index)))) ;(defun smtpmail-via-smtp (host,port,sender,destination,smtpmail-text-buffer) (defun smtpmail-fqdn () (if smtpmail-local-domain (concat (system-name) "." smtpmail-local-domain) (system-name))) (defsubst smtpmail-cred-server (cred) (nth 0 cred)) (defsubst smtpmail-cred-port (cred) (nth 1 cred)) (defsubst smtpmail-cred-key (cred) (nth 2 cred)) (defsubst smtpmail-cred-user (cred) (nth 2 cred)) (defsubst smtpmail-cred-cert (cred) (nth 3 cred)) (defsubst smtpmail-cred-passwd (cred) (nth 3 cred)) (defun smtpmail-find-credentials (cred server port) (catch 'done (let ((l cred) el) (while (setq el (pop l)) (when (and (equal server (smtpmail-cred-server el)) (equal port (smtpmail-cred-port el))) (throw 'done el)))))) (defun smtpmail-maybe-append-domain (recipient) (if (or (not smtpmail-sendto-domain) (string-match "@" recipient)) recipient (concat recipient "@" smtpmail-sendto-domain))) (defun smtpmail-intersection (list1 list2) (let ((result nil)) (dolist (el2 list2) (when (memq el2 list1) (push el2 result))) (nreverse result))) (defvar starttls-extra-args) (defvar starttls-extra-arguments) (defun smtpmail-open-stream (process-buffer host port) (let ((cred (smtpmail-find-credentials smtpmail-starttls-credentials host port))) (if (null (and cred (condition-case () (with-no-warnings (require 'starttls) (call-process (if starttls-use-gnutls starttls-gnutls-program starttls-program))) (error nil)))) ;; The normal case. (open-network-stream "SMTP" process-buffer host port) (let* ((cred-key (smtpmail-cred-key cred)) (cred-cert (smtpmail-cred-cert cred)) (starttls-extra-args (append starttls-extra-args (when (and (stringp cred-key) (stringp cred-cert) (file-regular-p (setq cred-key (expand-file-name cred-key))) (file-regular-p (setq cred-cert (expand-file-name cred-cert)))) (list "--key-file" cred-key "--cert-file" cred-cert)))) (starttls-extra-arguments (append starttls-extra-arguments (when (and (stringp cred-key) (stringp cred-cert) (file-regular-p (setq cred-key (expand-file-name cred-key))) (file-regular-p (setq cred-cert (expand-file-name cred-cert)))) (list "--x509keyfile" cred-key "--x509certfile" cred-cert))))) (starttls-open-stream "SMTP" process-buffer host port))))) (defun smtpmail-try-auth-methods (process supported-extensions host port) (let* ((mechs (cdr-safe (assoc 'auth supported-extensions))) (mech (car (smtpmail-intersection smtpmail-auth-supported mechs))) (cred (if (stringp smtpmail-auth-credentials) (let* ((netrc (netrc-parse smtpmail-auth-credentials)) (port-name (format "%s" (or port "smtp"))) (hostentry (netrc-machine netrc host port-name port-name))) (when hostentry (list host port (netrc-get hostentry "login") (netrc-get hostentry "password")))) (smtpmail-find-credentials smtpmail-auth-credentials host port))) (passwd (when cred (or (smtpmail-cred-passwd cred) (read-passwd (format "SMTP password for %s:%s: " (smtpmail-cred-server cred) (smtpmail-cred-port cred)))))) ret) (when (and cred mech) (cond ((eq mech 'cram-md5) (smtpmail-send-command process (upcase (format "AUTH %s" mech))) (if (or (null (car (setq ret (smtpmail-read-response process)))) (not (integerp (car ret))) (>= (car ret) 400)) (throw 'done nil)) (when (eq (car ret) 334) (let* ((challenge (substring (cadr ret) 4)) (decoded (base64-decode-string challenge)) (hash (rfc2104-hash 'md5 64 16 passwd decoded)) (response (concat (smtpmail-cred-user cred) " " hash)) ;; Osamu Yamane <yamane@green.ocn.ne.jp>: ;; SMTP auth fails because the SMTP server identifies ;; only the first part of the string (delimited by ;; new line characters) as a response from the ;; client, and the rest as distinct commands. ;; In my case, the response string is 80 characters ;; long. Without the no-line-break option for ;; base64-encode-sting, only the first 76 characters ;; are taken as a response to the server, and the ;; authentication fails. (encoded (base64-encode-string response t))) (smtpmail-send-command process (format "%s" encoded)) (if (or (null (car (setq ret (smtpmail-read-response process)))) (not (integerp (car ret))) (>= (car ret) 400)) (throw 'done nil))))) ((eq mech 'login) (smtpmail-send-command process "AUTH LOGIN") (if (or (null (car (setq ret (smtpmail-read-response process)))) (not (integerp (car ret))) (>= (car ret) 400)) (throw 'done nil)) (smtpmail-send-command process (base64-encode-string (smtpmail-cred-user cred) t)) (if (or (null (car (setq ret (smtpmail-read-response process)))) (not (integerp (car ret))) (>= (car ret) 400)) (throw 'done nil)) (smtpmail-send-command process (base64-encode-string passwd t)) (if (or (null (car (setq ret (smtpmail-read-response process)))) (not (integerp (car ret))) (>= (car ret) 400)) (throw 'done nil))) ((eq mech 'plain) ;; We used to send an empty initial request, and wait for an ;; empty response, and then send the password, but this ;; violate a SHOULD in RFC 2222 paragraph 5.1. Note that this ;; is not sent if the server did not advertise AUTH PLAIN in ;; the EHLO response. See RFC 2554 for more info. (smtpmail-send-command process (concat "AUTH PLAIN " (base64-encode-string (concat "\0" (smtpmail-cred-user cred) "\0" passwd) t))) (if (or (null (car (setq ret (smtpmail-read-response process)))) (not (integerp (car ret))) (not (equal (car ret) 235))) (throw 'done nil))) (t (error "Mechanism %s not implemented" mech))) ;; Remember the password. (when (and (not (stringp smtpmail-auth-credentials)) (null (smtpmail-cred-passwd cred))) (setcar (cdr (cdr (cdr cred))) passwd))))) (defun smtpmail-via-smtp (recipient smtpmail-text-buffer) (let ((process nil) (host (or smtpmail-smtp-server (error "`smtpmail-smtp-server' not defined"))) (port smtpmail-smtp-service) ;; smtpmail-mail-address should be set to the appropriate ;; buffer-local value by the caller, but in case not: (envelope-from (or smtpmail-mail-address (and mail-specify-envelope-from (mail-envelope-from)) user-mail-address)) response-code greeting process-buffer (supported-extensions '())) (unwind-protect (catch 'done ;; get or create the trace buffer (setq process-buffer (get-buffer-create (format "*trace of SMTP session to %s*" host))) ;; clear the trace buffer of old output (with-current-buffer process-buffer (setq buffer-undo-list t) (erase-buffer)) ;; open the connection to the server (setq process (smtpmail-open-stream process-buffer host port)) (and (null process) (throw 'done nil)) ;; set the send-filter (set-process-filter process 'smtpmail-process-filter) (with-current-buffer process-buffer (set-buffer-process-coding-system 'raw-text-unix 'raw-text-unix) (make-local-variable 'smtpmail-read-point) (setq smtpmail-read-point (point-min)) (if (or (null (car (setq greeting (smtpmail-read-response process)))) (not (integerp (car greeting))) (>= (car greeting) 400)) (throw 'done nil) ) (let ((do-ehlo t) (do-starttls t)) (while do-ehlo ;; EHLO (smtpmail-send-command process (format "EHLO %s" (smtpmail-fqdn))) (if (or (null (car (setq response-code (smtpmail-read-response process)))) (not (integerp (car response-code))) (>= (car response-code) 400)) (progn ;; HELO (smtpmail-send-command process (format "HELO %s" (smtpmail-fqdn))) (if (or (null (car (setq response-code (smtpmail-read-response process)))) (not (integerp (car response-code))) (>= (car response-code) 400)) (throw 'done nil))) (dolist (line (cdr (cdr response-code))) (let ((name (with-case-table ascii-case-table (mapcar (lambda (s) (intern (downcase s))) (split-string (substring line 4) "[ ]"))))) (and (eq (length name) 1) (setq name (car name))) (and name (cond ((memq (if (consp name) (car name) name) '(verb xvrb 8bitmime onex xone expn size dsn etrn enhancedstatuscodes help xusr auth=login auth starttls)) (setq supported-extensions (cons name supported-extensions))) (smtpmail-warn-about-unknown-extensions (message "Unknown extension %s" name))))))) (if (and do-starttls (smtpmail-find-credentials smtpmail-starttls-credentials host port) (member 'starttls supported-extensions) (numberp (process-id process))) (progn (smtpmail-send-command process (format "STARTTLS")) (if (or (null (car (setq response-code (smtpmail-read-response process)))) (not (integerp (car response-code))) (>= (car response-code) 400)) (throw 'done nil)) (starttls-negotiate process) (setq do-starttls nil)) (setq do-ehlo nil)))) (smtpmail-try-auth-methods process supported-extensions host port) (if (or (member 'onex supported-extensions) (member 'xone supported-extensions)) (progn (smtpmail-send-command process (format "ONEX")) (if (or (null (car (setq response-code (smtpmail-read-response process)))) (not (integerp (car response-code))) (>= (car response-code) 400)) (throw 'done nil)))) (if (and smtpmail-debug-verb (or (member 'verb supported-extensions) (member 'xvrb supported-extensions))) (progn (smtpmail-send-command process (format "VERB")) (if (or (null (car (setq response-code (smtpmail-read-response process)))) (not (integerp (car response-code))) (>= (car response-code) 400)) (throw 'done nil)))) (if (member 'xusr supported-extensions) (progn (smtpmail-send-command process (format "XUSR")) (if (or (null (car (setq response-code (smtpmail-read-response process)))) (not (integerp (car response-code))) (>= (car response-code) 400)) (throw 'done nil)))) ;; MAIL FROM:<sender> (let ((size-part (if (or (member 'size supported-extensions) (assoc 'size supported-extensions)) (format " SIZE=%d" (with-current-buffer smtpmail-text-buffer ;; size estimate: (+ (- (point-max) (point-min)) ;; Add one byte for each change-of-line ;; because of CR-LF representation: (count-lines (point-min) (point-max))))) "")) (body-part (if (member '8bitmime supported-extensions) ;; FIXME: ;; Code should be added here that transforms ;; the contents of the message buffer into ;; something the receiving SMTP can handle. ;; For a receiver that supports 8BITMIME, this ;; may mean converting BINARY to BASE64, or ;; adding Content-Transfer-Encoding and the ;; other MIME headers. The code should also ;; return an indication of what encoding the ;; message buffer is now, i.e. ASCII or ;; 8BITMIME. (if nil " BODY=8BITMIME" "") ""))) ; (smtpmail-send-command process (format "MAIL FROM:%s@%s" (user-login-name) (smtpmail-fqdn))) (smtpmail-send-command process (format "MAIL FROM:<%s>%s%s" envelope-from size-part body-part)) (if (or (null (car (setq response-code (smtpmail-read-response process)))) (not (integerp (car response-code))) (>= (car response-code) 400)) (throw 'done nil) )) ;; RCPT TO:<recipient> (let ((n 0)) (while (not (null (nth n recipient))) (smtpmail-send-command process (format "RCPT TO:<%s>" (smtpmail-maybe-append-domain (nth n recipient)))) (setq n (1+ n)) (setq response-code (smtpmail-read-response process)) (if (or (null (car response-code)) (not (integerp (car response-code))) (>= (car response-code) 400)) (throw 'done nil) ) )) ;; DATA (smtpmail-send-command process "DATA") (if (or (null (car (setq response-code (smtpmail-read-response process)))) (not (integerp (car response-code))) (>= (car response-code) 400)) (throw 'done nil) ) ;; Mail contents (smtpmail-send-data process smtpmail-text-buffer) ;;DATA end "." (smtpmail-send-command process ".") (if (or (null (car (setq response-code (smtpmail-read-response process)))) (not (integerp (car response-code))) (>= (car response-code) 400)) (throw 'done nil) ) ;;QUIT ; (smtpmail-send-command process "QUIT") ; (and (null (car (smtpmail-read-response process))) ; (throw 'done nil)) t )) (if process (with-current-buffer (process-buffer process) (smtpmail-send-command process "QUIT") (smtpmail-read-response process) ; (if (or (null (car (setq response-code (smtpmail-read-response process)))) ; (not (integerp (car response-code))) ; (>= (car response-code) 400)) ; (throw 'done nil) ; ) (delete-process process) (unless smtpmail-debug-info (kill-buffer process-buffer))))))) (defun smtpmail-process-filter (process output) (with-current-buffer (process-buffer process) (goto-char (point-max)) (insert output))) (defun smtpmail-read-response (process) (let ((case-fold-search nil) (response-strings nil) (response-continue t) (return-value '(nil ())) match-end) (catch 'done (while response-continue (goto-char smtpmail-read-point) (while (not (search-forward "\r\n" nil t)) (unless (memq (process-status process) '(open run)) (throw 'done nil)) (accept-process-output process) (goto-char smtpmail-read-point)) (setq match-end (point)) (setq response-strings (cons (buffer-substring smtpmail-read-point (- match-end 2)) response-strings)) (goto-char smtpmail-read-point) (if (looking-at "[0-9]+ ") (let ((begin (match-beginning 0)) (end (match-end 0))) (if smtpmail-debug-info (message "%s" (car response-strings))) (setq smtpmail-read-point match-end) ;; ignore lines that start with "0" (if (looking-at "0[0-9]+ ") nil (setq response-continue nil) (setq return-value (cons (string-to-number (buffer-substring begin end)) (nreverse response-strings))))) (if (looking-at "[0-9]+-") (progn (if smtpmail-debug-info (message "%s" (car response-strings))) (setq smtpmail-read-point match-end) (setq response-continue t)) (progn (setq smtpmail-read-point match-end) (setq response-continue nil) (setq return-value (cons nil (nreverse response-strings))))))) (setq smtpmail-read-point match-end)) return-value)) (defun smtpmail-send-command (process command) (goto-char (point-max)) (if (= (aref command 0) ?P) (insert "PASS <omitted>\r\n") (insert command "\r\n")) (setq smtpmail-read-point (point)) (process-send-string process command) (process-send-string process "\r\n")) (defun smtpmail-send-data-1 (process data) (goto-char (point-max)) (if (and (multibyte-string-p data) smtpmail-code-conv-from) (setq data (string-as-multibyte (encode-coding-string data smtpmail-code-conv-from)))) (if smtpmail-debug-info (insert data "\r\n")) (setq smtpmail-read-point (point)) ;; Escape "." at start of a line (if (eq (string-to-char data) ?.) (process-send-string process ".")) (process-send-string process data) (process-send-string process "\r\n") ) (defun smtpmail-send-data (process buffer) (let ((data-continue t) sending-data) (with-current-buffer buffer (goto-char (point-min))) (while data-continue (with-current-buffer buffer (setq sending-data (buffer-substring (point-at-bol) (point-at-eol))) (end-of-line 2) (setq data-continue (not (eobp)))) (smtpmail-send-data-1 process sending-data)))) (defun smtpmail-deduce-address-list (smtpmail-text-buffer header-start header-end) "Get address list suitable for smtp RCPT TO: <address>." (unwind-protect (with-current-buffer smtpmail-address-buffer (erase-buffer) (let ((case-fold-search t) (simple-address-list "") this-line this-line-end addr-regexp) (insert-buffer-substring smtpmail-text-buffer header-start header-end) (goto-char (point-min)) ;; RESENT-* fields should stop processing of regular fields. (save-excursion (setq addr-regexp (if (re-search-forward "^Resent-\\(to\\|cc\\|bcc\\):" header-end t) "^Resent-\\(to\\|cc\\|bcc\\):" "^\\(To:\\|Cc:\\|Bcc:\\)"))) (while (re-search-forward addr-regexp header-end t) (replace-match "") (setq this-line (match-beginning 0)) (forward-line 1) ;; get any continuation lines (while (and (looking-at "^[ \t]+") (< (point) header-end)) (forward-line 1)) (setq this-line-end (point-marker)) (setq simple-address-list (concat simple-address-list " " (mail-strip-quoted-names (buffer-substring this-line this-line-end)))) ) (erase-buffer) (insert " " simple-address-list "\n") (subst-char-in-region (point-min) (point-max) 10 ? t);; newline --> blank (subst-char-in-region (point-min) (point-max) ?, ? t);; comma --> blank (subst-char-in-region (point-min) (point-max) 9 ? t);; tab --> blank (goto-char (point-min)) ;; tidyness in case hook is not robust when it looks at this (while (re-search-forward "[ \t]+" header-end t) (replace-match " ")) (goto-char (point-min)) (let (recipient-address-list) (while (re-search-forward " \\([^ ]+\\) " (point-max) t) (backward-char 1) (setq recipient-address-list (cons (buffer-substring (match-beginning 1) (match-end 1)) recipient-address-list)) ) (setq smtpmail-recipient-address-list recipient-address-list)) ) ) ) ) (defun smtpmail-do-bcc (header-end) "Delete [Resent-]BCC: and their continuation lines from the header area. There may be multiple BCC: lines, and each may have arbitrarily many continuation lines." (let ((case-fold-search t)) (save-excursion (goto-char (point-min)) ;; iterate over all BCC: lines (while (re-search-forward "^\\(RESENT-\\)?BCC:" header-end t) (delete-region (match-beginning 0) (progn (forward-line 1) (point))) ;; get rid of any continuation lines (while (and (looking-at "^[ \t].*\n") (< (point) header-end)) (replace-match "")))))) (provide 'smtpmail) ;;; arch-tag: a76992df-6d71-43b7-9e72-4bacc6c05466 ;;; smtpmail.el ends here
author Bastien Guerry <bzg@altern.org>
date Wed, 13 Feb 2008 20:58:26 +0000
parents 107ccd98fa12
children 606f2d163a64 1e3a407766b9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
38414
67b464da13ec Some fixes to follow coding conventions.
Pavel Janík <Pavel@Janik.cz>
parents: 32526
diff changeset
1 ;;; esh-io.el --- I/O management
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
2
74509
f7702c5f335d Update copyright years.
Glenn Morris <rgm@gnu.org>
parents: 68648
diff changeset
3 ;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004,
79707
48c4bb2b7d11 Add 2008 to copyright years.
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
4 ;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
5
32526
8e57189d61b4 Add author information.
Gerd Moellmann <gerd@gnu.org>
parents: 31241
diff changeset
6 ;; Author: John Wiegley <johnw@gnu.org>
8e57189d61b4 Add author information.
Gerd Moellmann <gerd@gnu.org>
parents: 31241
diff changeset
7
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
8 ;; This file is part of GNU Emacs.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
9
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
11 ;; it under the terms of the GNU General Public License as published by
78220
a1e8300d3c55 Switch license to GPLv3 or later.
Glenn Morris <rgm@gnu.org>
parents: 75346
diff changeset
12 ;; the Free Software Foundation; either version 3, or (at your option)
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
13 ;; any later version.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
14
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
15 ;; GNU Emacs is distributed in the hope that it will be useful,
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
18 ;; GNU General Public License for more details.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
19
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
20 ;; You should have received a copy of the GNU General Public License
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
64085
18a818a2ee7c Update FSF's address.
Lute Kamstra <lute@gnu.org>
parents: 62915
diff changeset
22 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18a818a2ee7c Update FSF's address.
Lute Kamstra <lute@gnu.org>
parents: 62915
diff changeset
23 ;; Boston, MA 02110-1301, USA.
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
24
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
25 ;;; Commentary:
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
26
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
27 ;; At the moment, only output redirection is supported in Eshell. To
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
28 ;; use input redirection, the following syntax will work, assuming
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
29 ;; that the command after the pipe is always an external command:
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
30 ;;
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
31 ;; cat <file> | <command>
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
32 ;;
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
33 ;; Otherwise, output redirection and piping are provided in a manner
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
34 ;; consistent with most shells. Therefore, only unique features are
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
35 ;; mentioned here.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
36 ;;
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
37 ;;;_* Insertion
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
38 ;;
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
39 ;; To insert at the location of point in a buffer, use '>>>':
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
40 ;;
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
41 ;; echo alpha >>> #<buffer *scratch*>;
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
42 ;;
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
43 ;;;_* Pseudo-devices
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
44 ;;
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
45 ;; A few pseudo-devices are provided, since Emacs cannot write
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
46 ;; directly to a UNIX device file:
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
47 ;;
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
48 ;; echo alpha > /dev/null ; the bit bucket
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
49 ;; echo alpha > /dev/kill ; set the kill ring
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
50 ;; echo alpha >> /dev/clip ; append to the clipboard
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
51 ;;
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
52 ;;;_* Multiple output targets
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
53 ;;
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
54 ;; Eshell can write to multiple output targets, including pipes.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
55 ;; Example:
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
56 ;;
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
57 ;; (+ 1 2) > a > b > c ; prints number to all three files
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
58 ;; (+ 1 2) > a | wc ; prints to 'a', and pipes to 'wc'
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
59
87080
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
60 (provide 'esh-io)
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
61
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
62 (eval-when-compile (require 'eshell))
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
63
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
64 (defgroup eshell-io nil
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
65 "Eshell's I/O management code provides a scheme for treating many
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
66 different kinds of objects -- symbols, files, buffers, etc. -- as
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
67 though they were files."
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
68 :tag "I/O management"
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
69 :group 'eshell)
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
70
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
71 ;;; User Variables:
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
72
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
73 (defcustom eshell-io-load-hook '(eshell-io-initialize)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
74 "*A hook that gets run when `eshell-io' is loaded."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
75 :type 'hook
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
76 :group 'eshell-io)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
77
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
78 (defcustom eshell-number-of-handles 3
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
79 "*The number of file handles that eshell supports.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
80 Currently this is standard input, output and error. But even all of
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
81 these Emacs does not currently support with asynchronous processes
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
82 \(which is what eshell uses so that you can continue doing work in
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
83 other buffers) ."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
84 :type 'integer
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
85 :group 'eshell-io)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
86
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
87 (defcustom eshell-output-handle 1
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
88 "*The index of the standard output handle."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
89 :type 'integer
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
90 :group 'eshell-io)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
91
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
92 (defcustom eshell-error-handle 2
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
93 "*The index of the standard error handle."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
94 :type 'integer
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
95 :group 'eshell-io)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
96
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
97 (defcustom eshell-buffer-shorthand nil
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
98 "*If non-nil, a symbol name can be used for a buffer in redirection.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
99 If nil, redirecting to a buffer requires buffer name syntax. If this
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
100 variable is set, redirection directly to Lisp symbols will be
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
101 impossible.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
102
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
103 Example:
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
104
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
105 echo hello > '*scratch* ; works if `eshell-buffer-shorthand' is t
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
106 echo hello > #<buffer *scratch*> ; always works"
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
107 :type 'boolean
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
108 :group 'eshell-io)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
109
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
110 (defcustom eshell-print-queue-size 5
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
111 "*The size of the print queue, for doing buffered printing.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
112 This is basically a speed enhancement, to avoid blocking the Lisp code
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
113 from executing while Emacs is redisplaying."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
114 :type 'integer
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
115 :group 'eshell-io)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
116
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
117 (defcustom eshell-virtual-targets
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
118 '(("/dev/eshell" eshell-interactive-print nil)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
119 ("/dev/kill" (lambda (mode)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
120 (if (eq mode 'overwrite)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
121 (kill-new ""))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
122 'eshell-kill-append) t)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
123 ("/dev/clip" (lambda (mode)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
124 (if (eq mode 'overwrite)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
125 (let ((x-select-enable-clipboard t))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
126 (kill-new "")))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
127 'eshell-clipboard-append) t))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
128 "*Map virtual devices name to Emacs Lisp functions.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
129 If the user specifies any of the filenames above as a redirection
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
130 target, the function in the second element will be called.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
131
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
132 If the third element is non-nil, the redirection mode is passed as an
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
133 argument (which is the symbol `overwrite', `append' or `insert'), and
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
134 the function is expected to return another function -- which is the
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
135 output function. Otherwise, the second element itself is the output
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
136 function.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
137
31241
3099993cba0f See ChangeLog
John Wiegley <johnw@newartisans.com>
parents: 29934
diff changeset
138 The output function is then called repeatedly with single strings,
3099993cba0f See ChangeLog
John Wiegley <johnw@newartisans.com>
parents: 29934
diff changeset
139 which represents successive pieces of the output of the command, until nil
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
140 is passed, meaning EOF.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
141
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
142 NOTE: /dev/null is handled specially as a virtual target, and should
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
143 not be added to this variable."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
144 :type '(repeat
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
145 (list (string :tag "Target")
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
146 function
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
147 (choice (const :tag "Func returns output-func" t)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
148 (const :tag "Func is output-func" nil))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
149 :group 'eshell-io)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
150
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
151 (put 'eshell-virtual-targets 'risky-local-variable t)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
152
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
153 ;;; Internal Variables:
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
154
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
155 (defvar eshell-current-handles nil)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
156
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
157 (defvar eshell-last-command-status 0
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
158 "The exit code from the last command. 0 if successful.")
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
159
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
160 (defvar eshell-last-command-result nil
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
161 "The result of the last command. Not related to success.")
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
162
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
163 (defvar eshell-output-file-buffer nil
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
164 "If non-nil, the current buffer is a file output buffer.")
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
165
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
166 (defvar eshell-print-count)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
167 (defvar eshell-current-redirections)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
168
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
169 ;;; Functions:
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
170
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
171 (defun eshell-io-initialize ()
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
172 "Initialize the I/O subsystem code."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
173 (add-hook 'eshell-parse-argument-hook
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
174 'eshell-parse-redirection nil t)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
175 (make-local-variable 'eshell-current-redirections)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
176 (add-hook 'eshell-pre-rewrite-command-hook
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
177 'eshell-strip-redirections nil t)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
178 (add-hook 'eshell-post-rewrite-command-hook
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
179 'eshell-apply-redirections nil t))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
180
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
181 (defun eshell-parse-redirection ()
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
182 "Parse an output redirection, such as '2>'."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
183 (if (and (not eshell-current-quoted)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
184 (looking-at "\\([0-9]\\)?\\(<\\|>+\\)&?\\([0-9]\\)?\\s-*"))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
185 (if eshell-current-argument
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
186 (eshell-finish-arg)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
187 (let ((sh (match-string 1))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
188 (oper (match-string 2))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
189 ; (th (match-string 3))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
190 )
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
191 (if (string= oper "<")
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
192 (error "Eshell does not support input redirection"))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
193 (eshell-finish-arg
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
194 (prog1
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
195 (list 'eshell-set-output-handle
62915
b89e30bcd2bb Changed all uses of `directory-sep-char' to ?/, and all uses of
John Wiegley <johnw@newartisans.com>
parents: 62786
diff changeset
196 (or (and sh (string-to-number sh)) 1)
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
197 (list 'quote
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
198 (aref [overwrite append insert]
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
199 (1- (length oper)))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
200 (goto-char (match-end 0))))))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
201
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
202 (defun eshell-strip-redirections (terms)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
203 "Rewrite any output redirections in TERMS."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
204 (setq eshell-current-redirections (list t))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
205 (let ((tl terms)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
206 (tt (cdr terms)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
207 (while tt
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
208 (if (not (and (consp (car tt))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
209 (eq (caar tt) 'eshell-set-output-handle)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
210 (setq tt (cdr tt)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
211 tl (cdr tl))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
212 (unless (cdr tt)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
213 (error "Missing redirection target"))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
214 (nconc eshell-current-redirections
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
215 (list (list 'ignore
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
216 (append (car tt) (list (cadr tt))))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
217 (setcdr tl (cddr tt))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
218 (setq tt (cddr tt))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
219 (setq eshell-current-redirections
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
220 (cdr eshell-current-redirections))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
221
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
222 (defun eshell-apply-redirections (cmdsym)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
223 "Apply any redirection which were specified for COMMAND."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
224 (if eshell-current-redirections
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
225 (set cmdsym
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
226 (append (list 'progn)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
227 eshell-current-redirections
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
228 (list (symbol-value cmdsym))))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
229
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
230 (defun eshell-create-handles
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
231 (standard-output output-mode &optional standard-error error-mode)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
232 "Create a new set of file handles for a command.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
233 The default location for standard output and standard error will go to
31241
3099993cba0f See ChangeLog
John Wiegley <johnw@newartisans.com>
parents: 29934
diff changeset
234 STANDARD-OUTPUT and STANDARD-ERROR, respectively.
3099993cba0f See ChangeLog
John Wiegley <johnw@newartisans.com>
parents: 29934
diff changeset
235 OUTPUT-MODE and ERROR-MODE are either `overwrite', `append' or `insert';
3099993cba0f See ChangeLog
John Wiegley <johnw@newartisans.com>
parents: 29934
diff changeset
236 a nil value of mode defaults to `insert'."
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
237 (let ((handles (make-vector eshell-number-of-handles nil))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
238 (output-target (eshell-get-target standard-output output-mode))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
239 (error-target (eshell-get-target standard-error error-mode)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
240 (aset handles eshell-output-handle (cons output-target 1))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
241 (if standard-error
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
242 (aset handles eshell-error-handle (cons error-target 1))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
243 (aset handles eshell-error-handle (cons output-target 1)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
244 handles))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
245
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
246 (defun eshell-protect-handles (handles)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
247 "Protect the handles in HANDLES from a being closed."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
248 (let ((idx 0))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
249 (while (< idx eshell-number-of-handles)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
250 (if (aref handles idx)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
251 (setcdr (aref handles idx)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
252 (1+ (cdr (aref handles idx)))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
253 (setq idx (1+ idx))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
254 handles)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
255
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
256 (defun eshell-close-target (target status)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
257 "Close an output TARGET, passing STATUS as the result.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
258 STATUS should be non-nil on successful termination of the output."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
259 (cond
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
260 ((symbolp target) nil)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
261
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
262 ;; If we were redirecting to a file, save the file and close the
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
263 ;; buffer.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
264 ((markerp target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
265 (let ((buf (marker-buffer target)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
266 (when buf ; somebody's already killed it!
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
267 (save-current-buffer
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
268 (set-buffer buf)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
269 (when eshell-output-file-buffer
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
270 (save-buffer)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
271 (when (eq eshell-output-file-buffer t)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
272 (or status (set-buffer-modified-p nil))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
273 (kill-buffer buf)))))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
274
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
275 ;; If we're redirecting to a process (via a pipe, or process
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
276 ;; redirection), send it EOF so that it knows we're finished.
31241
3099993cba0f See ChangeLog
John Wiegley <johnw@newartisans.com>
parents: 29934
diff changeset
277 ((eshell-processp target)
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
278 (if (eq (process-status target) 'run)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
279 (process-send-eof target)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
280
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
281 ;; A plain function redirection needs no additional arguments
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
282 ;; passed.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
283 ((functionp target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
284 (funcall target status))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
285
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
286 ;; But a more complicated function redirection (which can only
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
287 ;; happen with aliases at the moment) has arguments that need to be
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
288 ;; passed along with it.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
289 ((consp target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
290 (apply (car target) status (cdr target)))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
291
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
292 (defun eshell-close-handles (exit-code &optional result handles)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
293 "Close all of the current handles, taking refcounts into account.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
294 EXIT-CODE is the process exit code; mainly, it is zero, if the command
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
295 completed successfully. RESULT is the quoted value of the last
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
296 command. If nil, then the meta variables for keeping track of the
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
297 last execution result should not be changed."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
298 (let ((idx 0))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
299 (assert (or (not result) (eq (car result) 'quote)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
300 (setq eshell-last-command-status exit-code
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
301 eshell-last-command-result (cadr result))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
302 (while (< idx eshell-number-of-handles)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
303 (let ((handles (or handles eshell-current-handles)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
304 (when (aref handles idx)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
305 (setcdr (aref handles idx)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
306 (1- (cdr (aref handles idx))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
307 (when (= (cdr (aref handles idx)) 0)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
308 (let ((target (car (aref handles idx))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
309 (if (not (listp target))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
310 (eshell-close-target target (= exit-code 0))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
311 (while target
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
312 (eshell-close-target (car target) (= exit-code 0))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
313 (setq target (cdr target)))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
314 (setcar (aref handles idx) nil))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
315 (setq idx (1+ idx)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
316 nil))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
317
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
318 (defun eshell-kill-append (string)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
319 "Call `kill-append' with STRING, if it is indeed a string."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
320 (if (stringp string)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
321 (kill-append string nil)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
322
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
323 (defun eshell-clipboard-append (string)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
324 "Call `kill-append' with STRING, if it is indeed a string."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
325 (if (stringp string)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
326 (let ((x-select-enable-clipboard t))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
327 (kill-append string nil))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
328
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
329 (defun eshell-get-target (target &optional mode)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
330 "Convert TARGET, which is a raw argument, into a valid output target.
31241
3099993cba0f See ChangeLog
John Wiegley <johnw@newartisans.com>
parents: 29934
diff changeset
331 MODE is either `overwrite', `append' or `insert'; if it is omitted or nil,
3099993cba0f See ChangeLog
John Wiegley <johnw@newartisans.com>
parents: 29934
diff changeset
332 it defaults to `insert'."
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
333 (setq mode (or mode 'insert))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
334 (cond
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
335 ((stringp target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
336 (let ((redir (assoc target eshell-virtual-targets)))
55613
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
337 (if redir
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
338 (if (nth 2 redir)
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
339 (funcall (nth 1 redir) mode)
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
340 (nth 1 redir))
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
341 (let* ((exists (get-file-buffer target))
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
342 (buf (find-file-noselect target t)))
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
343 (with-current-buffer buf
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
344 (if buffer-read-only
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
345 (error "Cannot write to read-only file `%s'" target))
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
346 (set (make-local-variable 'eshell-output-file-buffer)
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
347 (if (eq exists buf) 0 t))
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
348 (cond ((eq mode 'overwrite)
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
349 (erase-buffer))
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
350 ((eq mode 'append)
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
351 (goto-char (point-max))))
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
352 (point-marker))))))
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
353
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
354 ((or (bufferp target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
355 (and (boundp 'eshell-buffer-shorthand)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
356 (symbol-value 'eshell-buffer-shorthand)
62786
dc758ba35d6c (eshell-get-target): If `eshell-buffer-shorthand' is in use, and the
John Wiegley <johnw@newartisans.com>
parents: 60915
diff changeset
357 (symbolp target)
dc758ba35d6c (eshell-get-target): If `eshell-buffer-shorthand' is in use, and the
John Wiegley <johnw@newartisans.com>
parents: 60915
diff changeset
358 (not (memq target '(t nil)))))
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
359 (let ((buf (if (bufferp target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
360 target
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
361 (get-buffer-create
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
362 (symbol-name target)))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
363 (with-current-buffer buf
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
364 (cond ((eq mode 'overwrite)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
365 (erase-buffer))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
366 ((eq mode 'append)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
367 (goto-char (point-max))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
368 (point-marker))))
55613
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
369
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
370 ((functionp target) nil)
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
371
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
372 ((symbolp target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
373 (if (eq mode 'overwrite)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
374 (set target nil))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
375 target)
55613
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
376
31241
3099993cba0f See ChangeLog
John Wiegley <johnw@newartisans.com>
parents: 29934
diff changeset
377 ((or (eshell-processp target)
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
378 (markerp target))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
379 target)
55613
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
380
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
381 (t
60915
a72129314db4 * eshell/esh-io.el, eshell/esh-var.el: Replace `illegal' with
Werner LEMBERG <wl@gnu.org>
parents: 55613
diff changeset
382 (error "Invalid redirection target: %s"
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
383 (eshell-stringify target)))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
384
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
385 (eval-when-compile
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
386 (defvar grep-null-device))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
387
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
388 (defun eshell-set-output-handle (index mode &optional target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
389 "Set handle INDEX, using MODE, to point to TARGET."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
390 (when target
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
391 (if (and (stringp target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
392 (or (cond
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
393 ((boundp 'null-device)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
394 (string= target null-device))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
395 ((boundp 'grep-null-device)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
396 (string= target grep-null-device))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
397 (t nil))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
398 (string= target "/dev/null")))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
399 (aset eshell-current-handles index nil)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
400 (let ((where (eshell-get-target target mode))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
401 (current (car (aref eshell-current-handles index))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
402 (if (and (listp current)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
403 (not (member where current)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
404 (setq current (append current (list where)))
47971
526a8d279adb Bob Halley <halley@play-bow.org>: (eshell-set-output-handle): Fix so
John Wiegley <johnw@newartisans.com>
parents: 43337
diff changeset
405 (setq current (list where)))
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
406 (if (not (aref eshell-current-handles index))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
407 (aset eshell-current-handles index (cons nil 1)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
408 (setcar (aref eshell-current-handles index) current)))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
409
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
410 (defun eshell-interactive-output-p ()
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
411 "Return non-nil if current handles are bound for interactive display."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
412 (and (eq (car (aref eshell-current-handles
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
413 eshell-output-handle)) t)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
414 (eq (car (aref eshell-current-handles
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
415 eshell-error-handle)) t)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
416
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
417 (defvar eshell-print-queue nil)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
418 (defvar eshell-print-queue-count -1)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
419
87080
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
420 (defsubst eshell-print (object)
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
421 "Output OBJECT to the standard output handle."
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
422 (eshell-output-object object eshell-output-handle))
3767c8399782 Require individual files if needed when compiling, rather than
Glenn Morris <rgm@gnu.org>
parents: 78220
diff changeset
423
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
424 (defun eshell-flush (&optional reset-p)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
425 "Flush out any lines that have been queued for printing.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
426 Must be called before printing begins with -1 as its argument, and
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
427 after all printing is over with no argument."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
428 (ignore
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
429 (if reset-p
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
430 (setq eshell-print-queue nil
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
431 eshell-print-queue-count reset-p)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
432 (if eshell-print-queue
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
433 (eshell-print eshell-print-queue))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
434 (eshell-flush 0))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
435
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
436 (defun eshell-init-print-buffer ()
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
437 "Initialize the buffered printing queue."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
438 (eshell-flush -1))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
439
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
440 (defun eshell-buffered-print (&rest strings)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
441 "A buffered print -- *for strings only*."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
442 (if (< eshell-print-queue-count 0)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
443 (progn
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
444 (eshell-print (apply 'concat strings))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
445 (setq eshell-print-queue-count 0))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
446 (if (= eshell-print-queue-count eshell-print-queue-size)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
447 (eshell-flush))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
448 (setq eshell-print-queue
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
449 (concat eshell-print-queue (apply 'concat strings))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
450 eshell-print-queue-count (1+ eshell-print-queue-count))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
451
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
452 (defsubst eshell-error (object)
31241
3099993cba0f See ChangeLog
John Wiegley <johnw@newartisans.com>
parents: 29934
diff changeset
453 "Output OBJECT to the standard error handle."
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
454 (eshell-output-object object eshell-error-handle))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
455
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
456 (defsubst eshell-errorn (object)
31241
3099993cba0f See ChangeLog
John Wiegley <johnw@newartisans.com>
parents: 29934
diff changeset
457 "Output OBJECT followed by a newline to the standard error handle."
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
458 (eshell-error object)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
459 (eshell-error "\n"))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
460
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
461 (defsubst eshell-printn (object)
31241
3099993cba0f See ChangeLog
John Wiegley <johnw@newartisans.com>
parents: 29934
diff changeset
462 "Output OBJECT followed by a newline to the standard output handle."
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
463 (eshell-print object)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
464 (eshell-print "\n"))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
465
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
466 (defun eshell-output-object-to-target (object target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
467 "Insert OBJECT into TARGET.
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
468 Returns what was actually sent, or nil if nothing was sent."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
469 (cond
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
470 ((functionp target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
471 (funcall target object))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
472
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
473 ((symbolp target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
474 (if (eq target t) ; means "print to display"
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
475 (eshell-output-filter nil (eshell-stringify object))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
476 (if (not (symbol-value target))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
477 (set target object)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
478 (setq object (eshell-stringify object))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
479 (if (not (stringp (symbol-value target)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
480 (set target (eshell-stringify
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
481 (symbol-value target))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
482 (set target (concat (symbol-value target) object)))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
483
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
484 ((markerp target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
485 (if (buffer-live-p (marker-buffer target))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
486 (with-current-buffer (marker-buffer target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
487 (let ((moving (= (point) target)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
488 (save-excursion
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
489 (goto-char target)
55613
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
490 (unless (stringp object)
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
491 (setq object (eshell-stringify object)))
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
492 (insert-and-inherit object)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
493 (set-marker target (point-marker)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
494 (if moving
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
495 (goto-char target))))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
496
31241
3099993cba0f See ChangeLog
John Wiegley <johnw@newartisans.com>
parents: 29934
diff changeset
497 ((eshell-processp target)
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
498 (when (eq (process-status target) 'run)
55613
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
499 (unless (stringp object)
8e3531a00902 2004-05-15 John Wiegley <johnw@newartisans.com>
John Wiegley <johnw@newartisans.com>
parents: 52401
diff changeset
500 (setq object (eshell-stringify object)))
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
501 (process-send-string target object)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
502
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
503 ((consp target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
504 (apply (car target) object (cdr target))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
505 object)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
506
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
507 (defun eshell-output-object (object &optional handle-index handles)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
508 "Insert OBJECT, using HANDLE-INDEX specifically)."
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
509 (let ((target (car (aref (or handles eshell-current-handles)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
510 (or handle-index eshell-output-handle)))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
511 (if (and target (not (listp target)))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
512 (eshell-output-object-to-target object target)
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
513 (while target
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
514 (eshell-output-object-to-target object (car target))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
515 (setq target (cdr target))))))
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
516
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
517 ;;; Code:
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
518
52401
695cf19ef79e Add arch taglines
Miles Bader <miles@gnu.org>
parents: 47971
diff changeset
519 ;;; arch-tag: 9ca2080f-d5e0-4b26-aa0b-d59194a905a2
29876
edfec1c0d511 *** empty log message ***
Gerd Moellmann <gerd@gnu.org>
parents:
diff changeset
520 ;;; esh-io.el ends here