changeset 35:63b375f17a65

Initial revision
author Jim Blandy <jimb@redhat.com>
date Tue, 31 Oct 1989 15:59:53 +0000
parents edf8af31003b
children 9697c13298e5
files lisp/=grow-vers.el lisp/=inc-vers.el lisp/=mim-syntax.el lisp/=netunam.el lisp/=sun-keys.el lisp/=vmsx.el lisp/electric.el lisp/emulation/mlsupport.el lisp/loadup.el lisp/mail/rmailmsc.el lisp/mail/rnews.el lisp/mail/rnewspost.el lisp/mail/undigest.el lisp/misc.el lisp/sun-curs.el lisp/sun-fns.el lisp/term/sun-mouse.el lisp/term/sup-mouse.el lisp/vmsproc.el lisp/x-menu.el
diffstat 20 files changed, 4815 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/=grow-vers.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,30 @@
+;; Load this file to add a new level (starting at zero)
+;; to the Emacs version number recorded in version.el.
+;; Copyright (C) 1985 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+(insert-file-contents "lisp/version.el")
+
+(re-search-forward "emacs-version \"[0-9.]*")
+(insert ".0")
+
+;; Delete the share-link with the current version
+;; so that we do not alter the current version.
+(delete-file "lisp/version.el")
+(write-region (point-min) (point-max) "lisp/version.el" nil 'nomsg)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/=inc-vers.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,43 @@
+;; Load this file to increment the recorded Emacs version number.
+;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+(insert-file-contents "../lisp/version.el")
+
+(re-search-forward "emacs-version \"[^\"]*[0-9]+\"")
+(forward-char -1)
+(save-excursion
+  (save-restriction
+    (narrow-to-region (point)
+		      (progn (skip-chars-backward "0-9") (point)))
+    (goto-char (point-min))
+    (let ((version (read (current-buffer))))
+      (delete-region (point-min) (point-max))
+      (prin1 (1+ version) (current-buffer)))))
+(skip-chars-backward "^\"")
+(message "New Emacs version will be %s"
+	 (buffer-substring (point)
+			   (progn (skip-chars-forward "^\"") (point))))
+
+
+(write-region (point-min) (point-max) "../lisp/version.el" nil 'nomsg)
+(erase-buffer)
+(set-buffer-modified-p nil)
+
+(kill-emacs)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/=mim-syntax.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,91 @@
+;; Syntax checker for Mim (MDL).
+;; Copyright (C) 1985 Free Software Foundation, Inc.
+;; Principal author K. Shane Hartman
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+(require 'mim-mode)
+
+(defun slow-syntax-check-mim ()
+  "Check Mim syntax slowly.
+Points out the context of the error, if the syntax is incorrect."
+  (interactive)
+  (message "checking syntax...")
+  (let ((stop (point-max)) point-stack current last-bracket whoops last-point)
+    (save-excursion
+      (goto-char (point-min))
+      (while (and (not whoops)
+		  (re-search-forward "\\s(\\|\\s)\\|\"\\|[\\]" stop t))
+	(setq current (preceding-char))
+	(cond ((= current ?\")
+	       (condition-case nil
+		   (progn (re-search-forward "[^\\]\"")
+			  (setq current nil))
+		 (error (setq whoops (point)))))
+	      ((= current ?\\)
+	       (condition-case nil (forward-char 1) (error nil)))
+	      ((= (char-syntax current) ?\))
+	       (if (or (not last-bracket)
+		       (not (= (logand (lsh (aref (syntax-table) last-bracket) -8)
+				       ?\177)
+			       current)))
+		   (setq whoops (point))
+		 (setq last-point (car point-stack))
+		 (setq last-bracket (if last-point (char-after (1- last-point))))
+		 (setq point-stack (cdr point-stack))))
+	      (t
+	       (if last-point (setq point-stack (cons last-point point-stack)))
+	       (setq last-point (point))
+	       (setq last-bracket current)))))
+    (cond ((not (or whoops last-point))
+	   (message "Syntax correct"))
+	  (whoops
+	   (goto-char whoops)
+	   (cond ((equal current ?\")
+		  (error "Unterminated string"))
+		 ((not last-point)
+		  (error "Extraneous %s" (char-to-string current)))
+		 (t
+		  (error "Mismatched %s with %s"
+			   (save-excursion
+			     (setq whoops (1- (point)))
+			     (goto-char (1- last-point))
+			     (buffer-substring (point)
+					       (min (progn (end-of-line) (point))
+						    whoops)))
+			   (char-to-string current)))))
+	  (t
+	   (goto-char last-point)
+	   (error "Unmatched %s" (char-to-string last-bracket))))))
+      
+(defun fast-syntax-check-mim ()
+  "Checks Mim syntax quickly.
+Answers correct or incorrect, cannot point out the error context."
+  (interactive)
+  (save-excursion
+    (goto-char (point-min))
+    (let (state)
+      (while (and (not (eobp))
+		  (equal (car (setq state (parse-partial-sexp (point) (point-max) 0)))
+			 0)))
+      (if (equal (car state) 0)
+	  (message "Syntax correct")
+	(error "Syntax incorrect")))))
+
+
+	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/=netunam.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,152 @@
+;; HP-UX RFA Commands
+;; Copyright (C) 1988 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Author: cph@zurich.ai.mit.edu
+
+;;; $Header: netunam.el,v 1.3 88/12/21 16:32:23 GMT cph Exp $
+
+(defconst rfa-node-directory "/net/"
+  "Directory in which RFA network special files are stored.
+By HP convention, this is \"/net/\".")
+
+(defvar rfa-default-node nil
+  "If not nil, this is the name of the default RFA network special file.")
+
+(defvar rfa-password-memoize-p t
+  "If non-nil, remember login user's passwords after they have been entered.")
+
+(defvar rfa-password-alist '()
+  "An association from node-name strings to password strings.
+Used if `rfa-password-memoize-p' is non-nil.")
+
+(defvar rfa-password-per-node-p t
+  "If nil, login user uses same password on all machines.
+Has no effect if `rfa-password-memoize-p' is nil.")
+
+(defun rfa-set-password (password &optional node user)
+  "Add PASSWORD to the RFA password database.
+Optional second arg NODE is a string specifying a particular nodename;
+ if supplied and not nil, PASSWORD applies to only that node.
+Optional third arg USER is a string specifying the (remote) user whose
+ password this is; if not supplied this defaults to (user-login-name)."
+  (if (not user) (setq user (user-login-name)))
+  (let ((node-entry (assoc node rfa-password-alist)))
+    (if node-entry
+	(let ((user-entry (assoc user (cdr node-entry))))
+	  (if user-entry
+	      (rplacd user-entry password)
+	      (rplacd node-entry
+		      (nconc (cdr node-entry)
+			     (list (cons user password))))))
+	(setq rfa-password-alist
+	      (nconc rfa-password-alist
+		     (list (list node (cons user password))))))))
+
+(defun rfa-open (node &optional user password)
+  "Open a network connection to a server using remote file access.
+First argument NODE is the network node for the remote machine.
+Second optional argument USER is the user name to use on that machine.
+  If called interactively, the user name is prompted for.
+Third optional argument PASSWORD is the password string for that user.
+  If not given, this is filled in from the value of
+`rfa-password-alist', or prompted for.  A prefix argument of - will
+cause the password to be prompted for even if previously memoized."
+  (interactive
+   (list (read-file-name "rfa-open: " rfa-node-directory rfa-default-node t)
+	 (read-string "user-name: " (user-login-name))))
+  (let ((node
+	 (and (or rfa-password-per-node-p
+		  (not (equal user (user-login-name))))
+	      node)))
+    (if (not password)
+	(setq password
+	      (let ((password
+		     (cdr (assoc user (cdr (assoc node rfa-password-alist))))))
+		(or (and (not current-prefix-arg) password)
+		    (rfa-password-read
+		     (format "password for user %s%s: "
+			     user
+			     (if node (format " on node \"%s\"" node) ""))
+		     password))))))
+  (let ((result
+	 (sysnetunam (expand-file-name node rfa-node-directory)
+		     (concat user ":" password))))
+    (if (interactive-p)
+	(if result
+	    (message "Opened network connection to %s as %s" node user)
+	    (error "Unable to open network connection")))
+    (if (and rfa-password-memoize-p result)
+	(rfa-set-password password node user))
+    result))
+
+(defun rfa-close (node)
+  "Close a network connection to a server using remote file access.
+NODE is the network node for the remote machine."
+  (interactive
+   (list (read-file-name "rfa-close: " rfa-node-directory rfa-default-node t)))
+  (let ((result (sysnetunam (expand-file-name node rfa-node-directory) "")))
+    (cond ((not (interactive-p)) result)
+	  ((not result) (error "Unable to close network connection"))
+	  (t (message "Closed network connection to %s" node)))))
+
+(defun rfa-password-read (prompt default)
+  (let ((rfa-password-accumulator (or default "")))
+    (read-from-minibuffer prompt
+			  (and default
+			       (let ((copy (concat default))
+				     (index 0)
+				     (length (length default)))
+				 (while (< index length)
+				   (aset copy index ?.)
+				   (setq index (1+ index)))
+				 copy))
+			  rfa-password-map)
+    rfa-password-accumulator))
+
+(defvar rfa-password-map nil)
+(if (not rfa-password-map)
+    (let ((char ? ))
+      (setq rfa-password-map (make-keymap))
+      (while (< char 127)
+	(define-key rfa-password-map (char-to-string char)
+	  'rfa-password-self-insert)
+	(setq char (1+ char)))
+      (define-key rfa-password-map "\C-g"
+	'abort-recursive-edit)
+      (define-key rfa-password-map "\177"
+	'rfa-password-rubout)
+      (define-key rfa-password-map "\n"
+	'exit-minibuffer)
+      (define-key rfa-password-map "\r"
+	'exit-minibuffer)))
+
+(defvar rfa-password-accumulator nil)
+
+(defun rfa-password-self-insert ()
+  (interactive)
+  (setq rfa-password-accumulator
+	(concat rfa-password-accumulator
+		(char-to-string last-command-char)))
+  (insert ?.))
+
+(defun rfa-password-rubout ()
+  (interactive)
+  (delete-char -1)
+  (setq rfa-password-accumulator
+	(substring rfa-password-accumulator 0 -1)))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/=sun-keys.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,71 @@
+;;;
+;;; Support (cleanly) for Sun function keys.  Provides help facilities,
+;;; better diagnostics, etc.
+;;;
+;;; To use: make sure your .ttyswrc binds 'F1' to <ESC> * F1 <CR> and so on.
+;;;         load this lot from your start_up
+;;;
+;;; 
+;;;    Copyright (C) 1986 Free Software Foundation, Inc.
+;;; 
+;;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+;;;
+;;; Batten@uk.ac.bham.multics (Ian G. Batten)
+;;;
+
+(defun sun-function-keys-dispatch (arg)
+  "Dispatcher for function keys."
+  (interactive "p")
+  (let* ((key-stroke (read t))
+         (command (assq key-stroke sun-function-keys-command-list)))
+    (cond (command (funcall (cdr command) arg))
+          (t (error "Unbound function key %s" key-stroke)))))
+
+(defvar sun-function-keys-command-list 
+  '((F1 . sun-function-keys-describe-bindings)
+    (R8 . previous-line)                ; arrow keys
+    (R10 . backward-char)
+    (R12 . forward-char)
+    (R14 . next-line)))
+
+(defun sun-function-keys-bind-key (arg1 arg2)
+  "Bind a specified key."
+  (interactive "xFunction Key Cap Label:
+CCommand To Use:")
+  (setq sun-function-keys-command-list 
+        (cons (cons arg1 arg2) sun-function-keys-command-list)))
+
+(defun sun-function-keys-describe-bindings (arg)
+  "Describe the function key bindings we're running"
+  (interactive)
+  (with-output-to-temp-buffer "*Help*"
+    (sun-function-keys-write-bindings
+     (sort (copy-sequence sun-function-keys-command-list)
+           '(lambda (x y) (string-lessp (car x) (car y)))))))
+
+(defun sun-function-keys-write-bindings (list)
+  (cond ((null list)
+         t)
+        (t
+         (princ (format "%s: %s\n" 
+                        (car (car list))
+                        (cdr (car list))))
+         (sun-function-keys-write-bindings (cdr list)))))
+    
+(global-set-key "\e*" 'sun-function-keys-dispatch)
+
+(make-variable-buffer-local 'sun-function-keys-command-list)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/=vmsx.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,137 @@
+;; Run asynchronous VMS subprocesses under Emacs
+;; Copyright (C) 1986 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;; Written by Mukesh Prasad.
+
+(defvar display-subprocess-window nil
+  "If non-nil, the suprocess window is displayed whenever input is received.")
+
+(defvar command-prefix-string "$ "
+  "String to insert to distinguish commands entered by user.")
+
+(defvar subprocess-running nil)
+(defvar command-mode-map nil)
+
+(if command-mode-map
+    nil
+  (setq command-mode-map (make-sparse-keymap))
+  (define-key command-mode-map "\C-m" 'command-send-input)
+  (define-key command-mode-map "\C-u" 'command-kill-line))
+
+(defun subprocess-input (name str)
+   "Handles input from a subprocess.  Called by Emacs."
+   (if display-subprocess-window
+      (display-buffer subprocess-buf))
+   (let ((old-buffer (current-buffer)))
+      (set-buffer subprocess-buf)
+      (goto-char (point-max))
+      (insert str)
+      (insert ?\n)
+      (set-buffer old-buffer)))
+
+(defun subprocess-exit (name)
+   "Called by Emacs upon subprocess exit."
+   (setq subprocess-running nil))
+
+(defun start-subprocess ()
+   "Spawns an asynchronous subprocess with output redirected to
+the buffer *COMMAND*.  Within this buffer, use C-m to send
+the last line to the subprocess or to bring another line to
+the end."
+   (if subprocess-running
+       (return t))
+   (setq subprocess-buf (get-buffer-create "*COMMAND*"))
+   (save-excursion
+	(set-buffer subprocess-buf)
+	(use-local-map command-mode-map))
+   (setq subprocess-running (spawn-subprocess 1 'subprocess-input
+                                               'subprocess-exit))
+   ;; Initialize subprocess so it doesn't panic and die upon
+   ;; encountering the first error.
+   (and subprocess-running
+        (send-command-to-subprocess 1 "ON SEVERE_ERROR THEN CONTINUE")))
+
+(defvar subprocess-command-to-buffer-tmpdir "SYS$SCRATCH:"
+  "*Put temporary files from subprocess-command-to-buffer here.")
+
+(defun subprocess-command-to-buffer (command buffer)
+  "Execute command and redirect output into buffer.
+
+BUGS: only the output up to the end of the first image activation is trapped."
+  (if (not subprocess-running) 
+	  (start-subprocess))
+  (save-excursion
+	(set-buffer buffer)
+	(let ((output-filename
+	       (concat subprocess-command-to-buffer-tmpdir
+		       "OUTPUT-FOR-" (getenv "USER") ".LISTING")))
+	  (while (file-attributes output-filename)
+	    (delete-file output-filename))
+	  (send-command-to-subprocess 1 (concat "DEFINE/USER SYS$OUTPUT "
+						output-filename "-NEW"))
+	  (send-command-to-subprocess 1 command)
+	  (send-command-to-subprocess 1 (concat "RENAME " output-filename 
+						"-NEW " output-filename))
+	  (while (not (file-attributes output-filename))
+	    (sleep-for 2))
+	  (insert-file output-filename))))
+
+(defun subprocess-command ()
+  "Starts asynchronous subprocess if not running and switches to its window."
+  (interactive)
+  (if (not subprocess-running)
+      (start-subprocess))
+  (and subprocess-running
+      (progn (pop-to-buffer subprocess-buf) (goto-char (point-max)))))
+
+(defun command-send-input ()
+  "If at last line of buffer, sends the current line to
+the spawned subprocess.  Otherwise brings back current
+line to the last line for resubmission."
+  (interactive)
+  (beginning-of-line)
+  (let ((current-line (buffer-substring (point)
+                                        (progn (end-of-line) (point)))))
+    (if (eobp)
+      (progn
+        (if (not subprocess-running)
+            (start-subprocess))
+        (if subprocess-running
+          (progn
+            (beginning-of-line)
+            (send-command-to-subprocess 1 current-line)
+            (if command-prefix-string
+              (progn (beginning-of-line) (insert command-prefix-string)))
+            (next-line 1))))
+      ;; else -- if not at last line in buffer
+      (end-of-buffer)
+      (backward-char)
+      (next-line 1)
+      (if (string-equal command-prefix-string
+                (substring current-line 0 (length command-prefix-string)))
+	  (insert (substring current-line (length command-prefix-string)))
+          (insert current-line)))))
+
+(defun command-kill-line()
+  "Kills the current line.  Used in command mode."
+  (interactive)
+  (beginning-of-line)
+  (kill-line))
+
+(define-key esc-map "$" 'subprocess-command)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/electric.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,181 @@
+;; electric -- Window maker and Command loop for `electric' modes.
+;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
+;; Principal author K. Shane Hartman
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+(provide 'electric)                           ; zaaaaaaap
+
+;; perhaps this should be in subr.el...
+(defun shrink-window-if-larger-than-buffer (window)
+  (save-excursion
+    (set-buffer (window-buffer window))
+    (let ((w (selected-window)) ;save-window-excursion can't win
+	  (buffer-file-name buffer-file-name)
+	  (p (point))
+	  (n 0)
+	  (window-min-height 0)
+	  (buffer-read-only nil)
+	  (modified (buffer-modified-p))
+	  (buffer (current-buffer)))
+      (unwind-protect
+	  (progn
+	    (select-window window)
+	    (goto-char (point-min))
+	    (while (pos-visible-in-window-p (point-max))
+	      ;; defeat file locking... don't try this at home, kids!
+	      (setq buffer-file-name nil)
+	      (insert ?\n) (setq n (1+ n)))
+	    (if (> n 0) (shrink-window (1- n))))
+	(delete-region (point-min) (point))
+	(set-buffer-modified-p modified)
+	(goto-char p)
+	(select-window w)
+	;; Make sure we unbind buffer-read-only
+	;; with the proper current buffer.
+	(set-buffer buffer)))))
+      
+;; This loop is the guts for non-standard modes which retain control
+;; until some event occurs.  It is a `do-forever', the only way out is to
+;; throw.  It assumes that you have set up the keymap, window, and
+;; everything else: all it does is read commands and execute them -
+;; providing error messages should one occur (if there is no loop
+;; function - which see).  The required argument is a tag which should
+;; expect a value of nil if the user decides to punt. The
+;; second argument is a prompt string (defaults to "->").  Given third
+;; argument non-nil, it INHIBITS quitting unless the user types C-g at
+;; toplevel.  This is so user can do things like C-u C-g and not get
+;; thrown out.  Fourth argument, if non-nil, should be a function of two
+;; arguments which is called after every command is executed.  The fifth
+;; argument, if provided, is the state variable for the function.  If the
+;; loop-function gets an error, the loop will abort WITHOUT throwing
+;; (moral: use unwind-protect around call to this function for any
+;; critical stuff).  The second argument for the loop function is the
+;; conditions for any error that occurred or nil if none.
+
+(defun Electric-command-loop (return-tag
+			      &optional prompt inhibit-quit
+					loop-function loop-state)
+  (if (not prompt) (setq prompt "->"))
+  (let (cmd (err nil))
+    (while t
+      (setq cmd (read-key-sequence (if (stringp prompt)
+				       prompt (funcall prompt))))
+      (setq last-command-char (aref cmd (1- (length cmd)))
+	    this-command (key-binding cmd)
+	    cmd this-command)
+      (if (or (prog1 quit-flag (setq quit-flag nil))
+	      (= last-input-char ?\C-g))
+	  (progn (setq unread-command-char -1
+		       prefix-arg nil)
+		 ;; If it wasn't cancelling a prefix character, then quit.
+		 (if (or (= (length (this-command-keys)) 1)
+			 (not inhibit-quit)) ; safety
+		     (progn (ding)
+			    (message "Quit")
+			    (throw return-tag nil))
+		   (setq cmd nil))))
+      (setq current-prefix-arg prefix-arg)
+      (if cmd
+	  (condition-case conditions
+	      (progn (command-execute cmd)
+		     (if (or (prog1 quit-flag (setq quit-flag nil))
+			     (= last-input-char ?\C-g))
+			 (progn (setq unread-command-char -1)
+				(if (not inhibit-quit)
+				    (progn (ding)
+					   (message "Quit")
+					   (throw return-tag nil))
+				  (ding)))))
+	    (buffer-read-only (if loop-function
+				  (setq err conditions)
+				(ding)
+				(message "Buffer is read-only")
+				(sit-for 2)))
+	    (beginning-of-buffer (if loop-function
+				     (setq err conditions)
+				   (ding)
+				   (message "Beginning of Buffer")
+				   (sit-for 2)))
+	    (end-of-buffer (if loop-function
+			       (setq err conditions)
+			     (ding)
+			     (message "End of Buffer")
+			     (sit-for 2)))
+	    (error (if loop-function
+		       (setq err conditions)
+		     (ding)
+		     (message "Error: %s"
+			      (if (eq (car conditions) 'error)
+				  (car (cdr conditions))
+				(prin1-to-string conditions)))
+		     (sit-for 2))))
+	(ding))
+      (if loop-function (funcall loop-function loop-state err))))
+  (ding)
+  (throw return-tag nil))
+
+;; This function is like pop-to-buffer, sort of. 
+;; The algorithm is
+;; If there is a window displaying buffer
+;; 	Select it
+;; Else if there is only one window
+;; 	Split it, selecting the window on the bottom with height being
+;; 	the lesser of max-height (if non-nil) and the number of lines in
+;;      the buffer to be displayed subject to window-min-height constraint.
+;; Else
+;; 	Switch to buffer in the current window.
+;;
+;; Then if max-height is nil, and not all of the lines in the buffer
+;; are displayed, grab the whole screen.
+;;
+;; Returns selected window on buffer positioned at point-min.
+
+(defun Electric-pop-up-window (buffer &optional max-height)
+  (let* ((win (or (get-buffer-window buffer) (selected-window)))
+	 (buf (get-buffer buffer))
+	 (one-window (one-window-p t))
+	 (pop-up-windows t)
+	 (target-height)
+	 (lines))
+    (if (not buf)
+	(error "Buffer %s does not exist" buffer)
+      (save-excursion
+	(set-buffer buf)
+	(setq lines (count-lines (point-min) (point-max)))
+	(setq target-height
+	      (min (max (if max-height (min max-height (1+ lines)) (1+ lines))
+			window-min-height)
+		   (save-window-excursion
+		     (delete-other-windows)
+		     (1- (window-height (selected-window)))))))
+      (cond ((and (eq (window-buffer win) buf))
+	     (select-window win))
+	    (one-window
+	     (goto-char (window-start win))
+	     (pop-to-buffer buffer)
+	     (setq win (selected-window))
+	     (enlarge-window (- target-height (window-height win))))
+	    (t
+	     (switch-to-buffer buf)))
+      (if (and (not max-height)
+	       (> target-height (window-height (selected-window))))
+	  (progn (goto-char (window-start win))
+		 (enlarge-window (- target-height (window-height win)))))
+      (goto-char (point-min))
+      win)))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/emulation/mlsupport.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,405 @@
+;; Run-time support for mocklisp code.
+;; Copyright (C) 1985 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+(provide 'mlsupport)
+
+(defmacro ml-defun (&rest defs)
+  (list 'ml-defun-1 (list 'quote defs)))
+
+(defun ml-defun-1 (args)
+  (while args
+    (fset (car (car args)) (cons 'mocklisp (cdr (car args))))
+    (setq args (cdr args))))
+
+(defmacro declare-buffer-specific (&rest vars)
+  (cons 'progn (mapcar (function (lambda (var) (list 'make-variable-buffer-local (list 'quote var)))) vars)))
+
+(defun ml-set-default (varname value)
+  (set-default (intern varname) value))
+
+; Lossage: must make various things default missing args to the prefix arg
+; Alternatively, must make provide-prefix-argument do something hairy.
+
+(defun >> (val count) (lsh val (- count)))
+(defun novalue () nil)
+
+(defun ml-not (arg) (if (zerop arg) 1 0))
+
+(defun provide-prefix-arg (arg form)
+  (funcall (car form) arg))
+
+(defun define-keymap (name)
+  (fset (intern name) (make-keymap)))
+
+(defun ml-use-local-map (name)
+  (use-local-map (intern (concat name "-map"))))
+
+(defun ml-use-global-map (name)
+  (use-global-map (intern (concat name "-map"))))
+
+(defun local-bind-to-key (name key)
+  (or (current-local-map)
+      (use-local-map (make-keymap)))
+  (define-key (current-local-map)
+    (if (integerp key)
+	(if (>= key 128)
+	    (concat (char-to-string meta-prefix-char)
+		    (char-to-string (- key 128)))
+	  (char-to-string key))
+      key)
+    (intern name)))
+
+(defun bind-to-key (name key)
+  (define-key global-map (if (integerp key) (char-to-string key) key)
+    (intern name)))
+
+(defun ml-autoload (name file)
+  (autoload (intern name) file))
+
+(defun ml-define-string-macro (name defn)
+  (fset (intern name) defn))
+
+(defun push-back-character (char)
+  (setq unread-command-char char))
+
+(defun to-col (column)
+  (indent-to column 0))
+
+(defmacro is-bound (&rest syms)
+  (cons 'and (mapcar (function (lambda (sym) (list 'boundp (list 'quote sym)))) syms)))
+
+(defmacro declare-global (&rest syms)
+  (cons 'progn (mapcar (function (lambda (sym) (list 'defvar sym nil))) syms)))
+
+(defmacro error-occurred (&rest body)
+  (list 'condition-case nil (cons 'progn (append body '(nil))) '(error t)))
+
+(defun return-prefix-argument (value)
+  (setq prefix-arg value))
+
+(defun ml-prefix-argument ()
+  (if (null current-prefix-arg) 1
+    (if (listp current-prefix-arg) (car current-prefix-arg)
+      (if (eq current-prefix-arg '-) -1
+	current-prefix-arg))))
+
+(defun ml-print (varname)
+  (interactive "vPrint variable: ")
+  (if (boundp varname)
+    (message "%s => %s" (symbol-name varname) (symbol-value varname))
+    (message "%s has no value" (symbol-name varname))))
+
+(defun ml-set (str val) (set (intern str) val))
+
+(defun ml-message (&rest args) (message "%s" (apply 'concat args)))
+
+(defun kill-to-end-of-line ()
+  (ml-prefix-argument-loop
+    (if (eolp)
+	(kill-region (point) (1+ (point)))
+      (kill-region (point) (if (search-forward ?\n nil t)
+			       (1- (point)) (point-max))))))
+
+(defun set-auto-fill-hook (arg)
+  (setq auto-fill-function (intern arg)))
+
+(defun auto-execute (function pattern)
+  (if (/= (aref pattern 0) ?*)
+      (error "Only patterns starting with * supported in auto-execute"))
+  (setq auto-mode-alist (cons (cons (concat "\\." (substring pattern 1)
+					    "$")
+				    function)
+			      auto-mode-alist)))
+
+(defun move-to-comment-column ()
+  (indent-to comment-column))
+
+(defun erase-region ()
+  (delete-region (point) (mark)))
+
+(defun delete-region-to-buffer (bufname)
+  (copy-to-buffer bufname (point) (mark))
+  (delete-region (point) (mark)))
+
+(defun copy-region-to-buffer (bufname)
+  (copy-to-buffer bufname (point) (mark)))
+
+(defun append-region-to-buffer (bufname)
+  (append-to-buffer bufname (point) (mark)))
+
+(defun prepend-region-to-buffer (bufname)
+  (prepend-to-buffer bufname (point) (mark)))
+
+(defun delete-next-character ()
+  (delete-char (ml-prefix-argument)))
+
+(defun delete-next-word ()
+  (delete-region (point) (progn (forward-word (ml-prefix-argument)) (point))))
+
+(defun delete-previous-word ()
+  (delete-region (point) (progn (backward-word (ml-prefix-argument)) (point))))
+
+(defun delete-previous-character ()
+  (delete-backward-char (ml-prefix-argument)))
+
+(defun forward-character ()
+  (forward-char (ml-prefix-argument)))
+
+(defun backward-character ()
+  (backward-char (ml-prefix-argument)))
+
+(defun ml-newline ()
+  (newline (ml-prefix-argument)))
+
+(defun ml-next-line ()
+  (next-line (ml-prefix-argument)))
+
+(defun ml-previous-line ()
+  (previous-line (ml-prefix-argument)))
+
+(defun delete-to-kill-buffer ()
+  (kill-region (point) (mark)))
+
+(defun narrow-region ()
+  (narrow-to-region (point) (mark)))
+
+(defun ml-newline-and-indent ()
+  (let ((column (current-indentation)))
+    (newline (ml-prefix-argument))
+    (indent-to column)))
+
+(defun newline-and-backup ()
+  (open-line (ml-prefix-argument)))
+
+(defun quote-char ()
+  (quoted-insert (ml-prefix-argument)))
+
+(defun ml-current-column ()
+  (1+ (current-column)))
+
+(defun ml-current-indent ()
+  (1+ (current-indentation)))
+
+(defun region-around-match (&optional n)
+  (set-mark (match-beginning n))
+  (goto-char (match-end n)))
+
+(defun region-to-string ()
+  (buffer-substring (min (point) (mark)) (max (point) (mark))))
+
+(defun use-abbrev-table (name)
+  (let ((symbol (intern (concat name "-abbrev-table"))))
+    (or (boundp symbol)
+	(define-abbrev-table symbol nil))
+    (symbol-value symbol)))
+
+(defun define-hooked-local-abbrev (name exp hook)
+  (define-local-abbrev name exp (intern hook)))
+
+(defun define-hooked-global-abbrev (name exp hook)
+  (define-global-abbrev name exp (intern hook)))
+
+(defun case-word-lower ()
+  (ml-casify-word 'downcase-region))
+
+(defun case-word-upper ()
+  (ml-casify-word 'upcase-region))
+
+(defun case-word-capitalize ()
+  (ml-casify-word 'capitalize-region))
+
+(defun ml-casify-word (fun)
+  (save-excursion
+   (forward-char 1)
+   (forward-word -1)
+   (funcall fun (point)
+	    (progn (forward-word (ml-prefix-argument))
+		   (point)))))
+
+(defun case-region-lower ()
+  (downcase-region (point) (mark)))
+
+(defun case-region-upper ()
+  (upcase-region (point) (mark)))
+
+(defun case-region-capitalize ()
+  (capitalize-region (point) (mark)))
+
+(defvar saved-command-line-args nil)
+
+(defun argc ()
+  (or saved-command-line-args
+      (setq saved-command-line-args command-line-args
+	    command-line-args ()))
+  (length command-line-args))
+
+(defun argv (i)
+  (or saved-command-line-args
+      (setq saved-command-line-args command-line-args
+	    command-line-args ()))
+  (nth i saved-command-line-args))
+
+(defun invisible-argc ()
+  (length (or saved-command-line-args
+	      command-line-args)))
+
+(defun invisible-argv (i)
+  (nth i (or saved-command-line-args
+	     command-line-args)))
+
+(defun exit-emacs ()
+  (interactive)
+  (condition-case ()
+      (exit-recursive-edit)
+    (error (kill-emacs))))
+
+;; Lisp function buffer-size returns total including invisible;
+;; mocklisp wants just visible.
+(defun ml-buffer-size ()
+  (- (point-max) (point-min)))
+
+(defun previous-command ()
+  last-command)
+
+(defun beginning-of-window ()
+  (goto-char (window-start)))
+
+(defun end-of-window ()
+  (goto-char (window-start))
+  (vertical-motion (- (window-height) 2)))
+
+(defun ml-search-forward (string)
+  (search-forward string nil nil (ml-prefix-argument)))
+
+(defun ml-re-search-forward (string)
+  (re-search-forward string nil nil (ml-prefix-argument)))
+
+(defun ml-search-backward (string)
+  (search-backward string nil nil (ml-prefix-argument)))
+
+(defun ml-re-search-backward (string)
+  (re-search-backward string nil nil (ml-prefix-argument)))
+
+(defvar use-users-shell 1
+  "Mocklisp compatibility variable; 1 means use shell from SHELL env var.
+0 means use /bin/sh.")
+
+(defvar use-csh-option-f 1
+  "Mocklisp compatibility variable; 1 means pass -f when calling csh.")
+
+(defun filter-region (command)
+  (let ((shell (if (/= use-users-shell 0) shell-file-name "/bin/sh"))
+	(csh (equal (file-name-nondirectory shell) "csh")))
+    (call-process-region (point) (mark) shell t t nil
+			 (if (and csh use-csh-option-f) "-cf" "-c")
+			 (concat "exec " command))))
+
+(defun execute-monitor-command (command)
+  (let ((shell (if (/= use-users-shell 0) shell-file-name "/bin/sh"))
+	(csh (equal (file-name-nondirectory shell) "csh")))
+    (call-process shell nil t t
+		  (if (and csh use-csh-option-f) "-cf" "-c")
+		  (concat "exec " command))))
+
+(defun use-syntax-table (name)
+  (set-syntax-table (symbol-value (intern (concat name "-syntax-table")))))
+
+(defun line-to-top-of-window ()
+  (recenter (1- (ml-prefix-argument))))
+
+(defun ml-previous-page (&optional arg)
+  (let ((count (or arg (ml-prefix-argument))))
+    (while (> count 0)
+      (scroll-down nil)
+      (setq count (1- count)))
+    (while (< count 0)
+      (scroll-up nil)
+      (setq count (1+ count)))))
+
+(defun ml-next-page ()
+  (previous-page (- (ml-prefix-argument))))
+
+(defun page-next-window (&optional arg)
+  (let ((count (or arg (ml-prefix-argument))))
+    (while (> count 0)
+      (scroll-other-window nil)
+      (setq count (1- count)))
+    (while (< count 0)
+      (scroll-other-window '-)
+      (setq count (1+ count)))))
+
+(defun ml-next-window ()
+  (select-window (next-window)))
+
+(defun ml-previous-window ()
+  (select-window (previous-window)))
+
+(defun scroll-one-line-up ()
+  (scroll-up (ml-prefix-argument)))
+
+(defun scroll-one-line-down ()
+  (scroll-down (ml-prefix-argument)))
+
+(defun split-current-window ()
+  (split-window (selected-window)))
+
+(defun last-key-struck () last-command-char)
+
+(defun execute-mlisp-line (string)
+  (eval (read string)))
+
+(defun move-dot-to-x-y (x y)
+  (goto-char (window-start (selected-window)))
+  (vertical-motion (1- y))
+  (move-to-column (1- x)))
+
+(defun ml-modify-syntax-entry (string)
+  (let ((i 5)
+	(len (length string))
+	(datastring (substring string 0 2)))
+    (if (= (aref string 0) ?\-)
+	(aset datastring 0 ?\ ))
+    (if (= (aref string 2) ?\{)
+	(if (= (aref string 4) ?\ )
+	    (aset datastring 0 ?\<)
+	  (error "Two-char comment delimiter: use modify-syntax-entry directly")))
+    (if (= (aref string 3) ?\})
+	(if (= (aref string 4) ?\ )
+	    (aset datastring 0 ?\>)
+	  (error "Two-char comment delimiter: use modify-syntax-entry directly")))
+    (while (< i len)
+      (modify-syntax-entry (aref string i) datastring)
+      (setq i (1+ i))
+      (if (and (< i len)
+	       (= (aref string i) ?\-))
+	  (let ((c (aref string (1- i)))
+		(lim (aref string (1+ i))))
+	    (while (<= c lim)
+	      (modify-syntax-entry c datastring)
+	      (setq c (1+ c)))
+	    (setq i (+ 2 i)))))))
+
+
+
+(defun ml-substr (string from to)
+  (let ((length (length string)))
+    (if (< from 0) (setq from (+ from length)))
+    (if (< to 0) (setq to (+ to length)))
+    (substring string from (+ from to))))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/loadup.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,140 @@
+;;Load up standardly loaded Lisp files for Emacs.
+;; This is loaded into a bare Emacs to make a dumpable one.
+;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+(load "subr")
+(garbage-collect)
+(load "loaddefs.el")  ;Don't get confused if someone compiled loaddefs by mistake.
+(garbage-collect)
+(load "simple")
+(garbage-collect)
+(load "help")
+(garbage-collect)
+(load "files")
+(garbage-collect)
+(load "indent")
+(load "window")
+(load "paths.el")  ;Don't get confused if someone compiled paths by mistake.
+(garbage-collect)
+(load "startup")
+(load "lisp")
+(garbage-collect)
+(load "page")
+(load "register")
+(garbage-collect)
+(load "paragraphs")
+(load "lisp-mode")
+(garbage-collect)
+(load "text-mode")
+(load "fill")
+(garbage-collect)
+(load "c-mode")
+(garbage-collect)
+(load "isearch")
+(garbage-collect)
+(load "replace")
+(if (eq system-type 'vax-vms)
+    (progn
+      (garbage-collect)
+      (load "vmsproc")))
+(garbage-collect)
+(load "abbrev")
+(garbage-collect)
+(load "buff-menu")
+(if (eq system-type 'vax-vms)
+    (progn
+      (garbage-collect)
+      (load "vms-patch")))
+(if (fboundp 'atan)	; preload some constants and 
+    (progn		; floating pt. functions if 
+      (garbage-collect)	; we have float support.
+      (load "float-sup")))
+
+;If you want additional libraries to be preloaded and their
+;doc strings kept in the DOC file rather than in core,
+;you may load them with a "site-load.el" file.
+;But you must also cause them to be scanned when the DOC file
+;is generated.  For VMS, you must edit ../etc/makedoc.com.
+;For other systems, you must edit ../src/ymakefile.
+(if (load "site-load" t)
+    (garbage-collect))
+
+(load "version.el")  ;Don't get confused if someone compiled version.el by mistake.
+
+;; Note: all compiled Lisp files loaded above this point
+;; must be among the ones parsed by make-docfile
+;; to construct DOC.  Any that are not processed
+;; for DOC will not have doc strings in the dumped Emacs.
+
+(message "Finding pointers to doc strings...")
+(if (fboundp 'dump-emacs)
+    (let ((name emacs-version))
+      (while (string-match "[^-+_.a-zA-Z0-9]+" name)
+	(setq name (concat (downcase (substring name 0 (match-beginning 0)))
+			   "-"
+			   (substring name (match-end 0)))))
+      (copy-file (expand-file-name "../etc/DOC")
+		 (concat (expand-file-name "../etc/DOC-") name)
+		 t)
+      (Snarf-documentation (concat "DOC-" name)))
+    (Snarf-documentation "DOC"))
+(message "Finding pointers to doc strings...done")
+
+;Note: You can cause additional libraries to be preloaded
+;by writing a site-init.el that loads them.
+;See also "site-load" above.
+(load "site-init" t)
+(garbage-collect)
+
+(if (or (equal (nth 3 command-line-args) "dump")
+	(equal (nth 4 command-line-args) "dump"))
+    (if (eq system-type 'vax-vms)
+	(progn 
+	  (message "Dumping data as file temacs.dump")
+	  (dump-emacs "temacs.dump" "temacs")
+	  (kill-emacs))
+      (let ((name (concat "emacs-" emacs-version)))
+	(while (string-match "[^-+_.a-zA-Z0-9]+" name)
+	  (setq name (concat (downcase (substring name 0 (match-beginning 0)))
+			     "-"
+			     (substring name (match-end 0)))))
+	(message "Dumping under names xemacs and %s" name))
+      (condition-case ()
+	  (delete-file "xemacs")
+	(file-error nil))
+      (dump-emacs "xemacs" "temacs")
+      ;; Recompute NAME now, so that it isn't set when we dump.
+      (let ((name (concat "emacs-" emacs-version)))
+	(while (string-match "[^-+_.a-zA-Z0-9]+" name)
+	  (setq name (concat (downcase (substring name 0 (match-beginning 0)))
+			     "-"
+			     (substring name (match-end 0)))))
+	(add-name-to-file "xemacs" name t))
+      (kill-emacs)))
+
+;; Avoid error if user loads some more libraries now.
+(setq purify-flag nil)
+
+;; For machines with CANNOT_DUMP defined in config.h,
+;; this file must be loaded each time Emacs is run.
+;; So run the startup code now.
+
+(or (fboundp 'dump-emacs)
+    (eval top-level))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/mail/rmailmsc.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,45 @@
+;; Copyright (C) 1985 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+(defun set-rmail-inbox-list (file-name)
+  "Set the inbox list of the current RMAIL file to FILE-NAME.
+This may be a list of file names separated by commas.
+If FILE-NAME is empty, remove any inbox list."
+  (interactive "sSet mailbox list to (comma-separated list of filenames): ")
+  (save-excursion
+    (let ((names (rmail-parse-file-inboxes))
+	  (standard-output nil))
+      (if (or (not names)
+	      (y-or-n-p (concat "Replace "
+				(mapconcat 'identity names ", ")
+				"? ")))
+	  (let ((buffer-read-only nil))
+	    (widen)
+	    (goto-char (point-min))
+	    (search-forward "\n\^_")
+	    (re-search-backward "^Mail" nil t)
+	    (forward-line 0)
+	    (if (looking-at "Mail:")
+		(delete-region (point)
+			       (progn (forward-line 1)
+				      (point))))
+	    (if (not (string= file-name ""))
+		(insert "Mail: " file-name "\n"))))))
+  (setq rmail-inbox-list (rmail-parse-file-inboxes))
+  (rmail-show-message rmail-current-message))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/mail/rnews.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,979 @@
+;;; USENET news reader for gnu emacs
+;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;; Created Sun Mar 10,1985 at 21:35:01 ads and sundar@hernes.ai.mit.edu
+;; Should do the point pdl stuff sometime
+;; finito except pdl.... Sat Mar 16,1985 at 06:43:44
+;; lets keep the summary stuff out until we get it working ..
+;;	sundar@hermes.ai.mit.edu Wed Apr 10,1985 at 16:32:06
+;; hack slash maim. mly@prep.ai.mit.edu Thu 18 Apr, 1985 06:11:14
+;; modified to correct reentrance bug, to not bother with groups that
+;;   received no new traffic since last read completely, to find out
+;;   what traffic a group has available much more quickly when
+;;   possible, to do some completing reads for group names - should
+;;   be much faster...
+;;	KING@KESTREL.arpa, Thu Mar 13 09:03:28 1986
+;; made news-{next,previous}-group skip groups with no new messages; and
+;; added checking for unsubscribed groups to news-add-news-group
+;;	tower@prep.ai.mit.edu Jul 18 1986
+;; bound rmail-output to C-o; and changed header-field commands binding to
+;; agree with the new C-c C-f usage in sendmail
+;; 	tower@prep Sep  3 1986
+;; added news-rotate-buffer-body
+;;	tower@prep Oct 17 1986
+;; made messages more user friendly, cleanuped news-inews
+;; move posting and mail code to new file rnewpost.el
+;;	tower@prep Oct 29 1986
+;; added caesar-region, rename news-caesar-buffer-body, hacked accordingly
+;;	tower@prep Nov 21 1986
+;; added (provide 'rnews)	tower@prep 22 Apr 87
+(provide 'rnews)
+(require 'mail-utils)
+
+(autoload 'rmail-output "rmailout"
+  "Append this message to Unix mail file named FILE-NAME."
+  t)
+
+(autoload 'news-reply "rnewspost"
+  "Compose and post a reply to the current article on USENET.
+While composing the reply, use \\[mail-yank-original] to yank the original
+message into it."
+  t)
+
+(autoload 'news-mail-other-window "rnewspost"
+  "Send mail in another window.
+While composing the message, use \\[mail-yank-original] to yank the
+original message into it."
+  t)
+
+(autoload 'news-post-news "rnewspost"
+  "Begin editing a new USENET news article to be posted."
+  t)
+
+(autoload 'news-mail-reply "rnewspost"
+  "Mail a reply to the author of the current article.
+While composing the reply, use \\[mail-yank-original] to yank the original
+message into it."
+  t)
+
+(defvar news-group-hook-alist nil
+  "Alist of (GROUP-REGEXP . HOOK) pairs.
+Just before displaying a message, each HOOK is called
+if its GROUP-REGEXP matches the current newsgroup name.")
+
+(defvar rmail-last-file (expand-file-name "~/mbox.news"))
+
+;Now in paths.el.
+;(defvar news-path "/usr/spool/news/"
+;  "The root directory below which all news files are stored.")
+
+(defvar news-startup-file "$HOME/.newsrc" "Contains ~/.newsrc")
+(defvar news-certification-file "$HOME/.news-dates" "Contains ~/.news-dates")
+
+;; random headers that we decide to ignore.
+(defvar news-ignored-headers
+  "^Path:\\|^Posting-Version:\\|^Article-I.D.:\\|^Expires:\\|^Date-Received:\\|^References:\\|^Control:\\|^Xref:\\|^Lines:\\|^Posted:\\|^Relay-Version:\\|^Message-ID:\\|^Nf-ID:\\|^Nf-From:\\|^Approved:\\|^Sender:"
+  "All random fields within the header of a message.")
+
+(defvar news-mode-map nil)
+(defvar news-read-first-time-p t)
+;; Contains the (dotified) news groups of which you are a member. 
+(defvar news-user-group-list nil)
+
+(defvar news-current-news-group nil)
+(defvar news-current-group-begin nil)
+(defvar news-current-group-end  nil)
+(defvar news-current-certifications nil
+   	"An assoc list of a group name and the time at which it is
+known that the group had no new traffic")
+(defvar news-current-certifiable nil
+	"The time when the directory we are now working on was written")
+
+(defvar news-message-filter nil
+  "User specifiable filter function that will be called during
+formatting of the news file")
+
+;(defvar news-mode-group-string "Starting-Up"
+;  "Mode line group name info is held in this variable")
+(defvar news-list-of-files nil
+  "Global variable in which we store the list of files
+associated with the current newsgroup")
+(defvar news-list-of-files-possibly-bogus nil
+  "variable indicating we only are guessing at which files are available.
+Not currently used.")
+
+;; association list in which we store lists of the form
+;; (pointified-group-name (first last old-last))
+(defvar news-group-article-assoc nil)
+  
+(defvar news-current-message-number 0 "Displayed Article Number")
+(defvar news-total-current-group 0 "Total no of messages in group")
+
+(defvar news-unsubscribe-groups ())
+(defvar news-point-pdl () "List of visited news messages.")
+(defvar news-no-jumps-p t)
+(defvar news-buffer () "Buffer into which news files are read.")
+
+(defmacro news-push (item ref)
+  (list 'setq ref (list 'cons item ref)))
+
+(defmacro news-cadr (x) (list 'car (list 'cdr x)))
+(defmacro news-cdar (x) (list 'cdr (list 'car x)))
+(defmacro news-caddr (x) (list 'car (list 'cdr (list 'cdr x))))
+(defmacro news-cadar (x) (list 'car (list 'cdr (list 'car x))))
+(defmacro news-caadr (x) (list 'car (list 'car (list 'cdr x))))
+(defmacro news-cdadr (x) (list 'cdr (list 'car (list 'cdr x))))
+
+(defmacro news-wins (pfx index)
+  (` (file-exists-p (concat (, pfx) "/" (int-to-string (, index))))))
+
+(defvar news-max-plausible-gap 2
+	"* In an rnews directory, the maximum possible gap size.
+A gap is a sequence of missing messages between two messages that exist.
+An empty file does not contribute to a gap -- it ends one.")
+
+(defun news-find-first-and-last (prefix base)
+  (and (news-wins prefix base)
+       (cons (news-find-first-or-last prefix base -1)
+	     (news-find-first-or-last prefix base 1))))
+
+(defmacro news-/ (a1 a2)
+;; a form of / that guarantees that (/ -1 2) = 0
+  (if (zerop (/ -1 2))
+      (` (/ (, a1) (, a2)))
+    (` (if (< (, a1) 0)
+	   (- (/ (- (, a1)) (, a2)))
+	 (/ (, a1) (, a2))))))
+
+(defun news-find-first-or-last (pfx base dirn)
+  ;; first use powers of two to find a plausible ceiling
+  (let ((original-dir dirn))
+    (while (news-wins pfx (+ base dirn))
+      (setq dirn (* dirn 2)))
+    (setq dirn (news-/ dirn 2))
+    ;; Then use a binary search to find the high water mark
+    (let ((offset (news-/ dirn 2)))
+      (while (/= offset 0)
+	(if (news-wins pfx (+ base dirn offset))
+	    (setq dirn (+ dirn offset)))
+	(setq offset (news-/ offset 2))))
+    ;; If this high-water mark is bogus, recurse.
+    (let ((offset (* news-max-plausible-gap original-dir)))
+      (while (and (/= offset 0) (not (news-wins pfx (+ base dirn offset))))
+	(setq offset (- offset original-dir)))
+      (if (= offset 0)
+	  (+ base dirn)
+	(news-find-first-or-last pfx (+ base dirn offset) original-dir)))))
+
+(defun rnews ()
+"Read USENET news for groups for which you are a member and add or
+delete groups.
+You can reply to articles posted and send articles to any group.
+
+Type \\[describe-mode] once reading news to get a list of rnews commands."
+  (interactive)
+  (let ((last-buffer (buffer-name)))
+    (make-local-variable 'rmail-last-file)
+    (switch-to-buffer (setq news-buffer (get-buffer-create "*news*")))
+    (news-mode)
+    (setq news-buffer-save last-buffer)
+    (setq buffer-read-only nil)
+    (erase-buffer)
+    (setq buffer-read-only t)
+    (set-buffer-modified-p t)
+    (sit-for 0)
+    (message "Getting new USENET news...")
+    (news-set-mode-line)
+    (news-get-certifications)
+    (news-get-new-news)))
+
+(defun news-group-certification (group)
+  (cdr-safe (assoc group news-current-certifications)))
+
+
+(defun news-set-current-certifiable ()
+  ;; Record the date that corresponds to the directory you are about to check
+  (let ((file (concat news-path
+		      (string-subst-char ?/ ?. news-current-news-group))))
+    (setq news-current-certifiable
+	  (nth 5 (file-attributes
+		  (or (file-symlink-p file) file))))))
+
+(defun news-get-certifications ()
+  ;; Read the certified-read file from last session
+  (save-excursion
+    (save-window-excursion
+      (setq news-current-certifications
+	    (car-safe
+	     (condition-case var
+		 (let*
+		     ((file (substitute-in-file-name news-certification-file))
+		      (buf (find-file-noselect file)))
+		   (and (file-exists-p file)
+			(progn
+			  (switch-to-buffer buf 'norecord)
+			  (unwind-protect
+			      (read-from-string (buffer-string))
+			    (kill-buffer buf)))))
+	       (error nil)))))))
+
+(defun news-write-certifications ()
+  ;; Write a certification file.
+  ;; This is an assoc list of group names with doubletons that represent
+  ;; mod times of the directory when group is read completely.
+  (save-excursion
+    (save-window-excursion
+      (with-output-to-temp-buffer
+	  "*CeRtIfIcAtIoNs*"
+	  (print news-current-certifications))
+      (let ((buf (get-buffer "*CeRtIfIcAtIoNs*")))
+	(switch-to-buffer buf)
+	(write-file (substitute-in-file-name news-certification-file))
+	(kill-buffer buf)))))
+
+(defun news-set-current-group-certification ()
+  (let ((cgc (assoc news-current-news-group news-current-certifications)))
+    (if cgc (setcdr cgc news-current-certifiable)
+      (news-push (cons news-current-news-group news-current-certifiable)
+		 news-current-certifications))))
+
+(defun news-set-minor-modes ()
+  "Creates a minor mode list that has group name, total articles,
+and attribute for current article."
+  (setq news-minor-modes (list (cons 'foo
+				     (concat news-current-message-number
+					     "/"
+					     news-total-current-group
+					     (news-get-attribute-string)))))
+  ;; Detect Emacs versions 18.16 and up, which display
+  ;; directly from news-minor-modes by using a list for mode-name.
+  (or (boundp 'minor-mode-alist)
+      (setq minor-modes news-minor-modes)))
+
+(defun news-set-message-counters ()
+  "Scan through current news-groups filelist to figure out how many messages
+are there. Set counters for use with minor mode display."
+    (if (null news-list-of-files)
+	(setq news-current-message-number 0)))
+
+(if news-mode-map
+    nil
+  (setq news-mode-map (make-keymap))
+  (suppress-keymap news-mode-map)
+  (define-key news-mode-map "." 'beginning-of-buffer)
+  (define-key news-mode-map " " 'scroll-up)
+  (define-key news-mode-map "\177" 'scroll-down)
+  (define-key news-mode-map "n" 'news-next-message)
+  (define-key news-mode-map "c" 'news-make-link-to-message)
+  (define-key news-mode-map "p" 'news-previous-message)
+  (define-key news-mode-map "j" 'news-goto-message)
+  (define-key news-mode-map "q" 'news-exit)
+  (define-key news-mode-map "e" 'news-exit)
+  (define-key news-mode-map "\ej" 'news-goto-news-group)
+  (define-key news-mode-map "\en" 'news-next-group)
+  (define-key news-mode-map "\ep" 'news-previous-group)
+  (define-key news-mode-map "l" 'news-list-news-groups)
+  (define-key news-mode-map "?" 'describe-mode)
+  (define-key news-mode-map "g" 'news-get-new-news)
+  (define-key news-mode-map "f" 'news-reply)
+  (define-key news-mode-map "m" 'news-mail-other-window)
+  (define-key news-mode-map "a" 'news-post-news)
+  (define-key news-mode-map "r" 'news-mail-reply)
+  (define-key news-mode-map "o" 'news-save-item-in-file)
+  (define-key news-mode-map "\C-o" 'rmail-output)
+  (define-key news-mode-map "t" 'news-show-all-headers)
+  (define-key news-mode-map "x" 'news-force-update)
+  (define-key news-mode-map "A" 'news-add-news-group)
+  (define-key news-mode-map "u" 'news-unsubscribe-current-group)
+  (define-key news-mode-map "U" 'news-unsubscribe-group)
+  (define-key news-mode-map "\C-c\C-r" 'news-caesar-buffer-body))
+
+(defun news-mode ()
+  "News Mode is used by M-x rnews for reading USENET Newsgroups articles.
+New readers can find additional help in newsgroup: news.announce.newusers .
+All normal editing commands are turned off.
+Instead, these commands are available:
+
+.	move point to front of this news article (same as Meta-<).
+Space	scroll to next screen of this news article.
+Delete  scroll down previous page of this news article.
+n	move to next news article, possibly next group.
+p	move to previous news article, possibly previous group.
+j	jump to news article specified by numeric position.
+M-j     jump to news group.
+M-n     goto next news group.
+M-p     goto previous news group.
+l       list all the news groups with current status.
+?       print this help message.
+C-c C-r caesar rotate all letters by 13 places in the article's body (rot13).
+g       get new USENET news.
+f       post a reply article to USENET.
+a       post an original news article.
+A       add a newsgroup. 
+o	save the current article in the named file (append if file exists).
+C-o	output this message to a Unix-format mail file (append it).
+c       \"copy\" (actually link) current or prefix-arg msg to file.
+	warning: target directory and message file must be on same device
+		(UNIX magic)
+t       show all the headers this news article originally had.
+q	quit reading news after updating .newsrc file.
+e	exit updating .newsrc file.
+m	mail a news article.  Same as C-x 4 m.
+x       update last message seen to be the current message.
+r	mail a reply to this news article.  Like m but initializes some fields.
+u       unsubscribe from current newsgroup.
+U       unsubscribe from specified newsgroup."
+  (interactive)
+  (kill-all-local-variables)
+  (make-local-variable 'news-read-first-time-p)
+  (setq news-read-first-time-p t)
+  (make-local-variable 'news-current-news-group)
+;  (setq news-current-news-group "??")
+  (make-local-variable 'news-current-group-begin)
+  (setq news-current-group-begin 0)
+  (make-local-variable 'news-current-message-number)
+  (setq news-current-message-number 0)
+  (make-local-variable 'news-total-current-group)
+  (make-local-variable 'news-buffer-save)
+  (make-local-variable 'version-control)
+  (setq version-control 'never)
+  (make-local-variable 'news-point-pdl)
+;  This breaks it.  I don't have time to figure out why. -- RMS
+;  (make-local-variable 'news-group-article-assoc)
+  (setq major-mode 'news-mode)
+  (if (boundp 'minor-mode-alist)
+      ;; Emacs versions 18.16 and up.
+      (setq mode-name '("NEWS" news-minor-modes))
+    ;; Earlier versions display minor-modes via a special mechanism.
+    (setq mode-name "NEWS"))
+  (news-set-mode-line)
+  (set-syntax-table text-mode-syntax-table)
+  (use-local-map news-mode-map)
+  (setq local-abbrev-table text-mode-abbrev-table)
+  (run-hooks 'news-mode-hook))
+
+(defun string-subst-char (new old string)
+  (let (index)
+    (setq old (regexp-quote (char-to-string old))
+	  string (substring string 0))
+    (while (setq index (string-match old string))
+      (aset string index new)))
+  string)
+
+;; update read message number
+(defmacro news-update-message-read (ngroup nno)
+  (list 'setcar
+	(list 'news-cdadr
+	      (list 'assoc ngroup 'news-group-article-assoc))
+	nno))
+
+(defun news-parse-range (number-string)
+  "Parse string representing range of numbers of he form <a>-<b>
+to a list (a . b)"
+  (let ((n (string-match "-" number-string)))
+    (if n
+	(cons (string-to-int (substring number-string 0 n))
+	      (string-to-int (substring number-string (1+ n))))
+      (setq n (string-to-int number-string))
+      (cons n n))))
+
+;(defun is-in (elt lis)
+;  (catch 'foo
+;    (while lis
+;      (if (equal (car lis) elt)
+;	  (throw 'foo t)
+;	(setq lis (cdr lis))))))
+
+(defun news-get-new-news ()
+  "Get new USENET news, if there is any for the current user."
+  (interactive)
+  (if (not (null news-user-group-list))
+      (news-update-newsrc-file))
+  (setq news-group-article-assoc ())
+  (setq news-user-group-list ())
+  (message "Looking up %s file..." news-startup-file)
+  (let ((file (substitute-in-file-name news-startup-file))
+	(temp-user-groups ()))
+    (save-excursion
+      (let ((newsrcbuf (find-file-noselect file))
+	    start end endofline tem)
+	(set-buffer newsrcbuf)
+	(goto-char 0)
+	(while (search-forward ": " nil t)
+	  (setq end (point))
+	  (beginning-of-line)
+	  (setq start (point))
+	  (end-of-line)
+	  (setq endofline (point))
+	  (setq tem (buffer-substring start (- end 2)))
+	  (let ((range (news-parse-range
+			(buffer-substring end endofline))))
+	    (if (assoc tem news-group-article-assoc)
+		(message "You are subscribed twice to %s; I ignore second"
+			 tem)	      
+	      (setq temp-user-groups (cons tem temp-user-groups)
+		    news-group-article-assoc
+		    (cons (list tem (list (car range)
+					  (cdr range)
+					  (cdr range)))
+			  news-group-article-assoc)))))
+	(kill-buffer newsrcbuf)))      
+    (setq temp-user-groups (nreverse temp-user-groups))
+    (message "Prefrobnicating...")
+    (switch-to-buffer news-buffer)
+    (setq news-user-group-list temp-user-groups)
+    (while (and temp-user-groups
+		(not (news-read-files-into-buffer
+		      (car temp-user-groups) nil)))
+      (setq temp-user-groups (cdr temp-user-groups)))
+    (if (null temp-user-groups)
+	(message "No news is good news.")
+      (message ""))))
+
+(defun news-list-news-groups ()
+  "Display all the news groups to which you belong."
+  (interactive)
+  (with-output-to-temp-buffer "*Newsgroups*"
+    (save-excursion
+      (set-buffer standard-output)
+      (insert
+	"News Group        Msg No.       News Group        Msg No.\n")
+      (insert
+	"-------------------------       -------------------------\n")
+      (let ((temp news-user-group-list)
+	    (flag nil))
+	(while temp
+	  (let ((item (assoc (car temp) news-group-article-assoc)))
+	    (insert (car item))
+	    (indent-to (if flag 52 20))
+	    (insert (int-to-string (news-cadr (news-cadr item))))
+	    (if flag
+		(insert "\n")
+	      (indent-to 33))
+	    (setq temp (cdr temp) flag (not flag))))))))
+
+;; Mode line hack
+(defun news-set-mode-line ()
+  "Set mode line string to something useful."
+  (setq mode-line-process
+	(concat " "
+		(if (integerp news-current-message-number)
+		    (int-to-string news-current-message-number)
+		 "??")
+		"/"
+		(if (integerp news-current-group-end)
+		    (int-to-string news-current-group-end)
+		  news-current-group-end)))
+  (setq mode-line-buffer-identification
+	(concat "NEWS: "
+		news-current-news-group
+		;; Enough spaces to pad group name to 17 positions.
+		(substring "                 "
+			   0 (max 0 (- 17 (length news-current-news-group))))))
+  (set-buffer-modified-p t)
+  (sit-for 0))
+
+(defun news-goto-news-group (gp)
+  "Takes a string and goes to that news group."
+  (interactive (list (completing-read "NewsGroup: "
+				      news-group-article-assoc)))
+  (message "Jumping to news group %s..." gp)
+  (news-select-news-group gp)
+  (message "Jumping to news group %s... done." gp))
+
+(defun news-select-news-group (gp)
+  (let ((grp (assoc gp news-group-article-assoc)))
+    (if (null grp)
+ 	(error "Group %s not subscribed to" gp)
+      (progn
+	(news-update-message-read news-current-news-group
+				  (news-cdar news-point-pdl))
+	(news-read-files-into-buffer  (car grp) nil)
+	(news-set-mode-line)))))
+
+(defun news-goto-message (arg)
+  "Goes to the article ARG in current newsgroup."
+  (interactive "p")
+  (if (null current-prefix-arg)
+      (setq arg (read-no-blanks-input "Go to article: " "")))
+  (news-select-message arg))
+
+(defun news-select-message (arg)
+  (if (stringp arg) (setq arg (string-to-int arg)))
+  (let ((file (concat news-path
+		      (string-subst-char ?/ ?. news-current-news-group)
+		      "/" arg)))
+    (if (file-exists-p file)
+	(let ((buffer-read-only ()))
+	  (if (= arg 
+		 (or (news-cadr (memq (news-cdar news-point-pdl) news-list-of-files))
+		     0))
+	      (setcdr (car news-point-pdl) arg))
+	  (setq news-current-message-number arg)
+	  (news-read-in-file file)
+	  (news-set-mode-line))
+      (error "Article %d nonexistent" arg))))
+
+(defun news-force-update ()
+  "updates the position of last article read in the current news group"
+  (interactive)
+  (setcdr (car news-point-pdl) news-current-message-number)
+  (message "Updated to %d" news-current-message-number))
+
+(defun news-next-message (arg)
+  "Move ARG messages forward within one newsgroup.
+Negative ARG moves backward.
+If ARG is 1 or -1, moves to next or previous newsgroup if at end."
+  (interactive "p")
+  (let ((no (+ arg news-current-message-number)))
+    (if (or (< no news-current-group-begin) 
+	    (> no news-current-group-end))
+	(cond ((= arg 1)
+	       (news-set-current-group-certification)
+	       (news-next-group))
+	      ((= arg -1)
+	       (news-previous-group))
+	      (t (error "Article out of range")))
+      (let ((plist (news-get-motion-lists
+		     news-current-message-number
+		     news-list-of-files)))
+	(if (< arg 0)
+	    (news-select-message (nth (1- (- arg)) (car (cdr plist))))
+	  (news-select-message (nth (1- arg) (car plist))))))))
+
+(defun news-previous-message (arg)
+  "Move ARG messages backward in current newsgroup.
+With no arg or arg of 1, move one message
+and move to previous newsgroup if at beginning.
+A negative ARG means move forward."
+  (interactive "p")
+  (news-next-message (- arg)))
+
+(defun news-move-to-group (arg)
+  "Given arg move forward or backward to a new newsgroup."
+  (let ((cg news-current-news-group))
+    (let ((plist (news-get-motion-lists cg news-user-group-list))
+	  ngrp)
+      (if (< arg 0)
+	  (or (setq ngrp (nth (1- (- arg)) (news-cadr plist)))
+	      (error "No previous news groups"))
+	(or (setq ngrp (nth arg (car plist)))
+	    (error "No more news groups")))
+      (news-select-news-group ngrp))))
+
+(defun news-next-group ()
+  "Moves to the next user group."
+  (interactive)
+;  (message "Moving to next group...")
+  (news-move-to-group 0)
+  (while (null news-list-of-files)
+    (news-move-to-group 0)))
+;  (message "Moving to next group... done.")
+
+(defun news-previous-group ()
+  "Moves to the previous user group."
+  (interactive)
+;  (message "Moving to previous group...")
+  (news-move-to-group -1)
+  (while (null news-list-of-files)
+    (news-move-to-group -1)))
+;  (message "Moving to previous group... done.")
+
+(defun news-get-motion-lists (arg listy)
+  "Given a msgnumber/group this will return a list of two lists;
+one for moving forward and one for moving backward."
+  (let ((temp listy)
+	(result ()))
+    (catch 'out
+      (while temp
+	(if (equal (car temp) arg)
+	    (throw 'out (cons (cdr temp) (list result)))
+	  (setq result (nconc (list (car temp)) result))
+	  (setq temp (cdr temp)))))))
+
+;; miscellaneous io routines
+(defun news-read-in-file (filename)
+  (erase-buffer)
+  (let ((start (point)))
+  (insert-file-contents filename)
+  (news-convert-format)
+  ;; Run each hook that applies to the current newsgroup.
+  (let ((hooks news-group-hook-alist))
+    (while hooks
+      (goto-char start)
+      (if (string-match (car (car hooks)) news-group-name)
+	  (funcall (cdr (car hooks))))
+      (setq hooks (cdr hooks))))
+  (goto-char start)
+  (forward-line 1)
+  (if (eobp)
+      (message "(Empty file?)")
+    (goto-char start))))
+
+(defun news-convert-format ()
+  (save-excursion
+    (save-restriction
+      (let* ((start (point))
+	     (end (condition-case ()
+		      (progn (search-forward "\n\n") (point))
+		    (error nil)))
+	     has-from has-date)
+       (cond (end
+	      (narrow-to-region start end)
+	      (goto-char start)
+	      (setq has-from (search-forward "\nFrom:" nil t))
+	      (cond ((and (not has-from) has-date)
+		     (goto-char start)
+		     (search-forward "\nDate:")
+		     (beginning-of-line)
+		     (kill-line) (kill-line)))
+	      (news-delete-headers start)
+	      (goto-char start)))))))
+
+(defun news-show-all-headers ()
+  "Redisplay current news item with all original headers"
+  (interactive)
+  (let (news-ignored-headers
+	(buffer-read-only ()))
+    (erase-buffer)
+    (news-set-mode-line)
+    (news-read-in-file
+     (concat news-path
+	     (string-subst-char ?/ ?. news-current-news-group)
+	     "/" (int-to-string news-current-message-number)))))
+
+(defun news-delete-headers (pos)
+  (goto-char pos)
+  (and (stringp news-ignored-headers)
+       (while (re-search-forward news-ignored-headers nil t)
+	 (beginning-of-line)
+	 (delete-region (point)
+			(progn (re-search-forward "\n[^ \t]")
+			       (forward-char -1)
+			       (point))))))
+
+(defun news-exit ()
+  "Quit news reading session and update the .newsrc file."
+  (interactive)
+  (if (y-or-n-p "Do you really wanna quit reading news ? ")
+      (progn (message "Updating %s..." news-startup-file)
+	     (news-update-newsrc-file)
+	     (news-write-certifications)
+	     (message "Updating %s... done" news-startup-file)
+	     (message "Now do some real work")
+	     (and (fboundp 'bury-buffer) (bury-buffer (current-buffer)))
+	     (switch-to-buffer news-buffer-save)
+	     (setq news-user-group-list ()))
+    (message "")))
+
+(defun news-update-newsrc-file ()
+  "Updates the .newsrc file in the users home dir."
+  (let ((newsrcbuf (find-file-noselect
+		     (substitute-in-file-name news-startup-file)))
+	(tem news-user-group-list)
+	group)
+    (save-excursion
+      (if (not (null news-current-news-group))
+	  (news-update-message-read news-current-news-group
+				    (news-cdar news-point-pdl)))
+      (set-buffer newsrcbuf)
+      (while tem
+	(setq group (assoc (car tem) news-group-article-assoc))
+	(if (= (news-cadr (news-cadr group)) (news-caddr (news-cadr group)))
+	    nil
+	  (goto-char 0)
+	  (if (search-forward (concat (car group) ": ") nil t)
+	      (kill-line nil)
+	    (insert (car group) ": \n") (backward-char 1))
+	  (insert (int-to-string (car (news-cadr group))) "-"
+		  (int-to-string (news-cadr (news-cadr group)))))
+	(setq tem (cdr tem)))
+     (while news-unsubscribe-groups
+       (setq group (assoc (car news-unsubscribe-groups)
+			  news-group-article-assoc))
+       (goto-char 0)
+       (if (search-forward (concat (car group) ": ") nil t)
+	   (progn
+	      (backward-char 2)
+	      (kill-line nil)
+	      (insert "! " (int-to-string (car (news-cadr group)))
+		      "-" (int-to-string (news-cadr (news-cadr group))))))
+       (setq news-unsubscribe-groups (cdr news-unsubscribe-groups)))
+     (save-buffer)
+     (kill-buffer (current-buffer)))))
+
+
+(defun news-unsubscribe-group (group)
+  "Removes you from newgroup GROUP."
+  (interactive (list (completing-read  "Unsubscribe from group: "
+				      news-group-article-assoc)))
+  (news-unsubscribe-internal group))
+
+(defun news-unsubscribe-current-group ()
+  "Removes you from the newsgroup you are now reading."
+  (interactive)
+  (if (y-or-n-p "Do you really want to unsubscribe from this group ? ")
+      (news-unsubscribe-internal news-current-news-group)))
+
+(defun news-unsubscribe-internal (group)
+  (let ((tem (assoc group news-group-article-assoc)))
+    (if tem
+	(progn
+	  (setq news-unsubscribe-groups (cons group news-unsubscribe-groups))
+	  (news-update-message-read group (news-cdar news-point-pdl))
+	  (if (equal group news-current-news-group)
+	      (news-next-group))
+	  (message ""))
+      (error "Not subscribed to group: %s" group))))
+
+(defun news-save-item-in-file (file)
+  "Save the current article that is being read by appending to a file."
+  (interactive "FSave item in file: ")
+  (append-to-file (point-min) (point-max) file))
+
+(defun news-get-pruned-list-of-files (gp-list end-file-no)
+  "Given a news group it finds all files in the news group.
+The arg must be in slashified format.
+Using ls was found to be too slow in a previous version."
+  (let
+      ((answer
+	(and
+	 (not (and end-file-no
+		   (equal (news-set-current-certifiable)
+		     (news-group-certification gp-list))
+		   (setq news-list-of-files nil
+			 news-list-of-files-possibly-bogus t)))
+	 (let* ((file-directory (concat news-path
+					(string-subst-char ?/ ?. gp-list)))
+		tem
+		(last-winner
+		 (and end-file-no
+		      (news-wins file-directory end-file-no)
+		      (news-find-first-or-last file-directory end-file-no 1))))
+	   (setq news-list-of-files-possibly-bogus t news-list-of-files nil)
+	   (if last-winner
+	       (progn
+		 (setq news-list-of-files-possibly-bogus t
+		       news-current-group-end last-winner)
+		 (while (> last-winner end-file-no)
+		   (news-push last-winner news-list-of-files)
+		   (setq last-winner (1- last-winner)))
+		 news-list-of-files)
+	     (if (or (not (file-directory-p file-directory))
+		     (not (file-readable-p file-directory)))
+		 nil
+	       (setq news-list-of-files
+		     (condition-case error
+			 (directory-files file-directory)
+		       (file-error
+			(if (string= (nth 2 error) "permission denied")
+			    (message "Newsgroup %s is read-protected"
+				     gp-list)
+			  (signal 'file-error (cdr error)))
+			nil)))
+	       (setq tem news-list-of-files)
+	       (while tem
+		 (if (or (not (string-match "^[0-9]*$" (car tem)))
+			 ;; dont get confused by directories that look like numbers
+			 (file-directory-p
+			  (concat file-directory "/" (car tem)))
+			 (<= (string-to-int (car tem)) end-file-no))
+		     (setq news-list-of-files
+			   (delq (car tem) news-list-of-files)))
+		 (setq tem (cdr tem)))
+	       (if (null news-list-of-files)
+		   (progn (setq news-current-group-end 0)
+			  nil)
+		 (setq news-list-of-files
+		       (mapcar 'string-to-int news-list-of-files))
+		 (setq news-list-of-files (sort news-list-of-files '<))
+		 (setq news-current-group-end
+		       (elt news-list-of-files
+			    (1- (length news-list-of-files))))
+		 news-list-of-files)))))))
+    (or answer (progn (news-set-current-group-certification) nil))))
+
+(defun news-read-files-into-buffer (group reversep)
+  (let* ((files-start-end (news-cadr (assoc group news-group-article-assoc)))
+	 (start-file-no (car files-start-end))
+	 (end-file-no (news-cadr files-start-end))
+	 (buffer-read-only nil))
+    (setq news-current-news-group group)
+    (setq news-current-message-number nil)
+    (setq news-current-group-end nil)
+    (news-set-mode-line)
+    (news-get-pruned-list-of-files group end-file-no)
+    (news-set-mode-line)
+    ;; @@ should be a lot smarter than this if we have to move
+    ;; @@ around correctly.
+    (setq news-point-pdl (list (cons (car files-start-end)
+				     (news-cadr files-start-end))))
+    (if (null news-list-of-files)
+	(progn (erase-buffer)
+	       (setq news-current-group-end end-file-no)
+	       (setq news-current-group-begin end-file-no)
+	       (setq news-current-message-number end-file-no)
+	       (news-set-mode-line)
+;	       (message "No new articles in " group " group.")
+	       nil)
+      (setq news-current-group-begin (car news-list-of-files))
+      (if reversep
+	  (setq news-current-message-number news-current-group-end)
+	(if (> (car news-list-of-files) end-file-no)
+	    (setcdr (car news-point-pdl) (car news-list-of-files)))
+	(setq news-current-message-number news-current-group-begin))
+      (news-set-message-counters)
+      (news-set-mode-line)
+      (news-read-in-file (concat news-path
+				 (string-subst-char ?/ ?. group)
+				 "/"
+				 (int-to-string
+				   news-current-message-number)))
+      (news-set-message-counters)
+      (news-set-mode-line)
+      t)))
+
+(defun news-add-news-group (gp)
+  "Resubscribe to or add a USENET news group named GROUP (a string)."
+; @@ (completing-read ...)
+; @@ could be based on news library file ../active (slightly facist)
+; @@ or (expensive to compute) all directories under the news spool directory
+  (interactive "sAdd news group: ")
+  (let ((file-dir (concat news-path (string-subst-char ?/ ?. gp))))
+    (save-excursion
+      (if (null (assoc gp news-group-article-assoc))
+	  (let ((newsrcbuf (find-file-noselect
+			    (substitute-in-file-name news-startup-file))))
+	    (if (file-directory-p file-dir)
+		(progn
+		  (switch-to-buffer newsrcbuf)
+		  (goto-char 0)
+		  (if (search-forward (concat gp "! ") nil t)
+		      (progn
+			(message "Re-subscribing to group %s." gp)
+			;;@@ news-unsubscribe-groups isn't being used
+			;;(setq news-unsubscribe-groups
+			;;    (delq gp news-unsubscribe-groups))
+			(backward-char 2)
+			(delete-char 1)
+			(insert ":"))
+		    (progn
+		      (message
+		       "Added %s to your list of newsgroups." gp)
+		      (end-of-buffer)
+		      (insert gp ": 1-1\n")))
+		  (search-backward gp nil t)
+		  (let (start end endofline tem)
+		    (search-forward ": " nil t)
+		    (setq end (point))
+		    (beginning-of-line)
+		    (setq start (point))
+		    (end-of-line)
+		    (setq endofline (point))
+		    (setq tem (buffer-substring start (- end 2)))
+		    (let ((range (news-parse-range
+				  (buffer-substring end endofline))))
+		      (setq news-group-article-assoc
+			    (cons (list tem (list (car range)
+						  (cdr range)
+						  (cdr range)))
+				  news-group-article-assoc))))
+		  (save-buffer)
+		  (kill-buffer (current-buffer)))
+	      (message "Newsgroup %s doesn't exist." gp)))
+	(message "Already subscribed to group %s." gp)))))
+
+(defun news-make-link-to-message (number newname)
+	"Forges a link to an rnews message numbered number (current if no arg)
+Good for hanging on to a message that might or might not be
+automatically deleted."
+  (interactive "P
+FName to link to message: ")
+  (add-name-to-file
+   (concat news-path
+	   (string-subst-char ?/ ?. news-current-news-group)
+	   "/" (if number
+		   (prefix-numeric-value number)
+		 news-current-message-number))
+   newname))
+
+;;; caesar-region written by phr@prep.ai.mit.edu  Nov 86
+;;; modified by tower@prep Nov 86
+(defun caesar-region (&optional n)
+  "Caesar rotation of region by N, default 13, for decrypting netnews."
+  (interactive (if current-prefix-arg	; Was there a prefix arg?
+		   (list (prefix-numeric-value current-prefix-arg))
+		 (list nil)))
+  (cond ((not (numberp n)) (setq n 13))
+	((< n 0) (setq n (- 26 (% (- n) 26))))
+	(t (setq n (% n 26))))		;canonicalize N
+  (if (not (zerop n))		; no action needed for a rot of 0
+      (progn
+	(if (or (not (boundp 'caesar-translate-table))
+		(/= (aref caesar-translate-table ?a) (+ ?a n)))
+	    (let ((i 0) (lower "abcdefghijklmnopqrstuvwxyz") upper)
+	      (message "Building caesar-translate-table...")
+	      (setq caesar-translate-table (make-vector 256 0))
+	      (while (< i 256)
+		(aset caesar-translate-table i i)
+		(setq i (1+ i)))
+	      (setq lower (concat lower lower) upper (upcase lower) i 0)
+	      (while (< i 26)
+		(aset caesar-translate-table (+ ?a i) (aref lower (+ i n)))
+		(aset caesar-translate-table (+ ?A i) (aref upper (+ i n)))
+		(setq i (1+ i)))
+	      (message "Building caesar-translate-table... done")))
+	(let ((from (region-beginning))
+	      (to (region-end))
+	      (i 0) str len)
+	  (setq str (buffer-substring from to))
+	  (setq len (length str))
+	  (while (< i len)
+	    (aset str i (aref caesar-translate-table (aref str i)))
+	    (setq i (1+ i)))
+	  (goto-char from)
+	  (kill-region from to)
+	  (insert str)))))
+
+;;; news-caesar-buffer-body written by paul@media-lab.mit.edu  Wed Oct 1, 1986
+;;; hacked further by tower@prep.ai.mit.edu
+(defun news-caesar-buffer-body (&optional rotnum)
+  "Caesar rotates all letters in the current buffer by 13 places.
+Used to encode/decode possibly offensive messages (commonly in net.jokes).
+With prefix arg, specifies the number of places to rotate each letter forward.
+Mail and USENET news headers are not rotated."
+  (interactive (if current-prefix-arg	; Was there a prefix arg?
+		   (list (prefix-numeric-value current-prefix-arg))
+		 (list nil)))
+  (save-excursion
+    (let ((buffer-status buffer-read-only))
+      (setq buffer-read-only nil)
+      ;; setup the region
+      (set-mark (if (progn (goto-char (point-min))
+			    (search-forward
+			     (concat "\n"
+				     (if (equal major-mode 'news-mode)
+					 ""
+				       mail-header-separator)
+				     "\n") nil t))
+		     (point)
+		   (point-min)))
+      (goto-char (point-max))
+      (caesar-region rotnum)
+      (setq buffer-read-only buffer-status))))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/mail/rnewspost.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,390 @@
+;;; USENET news poster/mailer for GNU Emacs
+;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;; moved posting and mail code from rnews.el
+;;	tower@prep.ai.mit.edu Wed Oct 29 1986
+;; brought posting code almost up to the revision of RFC 850 for News 2.11
+;; - couldn't see handling the special meaning of the Keyword: poster
+;; - not worth the code space to support the old A news Title: (which
+;;   Subject: replaced) and Article-I.D.: (which Message-ID: replaced)
+;;	tower@prep Nov 86
+;; changed C-c C-r key-binding due to rename of news-caesar-buffer-body
+;;	tower@prep 21 Nov 86
+;; added (require 'rnews)	tower@prep 22 Apr 87
+;; restricted call of news-show-all-headers in news-post-news & news-reply
+;;	tower@prep 28 Apr 87
+;; commented out Posting-Front-End to save USENET bytes tower@prep Jul 31 87
+;; commented out -n and -t args in news-inews     tower@prep 15 Oct 87
+(require 'sendmail)
+(require 'rnews)
+
+;Now in paths.el.
+;(defvar news-inews-program "inews"
+;  "Function to post news.")
+
+;; Replying and posting news items are done by these functions.
+;; imported from rmail and modified to work with rnews ...
+;; Mon Mar 25,1985 at 03:07:04 ads@mit-hermes.
+;; this is done so that rnews can operate independently from rmail.el and
+;; sendmail and dosen't have to autoload these functions.
+;;
+;;; >> Nuked by Mly to autoload those functions again, as the duplication of
+;;; >>  code was making maintenance too difficult.
+
+(defvar news-reply-mode-map () "Mode map used by news-reply.")
+
+(or news-reply-mode-map
+    (progn
+      (setq news-reply-mode-map (make-keymap))
+      (define-key news-reply-mode-map "\C-c?" 'describe-mode)
+      (define-key news-reply-mode-map "\C-c\C-f\C-d" 'news-reply-distribution)
+      (define-key news-reply-mode-map "\C-c\C-f\C-k" 'news-reply-keywords)
+      (define-key news-reply-mode-map "\C-c\C-f\C-n" 'news-reply-newsgroups)
+      (define-key news-reply-mode-map "\C-c\C-f\C-f" 'news-reply-followup-to)
+      (define-key news-reply-mode-map "\C-c\C-f\C-s" 'mail-subject)
+      (define-key news-reply-mode-map "\C-c\C-f\C-a" 'news-reply-summary)
+      (define-key news-reply-mode-map "\C-c\C-r" 'news-caesar-buffer-body)
+      (define-key news-reply-mode-map "\C-c\C-w" 'news-reply-signature)
+      (define-key news-reply-mode-map "\C-c\C-y" 'news-reply-yank-original)
+      (define-key news-reply-mode-map "\C-c\C-q" 'mail-fill-yanked-message)
+      (define-key news-reply-mode-map "\C-c\C-c" 'news-inews)
+      (define-key news-reply-mode-map "\C-c\C-s" 'news-inews)))
+
+(defun news-reply-mode ()
+  "Major mode for editing news to be posted on USENET.
+First-time posters are asked to please read the articles in newsgroup:
+                                                     news.announce.newusers .
+Like Text Mode but with these additional commands:
+
+C-c C-s  news-inews (post the message)    C-c C-c  news-inews
+C-c C-f	 move to a header field (and create it if there isn't):
+	 C-c C-f C-n  move to Newsgroups:	C-c C-f C-s  move to Subj:
+	 C-c C-f C-f  move to Followup-To:      C-c C-f C-k  move to Keywords:
+	 C-c C-f C-d  move to Distribution:	C-c C-f C-a  move to Summary:
+C-c C-y  news-reply-yank-original (insert current message, in NEWS).
+C-c C-q  mail-fill-yanked-message (fill what was yanked).
+C-c C-r  caesar rotate all letters by 13 places in the article's body (rot13)."
+  (interactive)
+  ;; require...
+  (or (fboundp 'mail-setup) (load "sendmail"))
+  (kill-all-local-variables)
+  (make-local-variable 'mail-reply-buffer)
+  (setq mail-reply-buffer nil)
+  (set-syntax-table text-mode-syntax-table)
+  (use-local-map news-reply-mode-map)
+  (setq local-abbrev-table text-mode-abbrev-table)
+  (setq major-mode 'news-reply-mode)
+  (setq mode-name "News")
+  (make-local-variable 'paragraph-separate)
+  (make-local-variable 'paragraph-start)
+  (setq paragraph-start (concat "^" mail-header-separator "$\\|"
+				paragraph-start))
+  (setq paragraph-separate (concat "^" mail-header-separator "$\\|"
+				   paragraph-separate))
+  (run-hooks 'text-mode-hook 'news-reply-mode-hook))
+
+(defvar news-reply-yank-from
+  "Save From: field for news-reply-yank-original."
+  "")
+
+(defvar news-reply-yank-message-id
+  "Save Message-Id: field for news-reply-yank-original."
+  "")
+
+(defun news-reply-yank-original (arg)
+  "Insert the message being replied to, if any (in rmail).
+Puts point before the text and mark after.
+Indents each nonblank line ARG spaces (default 3).
+Just \\[universal-argument] as argument means don't indent
+and don't delete any header fields."
+  (interactive "P")
+  (mail-yank-original arg)
+  (exchange-point-and-mark)
+  (run-hooks 'news-reply-header-hook))
+
+(defvar news-reply-header-hook
+  '(lambda ()
+	 (insert "In article " news-reply-yank-message-id
+			 " " news-reply-yank-from " writes:\n\n"))
+  "Hook for inserting a header at the top of a yanked message.")
+
+(defun news-reply-newsgroups ()
+  "Move point to end of Newsgroups: field.
+RFC 850 constrains the Newsgroups: field to be a comma separated list of valid
+newsgroups names at your site:
+Newsgroups: news.misc,comp.misc,rec.misc"
+  (interactive)
+  (expand-abbrev)
+  (goto-char (point-min))
+  (mail-position-on-field "Newsgroups"))
+
+(defun news-reply-followup-to ()
+  "Move point to end of Followup-To: field.  Create the field if none.
+One usually requests followups to only one newsgroup.
+RFC 850 constrains the Followup-To: field to be a comma separated list of valid
+newsgroups names at your site, that are also in the Newsgroups: field:
+Newsgroups: news.misc,comp.misc,rec.misc,misc.misc,soc.misc
+Followup-To: news.misc,comp.misc,rec.misc"
+  (interactive)
+  (expand-abbrev)
+  (or (mail-position-on-field "Followup-To" t)
+      (progn (mail-position-on-field "newsgroups")
+	     (insert "\nFollowup-To: ")))
+	 ;; @@ could do a completing read based on the Newsgroups: field to
+	 ;; @@ fill in the Followup-To: field
+)
+
+(defun news-reply-distribution ()
+  "Move point to end of Distribution: optional field.
+Create the field if none.  Without this field the posting goes to all of
+USENET.  The field is used to restrict the posting to parts of USENET."
+  (interactive)
+  (expand-abbrev)
+  (mail-position-on-field "Distribution")
+  ;; @@could do a completing read based on the news library file:
+  ;; @@    ../distributions  to fill in the field.
+  )
+
+(defun news-reply-keywords ()
+  "Move point to end of Keywords: optional field.  Create the field if none.
+Used as an aid to the news reader, it can contain a few, well selected keywords
+identifying the message."
+  (interactive)
+  (expand-abbrev)
+  (mail-position-on-field "Keywords"))
+
+(defun news-reply-summary ()
+  "Move point to end of Summary: optional field.  Create the field if none.
+Used as an aid to the news reader, it can contain a succinct
+summary (abstract) of the message."
+  (interactive)
+  (expand-abbrev)
+  (mail-position-on-field "Summary"))
+
+(defun news-reply-signature ()
+  "The inews program appends ~/.signature automatically."
+  (interactive)
+  (message "~/.signature will be appended automatically."))
+
+(defun news-setup (to subject in-reply-to newsgroups replybuffer)
+  "Setup the news reply or posting buffer with the proper headers and in
+news-reply-mode."
+  (setq mail-reply-buffer replybuffer)
+  (let ((mail-setup-hook nil))
+    (if (null to)
+	;; this hack is needed so that inews wont be confused by 
+	;; the fcc: and bcc: fields
+	(let ((mail-self-blind nil)
+	      (mail-archive-file-name nil))
+	  (mail-setup to subject in-reply-to nil replybuffer nil)
+	  (beginning-of-line)
+	  (kill-line 1)
+	  (goto-char (point-max)))
+      (mail-setup to subject in-reply-to nil replybuffer nil))
+    ;;;(mail-position-on-field "Posting-Front-End")
+    ;;;(insert (emacs-version))
+    (goto-char (point-max))
+    (if (let ((case-fold-search t))
+	  (re-search-backward "^Subject:" (point-min) t))
+	(progn (beginning-of-line)
+	       (insert "Newsgroups: " (or newsgroups "") "\n")
+	       (if (not newsgroups)
+		   (backward-char 1)
+		 (goto-char (point-max)))))
+    (run-hooks 'news-setup-hook)))
+   
+(defun news-inews ()
+  "Send a news message using inews."
+  (interactive)
+  (let* (newsgroups subject
+		    (case-fold-search nil))
+    (save-excursion
+      (save-restriction
+	(goto-char (point-min))
+	(search-forward (concat "\n" mail-header-separator "\n"))
+	(narrow-to-region (point-min) (point))
+	(setq newsgroups (mail-fetch-field "newsgroups")
+	      subject (mail-fetch-field "subject")))
+      (widen)
+      (goto-char (point-min))
+      (run-hooks 'news-inews-hook)
+      (goto-char (point-min))
+      (search-forward (concat "\n" mail-header-separator "\n"))
+      (replace-match "\n\n")
+      (goto-char (point-max))
+      ;; require a newline at the end for inews to append .signature to
+      (or (= (preceding-char) ?\n)
+	  (insert ?\n))
+      (message "Posting to USENET...")
+      (call-process-region (point-min) (point-max) 
+			   news-inews-program nil 0 nil
+			   "-h")	; take all header lines!
+			   ;@@ setting of subject and newsgroups still needed?
+			   ;"-t" subject
+			   ;"-n" newsgroups
+      (message "Posting to USENET... done")
+      (goto-char (point-min))		;restore internal header separator
+      (search-forward "\n\n")
+      (replace-match (concat "\n" mail-header-separator "\n"))
+      (set-buffer-modified-p nil))
+    (and (fboundp 'bury-buffer) (bury-buffer))))
+
+;@@ shares some code with news-reply and news-post-news
+(defun news-mail-reply ()
+  "Mail a reply to the author of the current article.
+While composing the reply, use \\[news-reply-yank-original] to yank the
+original message into it."
+  (interactive)
+  (let (from cc subject date to reply-to
+	     (buffer (current-buffer)))
+    (save-restriction
+      (narrow-to-region (point-min) (progn (goto-line (point-min))
+					   (search-forward "\n\n")
+					   (- (point) 1)))
+      (setq from (mail-fetch-field "from")
+	    subject (mail-fetch-field "subject")
+	    reply-to (mail-fetch-field "reply-to")
+	    date (mail-fetch-field "date"))
+      (setq to from)
+      (pop-to-buffer "*mail*")
+      (mail nil
+	    (if reply-to reply-to to)
+	    subject
+	    (let ((stop-pos (string-match "  *at \\|  *@ \\| *(\\| *<" from)))
+	      (concat (if stop-pos (substring from 0 stop-pos) from)
+		      "'s message of "
+		      date))
+	    nil
+	   buffer))))
+
+;@@ the guts of news-reply and news-post-news should be combined. -tower
+(defun news-reply ()
+  "Compose and post a reply (aka a followup) to the current article on USENET.
+While composing the followup, use \\[news-reply-yank-original] to yank the
+original message into it."
+  (interactive)
+  (if (y-or-n-p "Are you sure you want to followup to all of USENET? ")
+      (let (from cc subject date to followup-to newsgroups message-of
+		 references distribution message-id
+		 (buffer (current-buffer)))
+	(save-restriction
+	  (and (not (= 0 (buffer-size))) ;@@real problem is non-existence of
+					;@@	of article file
+	       (equal major-mode 'news-mode) ;@@ if rmail-mode,
+					;@@	should show full headers
+	       (progn
+		 (news-show-all-headers) ;@@ should save/restore header state,
+					;@@	but rnews.el lacks support
+		 (narrow-to-region (point-min) (progn (goto-char (point-min))
+						      (search-forward "\n\n")
+						      (- (point) 1)))))
+	  (setq from (mail-fetch-field "from")
+		news-reply-yank-from from
+		;; @@ not handling old Title: field
+		subject (mail-fetch-field "subject")
+		date (mail-fetch-field "date")
+		followup-to (mail-fetch-field "followup-to")
+		newsgroups (or followup-to
+			       (mail-fetch-field "newsgroups"))
+		references (mail-fetch-field "references")
+		;; @@ not handling old Article-I.D.: field
+		distribution (mail-fetch-field "distribution")
+		message-id (mail-fetch-field "message-id")
+		news-reply-yank-message-id message-id)
+	  (pop-to-buffer "*post-news*")
+	  (news-reply-mode)
+	  (if (and (buffer-modified-p)
+		   (not
+		    (y-or-n-p "Unsent article being composed; erase it? ")))
+	      ()
+	    (progn
+	      (erase-buffer)
+	      (and subject
+		   (progn (if (string-match "\\`Re: " subject)
+			      (while (string-match "\\`Re: " subject)
+				(setq subject (substring subject 4))))
+			  (setq subject (concat "Re: " subject))))
+	      (and from
+		   (progn
+		     (let ((stop-pos
+			    (string-match "  *at \\|  *@ \\| *(\\| *<" from)))
+		       (setq message-of
+			     (concat
+			      (if stop-pos (substring from 0 stop-pos) from)
+			      "'s message of "
+			      date)))))
+	      (news-setup
+	       nil
+	       subject
+	       message-of
+	       newsgroups
+	       buffer)
+	      (if followup-to
+		  (progn (news-reply-followup-to)
+			 (insert followup-to)))
+	      (if distribution
+		  (progn
+		    (mail-position-on-field "Distribution")
+		    (insert distribution)))
+	      (mail-position-on-field "References")
+	      (if references
+		  (insert references))
+	      (if (and references message-id)
+		  (insert " "))
+	      (if message-id
+		  (insert message-id))
+	      (goto-char (point-max))))))
+    (message "")))
+
+;@@ the guts of news-reply and news-post-news should be combined. -tower
+(defun news-post-news ()
+  "Begin editing a new USENET news article to be posted.
+Type \\[describe-mode] once editing the article to get a list of commands."
+  (interactive)
+  (if (y-or-n-p "Are you sure you want to post to all of USENET? ")
+      (let ((buffer (current-buffer)))
+	(save-restriction
+	  (and (not (= 0 (buffer-size))) ;@@real problem is non-existence of
+					;@@	of article file
+	       (equal major-mode 'news-mode) ;@@ if rmail-mode,
+					;@@	should show full headers
+	       (progn
+		 (news-show-all-headers) ;@@ should save/restore header state,
+					;@@	but rnews.el lacks support
+		 (narrow-to-region (point-min) (progn (goto-char (point-min))
+						      (search-forward "\n\n")
+						      (- (point) 1)))))
+	  (setq news-reply-yank-from (mail-fetch-field "from")
+		;; @@ not handling old Article-I.D.: field
+		news-reply-yank-message-id (mail-fetch-field "message-id")))
+	(pop-to-buffer "*post-news*")
+	(news-reply-mode)
+	(if (and (buffer-modified-p)
+		 (not (y-or-n-p "Unsent article being composed; erase it? ")))
+	    ()				;@@ not saving point from last time
+	  (progn (erase-buffer)
+		 (news-setup () () () () buffer))))
+  (message "")))
+
+(defun news-mail-other-window ()
+  "Send mail in another window.
+While composing the message, use \\[news-reply-yank-original] to yank the
+original message into it."
+  (interactive)
+  (mail-other-window nil nil nil nil nil (current-buffer)))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/mail/undigest.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,105 @@
+;; "RMAIL" mail reader for Emacs.
+;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;; note Interent RFP934
+
+(defun undigestify-rmail-message ()
+  "Break up a digest message into its constituent messages.
+Leaves original message, deleted, before the undigestified messages."
+  (interactive)
+  (widen)
+  (let ((buffer-read-only nil)
+	(msg-string (buffer-substring (rmail-msgbeg rmail-current-message)
+				      (rmail-msgend rmail-current-message))))
+    (goto-char (rmail-msgend rmail-current-message))
+    (narrow-to-region (point) (point))
+    (insert msg-string)
+    (narrow-to-region (point-min) (1- (point-max))))
+  (let ((error t)
+	(buffer-read-only nil))
+    (unwind-protect
+	(progn
+	  (save-restriction
+	    (goto-char (point-min))
+	    (delete-region (point-min)
+			   (progn (search-forward "\n*** EOOH ***\n")
+				  (point)))
+	    (insert "\^_\^L\n0, unseen,,\n*** EOOH ***\n")
+	    (narrow-to-region (point)
+			      (point-max))
+	    (let* ((fill-prefix "")
+		   (case-fold-search t)
+		   (digest-name
+		    (mail-strip-quoted-names
+		     (or (save-restriction
+			   (search-forward "\n\n")
+			   (narrow-to-region (point-min) (point))
+			   (goto-char (point-max))
+			   (or (mail-fetch-field "Reply-To")
+			       (mail-fetch-field "To")
+			       (mail-fetch-field "Apparently-To")
+			       (mail-fetch-field "From")))
+			 (error "Message is not a digest")))))
+	      (save-excursion
+		(goto-char (point-max))
+		(skip-chars-backward " \t\n")
+		(let ((count 10) found)
+		  ;; compensate for broken un*x digestifiers.  Sigh Sigh.
+		  (while (and (> count 0) (not found))
+		    (forward-line -1)
+		    (setq count (1- count))
+		    (if (looking-at (concat "End of.*Digest.*\n"
+					    (regexp-quote "*********") "*"
+					    "\\(\n------*\\)*"))
+			(setq found t)))
+		  (if (not found) (error "Message is not a digest"))))
+	      (re-search-forward (concat "^" (make-string 55 ?-) "-*\n*"))
+	      (replace-match "\^_\^L\n0, unseen,,\n*** EOOH ***\n")
+	      (save-restriction
+		(narrow-to-region (point)
+				  (progn (search-forward "\n\n")
+					 (point)))
+		(if (mail-fetch-field "To") nil
+		  (goto-char (point-min))
+		  (insert "To: " digest-name "\n")))
+	      (while (re-search-forward
+		      (concat "\n\n" (make-string 27 ?-) "-*\n*")
+		      nil t)
+		(replace-match "\n\n\^_\^L\n0, unseen,,\n*** EOOH ***\n")
+		(save-restriction
+		  (if (looking-at "End ")
+		      (insert "To: " digest-name "\n\n")
+		    (narrow-to-region (point)
+				      (progn (search-forward "\n\n"
+							     nil 'move)
+					     (point))))
+		  (if (mail-fetch-field "To") nil
+		    (goto-char (point-min))
+		    (insert "To: " digest-name "\n"))))))
+	  (setq error nil)
+	  (message "Message successfully undigestified")
+	  (let ((n rmail-current-message))
+	    (rmail-forget-messages)
+	    (rmail-show-message n)
+	    (rmail-delete-forward)))
+      (cond (error
+	     (narrow-to-region (point-min) (1+ (point-max)))
+	     (delete-region (point-min) (point-max))
+	     (rmail-show-message rmail-current-message))))))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/misc.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,51 @@
+;; Basic editing commands for Emacs
+;; Copyright (C) 1989 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+(defun copy-from-above-command (&optional arg)
+  "Copy characters from previous nonblank line, starting just above point.
+Copy ARG characters, but not past the end of that line.
+If no argument given, copy the entire rest of the line.
+The characters copied are inserted in the buffer before point."
+  (interactive "P")
+  (let ((cc (current-column))
+	n
+	(string ""))
+    (save-excursion
+      (beginning-of-line)
+      (backward-char 1)
+      (skip-chars-backward "\ \t\n")
+      (move-to-column cc)
+      ;; Default is enough to copy the whole rest of the line.
+      (setq n (if arg (prefix-numeric-value arg) (point-max)))
+      ;; If current column winds up in middle of a tab,
+      ;; copy appropriate number of "virtual" space chars.
+      (if (< cc (current-column))
+	  (if (= (preceding-char) ?\t)
+	      (progn
+		(setq string (make-string (min n (- (current-column) cc)) ?\ ))
+		(setq n (- n (min n (- (current-column) cc)))))
+	    ;; In middle of ctl char => copy that whole char.
+	    (backward-char 1)))
+      (setq string (concat string
+			   (buffer-substring
+			    (point)
+			    (min (save-excursion (end-of-line) (point))
+				 (+ n (point)))))))
+    (insert string)))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/sun-curs.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,207 @@
+;; Cursor definitions for Sun windows
+;; Copyright (C) 1987 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;;
+;;; Added some more cursors and moved the hot spots
+;;; Cursor defined by 16 pairs of 16-bit numbers
+;;;
+;;; 9-dec-86 Jeff Peck, Sun Microsystems Inc. <peck@sun.com>
+
+(provide 'sm-cursors)
+
+(defvar sc::cursors nil "List of known cursors")
+
+(defmacro defcursor (name x y string)
+  (if (not (memq name sc::cursors)) 
+      (setq sc::cursors (cons name sc::cursors)))
+  (list 'defconst name (list 'vector x y string)))
+
+;;; push should be defined in common lisp, but if not use this:
+;(defmacro push (v l)
+;  "The ITEM is evaluated and consed onto LIST, a list-valued atom"
+;  (list 'setq l (list 'cons v l)))
+
+;;;
+;;; The standard default cursor
+;;;
+(defcursor sc:right-arrow 15 0
+  (concat '(0 1 0 3 0 7 0 15 0 31 0 63 0 127 0 15
+	      0 27 0 25 0 48 0 48 0 96 0 96 0 192 0 192)))
+
+;;(sc:set-cursor sc:right-arrow)
+
+(defcursor sc:fat-left-arrow 0 8
+  (concat '(1 0 3 0 7 0 15 0 31 0 63 255 127 255 255 255
+	      255 255 127 255 63 255 31 0 15 0 7 0 3 0 1 0)))
+
+(defcursor sc:box 8 8
+  (concat '(15 252 8 4 8 4 8 4 8 4 8 4 8 4 8 4
+	       8 132 8 4 8 4 8 4 8 4 8 4 8 4 15 252)))
+
+(defcursor sc:hourglass 8 8
+  (concat "\177\376\100\002\040\014\032\070"
+	  "\017\360\007\340\003\300\001\200"
+	  "\001\200\002\100\005\040\010\020"
+	  "\021\210\043\304\107\342\177\376"))
+
+(defun sc:set-cursor (icon)
+  "Change the Sun mouse cursor to ICON.
+If ICON is nil, switch to the system default cursor,
+Otherwise, ICON should be a vector or the name of a vector of [x y 32-chars]"
+  (interactive "XIcon Name: ")
+  (if (symbolp icon) (setq icon (symbol-value icon)))
+  (sun-change-cursor-icon icon))
+
+(make-local-variable '*edit-icon*)
+(make-variable-buffer-local 'icon-edit)
+(setq-default icon-edit nil)
+(or (assq 'icon-edit minor-mode-alist)
+    (push '(icon-edit " IconEdit") minor-mode-alist))
+
+(defun sc:edit-cursor (icon)
+  "convert icon to rectangle, edit, and repack"
+  (interactive "XIcon Name: ")
+  (if (not icon) (setq icon (sc::menu-choose-cursor (selected-window) 1 1)))
+  (if (symbolp icon) (setq icon (symbol-value icon)))
+  (if (get-buffer "icon-edit") (kill-buffer "icon-edit"))
+  (switch-to-buffer "icon-edit")
+  (local-set-mouse '(text right) 'sc::menu-function)
+  (local-set-mouse '(text left) '(sc::pic-ins-at-mouse 32))
+  (local-set-mouse '(text middle) '(sc::pic-ins-at-mouse 64))
+  (local-set-mouse '(text left middle) 'sc::hotspot)
+  (sc::display-icon icon)
+  (picture-mode)
+  (setq icon-edit t)	; for mode line display
+)
+
+(defun sc::pic-ins-at-mouse (char)
+  "Picture insert char at mouse location"
+  (mouse-move-point *mouse-window* (min 15 *mouse-x*) (min 15 *mouse-y*))
+  (move-to-column-force (1+ (min 15 (current-column))))
+  (delete-char -1)
+  (insert char)
+  (sc::goto-hotspot))
+    
+(defun sc::menu-function (window x y)
+  (sun-menu-evaluate window (1+ x) y sc::menu))
+
+(defmenu sc::menu
+  ("Cursor Menu")
+  ("Pack & Use" sc::pack-buffer-to-cursor)
+  ("Pack to Icon" sc::pack-buffer-to-icon 
+		  (sc::menu-choose-cursor *menu-window* *menu-x* *menu-y*))
+  ("New Icon" call-interactively 'sc::make-cursor)
+  ("Edit Icon" sc:edit-cursor 
+	       (sc::menu-choose-cursor *menu-window* *menu-x* *menu-y*))
+  ("Set Cursor" sc:set-cursor
+		(sc::menu-choose-cursor *menu-window* *menu-x* *menu-y*)) 
+  ("Reset Cursor" sc:set-cursor nil)
+  ("Help". sc::edit-icon-help-menu)
+  ("Quit" sc::quit-edit)
+  )
+
+(defun sc::quit-edit ()
+  (interactive)
+  (bury-buffer (current-buffer))
+  (switch-to-buffer (other-buffer) 'no-record))
+
+(defun sc::make-cursor (symbol)
+  (interactive "SIcon Name: ")
+  (eval (list 'defcursor symbol 0 0 ""))
+  (sc::pack-buffer-to-icon (symbol-value symbol)))
+
+(defmenu sc::edit-icon-help-menu
+  ("Simple Icon Editor")
+  ("Left     => CLEAR")
+  ("Middle   => SET")
+  ("L & M    => HOTSPOT")
+  ("Right    => MENU"))
+
+(defun sc::edit-icon-help ()
+  (message "Left=> CLEAR  Middle=> SET  Left+Middle=> HOTSPOT  Right=> MENU"))
+
+(defun sc::pack-buffer-to-cursor ()
+    (sc::pack-buffer-to-icon *edit-icon*)
+    (sc:set-cursor *edit-icon*))
+
+(defun sc::menu-choose-cursor (window x y)
+  "Presents a menu of cursor names, and returns one or nil"
+  (let ((curs sc::cursors) 
+	(items))
+    (while curs
+      (push (sc::menu-item-for-cursor (car curs)) items)
+      (setq curs (cdr curs)))
+    (push (list "Choose Cursor") items)
+    (setq menu (menu-create items))
+    (sun-menu-evaluate window x y menu)))
+
+(defun sc::menu-item-for-cursor (cursor)
+  "apply function to selected cursor"
+  (list (symbol-name cursor) 'quote cursor))
+
+(defun sc::hotspot (window x y)
+  (aset *edit-icon* 0 x)
+  (aset *edit-icon* 1 y)
+  (sc::goto-hotspot))
+
+(defun sc::goto-hotspot ()
+  (goto-line (1+ (aref *edit-icon* 1)))
+  (move-to-column (aref *edit-icon* 0)))
+
+(defun sc::display-icon (icon)
+  (setq *edit-icon* (copy-sequence icon))
+  (let ((string (aref *edit-icon* 2))
+	(index 0))
+    (while (< index 32)
+      (let ((char (aref string index))
+	    (bit 128))
+	(while (> bit 0)
+	  (insert (sc::char-at-bit char bit))
+	  (setq bit (lsh bit -1))))
+      (if (eq 1 (% index 2)) (newline))
+      (setq index (1+ index))))
+  (sc::goto-hotspot))
+
+(defun sc::char-at-bit (char bit)
+  (if (> (logand char bit) 0) "@" " "))
+
+(defun sc::pack-buffer-to-icon (icon)
+  "Pack 16 x 16 field into icon string"
+  (goto-char (point-min))
+  (aset icon 0 (aref *edit-icon* 0))
+  (aset icon 1 (aref *edit-icon* 1))
+  (aset icon 2 (mapconcat 'sc::pack-one-line "1234567890123456" ""))
+  (sc::goto-hotspot)
+  )
+  
+(defun sc::pack-one-line (dummy)
+  (let* (char chr1 chr2)
+    (setq char 0 chr1 (mapconcat 'sc::pack-one-char "12345678" "") chr1 char)
+    (setq char 0 chr2 (mapconcat 'sc::pack-one-char "12345678" "") chr2 char)
+    (forward-line 1)
+    (concat (char-to-string chr1) (char-to-string chr2))
+    ))
+
+(defun sc::pack-one-char (dummy)
+  "pack following char into char, unless eolp"
+  (if (or (eolp) (char-equal (following-char) 32))
+      (setq char (lsh char 1)) 
+    (setq char (1+ (lsh char 1))))
+  (if (not (eolp))(forward-char)))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/sun-fns.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,630 @@
+;; Subroutines of Mouse handling for Sun windows
+;; Copyright (C) 1987 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Submitted Mar. 1987, Jeff Peck
+;;;		 	 Sun Microsystems Inc. <peck@sun.com>
+;;; Conceived Nov. 1986, Stan Jefferson,
+;;;                      Computer Science Lab, SRI International.
+;;; GoodIdeas Feb. 1987, Steve Greenbaum
+;;; & UpClicks           Reasoning Systems, Inc.
+;;;
+(provide 'sun-fns)
+(require 'sun-mouse)
+;;;
+;;; Functions for manipulating via the mouse and mouse-map definitions
+;;; for accessing them.  Also definitons of mouse menus.
+;;; This file you should freely modify to reflect you personal tastes.
+;;;
+;;; First half of file defines functions to implement mouse commands,
+;;; Don't delete any of those, just add what ever else you need.
+;;; Second half of file defines mouse bindings, do whatever you want there.
+
+;;;
+;;;         Mouse Functions.
+;;;
+;;; These functions follow the sun-mouse-handler convention of being called
+;;; with three arguements: (window x-pos y-pos)
+;;; This makes it easy for a mouse executed command to know where the mouse is.
+;;; Use the macro "eval-in-window" to execute a function 
+;;; in a temporarily selected window.
+;;;
+;;; If you have a function that must be called with other arguments
+;;; bind the mouse button to an s-exp that contains the necessary parameters.
+;;; See "minibuffer" bindings for examples.
+;;;
+(defconst cursor-pause-milliseconds 300
+  "*Number of milliseconds to display alternate cursor (usually the mark)")
+
+(defun indicate-region (&optional pause)
+  "Bounce cursor to mark for cursor-pause-milliseconds and back again"
+  (or pause (setq pause cursor-pause-milliseconds))
+  (let ((point (point)))
+    (goto-char (mark))
+    (sit-for-millisecs pause)
+    ;(update-display)
+    ;(sleep-for-millisecs pause)
+    (goto-char point)))
+
+
+;;;
+;;; Text buffer operations
+;;;
+(defun mouse-move-point (window x y)
+  "Move point to mouse cursor."
+  (select-window window)
+  (move-to-loc x y)
+  (if (memq last-command	; support the mouse-copy/delete/yank
+	    '(mouse-copy mouse-delete mouse-yank-move))
+      (setq this-command 'mouse-yank-move))
+  )
+
+(defun mouse-set-mark (window x y)
+  "Set mark at mouse cursor."
+  (eval-in-window window	;; use this to get the unwind protect
+    (let ((point (point)))
+      (move-to-loc x y)
+      (set-mark (point))
+      (goto-char point)
+      (indicate-region)))
+  )
+
+(defun mouse-set-mark-and-select (window x y)
+  "Set mark at mouse cursor, and select that window."
+  (select-window window)
+  (mouse-set-mark window x y)
+  )
+
+(defun mouse-set-mark-and-stuff (w x y)
+  "Set mark at mouse cursor, and put region in stuff buffer."
+  (mouse-set-mark-and-select w x y)
+  (sun-select-region (region-beginning) (region-end)))
+
+;;;
+;;; Simple mouse dragging stuff: marking with button up
+;;;
+
+(defvar *mouse-drag-window* nil)
+(defvar *mouse-drag-x* -1)
+(defvar *mouse-drag-y* -1)
+
+(defun mouse-drag-move-point (window x y)
+  "Move point to mouse cursor, and allow dragging."
+  (mouse-move-point window x y)
+  (setq *mouse-drag-window* window
+	*mouse-drag-x* x
+	*mouse-drag-y* y))
+
+(defun mouse-drag-set-mark-stuff (window x y)
+  "The up click handler that goes with mouse-drag-move-point.
+If mouse is in same WINDOW but at different X or Y than when
+mouse-drag-move-point was last executed, set the mark at mouse
+and put the region in the stuff buffer."
+  (if (and (eq *mouse-drag-window* window)
+	   (not (and (equal *mouse-drag-x* x)
+		     (equal *mouse-drag-y* y))))
+      (mouse-set-mark-and-stuff window x y)
+    (setq this-command last-command))	; this was just an upclick no-op.
+  )
+
+(defun mouse-select-or-drag-move-point (window x y)
+  "Select window if not selected, otherwise do mouse-drag-move-point."
+  (if (eq (selected-window) window)
+      (mouse-drag-move-point window x y)
+    (mouse-select-window window x y)))
+
+;;;
+;;; esoteria:
+;;;
+(defun mouse-exch-pt-and-mark (window x y)
+  "Exchange point and mark."
+  (select-window window)
+  (exchange-point-and-mark)
+  )
+
+(defun mouse-call-kbd-macro (window x y)
+  "Invokes last keyboard macro at mouse cursor."
+  (mouse-move-point window x y)
+  (call-last-kbd-macro)
+  )
+
+(defun mouse-mark-thing (window x y)
+  "Set point and mark to text object using syntax table.
+The resulting region is put in the sun-window stuff buffer.
+Left or right Paren syntax marks an s-expression.  
+Clicking at the end of a line marks the line including a trailing newline.  
+If it doesn't recognize one of these it marks the character at point."
+  (mouse-move-point window x y)
+  (if (eobp) (open-line 1))
+  (let* ((char (char-after (point)))
+         (syntax (char-syntax char)))
+    (cond
+     ((eq syntax ?w)			; word.
+      (forward-word 1)
+      (set-mark (point))
+      (forward-word -1))
+     ;; try to include a single following whitespace (is this a good idea?)
+     ;; No, not a good idea since inconsistent.
+     ;;(if (eq (char-syntax (char-after (mark))) ?\ )
+     ;;    (set-mark (1+ (mark))))
+     ((eq syntax ?\( )			; open paren.
+      (mark-sexp 1))
+     ((eq syntax ?\) )			; close paren.
+      (forward-char 1)
+      (mark-sexp -1)
+      (exchange-point-and-mark))
+     ((eolp)				; mark line if at end.
+      (set-mark (1+ (point)))
+      (beginning-of-line 1))
+     (t					; mark character
+      (set-mark (1+ (point)))))
+    (indicate-region))			; display region boundary.
+  (sun-select-region (region-beginning) (region-end))
+  )
+
+(defun mouse-kill-thing (window x y)
+  "Kill thing at mouse, and put point there."
+  (mouse-mark-thing window x y)
+  (kill-region-and-unmark (region-beginning) (region-end))
+  )
+
+(defun mouse-kill-thing-there (window x y)
+  "Kill thing at mouse, leave point where it was.
+See mouse-mark-thing for a description of the objects recognized."
+  (eval-in-window window 
+    (save-excursion
+      (mouse-mark-thing window x y)
+      (kill-region (region-beginning) (region-end))))
+  )
+
+(defun mouse-save-thing (window x y &optional quiet)
+  "Put thing at mouse in kill ring.
+See mouse-mark-thing for a description of the objects recognized."
+  (mouse-mark-thing window x y)
+  (copy-region-as-kill (region-beginning) (region-end))
+  (if (not quiet) (message "Thing saved"))
+  )
+
+(defun mouse-save-thing-there (window x y &optional quiet)
+  "Put thing at mouse in kill ring, leave point as is.
+See mouse-mark-thing for a description of the objects recognized."
+  (eval-in-window window
+    (save-excursion
+      (mouse-save-thing window x y quiet))))
+
+;;;
+;;; Mouse yanking...
+;;;
+(defun mouse-copy-thing (window x y)
+  "Put thing at mouse in kill ring, yank to point.
+See mouse-mark-thing for a description of the objects recognized."
+  (setq last-command 'not-kill)	 ;Avoids appending to previous kills.
+  (mouse-save-thing-there window x y t)
+  (yank)
+  (setq this-command 'yank))
+
+(defun mouse-move-thing (window x y)
+  "Kill thing at mouse, yank it to point.
+See mouse-mark-thing for a description of the objects recognized."
+  (setq last-command 'not-kill)	 ;Avoids appending to previous kills.
+  (mouse-kill-thing-there window x y)
+  (yank)
+  (setq this-command 'yank))
+
+(defun mouse-yank-at-point (&optional window x y)
+  "Yank from kill-ring at point; then cycle thru kill ring."
+  (if (eq last-command 'yank)
+      (let ((before (< (point) (mark))))
+	(delete-region (point) (mark))
+	(rotate-yank-pointer 1)
+	(insert (car kill-ring-yank-pointer))
+	(if before (exchange-point-and-mark)))
+    (yank))
+  (setq this-command 'yank))
+
+(defun mouse-yank-at-mouse (window x y)
+  "Yank from kill-ring at mouse; then cycle thru kill ring."
+  (mouse-move-point window x y)
+  (mouse-yank-at-point window x y))
+
+(defun mouse-save/delete/yank (&optional window x y)
+  "Context sensitive save/delete/yank.
+Consecutive clicks perform as follows:
+    * first click saves region to kill ring,
+    * second click kills region,
+    * third click yanks from kill ring,
+    * subsequent clicks cycle thru kill ring.
+If mouse-move-point is performed after the first or second click,
+the next click will do a yank, etc.  Except for a possible mouse-move-point,
+this command is insensitive to mouse location."
+  (cond
+   ((memq last-command '(mouse-delete yank mouse-yank-move))	; third+ click
+    (mouse-yank-at-point))
+   ((eq last-command 'mouse-copy)	; second click
+    (kill-region (region-beginning) (region-end))
+    (setq this-command 'mouse-delete))
+   (t					; first click
+    (copy-region-as-kill (region-beginning) (region-end))
+    (message "Region saved")
+    (setq this-command 'mouse-copy))
+   ))
+
+
+(defun mouse-split-horizontally (window x y)
+  "Splits the window horizontally at mouse cursor."
+  (eval-in-window window (split-window-horizontally (1+ x))))
+
+(defun mouse-split-vertically (window x y)
+  "Split the window vertically at the mouse cursor."
+  (eval-in-window window (split-window-vertically (1+ y))))
+
+(defun mouse-select-window (window x y)
+  "Selects the window, restoring point."
+  (select-window window))
+
+(defun mouse-delete-other-windows (window x y)
+  "Deletes all windows except the one mouse is in."
+  (delete-other-windows window))
+
+(defun mouse-delete-window (window x y)
+  "Deletes the window mouse is in."
+  (delete-window window))
+
+(defun mouse-undo (window x y)
+  "Invokes undo in the window mouse is in."
+  (eval-in-window window (undo)))
+
+;;;
+;;; Scroll operations
+;;;
+
+;;; The move-to-window-line is used below because otherwise
+;;; scrolling a non-selected process window with the mouse, after
+;;; the process has written text past the bottom of the window,
+;;; gives an "End of buffer" error, and then scrolls.  The
+;;; move-to-window-line seems to force recomputing where things are.
+(defun mouse-scroll-up (window x y)
+  "Scrolls the window upward."
+  (eval-in-window window (move-to-window-line 1) (scroll-up nil)))
+
+(defun mouse-scroll-down (window x y)
+  "Scrolls the window downward."
+  (eval-in-window window (scroll-down nil)))
+
+(defun mouse-scroll-proportional (window x y)
+  "Scrolls the window proportionally corresponding to window
+relative X divided by window width."
+  (eval-in-window window 
+    (if (>= x (1- (window-width)))
+	;; When x is maximun (equal to or 1 less than window width),
+	;; goto end of buffer.  We check for this special case
+	;; becuase the calculated goto-char often goes short of the
+	;; end due to roundoff error, and we often really want to go
+	;; to the end.
+	(goto-char (point-max))
+      (progn
+	(goto-char (+ (point-min)	; For narrowed regions.
+		      (* x (/ (- (point-max) (point-min))
+			      (1- (window-width))))))
+	(beginning-of-line))
+      )
+    (what-cursor-position)		; Report position.
+    ))
+
+(defun mouse-line-to-top (window x y)
+  "Scrolls the line at the mouse cursor up to the top."
+  (eval-in-window window (scroll-up y)))
+
+(defun mouse-top-to-line (window x y)
+  "Scrolls the top line down to the mouse cursor."
+  (eval-in-window window (scroll-down y)))
+
+(defun mouse-line-to-bottom (window x y)
+  "Scrolls the line at the mouse cursor to the bottom."
+  (eval-in-window window (scroll-up (+ y (- 2 (window-height))))))
+
+(defun mouse-bottom-to-line (window x y)
+  "Scrolls the bottom line up to the mouse cursor."
+  (eval-in-window window (scroll-down (+ y (- 2 (window-height))))))
+
+(defun mouse-line-to-middle (window x y)
+  "Scrolls the line at the mouse cursor to the middle."
+  (eval-in-window window (scroll-up (- y -1 (/ (window-height) 2)))))
+
+(defun mouse-middle-to-line (window x y)
+  "Scrolls the line at the middle to the mouse cursor."
+  (eval-in-window window (scroll-up (- (/ (window-height) 2) y 1))))
+
+
+;;;
+;;; main emacs menu.
+;;;
+(defmenu expand-menu
+  ("Vertically" mouse-expand-vertically *menu-window*)
+  ("Horizontally" mouse-expand-horizontally *menu-window*))
+
+(defmenu delete-window-menu
+  ("This One" delete-window *menu-window*)
+  ("All Others" delete-other-windows *menu-window*))
+
+(defmenu mouse-help-menu
+  ("Text Region"
+   mouse-help-region *menu-window* *menu-x* *menu-y* 'text)
+  ("Scrollbar"
+   mouse-help-region *menu-window* *menu-x* *menu-y* 'scrollbar)
+  ("Modeline"
+   mouse-help-region *menu-window* *menu-x* *menu-y* 'modeline)
+  ("Minibuffer"
+   mouse-help-region *menu-window* *menu-x* *menu-y* 'minibuffer)
+  )
+  
+(defmenu emacs-quit-menu
+  ("Suspend" suspend-emacstool)
+  ("Quit" save-buffers-kill-emacs))
+
+(defmenu emacs-menu
+  ("Emacs Menu")
+  ("Stuff Selection" sun-yank-selection)
+  ("Expand" . expand-menu)
+  ("Delete Window" . delete-window-menu)
+  ("Previous Buffer" mouse-select-previous-buffer *menu-window*)
+  ("Save Buffers" save-some-buffers)
+  ("List Directory" list-directory nil)
+  ("Dired" dired nil)
+  ("Mouse Help" . mouse-help-menu)
+  ("Quit" . emacs-quit-menu))
+
+(defun emacs-menu-eval (window x y)
+  "Pop-up menu of editor commands."
+  (sun-menu-evaluate window (1+ x) (1- y) 'emacs-menu))
+
+(defun mouse-expand-horizontally (window)
+  (eval-in-window window
+    (enlarge-window 4 t)
+    (update-display)		; Try to redisplay, since can get confused.
+    ))
+
+(defun mouse-expand-vertically (window)
+  (eval-in-window window (enlarge-window 4)))
+
+(defun mouse-select-previous-buffer (window)
+  "Switch buffer in mouse window to most recently selected buffer."
+  (eval-in-window window (switch-to-buffer (other-buffer))))
+
+;;;
+;;; minibuffer menu
+;;;
+(defmenu minibuffer-menu 
+  ("Minibuffer" message "Just some miscellanous minibuffer commands")
+  ("Stuff" sun-yank-selection)
+  ("Do-It" exit-minibuffer)
+  ("Abort" abort-recursive-edit)
+  ("Suspend" suspend-emacs))
+
+(defun minibuffer-menu-eval (window x y)
+  "Pop-up menu of commands."
+  (sun-menu-evaluate window x (1- y) 'minibuffer-menu))
+
+(defun mini-move-point (window x y)
+  ;; -6 is good for most common cases
+  (mouse-move-point window (- x 6) 0))
+
+(defun mini-set-mark-and-stuff (window x y)
+  ;; -6 is good for most common cases
+  (mouse-set-mark-and-stuff window (- x 6) 0))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
+;;; Buffer-mode Mouse commands
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
+
+(defun Buffer-at-mouse (w x y)
+  "Calls Buffer-menu-buffer from mouse click."
+  (save-window-excursion 
+    (mouse-move-point w x y)
+    (beginning-of-line)
+    (Buffer-menu-buffer t)))
+
+(defun mouse-buffer-bury (w x y)
+  "Bury the indicated buffer."
+  (bury-buffer (Buffer-at-mouse w x y))
+  )
+
+(defun mouse-buffer-select (w x y)
+  "Put the indicated buffer in selected window."
+  (switch-to-buffer (Buffer-at-mouse w x y))
+  (list-buffers)
+  )
+
+(defun mouse-buffer-delete (w x y)
+  "mark indicated buffer for delete"
+  (save-window-excursion
+    (mouse-move-point w x y)
+    (Buffer-menu-delete)
+    ))
+
+(defun mouse-buffer-execute (w x y)
+  "execute buffer-menu selections"
+  (save-window-excursion
+    (mouse-move-point w x y)
+    (Buffer-menu-execute)
+    ))
+  
+(defun enable-mouse-in-buffer-list ()
+  "Call this to enable mouse selections in *Buffer List*
+    LEFT puts the indicated buffer in the selected window.
+    MIDDLE buries the indicated buffer.
+    RIGHT marks the indicated buffer for deletion.
+    MIDDLE-RIGHT deletes the marked buffers.
+To unmark a buffer marked for deletion, select it with LEFT."
+  (save-window-excursion
+    (list-buffers)			; Initialize *Buffer List*
+    (set-buffer "*Buffer List*")
+    (local-set-mouse '(text middle) 'mouse-buffer-bury)
+    (local-set-mouse '(text left) 'mouse-buffer-select)	    
+    (local-set-mouse '(text right) 'mouse-buffer-delete)
+    (local-set-mouse '(text middle right) 'mouse-buffer-execute)
+    )
+  )
+
+
+;;;*******************************************************************
+;;;
+;;;           Global Mouse Bindings.
+;;;
+;;; There is some sense to this mouse binding madness:
+;;; LEFT and RIGHT scrolls are inverses.
+;;; SHIFT makes an opposite meaning in the scroll bar.
+;;; SHIFT is an alternative to DOUBLE (but double chords do not exist).
+;;; META makes the scrollbar functions work in the text region.
+;;; MIDDLE operates the mark
+;;; LEFT operates at point
+
+;;; META commands are generally non-destructive,
+;;; SHIFT is a little more dangerous.
+;;; CONTROL is for the really complicated ones.
+
+;;; CONTROL-META-SHIFT-RIGHT gives help on that region.
+
+;;;
+;;; Text Region mousemap
+;;;
+;; The basics: Point, Mark, Menu, Sun-Select:
+(global-set-mouse '(text        left)	'mouse-drag-move-point)
+(global-set-mouse '(text     up left)	'mouse-drag-set-mark-stuff)
+(global-set-mouse '(text shift  left)	'mouse-exch-pt-and-mark)
+(global-set-mouse '(text double left)	'mouse-exch-pt-and-mark)
+
+(global-set-mouse '(text	middle)	'mouse-set-mark-and-stuff)
+
+(global-set-mouse '(text	right)	'emacs-menu-eval)
+(global-set-mouse '(text shift	right)	'(sun-yank-selection))
+(global-set-mouse '(text double	right)	'(sun-yank-selection))
+
+;; The Slymoblics multi-command for Save, Kill, Copy, Move:
+(global-set-mouse '(text shift	middle)	'mouse-save/delete/yank)
+(global-set-mouse '(text double	middle)	'mouse-save/delete/yank)
+
+;; Save, Kill, Copy, Move Things:
+;; control-left composes with control middle/right to produce copy/move
+(global-set-mouse '(text control middle	    )	'mouse-save-thing-there)
+(global-set-mouse '(text control right      )	'mouse-kill-thing-there)
+(global-set-mouse '(text control 	left)	'mouse-yank-at-point)
+(global-set-mouse '(text control middle	left)	'mouse-copy-thing)
+(global-set-mouse '(text control right	left)	'mouse-move-thing)
+(global-set-mouse '(text control right middle)	'mouse-mark-thing)
+
+;; The Universal mouse help command (press all buttons):
+(global-set-mouse '(text shift  control meta right)	'mouse-help-region)
+(global-set-mouse '(text double control meta right)	'mouse-help-region)
+
+;;; Meta in Text Region is like meta version in scrollbar:
+(global-set-mouse '(text meta        left)	'mouse-line-to-top)
+(global-set-mouse '(text meta shift  left)	'mouse-line-to-bottom)
+(global-set-mouse '(text meta double left)	'mouse-line-to-bottom)
+(global-set-mouse '(text meta         middle)	'mouse-line-to-middle)
+(global-set-mouse '(text meta shift   middle)	'mouse-middle-to-line)
+(global-set-mouse '(text meta double  middle)	'mouse-middle-to-line)
+(global-set-mouse '(text meta control middle)	'mouse-split-vertically)
+(global-set-mouse '(text meta        right)	'mouse-top-to-line)
+(global-set-mouse '(text meta shift  right)	'mouse-bottom-to-line)
+(global-set-mouse '(text meta double right)	'mouse-bottom-to-line)
+
+;; Miscellaneous:
+(global-set-mouse '(text meta control left)	'mouse-call-kbd-macro)
+(global-set-mouse '(text meta control right)	'mouse-undo)
+
+;;;
+;;; Scrollbar mousemap.
+;;; Are available in the Scrollbar Region, or with Meta Text (or Meta Scrollbar)
+;;;
+(global-set-mouse '(scrollbar        left)	'mouse-line-to-top)
+(global-set-mouse '(scrollbar shift  left)	'mouse-line-to-bottom)
+(global-set-mouse '(scrollbar double left)	'mouse-line-to-bottom)
+
+(global-set-mouse '(scrollbar         middle)	'mouse-line-to-middle)
+(global-set-mouse '(scrollbar shift   middle)	'mouse-middle-to-line)
+(global-set-mouse '(scrollbar double  middle)	'mouse-middle-to-line)
+(global-set-mouse '(scrollbar control middle)	'mouse-split-vertically)
+
+(global-set-mouse '(scrollbar        right)	'mouse-top-to-line)
+(global-set-mouse '(scrollbar shift  right)	'mouse-bottom-to-line)
+(global-set-mouse '(scrollbar double right)	'mouse-bottom-to-line)
+
+(global-set-mouse '(scrollbar meta        left)		'mouse-line-to-top)
+(global-set-mouse '(scrollbar meta shift  left)		'mouse-line-to-bottom)
+(global-set-mouse '(scrollbar meta double left)		'mouse-line-to-bottom)
+(global-set-mouse '(scrollbar meta         middle)	'mouse-line-to-middle)
+(global-set-mouse '(scrollbar meta shift   middle)	'mouse-middle-to-line)
+(global-set-mouse '(scrollbar meta double  middle)	'mouse-middle-to-line)
+(global-set-mouse '(scrollbar meta control middle)	'mouse-split-vertically)
+(global-set-mouse '(scrollbar meta        right)	'mouse-top-to-line)
+(global-set-mouse '(scrollbar meta shift  right)	'mouse-bottom-to-line)
+(global-set-mouse '(scrollbar meta double right)	'mouse-bottom-to-line)
+
+;; And the help menu:
+(global-set-mouse '(scrollbar shift  control meta right) 'mouse-help-region)
+(global-set-mouse '(scrollbar double control meta right) 'mouse-help-region)
+
+;;;
+;;; Modeline mousemap.
+;;;
+;;; Note: meta of any single button selects window.
+
+(global-set-mouse '(modeline      left)	'mouse-scroll-up)
+(global-set-mouse '(modeline meta left)	'mouse-select-window)
+
+(global-set-mouse '(modeline         middle)	'mouse-scroll-proportional)
+(global-set-mouse '(modeline meta    middle)	'mouse-select-window)
+(global-set-mouse '(modeline control middle)	'mouse-split-horizontally)
+
+(global-set-mouse '(modeline      right)	'mouse-scroll-down)
+(global-set-mouse '(modeline meta right)	'mouse-select-window)
+
+;;; control-left selects this window, control-right deletes it.
+(global-set-mouse '(modeline control left)	'mouse-delete-other-windows)
+(global-set-mouse '(modeline control right)	'mouse-delete-window)
+
+;; in case of confusion, just select it:
+(global-set-mouse '(modeline control left right)'mouse-select-window)
+
+;; even without confusion (and without the keyboard) select it:
+(global-set-mouse '(modeline left right)	'mouse-select-window)
+
+;; And the help menu:
+(global-set-mouse '(modeline shift  control meta right)	'mouse-help-region)
+(global-set-mouse '(modeline double control meta right)	'mouse-help-region)
+
+;;;
+;;; Minibuffer Mousemap
+;;; Demonstrating some variety:
+;;;
+(global-set-mouse '(minibuffer left)		'mini-move-point)
+
+(global-set-mouse '(minibuffer         middle)	'mini-set-mark-and-stuff)
+
+(global-set-mouse '(minibuffer shift   middle) '(select-previous-complex-command))
+(global-set-mouse '(minibuffer double  middle) '(select-previous-complex-command))
+(global-set-mouse '(minibuffer control middle) '(next-complex-command 1))
+(global-set-mouse '(minibuffer meta    middle) '(previous-complex-command 1))
+
+(global-set-mouse '(minibuffer right)	'minibuffer-menu-eval)
+
+(global-set-mouse '(minibuffer shift  control meta right)  'mouse-help-region)
+(global-set-mouse '(minibuffer double control meta right)  'mouse-help-region)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/term/sun-mouse.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,668 @@
+;; Mouse handling for Sun windows
+;; Copyright (C) 1987 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Jeff Peck, Sun Microsystems, Jan 1987.
+;;; Original idea by Stan Jefferson
+
+(provide 'sun-mouse)
+
+;;;
+;;;     Modelled after the GNUEMACS keymap interface.
+;;;
+;;; User Functions:
+;;;   make-mousemap, copy-mousemap, 
+;;;   define-mouse, global-set-mouse, local-set-mouse,
+;;;   use-global-mousemap, use-local-mousemap,
+;;;   mouse-lookup, describe-mouse-bindings
+;;;
+;;; Options:
+;;;   extra-click-wait, scrollbar-width
+;;;
+
+(defvar extra-click-wait 150
+  "*Number of milliseconds to wait for an extra click.
+Set this to zero if you don't want chords or double clicks.")
+
+(defvar scrollbar-width 5
+  "*The character width of the scrollbar.
+The cursor is deemed to be in the right edge scrollbar if it is this near the
+right edge, and more than two chars past the end of the indicated line.
+Setting to nil limits the scrollbar to the edge or vertical dividing bar.")
+
+;;;
+;;; Mousemaps
+;;;
+(defun make-mousemap ()
+  "Returns a new mousemap."
+  (cons 'mousemap nil))
+
+(defun copy-mousemap (mousemap)
+  "Return a copy of mousemap."
+  (copy-alist mousemap))
+
+(defun define-mouse (mousemap mouse-list def)
+  "Args MOUSEMAP, MOUSE-LIST, DEF.  Define MOUSE-LIST in MOUSEMAP as DEF.
+MOUSE-LIST is a list of atoms specifing a mouse hit according to these rules:
+  * One of these atoms specifies the active region of the definition.
+	text, scrollbar, modeline, minibuffer
+  * One or two or these atoms specify the button or button combination.
+        left, middle, right, double
+  * Any combination of these atoms specify the active shift keys.
+        control, shift, meta
+  * With a single unshifted button, you can add
+	up
+    to indicate an up-click.
+The atom `double' is used with a button designator to denote a double click.
+Two button chords are denoted by listing the two buttons.
+See sun-mouse-handler for the treatment of the form DEF."
+  (mousemap-set (mouse-list-to-mouse-code mouse-list) mousemap def))
+
+(defun global-set-mouse (mouse-list def)
+  "Give MOUSE-EVENT-LIST a local definition of DEF.
+See define-mouse for a description of MOUSE-EVENT-LIST and DEF.
+Note that if MOUSE-EVENT-LIST has a local definition in the current buffer,
+that local definition will continue to shadow any global definition."
+  (interactive "xMouse event: \nxDefinition: ")
+  (define-mouse current-global-mousemap mouse-list def))
+
+(defun local-set-mouse (mouse-list def)
+  "Give MOUSE-EVENT-LIST a local definition of DEF.
+See define-mouse for a description of the arguments.
+The definition goes in the current buffer's local mousemap.
+Normally buffers in the same major mode share a local mousemap."
+  (interactive "xMouse event: \nxDefinition: ")
+  (if (null current-local-mousemap)
+      (setq current-local-mousemap (make-mousemap)))
+  (define-mouse current-local-mousemap mouse-list def))
+
+(defun use-global-mousemap (mousemap)
+  "Selects MOUSEMAP as the global mousemap."
+  (setq current-global-mousemap mousemap))
+
+(defun use-local-mousemap (mousemap)
+  "Selects MOUSEMAP as the local mousemap.
+nil for MOUSEMAP means no local mousemap."
+  (setq current-local-mousemap mousemap))
+
+
+;;;
+;;; Interface to the Mouse encoding defined in Emacstool.c
+;;;
+;;; Called when mouse-prefix is sent to emacs, additional
+;;; information is read in as a list (button x y time-delta)
+;;;
+;;; First, some generally useful functions:
+;;;
+
+(defun logtest (x y)
+  "True if any bits set in X are also set in Y.
+Just like the Common Lisp function of the same name."
+  (not (zerop (logand x y))))
+
+
+;;;
+;;; Hit accessors.
+;;;
+
+(defconst sm::ButtonBits 7)		; Lowest 3 bits.
+(defconst sm::ShiftmaskBits 56)		; Second lowest 3 bits (56 = 63 - 7).
+(defconst sm::DoubleBits 64)		; Bit 7.
+(defconst sm::UpBits 128)		; Bit 8.
+
+;;; All the useful code bits
+(defmacro sm::hit-code (hit)
+  (` (nth 0 (, hit))))
+;;; The button, or buttons if a chord.
+(defmacro sm::hit-button (hit)
+  (` (logand sm::ButtonBits (nth 0 (, hit)))))
+;;; The shift, control, and meta flags.
+(defmacro sm::hit-shiftmask (hit)
+  (` (logand sm::ShiftmaskBits (nth 0 (, hit)))))
+;;; Set if a double click (but not a chord).
+(defmacro sm::hit-double (hit)
+  (` (logand sm::DoubleBits (nth 0 (, hit)))))
+;;; Set on button release (as opposed to button press).
+(defmacro sm::hit-up (hit)
+  (` (logand sm::UpBits (nth 0 (, hit)))))
+;;; Screen x position.
+(defmacro sm::hit-x (hit) (list 'nth 1 hit))
+;;; Screen y position.
+(defmacro sm::hit-y (hit) (list 'nth 2 hit))
+;;; Millisconds since last hit.
+(defmacro sm::hit-delta (hit) (list 'nth 3 hit))
+
+(defmacro sm::hit-up-p (hit)		; A predicate.
+  (` (not (zerop (sm::hit-up (, hit))))))
+
+;;;
+;;; Loc accessors.  for sm::window-xy
+;;;
+(defmacro sm::loc-w (loc) (list 'nth 0 loc))
+(defmacro sm::loc-x (loc) (list 'nth 1 loc))
+(defmacro sm::loc-y (loc) (list 'nth 2 loc))
+
+(defmacro eval-in-buffer (buffer &rest forms)
+  "Macro to switches to BUFFER, evaluates FORMS, returns to original buffer."
+  ;; When you don't need the complete window context of eval-in-window
+  (` (let ((StartBuffer (current-buffer)))
+    (unwind-protect
+	(progn
+	  (set-buffer (, buffer))
+	  (,@ forms))
+    (set-buffer StartBuffer)))))
+
+(put 'eval-in-buffer 'lisp-indent-function 1)
+
+;;; this is used extensively by sun-fns.el
+;;;
+(defmacro eval-in-window (window &rest forms)
+  "Switch to WINDOW, evaluate FORMS, return to original window."
+  (` (let ((OriginallySelectedWindow (selected-window)))
+       (unwind-protect
+	   (progn
+	     (select-window (, window))
+	     (,@ forms))
+	 (select-window OriginallySelectedWindow)))))
+(put 'eval-in-window 'lisp-indent-function 1)
+
+;;;
+;;; handy utility, generalizes window_loop
+;;;
+
+;;; It's a macro (and does not evaluate its arguments).
+(defmacro eval-in-windows (form &optional yesmini)
+  "Switches to each window and evaluates FORM.  Optional argument
+YESMINI says to include the minibuffer as a window.
+This is a macro, and does not evaluate its arguments."
+  (` (let ((OriginallySelectedWindow (selected-window)))
+       (unwind-protect 
+	   (while (progn
+		    (, form)
+		    (not (eq OriginallySelectedWindow
+			     (select-window
+			      (next-window nil (, yesmini)))))))
+	 (select-window OriginallySelectedWindow)))))
+(put 'eval-in-window 'lisp-indent-function 0)
+
+(defun move-to-loc (x y)
+  "Move cursor to window location X, Y.
+Handles wrapped and horizontally scrolled lines correctly."
+  (move-to-window-line y)
+  ;; window-line-end expects this to return the window column it moved to.
+  (let ((cc (current-column))
+	(nc (move-to-column
+	     (if (zerop (window-hscroll))
+		 (+ (current-column)
+		    (min (- (window-width) 2)	; To stay on the line.
+			 x))
+	       (+ (window-hscroll) -1
+		  (min (1- (window-width))	; To stay on the line.
+		       x))))))
+    (- nc cc)))
+
+
+(defun minibuffer-window-p (window)
+  "True iff this WINDOW is minibuffer."
+  (= (screen-height)
+     (nth 3 (window-edges window))	; The bottom edge.
+     ))
+
+
+(defun sun-mouse-handler (&optional hit)
+  "Evaluates the function or list associated with a mouse hit.
+Expecting to read a hit, which is a list: (button x y delta).  
+A form bound to button by define-mouse is found by mouse-lookup. 
+The variables: *mouse-window*, *mouse-x*, *mouse-y* are bound.  
+If the form is a symbol (symbolp), it is funcall'ed with *mouse-window*,
+*mouse-x*, and *mouse-y* as arguments; if the form is a list (listp),
+the form is eval'ed; if the form is neither of these, it is an error.
+Returns nil."
+  (interactive)
+  (if (null hit) (setq hit (sm::combined-hits)))
+  (let ((loc (sm::window-xy (sm::hit-x hit) (sm::hit-y hit))))
+    (let ((*mouse-window* (sm::loc-w loc))
+	  (*mouse-x* (sm::loc-x loc))
+	  (*mouse-y* (sm::loc-y loc))
+	  (mouse-code (mouse-event-code hit loc)))
+      (let ((form (eval-in-buffer (window-buffer *mouse-window*)
+		    (mouse-lookup mouse-code))))
+	(cond ((null form)
+	       (if (not (sm::hit-up-p hit))	; undefined up hits are ok.
+		   (error "Undefined mouse event: %s" 
+			  (prin1-to-string 
+			   (mouse-code-to-mouse-list mouse-code)))))
+	      ((symbolp form)
+	       (setq this-command form)
+	       (funcall form *mouse-window* *mouse-x* *mouse-y*))
+	      ((listp form)
+	       (setq this-command (car form))
+	       (eval form))
+	      (t
+	       (error "Mouse action must be symbol or list, but was: %s"
+		      form))))))
+  ;; Don't let 'sun-mouse-handler get on last-command,
+  ;; since this function should be transparent.
+  (if (eq this-command 'sun-mouse-handler)
+      (setq this-command last-command))
+  ;; (message (prin1-to-string this-command))	; to see what your buttons did
+  nil)
+
+(defun sm::combined-hits ()
+  "Read and return next mouse-hit, include possible double click"
+  (let ((hit1 (mouse-hit-read)))
+    (if (not (sm::hit-up-p hit1))	; Up hits dont start doubles or chords.
+	(let ((hit2 (mouse-second-hit extra-click-wait)))
+	  (if hit2	; we cons'd it, we can smash it.
+	      ; (setf (sm::hit-code hit1) (logior (sm::hit-code hit1) ...))
+	      (setcar hit1 (logior (sm::hit-code hit1) 
+				   (sm::hit-code hit2)
+				   (if (= (sm::hit-button hit1) 
+					  (sm::hit-button hit2))
+				       sm::DoubleBits 0))))))
+    hit1))
+
+(defun mouse-hit-read ()
+  "Read mouse-hit list from keyboard.  Like (read 'read-char),
+but that uses minibuffer, and mucks up last-command."
+  (let ((char-list nil) (char nil))
+    (while (not (equal 13		; Carriage return.
+		       (prog1 (setq char (read-char)) 
+			 (setq char-list (cons char char-list))))))
+    (read (mapconcat 'char-to-string (nreverse char-list) ""))
+    ))
+
+;;; Second Click Hackery....
+;;; if prefix is not mouse-prefix, need a way to unread the char...
+;;; or else have mouse flush input queue, or else need a peek at next char.
+
+;;; There is no peek, but since one character can be unread, we only
+;;; have to flush the queue when the command after a mouse click
+;;; starts with mouse-prefix1 (see below).
+;;;   Something to do later:  We could buffer the read commands and
+;;; execute them ourselves after doing the mouse command (using
+;;; lookup-key ??).
+
+(defvar mouse-prefix1 24		; C-x
+  "First char of mouse-prefix.  Used to detect double clicks and chords.")
+
+(defvar mouse-prefix2 0			; C-@
+  "Second char of mouse-prefix.  Used to detect double clicks and chords.")
+
+
+(defun mouse-second-hit (hit-wait)
+  "Returns the next mouse hit occurring within HIT-WAIT milliseconds."
+  (if (sit-for-millisecs hit-wait) nil	; No input within hit-wait millisecs.
+    (let ((pc1 (read-char)))
+      (if (or (not (equal pc1 mouse-prefix1))
+	      (sit-for-millisecs 3))	; a mouse prefix will have second char
+	  (progn (setq unread-command-char pc1)	; Can get away with one unread.
+		 nil)			; Next input not mouse event.
+	(let ((pc2 (read-char)))
+	  (if (not (equal pc2 mouse-prefix2))
+	      (progn (setq unread-command-char pc1) ; put back the ^X
+;;; Too bad can't do two: (setq unread-command-char (list pc1 pc2))
+		(ding)			; user will have to retype that pc2.
+		nil)			; This input is not a mouse event.
+	    ;; Next input has mouse prefix and is within time limit.
+	    (let ((new-hit (mouse-hit-read))) ; Read the new hit.
+		(if (sm::hit-up-p new-hit)	; Ignore up events when timing.
+		    (mouse-second-hit (- hit-wait (sm::hit-delta new-hit)))
+		  new-hit		; New down hit within limit, return it.
+		  ))))))))
+
+(defun sm::window-xy (x y)
+  "Find window containing screen coordinates X and Y.
+Returns list (window x y) where x and y are relative to window."
+  (or
+   (catch 'found
+     (eval-in-windows 
+      (let ((we (window-edges (selected-window))))
+	(let ((le (nth 0 we))
+	      (te (nth 1 we))
+	      (re (nth 2 we))
+	      (be (nth 3 we)))
+	  (if (= re (screen-width))
+	      ;; include the continuation column with this window
+	      (setq re (1+ re)))
+	  (if (= be (screen-height))
+	      ;; include partial line at bottom of screen with this window
+	      ;; id est, if window is not multple of char size.
+	      (setq be (1+ be)))
+
+	  (if (and (>= x le) (< x re)
+		   (>= y te) (< y be))
+	      (throw 'found 
+		     (list (selected-window) (- x le) (- y te))))))
+      t))				; include minibuffer in eval-in-windows
+   ;;If x,y from a real mouse click, we shouldn't get here.
+   (list nil x y)
+   ))
+
+(defun sm::window-region (loc)
+  "Parse LOC into a region symbol.
+Returns one of (text scrollbar modeline minibuffer)"
+  (let ((w (sm::loc-w loc))
+	(x (sm::loc-x loc))
+	(y (sm::loc-y loc)))
+    (let ((right (1- (window-width w)))
+	  (bottom (1- (window-height w))))
+      (cond ((minibuffer-window-p w) 'minibuffer)
+	    ((>= y bottom) 'modeline)
+	    ((>= x right) 'scrollbar)
+	    ;; far right column (window seperator) is always a scrollbar
+	    ((and scrollbar-width
+		  ;; mouse within scrollbar-width of edge.
+		  (>= x (- right scrollbar-width))
+		  ;; mouse a few chars past the end of line.
+		  (>= x (+ 2 (window-line-end w x y))))
+	     'scrollbar)
+	    (t 'text)))))
+
+(defun window-line-end (w x y)
+  "Return WINDOW column (ignore X) containing end of line Y"
+  (eval-in-window w (save-excursion (move-to-loc (screen-width) y))))
+
+;;;
+;;; The encoding of mouse events into a mousemap.
+;;; These values must agree with coding in emacstool:
+;;;
+(defconst sm::keyword-alist 
+  '((left . 1) (middle . 2) (right . 4)
+    (shift . 8) (control . 16) (meta . 32) (double . 64) (up . 128)
+    (text . 256) (scrollbar . 512) (modeline . 1024) (minibuffer . 2048)
+    ))
+
+(defun mouse-event-code (hit loc)
+  "Maps MOUSE-HIT and LOC into a mouse-code."
+;;;Region is a code for one of text, modeline, scrollbar, or minibuffer.
+  (logior (sm::hit-code hit)
+	  (mouse-region-to-code (sm::window-region loc))))
+
+(defun mouse-region-to-code (region)
+  "Returns partial mouse-code for specified REGION."
+  (cdr (assq region sm::keyword-alist)))
+
+(defun mouse-list-to-mouse-code (mouse-list)
+  "Map a MOUSE-LIST to a mouse-code."
+  (apply 'logior
+	 (mapcar (function (lambda (x)
+			     (cdr (assq x sm::keyword-alist))))
+		  mouse-list)))
+
+(defun mouse-code-to-mouse-list (mouse-code)
+  "Map a MOUSE-CODE to a mouse-list."
+  (apply 'nconc (mapcar
+		 (function (lambda (x)
+			     (if (logtest mouse-code (cdr x))
+				 (list (car x)))))
+		 sm::keyword-alist)))
+
+(defun mousemap-set (code mousemap value)
+  (let* ((alist (cdr mousemap))
+	 (assq-result (assq code alist)))
+    (if assq-result
+	(setcdr assq-result value)
+      (setcdr mousemap (cons (cons code value) alist)))))
+
+(defun mousemap-get (code mousemap)
+  (cdr (assq code (cdr mousemap))))
+
+(defun mouse-lookup (mouse-code)
+  "Look up MOUSE-EVENT and return the definition. nil means undefined."
+  (or (mousemap-get mouse-code current-local-mousemap)
+      (mousemap-get mouse-code current-global-mousemap)))
+
+;;;
+;;; I (jpeck) don't understand the utility of the next four functions
+;;; ask Steven Greenbaum <froud@kestrel>
+;;;
+(defun mouse-mask-lookup (mask list)
+  "Args MASK (a bit mask) and LIST (a list of (code . form) pairs).
+Returns a list of elements of LIST whose code or'ed with MASK is non-zero."
+  (let ((result nil))
+    (while list
+      (if (logtest mask (car (car list)))
+	  (setq result (cons (car list) result)))
+      (setq list (cdr list)))
+    result))
+
+(defun mouse-union (l l-unique)
+  "Return the union of list of mouse (code . form) pairs L and L-UNIQUE,
+where L-UNIQUE is considered to be union'ized already."
+  (let ((result l-unique))
+    (while l
+      (let ((code-form-pair (car l)))
+	(if (not (assq (car code-form-pair) result))
+	    (setq result (cons code-form-pair result))))
+      (setq l (cdr l)))
+    result))
+
+(defun mouse-union-first-prefered (l1 l2)
+  "Return the union of lists of mouse (code . form) pairs L1 and L2,
+based on the code's, with preference going to elements in L1."
+  (mouse-union l2 (mouse-union l1 nil)))
+
+(defun mouse-code-function-pairs-of-region (region)
+  "Return a list of (code . function) pairs, where each code is
+currently set in the REGION."
+  (let ((mask (mouse-region-to-code region)))
+    (mouse-union-first-prefered
+     (mouse-mask-lookup mask (cdr current-local-mousemap))
+     (mouse-mask-lookup mask (cdr current-global-mousemap))
+     )))
+
+;;;
+;;; Functions for DESCRIBE-MOUSE-BINDINGS
+;;; And other mouse documentation functions
+;;; Still need a good procedure to print out a help sheet in readable format.
+;;;
+
+(defun one-line-doc-string (function)
+  "Returns first line of documentation string for FUNCTION.
+If there is no documentation string, then the string
+\"No documentation\" is returned."
+  (while (consp function) (setq function (car function)))
+  (let ((doc (documentation function)))
+    (if (null doc)
+	"No documentation."
+      (string-match "^.*$" doc)
+      (substring doc 0 (match-end 0)))))
+
+(defun print-mouse-format (binding)
+  (princ (car binding))
+  (princ ": ")
+  (mapcar (function
+	   (lambda (mouse-list)
+	     (princ mouse-list)
+	     (princ " ")))
+	  (cdr binding))
+  (terpri)
+  (princ "  ")
+  (princ (one-line-doc-string (car binding)))
+  (terpri)
+  )
+
+(defun print-mouse-bindings (region)
+  "Prints mouse-event bindings for REGION."
+  (mapcar 'print-mouse-format (sm::event-bindings region)))
+
+(defun sm::event-bindings (region)
+  "Returns an alist of (function . (mouse-list1 ... mouse-listN)) for REGION,
+where each mouse-list is bound to the function in REGION."
+  (let ((mouse-bindings (mouse-code-function-pairs-of-region region))
+	(result nil))
+    (while mouse-bindings
+      (let* ((code-function-pair (car mouse-bindings))
+	     (current-entry (assoc (cdr code-function-pair) result)))
+	(if current-entry
+	    (setcdr current-entry
+		    (cons (mouse-code-to-mouse-list (car code-function-pair))
+			  (cdr current-entry)))
+	  (setq result (cons (cons (cdr code-function-pair)
+				   (list (mouse-code-to-mouse-list
+					  (car code-function-pair))))
+			     result))))
+      (setq mouse-bindings (cdr mouse-bindings))
+      )
+    result))
+
+(defun describe-mouse-bindings ()
+  "Lists all current mouse-event bindings."
+  (interactive)
+  (with-output-to-temp-buffer "*Help*"
+    (princ "Text Region") (terpri)
+    (princ "---- ------") (terpri)
+    (print-mouse-bindings 'text) (terpri)
+    (princ "Modeline Region") (terpri)
+    (princ "-------- ------") (terpri)
+    (print-mouse-bindings 'modeline) (terpri)
+    (princ "Scrollbar Region") (terpri)
+    (princ "--------- ------") (terpri)
+    (print-mouse-bindings 'scrollbar)))
+
+(defun describe-mouse-briefly (mouse-list)
+  "Print a short description of the function bound to MOUSE-LIST."
+  (interactive "xDescibe mouse list briefly: ")
+  (let ((function (mouse-lookup (mouse-list-to-mouse-code mouse-list))))
+    (if function
+	(message "%s runs the command %s" mouse-list function)
+      (message "%s is undefined" mouse-list))))
+
+(defun mouse-help-menu (function-and-binding)
+  (cons (prin1-to-string (car function-and-binding))
+	(menu-create	; Two sub-menu items of form ("String" . nil)
+	 (list (list (one-line-doc-string (car function-and-binding)))
+	       (list (prin1-to-string (cdr function-and-binding)))))))
+
+(defun mouse-help-region (w x y &optional region)
+  "Displays a menu of mouse functions callable in this region."
+  (let* ((region (or region (sm::window-region (list w x y))))
+	 (mlist (mapcar (function mouse-help-menu)
+			(sm::event-bindings region)))
+	 (menu (menu-create (cons (list (symbol-name region)) mlist)))
+	 (item (sun-menu-evaluate w 0 y menu))
+	 )))
+
+;;;
+;;; Menu interface functions
+;;;
+;;; use defmenu, because this interface is subject to change
+;;; really need a menu-p, but we use vectorp and the context...
+;;;
+(defun menu-create (items)
+  "Functional form for defmenu, given a list of ITEMS returns a menu.
+Each ITEM is a (STRING . VALUE) pair."
+  (apply 'vector items)
+  )
+
+(defmacro defmenu (menu &rest itemlist)
+  "Defines MENU to be a menu, the ITEMS are (STRING . VALUE) pairs.
+See sun-menu-evaluate for interpretation of ITEMS."
+  (list 'defconst menu (funcall 'menu-create itemlist))
+  )
+
+(defun sun-menu-evaluate (*menu-window* *menu-x* *menu-y* menu)
+  "Display a pop-up menu in WINDOW at X Y and evaluate selected item
+of MENU.  MENU (or its symbol-value) should be a menu defined by defmenu.
+  A menu ITEM is a (STRING . FORM) pair;
+the FORM associated with the selected STRING is evaluated,
+and the resulting value is returned.  Generally these FORMs are
+evaluated for their side-effects rather than their values.
+  If the selected form is a menu or a symbol whose value is a menu, 
+then it is displayed and evaluated as a pullright menu item.
+  If the the FORM of the first ITEM is nil, the STRING of the item
+is used as a label for the menu, i.e. it's inverted and not selectible."
+
+  (if (symbolp menu) (setq menu (symbol-value menu)))
+  (eval (sun-menu-internal *menu-window* *menu-x* *menu-y* 4 menu)))
+
+(defun sun-get-frame-data (code)
+  "Sends the tty-sub-window escape sequence CODE to terminal,
+and returns a cons of the two numbers in returned escape sequence.
+That is it returns (cons <car> <cdr>) from \"\\E[n;<car>;<cdr>t\". 
+CODE values: 13 = Tool-Position, 14 = Size-in-Pixels, 18 = Size-in-Chars."
+  (send-string-to-terminal (concat "\033[" (int-to-string code) "t"))
+  (let (char str x y)
+    (while (not (equal 116 (setq char (read-char)))) ; #\t = 116
+      (setq str (cons char str)))
+    (setq str (mapconcat 'char-to-string (nreverse str) ""))
+    (string-match ";[0-9]*" str)
+    (setq y (substring str (1+ (match-beginning 0)) (match-end 0)))
+    (setq str (substring str (match-end 0)))
+    (string-match ";[0-9]*" str)
+    (setq x (substring str (1+ (match-beginning 0)) (match-end 0)))
+    (cons (string-to-int y) (string-to-int x))))
+
+(defun sm::font-size ()
+  "Returns font size in pixels: (cons Ysize Xsize)"
+  (let ((pix (sun-get-frame-data 14))	; returns size in pixels
+	(chr (sun-get-frame-data 18)))	; returns size in chars
+    (cons (/ (car pix) (car chr)) (/ (cdr pix) (cdr chr)))))
+
+(defvar sm::menu-kludge-x nil 
+  "Cached frame-to-window X-Offset for sm::menu-kludge")
+(defvar sm::menu-kludge-y nil 
+  "Cached frame-to-window Y-Offset for sm::menu-kludge")
+
+(defun sm::menu-kludge ()
+  "If sunfns.c uses <Menu_Base_Kludge> this function must be here!"
+  (or sm::menu-kludge-y
+      (let ((fs (sm::font-size)))
+	(setq sm::menu-kludge-y (+ 8 (car fs))	; a title line and borders
+	      sm::menu-kludge-x 4)))	; best values depend on .defaults/Menu
+  (let ((wl (sun-get-frame-data 13)))		; returns frame location
+    (cons (+ (car wl) sm::menu-kludge-y)
+	  (+ (cdr wl) sm::menu-kludge-x))))
+
+;;;
+;;;  Function interface to selection/region
+;;;  primative functions are defined in sunfns.c
+;;;
+(defun sun-yank-selection ()
+  "Set mark and yank the contents of the current sunwindows selection
+into the current buffer at point."
+  (interactive "*")
+  (set-mark-command nil)
+  (insert-string (sun-get-selection)))
+
+(defun sun-select-region (beg end)
+  "Set the sunwindows selection to the region in the current buffer."
+  (interactive "r")
+  (sun-set-selection (buffer-substring beg end)))
+
+;;;
+;;; Support for emacstool
+;;; This closes the window instead of stopping emacs.
+;;;
+(defun suspend-emacstool (&optional stuffstring)
+  "If running under as a detached process emacstool,
+you don't want to suspend  (there is no way to resume), 
+just close the window, and wait for reopening."
+  (interactive)
+  (run-hooks 'suspend-hook)
+  (if stuffstring (send-string-to-terminal stuffstring))
+  (send-string-to-terminal "\033[2t")	; To close EmacsTool window.
+  (run-hooks 'suspend-resume-hook))
+;;;
+;;; initialize mouse maps
+;;;
+
+(make-variable-buffer-local 'current-local-mousemap)
+(setq-default current-local-mousemap nil)
+(defvar current-global-mousemap (make-mousemap))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/term/sup-mouse.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,207 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;									     ;;
+;;	File:     sup-mouse.el						     ;;
+;;	Author:   Wolfgang Rupprecht					     ;;
+;;	Created:  Fri Nov 21 19:22:22 1986				     ;;
+;;	Contents: supdup mouse support for lisp machines		     ;;
+;;									     ;;
+;;     (from code originally written by John Robinson@bbn for the bitgraph)  ;;
+;;									     ;;
+;;	$Log$								     ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; GNU Emacs code for lambda/supdup mouse
+;; Copyright (C) Free Software Foundation 1985, 1986
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;;  User customization option:
+
+(defvar sup-mouse-fast-select-window nil
+  "*Non-nil for mouse hits to select new window, then execute; else just select.")
+
+(defconst mouse-left 0)
+(defconst mouse-center 1)
+(defconst mouse-right 2)
+
+(defconst mouse-2left 4)
+(defconst mouse-2center 5)
+(defconst mouse-2right 6)
+
+(defconst mouse-3left 8)
+(defconst mouse-3center 9)
+(defconst mouse-3right 10)
+
+;;;  Defuns:
+
+(defun sup-mouse-report ()
+  "This function is called directly by the mouse, it parses and
+executes the mouse commands.
+
+ L move point          *  |---- These apply for mouse click in a window.
+2L delete word            |
+3L copy word		  | If sup-mouse-fast-select-window is nil,
+ C move point and yank *  | just selects that window.
+2C yank pop		  |
+ R set mark            *  |
+2R delete region	  |
+3R copy region		  |
+
+on modeline		    on \"scroll bar\"	in minibuffer
+ L scroll-up		    line to top		execute-extended-command
+ C proportional goto-char   line to middle	mouse-help
+ R scroll-down		    line to bottom	eval-expression"
+  
+  (interactive)
+  (let*
+;; expect a string of <esc>:<buttons>;<x-pos>;<y-pos>c
+      ((buttons (sup-get-tty-num ?\;))
+       (x (sup-get-tty-num ?\;))
+       (y (sup-get-tty-num ?c))
+       (window (sup-pos-to-window x y))
+       (edges (window-edges window))
+       (old-window (selected-window))
+       (in-minibuf-p (eq y (1- (screen-height))))
+       (same-window-p (and (not in-minibuf-p) (eq window old-window)))
+       (in-modeline-p (eq y (1- (nth 3 edges))))
+       (in-scrollbar-p (>= x (1- (nth 2 edges)))))
+    (setq x (- x (nth 0 edges)))
+    (setq y (- y (nth 1 edges)))
+
+;    (error "mouse-hit %d %d %d" buttons x y) ;;;; debug
+
+    (cond (in-modeline-p
+	   (select-window window)
+	   (cond ((= buttons mouse-left)
+		  (scroll-up))
+		 ((= buttons mouse-right)
+		  (scroll-down))
+		 ((= buttons mouse-center)
+		  (goto-char (/ (* x
+				   (- (point-max) (point-min)))
+				(1- (window-width))))
+		  (beginning-of-line)
+		  (what-cursor-position)))
+	   (select-window old-window))
+	  (in-scrollbar-p
+	   (select-window window)
+	   (scroll-up
+	    (cond ((= buttons mouse-left)
+		   y)
+		  ((= buttons mouse-right)
+		   (+ y (- 2 (window-height))))
+		  ((= buttons mouse-center)
+		   (/ (+ 2 y y (- (window-height))) 2))
+		  (t
+		   0)))
+	   (select-window old-window))
+	  (same-window-p
+	   (cond ((= buttons mouse-left)
+		  (sup-move-point-to-x-y x y))
+		 ((= buttons mouse-2left)
+		  (sup-move-point-to-x-y x y)
+		  (kill-word 1))
+		 ((= buttons mouse-3left)
+		  (sup-move-point-to-x-y x y)
+		  (save-excursion
+		    (copy-region-as-kill
+		     (point) (progn (forward-word 1) (point))))
+		  (setq this-command 'yank)
+		  )
+		 ((= buttons mouse-right)
+		  (push-mark)
+		  (sup-move-point-to-x-y x y)
+		  (exchange-point-and-mark))
+		 ((= buttons mouse-2right)
+		  (push-mark)
+		  (sup-move-point-to-x-y x y)
+		  (kill-region (mark) (point)))
+		 ((= buttons mouse-3right)
+		  (push-mark)
+		  (sup-move-point-to-x-y x y)
+		  (copy-region-as-kill (mark) (point))
+		  (setq this-command 'yank))
+		 ((= buttons mouse-center)
+		  (sup-move-point-to-x-y x y)
+		  (setq this-command 'yank)
+		  (yank))
+		 ((= buttons mouse-2center)
+		  (yank-pop 1))
+		 )
+	   )
+	  (in-minibuf-p
+	   (cond ((= buttons mouse-right)
+		  (call-interactively 'eval-expression))
+		 ((= buttons mouse-left)
+		  (call-interactively 'execute-extended-command))
+		 ((= buttons mouse-center)
+		  (describe-function 'sup-mouse-report)); silly self help 
+		 ))
+	  (t				;in another window
+	   (select-window window)
+	   (cond ((not sup-mouse-fast-select-window))
+		 ((= buttons mouse-left)
+		  (sup-move-point-to-x-y x y))
+		 ((= buttons mouse-right)
+		  (push-mark)
+		  (sup-move-point-to-x-y x y)
+		  (exchange-point-and-mark))
+		 ((= buttons mouse-center)
+		  (sup-move-point-to-x-y x y)
+		  (setq this-command 'yank)
+		  (yank))
+		 ))
+	  )))
+
+
+(defun sup-get-tty-num (term-char)
+  "Read from terminal until TERM-CHAR is read, and return intervening number.
+Upon non-numeric not matching TERM-CHAR signal an error."
+  (let
+      ((num 0)
+       (char (read-char)))
+    (while (and (>= char ?0)
+		(<= char ?9))
+      (setq num (+ (* num 10) (- char ?0)))
+      (setq char (read-char)))
+    (or (eq term-char char)
+	(error "Invalid data format in mouse command"))
+    num))
+
+(defun sup-move-point-to-x-y (x y)
+  "Position cursor in window coordinates.
+X and Y are 0-based character positions in the window."
+  (move-to-window-line y)
+  (move-to-column x)
+  )
+
+(defun sup-pos-to-window (x y)
+  "Find window corresponding to screen coordinates.
+X and Y are 0-based character positions on the screen."
+  (let ((edges (window-edges))
+	(window nil))
+    (while (and (not (eq window (selected-window)))
+		(or (<  y (nth 1 edges))
+		    (>= y (nth 3 edges))
+		    (<  x (nth 0 edges))
+		    (>= x (nth 2 edges))))
+      (setq window (next-window window))
+      (setq edges (window-edges window))
+      )
+    (or window (selected-window))
+    )
+  )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/vmsproc.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,138 @@
+;; Run asynchronous VMS subprocesses under Emacs
+;; Copyright (C) 1986 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;; Written by Mukesh Prasad.
+
+(defvar display-subprocess-window nil
+  "If non-nil, the suprocess window is displayed whenever input is received.")
+
+(defvar command-prefix-string "$ "
+  "String to insert to distinguish commands entered by user.")
+
+(defvar subprocess-running nil)
+(defvar command-mode-map nil)
+
+(if command-mode-map
+    nil
+  (setq command-mode-map (make-sparse-keymap))
+  (define-key command-mode-map "\C-m" 'command-send-input)
+  (define-key command-mode-map "\C-u" 'command-kill-line))
+
+(defun subprocess-input (name str)
+  "Handles input from a subprocess.  Called by Emacs."
+  (if display-subprocess-window
+      (display-buffer subprocess-buf))
+  (let ((old-buffer (current-buffer)))
+    (set-buffer subprocess-buf)
+    (goto-char (point-max))
+    (insert str)
+    (insert ?\n)
+    (set-buffer old-buffer)))
+
+(defun subprocess-exit (name)
+  "Called by Emacs upon subprocess exit."
+  (setq subprocess-running nil))
+
+(defun start-subprocess ()
+  "Spawns an asynchronous subprocess with output redirected to
+the buffer *COMMAND*.  Within this buffer, use C-m to send
+the last line to the subprocess or to bring another line to
+the end."
+  (if subprocess-running
+      (return t))
+  (setq subprocess-buf (get-buffer-create "*COMMAND*"))
+  (save-excursion
+    (set-buffer subprocess-buf)
+    (use-local-map command-mode-map))
+  (setq subprocess-running (spawn-subprocess 1 'subprocess-input
+					     'subprocess-exit))
+  ;; Initialize subprocess so it doesn't panic and die upon
+  ;; encountering the first error.
+  (and subprocess-running
+       (send-command-to-subprocess 1 "ON SEVERE_ERROR THEN CONTINUE")))
+
+(defun subprocess-command-to-buffer (command buffer)
+  "Execute COMMAND and redirect output into BUFFER."
+  (let (cmd args)
+    (setq cmd (substring command 0 (string-match " " command)))
+    (setq args (substring command (string-match " " command)))
+    (call-process cmd nil buffer nil "*dcl*" args)))
+;BUGS: only the output up to the end of the first image activation is trapped.
+;  (if (not subprocess-running)
+;      (start-subprocess))
+;  (save-excursion
+;    (set-buffer buffer)
+;    (let ((output-filename (concat "SYS$SCRATCH:OUTPUT-FOR-"
+;				   (getenv "USER") ".LISTING")))
+;      (while (file-exists-p output-filename)
+;	(delete-file output-filename))
+;      (define-logical-name "SYS$OUTPUT" (concat output-filename "-NEW"))
+;      (send-command-to-subprocess 1 command)
+;      (send-command-to-subprocess 1 (concat
+;				     "RENAME " output-filename
+;				     "-NEW " output-filename))
+;      (while (not (file-exists-p output-filename))
+;	(sleep-for 1))
+;      (define-logical-name "SYS$OUTPUT" nil)
+;      (insert-file output-filename)
+;      (delete-file output-filename))))
+
+(defun subprocess-command ()
+  "Starts asynchronous subprocess if not running and switches to its window."
+  (interactive)
+  (if (not subprocess-running)
+      (start-subprocess))
+  (and subprocess-running
+       (progn (pop-to-buffer subprocess-buf) (goto-char (point-max)))))
+
+(defun command-send-input ()
+  "If at last line of buffer, sends the current line to
+the spawned subprocess.  Otherwise brings back current
+line to the last line for resubmission."
+  (interactive)
+  (beginning-of-line)
+  (let ((current-line (buffer-substring (point)
+                                        (progn (end-of-line) (point)))))
+    (if (eobp)
+	(progn
+	  (if (not subprocess-running)
+	      (start-subprocess))
+	  (if subprocess-running
+	      (progn
+		(beginning-of-line)
+		(send-command-to-subprocess 1 current-line)
+		(if command-prefix-string
+		    (progn (beginning-of-line) (insert command-prefix-string)))
+		(next-line 1))))
+      ;; else -- if not at last line in buffer
+      (end-of-buffer)
+      (backward-char)
+      (next-line 1)
+      (if (string-equal command-prefix-string
+			(substring current-line 0 (length command-prefix-string)))
+	  (insert (substring current-line (length command-prefix-string)))
+	(insert current-line)))))
+
+(defun command-kill-line()
+  "Kills the current line.  Used in command mode."
+  (interactive)
+  (beginning-of-line)
+  (kill-line))
+
+(define-key esc-map "$" 'subprocess-command)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/x-menu.el	Tue Oct 31 15:59:53 1989 +0000
@@ -0,0 +1,145 @@
+;; Copyright (C) 1986 Free Software Foundation, Inc.
+
+;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+(defmacro caar (conscell)
+  (list 'car (list 'car conscell)))
+
+(defmacro cdar (conscell)
+  (list 'cdr (list 'car conscell)))
+
+(defun x-menu-mode ()
+  "Major mode for creating permanent menus for use with X.
+These menus are implemented entirely in Lisp; popup menus, implemented
+with x-popup-menu, are implemented using XMenu primitives."
+  (make-local-variable 'x-menu-items-per-line)
+  (make-local-variable 'x-menu-item-width)
+  (make-local-variable 'x-menu-items-alist)
+  (make-local-variable 'x-process-mouse-hook)
+  (make-local-variable 'x-menu-assoc-buffer)
+  (setq buffer-read-only t)
+  (setq truncate-lines t)
+  (setq x-process-mouse-hook 'x-menu-pick-entry)
+  (setq mode-line-buffer-identification '("MENU: %32b")))
+
+(defvar x-menu-max-width 0)
+(defvar x-menu-items-per-line 0)
+(defvar x-menu-item-width 0)
+(defvar x-menu-items-alist nil)
+(defvar x-menu-assoc-buffer nil)
+
+(defvar x-menu-item-spacing 1
+  "*Minimum horizontal spacing between objects in a permanent X menu.")
+
+(defun x-menu-create-menu (name)
+  "Create a permanent X menu.  Returns an item which should be used as a
+menu object whenever referring to the menu."
+  (let ((old (current-buffer))
+	(buf (get-buffer-create name)))
+    (set-buffer buf)
+    (x-menu-mode)
+    (setq x-menu-assoc-buffer old)
+    (set-buffer old)
+    buf))
+
+(defun x-menu-change-associated-buffer (menu buffer)
+  "Change associated buffer of MENU to BUFFER.  BUFFER should be a buffer
+object."
+  (let ((old (current-buffer)))
+    (set-buffer menu)
+    (setq x-menu-assoc-buffer buffer)
+    (set-buffer old)))
+
+(defun x-menu-add-item (menu item binding)
+  "Adds to MENU an item with name ITEM, associated with BINDING.
+Following a sequence of calls to x-menu-add-item, a call to x-menu-compute
+should be performed before the menu will be made available to the user.
+
+BINDING should be a function of one argument, which is the numerical
+button/key code as defined in x-menu.el."
+  (let ((old (current-buffer))
+	elt)
+    (set-buffer menu)
+    (if (setq elt (assoc item x-menu-items-alist))
+	(rplacd elt binding)
+      (setq x-menu-items-alist (append x-menu-items-alist
+				       (list (cons item binding)))))
+    (set-buffer old)
+    item))
+
+(defun x-menu-delete-item (menu item)
+  "Deletes from MENU the item named ITEM.  x-menu-compute should be called
+before the menu is made available to the user."
+  (let ((old (current-buffer))
+	elt)
+    (set-buffer menu)
+    (if (setq elt (assoc item x-menu-items-alist))
+	(rplaca elt nil))
+    (set-buffer old)
+    item))
+
+(defun x-menu-activate (menu)
+  "Computes all necessary parameters for MENU.  This must be called whenever
+a menu is modified before it is made available to the user.
+
+This also creates the menu itself."
+  (let ((buf (current-buffer)))
+    (pop-to-buffer menu)
+    (let (buffer-read-only)
+      (setq x-menu-max-width (1- (screen-width)))
+      (setq x-menu-item-width 0)
+      (let (items-head
+	    (items-tail x-menu-items-alist))
+	(while items-tail
+	  (if (caar items-tail)
+	      (progn (setq items-head (cons (car items-tail) items-head))
+		     (setq x-menu-item-width
+			   (max x-menu-item-width
+				(length (caar items-tail))))))
+	  (setq items-tail (cdr items-tail)))
+	(setq x-menu-items-alist (reverse items-head)))
+      (setq x-menu-item-width (+ x-menu-item-spacing x-menu-item-width))
+      (setq x-menu-items-per-line
+	    (max 1 (/ x-menu-max-width x-menu-item-width)))
+      (erase-buffer)
+      (let ((items-head x-menu-items-alist))
+	(while items-head
+	  (let ((items 0))
+	    (while (and items-head
+			(<= (setq items (1+ items)) x-menu-items-per-line))
+	      (insert (format (concat "%"
+				      (int-to-string x-menu-item-width) "s")
+			      (caar items-head)))
+	      (setq items-head (cdr items-head))))
+	  (insert ?\n)))
+      (shrink-window (max 0
+			  (- (window-height)
+			     (1+ (count-lines (point-min) (point-max))))))
+      (goto-char (point-min)))
+    (pop-to-buffer buf)))
+
+(defun x-menu-pick-entry (position event)
+  "Internal function for dispatching on mouse/menu events"
+  (let*	((x (min (1- x-menu-items-per-line)
+		 (/ (current-column) x-menu-item-width)))
+	 (y (- (count-lines (point-min) (point))
+	       (if (zerop (current-column)) 0 1)))
+	 (item (+ x (* y x-menu-items-per-line)))
+	 (litem (cdr (nth item x-menu-items-alist))))
+    (and litem (funcall litem event)))
+  (pop-to-buffer x-menu-assoc-buffer))