(scheme-mode-variables): Set comment-start-skip to ignore backslash-quoted
[bpt/emacs.git] / lisp / subr.el
index 9759799..f5087fc 100644 (file)
@@ -1,6 +1,6 @@
 ;;; subr.el --- basic lisp subroutines for Emacs
 
-;;; Copyright (C) 1985, 1986, 1992 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1992, 1994, 1995 Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
@@ -15,8 +15,9 @@
 ;; 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.
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
 
 ;;; Code:
 
 A call of the form (lambda ARGS DOCSTRING INTERACTIVE BODY) is
 self-quoting; the result of evaluating the lambda expression is the
 expression itself.  The lambda expression may then be treated as a
-function, i. e. stored as the function value of a symbol, passed to
-funcall or mapcar, etcetera.
+function, i.e., stored as the function value of a symbol, passed to
+funcall or mapcar, etc.
+
 ARGS should take the same form as an argument list for a `defun'.
-DOCSTRING should be a string, as described for `defun'.  It may be omitted.
+DOCSTRING is an optional documentation string.
+ If present, it should describe how to call the function.
+ But documentation strings are usually not useful in nameless functions.
 INTERACTIVE should be a call to the function `interactive', which see.
 It may also be omitted.
 BODY should be a list of lisp expressions."
@@ -51,39 +55,6 @@ BODY should be a list of lisp expressions."
 ;;                  'args))))
 
 \f
-;;;; Window tree functions.
-
-(defun one-window-p (&optional nomini)
-  "Returns non-nil if there is only one window.
-Optional arg NOMINI non-nil means don't count the minibuffer
-even if it is active."
-  (let ((base-window (selected-window)))
-    (if (and nomini (eq base-window (minibuffer-window)))
-       (setq base-window (next-window base-window)))
-    (eq base-window
-       (next-window base-window (if nomini 'arg)))))
-
-(defun walk-windows (proc &optional minibuf all-frames)
-  "Cycle through all visible windows, calling PROC for each one.
-PROC is called with a window as argument.
-Optional second arg MINIBUF t means count the minibuffer window
-even if not active.  If MINIBUF is neither t nor nil it means
-not to count the minibuffer even if it is active.
-
-Optional third arg ALL-FRAMES, if t, means include all frames.
-ALL-FRAMES nil or omitted means cycle within the selected frame,
-but include the minibuffer window (if MINIBUF says so) that that
-frame uses, even if it is on another frame.
-If ALL-FRAMES is neither nil nor t, stick strictly to the selected frame."
-  (let* ((walk-windows-start (selected-window))
-        (walk-windows-current walk-windows-start))
-    (while (progn
-            (setq walk-windows-current
-                  (next-window walk-windows-current minibuf all-frames))
-            (funcall proc walk-windows-current)
-            (not (eq walk-windows-current walk-windows-start))))))
-
-\f
 ;;;; Keymap support.
 
 (defun undefined ()
@@ -98,11 +69,7 @@ If ALL-FRAMES is neither nil nor t, stick strictly to the selected frame."
   "Make MAP override all normally self-inserting keys to be undefined.
 Normally, as an exception, digits and minus-sign are set to make prefix args,
 but optional second arg NODIGITS non-nil treats them like other chars."
-  (let ((i 0))
-    (while (<= i 127)
-      (if (eql (lookup-key global-map (char-to-string i)) 'self-insert-command)
-         (define-key map (char-to-string i) 'undefined))
-      (setq i (1+ i))))
+  (substitute-key-definition 'self-insert-command 'undefined map global-map)
   (or nodigits
       (let (loop)
        (define-key map "-" 'negative-argument)
@@ -121,6 +88,9 @@ but optional second arg NODIGITS non-nil treats them like other chars."
 ;      (copy-sequence keymap)
 ;      (copy-alist keymap)))
 
+(defvar key-substitution-in-progress nil
+ "Used internally by substitute-key-definition.")
+
 (defun substitute-key-definition (olddef newdef keymap &optional oldmap prefix)
   "Replace OLDDEF with NEWDEF for any keys in KEYMAP now defined as OLDDEF.
 In other words, OLDDEF is replaced with NEWDEF where ever it appears.
@@ -129,7 +99,9 @@ in KEYMAP as NEWDEF those chars which are defined as OLDDEF in OLDMAP."
   (or prefix (setq prefix ""))
   (let* ((scan (or oldmap keymap))
         (vec1 (vector nil))
-        (prefix1 (vconcat prefix vec1)))
+        (prefix1 (vconcat prefix vec1))
+        (key-substitution-in-progress
+         (cons scan key-substitution-in-progress)))
     ;; Scan OLDMAP, finding each char or event-symbol that
     ;; has any definition, and act on it with hack-key.
     (while (consp scan)
@@ -140,17 +112,32 @@ in KEYMAP as NEWDEF those chars which are defined as OLDDEF in OLDMAP."
            ;; the inside of the following let that handles array elements.
            (aset vec1 0 char)
            (aset prefix1 (length prefix) char)
-           (let (inner-def)
+           (let (inner-def skipped)
              ;; Skip past menu-prompt.
              (while (stringp (car-safe defn))
+               (setq skipped (cons (car defn) skipped))
                (setq defn (cdr defn)))
+             ;; Skip past cached key-equivalence data for menu items.
+             (and (consp defn) (consp (car defn))
+                  (setq defn (cdr defn)))
              (setq inner-def defn)
+             ;; Look past a symbol that names a keymap.
              (while (and (symbolp inner-def)
                          (fboundp inner-def))
                (setq inner-def (symbol-function inner-def)))
              (if (eq defn olddef)
-                 (define-key keymap prefix1 newdef)
-               (if (keymapp defn)
+                 (define-key keymap prefix1 (nconc (nreverse skipped) newdef))
+               (if (and (keymapp defn)
+                        ;; Avoid recursively scanning
+                        ;; where KEYMAP does not have a submap.
+                        (let ((elt (lookup-key keymap prefix1)))
+                          (or (null elt)
+                              (keymapp elt)))
+                        ;; Avoid recursively rescanning keymap being scanned.
+                        (not (memq inner-def
+                                   key-substitution-in-progress)))
+                   ;; If this one isn't being scanned already,
+                   ;; scan it now.
                    (substitute-key-definition olddef newdef keymap
                                               inner-def
                                               prefix1)))))
@@ -164,23 +151,68 @@ in KEYMAP as NEWDEF those chars which are defined as OLDDEF in OLDMAP."
                  ;; the inside of the previous let.
                  (aset vec1 0 char)
                  (aset prefix1 (length prefix) char)
-                 (let (inner-def)
+                 (let (inner-def skipped)
                    ;; Skip past menu-prompt.
                    (while (stringp (car-safe defn))
+                     (setq skipped (cons (car defn) skipped))
                      (setq defn (cdr defn)))
+                   (and (consp defn) (consp (car defn))
+                        (setq defn (cdr defn)))
                    (setq inner-def defn)
                    (while (and (symbolp inner-def)
                                (fboundp inner-def))
                      (setq inner-def (symbol-function inner-def)))
                    (if (eq defn olddef)
-                       (define-key keymap prefix1 newdef)
-                     (if (keymapp defn)
+                       (define-key keymap prefix1
+                         (nconc (nreverse skipped) newdef))
+                     (if (and (keymapp defn)
+                              (let ((elt (lookup-key keymap prefix1)))
+                                (or (null elt)
+                                    (keymapp elt)))
+                              (not (memq inner-def
+                                         key-substitution-in-progress)))
                          (substitute-key-definition olddef newdef keymap
                                                     inner-def
                                                     prefix1)))))
                (setq i (1+ i))))))
       (setq scan (cdr scan)))))
 
+(defun define-key-after (keymap key definition after)
+  "Add binding in KEYMAP for KEY => DEFINITION, right after AFTER's binding.
+This is like `define-key' except that the binding for KEY is placed
+just after the binding for the event AFTER, instead of at the beginning
+of the map.
+The order matters when the keymap is used as a menu.
+KEY must contain just one event type--that is to say, it must be
+a string or vector of length 1."
+  (or (keymapp keymap)
+      (signal 'wrong-type-argument (list 'keymapp keymap)))
+  (if (> (length key) 1)
+      (error "multi-event key specified in `define-key-after'"))
+  (let ((tail keymap) done inserted
+       (first (aref key 0)))
+    (while (and (not done) tail)
+      ;; Delete any earlier bindings for the same key.
+      (if (eq (car-safe (car (cdr tail))) first)
+         (setcdr tail (cdr (cdr tail))))
+      ;; When we reach AFTER's binding, insert the new binding after.
+      ;; If we reach an inherited keymap, insert just before that.
+      ;; If we reach the end of this keymap, insert at the end.
+      (if (or (eq (car-safe (car tail)) after)
+             (eq (car (cdr tail)) 'keymap)
+             (null (cdr tail)))
+         (progn
+           ;; Stop the scan only if we find a parent keymap.
+           ;; Keep going past the inserted element
+           ;; so we can delete any duplications that come later.
+           (if (eq (car (cdr tail)) 'keymap)
+               (setq done t))
+           ;; Don't insert more than once.
+           (or inserted
+               (setcdr tail (cons (cons (aref key 0) definition) (cdr tail))))
+           (setq inserted t)))
+      (setq tail (cdr tail)))))
+
 (defun keyboard-translate (from to)
   "Translate character FROM to TO at a low level.
 This function creates a `keyboard-translate-table' if necessary
@@ -191,7 +223,8 @@ and then modifies one entry in it."
          (> to   (length keyboard-translate-table)))
       (progn
        (let* ((i (length keyboard-translate-table))
-              (table (make-string (- 256 i) 0)))
+              (table (concat keyboard-translate-table
+                             (make-string (- 256 i) 0))))
          (while (< i 256)
            (aset table i i)
            (setq i (1+ i)))
@@ -230,12 +263,10 @@ The normal global definition of the character C-x indirects to this keymap.")
 \f
 ;;;; Event manipulation functions.
 
-;; This code exists specifically to make sure that the
-;; resulting number does not appear in the .elc file.
-;; The number is negative on most machines, but not on all!
-(defconst listify-key-sequence-1
-   (lsh 1 7))
-(setq listify-key-sequence-1 (logior (lsh 1 23) listify-key-sequence-1))
+;; The call to `read' is to ensure that the value is computed at load time
+;; and not compiled into the .elc file.  The value is negative on most
+;; machines, but not on all!
+(defconst listify-key-sequence-1 (logior 128 (read "?\\M-\\^@")))
 
 (defun listify-key-sequence (key)
   "Convert a key sequence to a list of events."
@@ -259,26 +290,27 @@ The normal global definition of the character C-x indirects to this keymap.")
 (defun event-modifiers (event)
   "Returns a list of symbols representing the modifier keys in event EVENT.
 The elements of the list may include `meta', `control',
-`shift', `hyper', `super', `alt', `click', `drag', and `down'."
+`shift', `hyper', `super', `alt', `click', `double', `triple', `drag',
+and `down'."
   (let ((type event))
     (if (listp type)
        (setq type (car type)))
     (if (symbolp type)
        (cdr (get type 'event-symbol-elements))
       (let ((list nil))
-       (or (zerop (logand type (lsh 1 23)))
+       (or (zerop (logand type ?\M-\^@))
            (setq list (cons 'meta list)))
-       (or (and (zerop (logand type (lsh 1 22)))
+       (or (and (zerop (logand type ?\C-\^@))
                 (>= (logand type 127) 32))
            (setq list (cons 'control list)))
-       (or (and (zerop (logand type (lsh 1 21)))
+       (or (and (zerop (logand type ?\S-\^@))
                 (= (logand type 255) (downcase (logand type 255))))
            (setq list (cons 'shift list)))
-       (or (zerop (logand type (lsh 1 20)))
+       (or (zerop (logand type ?\H-\^@))
            (setq list (cons 'hyper list)))
-       (or (zerop (logand type (lsh 1 19)))
+       (or (zerop (logand type ?\s-\^@))
            (setq list (cons 'super list)))
-       (or (zerop (logand type (lsh 1 18)))
+       (or (zerop (logand type ?\A-\^@))
            (setq list (cons 'alt list)))
        list))))
 
@@ -303,7 +335,7 @@ If EVENT is a mouse press or a mouse click, this returns the location
 of the event.
 If EVENT is a drag, this returns the drag's starting position.
 The return value is of the form
-   (WINDOW BUFFER-POSITION (COL . ROW) TIMESTAMP)
+   (WINDOW BUFFER-POSITION (X . Y) TIMESTAMP)
 The `posn-' functions access elements of such lists."
   (nth 1 event))
 
@@ -311,42 +343,72 @@ The `posn-' functions access elements of such lists."
   "Return the ending location of EVENT.  EVENT should be a click or drag event.
 If EVENT is a click event, this function is the same as `event-start'.
 The return value is of the form
-   (WINDOW BUFFER-POSITION (COL . ROW) TIMESTAMP)
+   (WINDOW BUFFER-POSITION (X . Y) TIMESTAMP)
 The `posn-' functions access elements of such lists."
   (nth (if (consp (nth 2 event)) 2 1) event))
 
+(defsubst event-click-count (event)
+  "Return the multi-click count of EVENT, a click or drag event.
+The return value is a positive integer."
+  (if (integerp (nth 2 event)) (nth 2 event) 1))
+
 (defsubst posn-window (position)
   "Return the window in POSITION.
 POSITION should be a list of the form
-   (WINDOW BUFFER-POSITION (COL . ROW) TIMESTAMP)
+   (WINDOW BUFFER-POSITION (X . Y) TIMESTAMP)
 as returned by the `event-start' and `event-end' functions."
   (nth 0 position))
 
 (defsubst posn-point (position)
   "Return the buffer location in POSITION.
 POSITION should be a list of the form
-   (WINDOW BUFFER-POSITION (COL . ROW) TIMESTAMP)
+   (WINDOW BUFFER-POSITION (X . Y) TIMESTAMP)
 as returned by the `event-start' and `event-end' functions."
-  (nth 1 position))
+  (if (consp (nth 1 position))
+      (car (nth 1 position))
+    (nth 1 position)))
 
-(defsubst posn-col-row (position)
-  "Return the row and column in POSITION.
+(defsubst posn-x-y (position)
+  "Return the x and y coordinates in POSITION.
 POSITION should be a list of the form
-   (WINDOW BUFFER-POSITION (COL . ROW) TIMESTAMP)
+   (WINDOW BUFFER-POSITION (X . Y) TIMESTAMP)
 as returned by the `event-start' and `event-end' functions."
   (nth 2 position))
 
+(defun posn-col-row (position)
+  "Return the column and row in POSITION, measured in characters.
+POSITION should be a list of the form
+   (WINDOW BUFFER-POSITION (X . Y) TIMESTAMP)
+as returned by the `event-start' and `event-end' functions.
+For a scroll-bar event, the result column is 0, and the row
+corresponds to the vertical position of the click in the scroll bar."
+  (let ((pair   (nth 2 position))
+       (window (posn-window position)))
+    (if (eq (if (consp (nth 1 position))
+               (car (nth 1 position))
+             (nth 1 position))
+           'vertical-scroll-bar)
+       (cons 0 (scroll-bar-scale pair (1- (window-height window))))
+      (if (eq (if (consp (nth 1 position))
+                 (car (nth 1 position))
+               (nth 1 position))
+             'horizontal-scroll-bar)
+         (cons (scroll-bar-scale pair (window-width window)) 0)
+       (let* ((frame (if (framep window) window (window-frame window)))
+              (x (/ (car pair) (frame-char-width frame)))
+              (y (/ (cdr pair) (frame-char-height frame))))
+         (cons x y))))))
+
 (defsubst posn-timestamp (position)
   "Return the timestamp of POSITION.
 POSITION should be a list of the form
-   (WINDOW BUFFER-POSITION (COL . ROW) TIMESTAMP)
+   (WINDOW BUFFER-POSITION (X . Y) TIMESTAMP)
 as returned by the `event-start' and `event-end' functions."
   (nth 3 position))
 
 \f
 ;;;; Obsolescent names for functions.
 
-(defalias 'make-syntax-table 'copy-syntax-table)
 (defalias 'dot 'point)
 (defalias 'dot-marker 'point-marker)
 (defalias 'dot-min 'point-min)
@@ -361,13 +423,6 @@ as returned by the `event-start' and `event-end' functions."
 (defalias 'eval-current-buffer 'eval-buffer)
 (defalias 'compiled-function-p 'byte-code-function-p)
 
-;;; This name isn't mentioned in the manual, and we've been hoping to
-;;; phase it out, but there's still a lot of code out there, even for
-;;; Emacs 18.59, which uses mod.  I'm going to let the byte compiler's
-;;; make-obsolete function to poke people a little more, and leave the
-;;; `mod' name around for a while longer.
-(defalias 'mod '%)
-
 ;; Some programs still use this as a function.
 (defun baud-rate ()
   "Obsolete function returning the value of the `baud-rate' variable.
@@ -390,6 +445,7 @@ Please convert your programs to use the variable `baud-rate' directly."
 (defalias 'search-forward-regexp (symbol-function 're-search-forward))
 (defalias 'search-backward-regexp (symbol-function 're-search-backward))
 (defalias 'int-to-string 'number-to-string)
+(defalias 'set-match-data 'store-match-data)
 
 ;;; Should this be an obsolete name?  If you decide it should, you get
 ;;; to go through all the sources and change them.
@@ -397,57 +453,147 @@ Please convert your programs to use the variable `baud-rate' directly."
 \f
 ;;;; Hook manipulation functions.
 
-(defun run-hooks (&rest hooklist)
-  "Takes hook names and runs each one in turn.  Major mode functions use this.
-Each argument should be a symbol, a hook variable.
-These symbols are processed in the order specified.
-If a hook symbol has a non-nil value, that value may be a function
-or a list of functions to be called to run the hook.
-If the value is a function, it is called with no arguments.
-If it is a list, the elements are called, in order, with no arguments."
-  (while hooklist
-    (let ((sym (car hooklist)))
-      (and (boundp sym)
-          (symbol-value sym)
-          (let ((value (symbol-value sym)))
-            (if (and (listp value) (not (eq (car value) 'lambda)))
-                (mapcar 'funcall value)
-              (funcall value)))))
-    (setq hooklist (cdr hooklist))))
-
-;; Tell C code how to call this function.
+;; We used to have this variable so that C code knew how to run hooks.  That
+;; calling convention is made obsolete now the hook running functions are in C.
 (defconst run-hooks 'run-hooks
   "Variable by which C primitives find the function `run-hooks'.
-Don't change it.")
-
-(defun add-hook (hook function &optional append)
-  "Add to the value of HOOK the function FUNCTION unless already present (it
-becomes the first hook on the list unless optional APPEND is non-nil, in
-which case it becomes the last).  HOOK should be a symbol, and FUNCTION may be
-any valid function.  HOOK's value should be a list of functions, not a single
-function.  If HOOK is void, it is first set to nil."
+Don't change it.  Don't use it either; use the hook running C primitives.")
+
+(defun make-local-hook (hook)
+  "Make the hook HOOK local to the current buffer.
+When a hook is local, its local and global values
+work in concert: running the hook actually runs all the hook
+functions listed in *either* the local value *or* the global value
+of the hook variable.
+
+This function works by making `t' a member of the buffer-local value,
+which acts as a flag to run the hook functions in the default value as
+well.  This works for all normal hooks, but does not work for most
+non-normal hooks yet.  We will be changing the callers of non-normal
+hooks so that they can handle localness; this has to be done one by
+one.
+
+This function does nothing if HOOK is already local in the current
+buffer.
+
+Do not use `make-local-variable' to make a hook variable buffer-local."
+  (if (local-variable-p hook)
+      nil
+    (or (boundp hook) (set hook nil))
+    (make-local-variable hook)
+    (set hook (list t))))
+
+(defun add-hook (hook function &optional append local)
+  "Add to the value of HOOK the function FUNCTION.
+FUNCTION is not added if already present.
+FUNCTION is added (if necessary) at the beginning of the hook list
+unless the optional argument APPEND is non-nil, in which case
+FUNCTION is added at the end.
+
+The optional fourth argument, LOCAL, if non-nil, says to modify
+the hook's buffer-local value rather than its default value.
+This makes no difference if the hook is not buffer-local.
+To make a hook variable buffer-local, always use
+`make-local-hook', not `make-local-variable'.
+
+HOOK should be a symbol, and FUNCTION may be any valid function.  If
+HOOK is void, it is first set to nil.  If HOOK's value is a single
+function, it is changed to a list of functions."
   (or (boundp hook) (set hook nil))
-  (or (if (consp function)
-         ;; Clever way to tell whether a given lambda-expression
-         ;; is equal to anything in the hook.
-         (let ((tail (assoc (cdr function) (symbol-value hook))))
-           (equal function tail))
-       (memq function (symbol-value hook)))
-      (set hook 
-          (if append
-              (nconc (symbol-value hook) (list function))
-            (cons function (symbol-value hook))))))
-
+  (or (default-boundp hook) (set-default hook nil))
+  ;; If the hook value is a single function, turn it into a list.
+  (let ((old (symbol-value hook)))
+    (if (or (not (listp old)) (eq (car old) 'lambda))
+       (set hook (list old))))
+  (if (or local
+         ;; Detect the case where make-local-variable was used on a hook
+         ;; and do what we used to do.
+         (and (local-variable-if-set-p hook)
+              (not (memq t (symbol-value hook)))))
+      ;; Alter the local value only.
+      (or (if (consp function)
+             (member function (symbol-value hook))
+           (memq function (symbol-value hook)))
+         (set hook 
+              (if append
+                  (append (symbol-value hook) (list function))
+                (cons function (symbol-value hook)))))
+    ;; Alter the global value (which is also the only value,
+    ;; if the hook doesn't have a local value).
+    (or (if (consp function)
+           (member function (default-value hook))
+         (memq function (default-value hook)))
+       (set-default hook 
+                    (if append
+                        (append (default-value hook) (list function))
+                      (cons function (default-value hook)))))))
+
+(defun remove-hook (hook function &optional local)
+  "Remove from the value of HOOK the function FUNCTION.
+HOOK should be a symbol, and FUNCTION may be any valid function.  If
+FUNCTION isn't the value of HOOK, or, if FUNCTION doesn't appear in the
+list of hooks to run in HOOK, then nothing is done.  See `add-hook'.
+
+The optional third argument, LOCAL, if non-nil, says to modify
+the hook's buffer-local value rather than its default value.
+This makes no difference if the hook is not buffer-local.
+To make a hook variable buffer-local, always use
+`make-local-hook', not `make-local-variable'."
+  (if (or (not (boundp hook))          ;unbound symbol, or
+         (not (default-boundp 'hook))
+         (null (symbol-value hook))    ;value is nil, or
+         (null function))              ;function is nil, then
+      nil                              ;Do nothing.
+    (if (or local
+           ;; Detect the case where make-local-variable was used on a hook
+           ;; and do what we used to do.
+           (and (local-variable-p hook)
+                (not (memq t (symbol-value hook)))))
+       (let ((hook-value (symbol-value hook)))
+         (if (consp hook-value)
+             (if (member function hook-value)
+                 (setq hook-value (delete function (copy-sequence hook-value))))
+           (if (equal hook-value function)
+               (setq hook-value nil)))
+         (set hook hook-value))
+      (let ((hook-value (default-value hook)))
+       (if (consp hook-value)
+           (if (member function hook-value)
+               (setq hook-value (delete function (copy-sequence hook-value))))
+         (if (equal hook-value function)
+             (setq hook-value nil)))
+       (set-default hook hook-value)))))
+
+(defun add-to-list (list-var element)
+  "Add to the value of LIST-VAR the element ELEMENT if it isn't there yet.
+The test for presence of ELEMENT is done with `equal'.
+If you want to use `add-to-list' on a variable that is not defined
+until a certain package is loaded, you should put the call to `add-to-list'
+into a hook function that will be run only after loading the package.
+`eval-after-load' provides one way to do this.  In some cases
+other hooks, such as major mode hooks, can do the job."
+  (or (member element (symbol-value list-var))
+      (set list-var (cons element (symbol-value list-var)))))
 \f
 ;;;; Specifying things to do after certain files are loaded.
 
 (defun eval-after-load (file form)
   "Arrange that, if FILE is ever loaded, FORM will be run at that time.
 This makes or adds to an entry on `after-load-alist'.
+If FILE is already loaded, evaluate FORM right now.
+It does nothing if FORM is already on the list for FILE.
 FILE should be the name of a library, with no directory name."
+  ;; Make sure there is an element for FILE.
   (or (assoc file after-load-alist)
       (setq after-load-alist (cons (list file) after-load-alist)))
-  (nconc (assoc file after-load-alist) (list form))
+  ;; Add FORM to the element if it isn't there.
+  (let ((elt (assoc file after-load-alist)))
+    (or (member form (cdr elt))
+       (progn
+         (nconc elt (list form))
+         ;; If the file has been loaded already, run FORM right away.
+         (and (assoc file load-history)
+              (eval form)))))
   form)
 
 (defun eval-next-after-load (file)
@@ -464,10 +610,14 @@ FILE should be the name of a library, with no directory name."
 digit, we read up to two more octal digits and return the character
 represented by the octal number consisting of those digits.
 Optional argument PROMPT specifies a string to use to prompt the user."
-  (let ((count 0) (code 0) char)
+  (let ((message-log-max nil) (count 0) (code 0) char)
     (while (< count 3)
       (let ((inhibit-quit (zerop count))
-           (help-form nil))
+           ;; Don't let C-h get the help message--only help function keys.
+           (help-char nil)
+           (help-form
+            "Type the special character you want to use,
+or three octal digits representing its character code."))
        (and prompt (message "%s-" prompt))
        (setq char (read-char))
        (if inhibit-quit (setq quit-flag nil)))
@@ -475,16 +625,17 @@ Optional argument PROMPT specifies a string to use to prompt the user."
            ((and (<= ?0 char) (<= char ?7))
             (setq code (+ (* code 8) (- char ?0))
                   count (1+ count))
-            (and prompt (message (setq prompt
-                                       (format "%s %c" prompt char)))))
+            (and prompt (setq prompt (message "%s %c" prompt char))))
            ((> count 0)
             (setq unread-command-events (list char) count 259))
            (t (setq code char count 259))))
-    (logand 255 code)))
+    ;; Turn a meta-character into a character with the 0200 bit set.
+    (logior (if (/= (logand code ?\M-\^@) 0) 128 0)
+           (logand 255 code))))
 
 (defun force-mode-line-update (&optional all)
   "Force the mode-line of the current buffer to be redisplayed.
-With optional non-nil ALL then force then force redisplay of all mode-lines."
+With optional non-nil ALL, force redisplay of all mode-lines."
   (if all (save-excursion (set-buffer (other-buffer))))
   (set-buffer-modified-p (buffer-modified-p)))
 
@@ -497,6 +648,8 @@ Display MESSAGE (optional fourth arg) in the echo area.
 If MESSAGE is nil, instructions to type EXIT-CHAR are displayed there."
   (or exit-char (setq exit-char ?\ ))
   (let ((buffer-read-only nil)
+       ;; Don't modify the undo list at all.
+       (buffer-undo-list t)
        (modified (buffer-modified-p))
        (name buffer-file-name)
        insert-end)
@@ -507,7 +660,17 @@ If MESSAGE is nil, instructions to type EXIT-CHAR are displayed there."
            ;; defeat file locking... don't try this at home, kids!
            (setq buffer-file-name nil)
            (insert-before-markers string)
-           (setq insert-end (point)))
+           (setq insert-end (point))
+           ;; If the message end is off screen, recenter now.
+           (if (> (window-end) insert-end)
+               (recenter (/ (window-height) 2)))
+           ;; If that pushed message start off the screen,
+           ;; scroll to start it at the top of the screen.
+           (move-to-window-line 0)
+           (if (> (point) pos)
+               (progn
+                 (goto-char pos)
+                 (recenter 0))))
          (message (or message "Type %s to continue editing.")
                   (single-key-description exit-char))
          (let ((char (read-event)))
@@ -522,20 +685,44 @@ If MESSAGE is nil, instructions to type EXIT-CHAR are displayed there."
 \f
 ;;;; Miscellanea.
 
-(defun ignore (&rest ignore) 
-  "Do nothing.
-Accept any number of arguments, but ignore them."
+;; A number of major modes set this locally.
+;; Give it a global value to avoid compiler warnings.
+(defvar font-lock-defaults nil)
+
+;; Avoid compiler warnings about this variable,
+;; which has a special meaning on certain system types.
+(defvar buffer-file-type nil
+  "Non-nil if the visited file is a binary file.
+This variable is meaningful on MS-DOG and Windows NT.
+On those systems, it is automatically local in every buffer.
+On other systems, this variable is normally always nil.")
+
+;; This should probably be written in C (i.e., without using `walk-windows').
+(defun get-buffer-window-list (buffer &optional minibuf frame)
+  "Return windows currently displaying BUFFER, or nil if none.
+See `walk-windows' for the meaning of MINIBUF and FRAME."
+  (let ((buffer (if (bufferp buffer) buffer (get-buffer buffer))) windows)
+    (walk-windows (function (lambda (window)
+                             (if (eq (window-buffer window) buffer)
+                                 (setq windows (cons window windows)))))
+                 minibuf frame)
+    windows))
+
+(defun ignore (&rest ignore)
+  "Do nothing and return nil.
+This function accepts any number of arguments, but ignores them."
+  (interactive)
   nil)
 
 (defun error (&rest args)
-  "Signal an error, making error message by passing all args to `format'."
+  "Signal an error, making error message by passing all args to `format'.
+In Emacs, the convention is that error messages start with a capital
+letter but *do not* end with a period.  Please follow this convention
+for the sake of consistency."
   (while t
     (signal 'error (list (apply 'format args)))))
 
-(defun user-original-login-name ()
-  "Return user's login name from original login.
-This tries to remain unaffected by `su', by looking in environment variables."
-  (or (getenv "LOGNAME") (getenv "USER") (user-login-name)))
+(defalias 'user-original-login-name 'user-login-name)
 
 (defun start-process-shell-command (name buffer &rest args)
   "Start a program in a subprocess.  Return the process object for it.
@@ -548,20 +735,131 @@ BUFFER is the buffer or (buffer-name) to associate with the process.
  with any buffer
 Third arg is command name, the name of a shell command.
 Remaining arguments are the arguments for the command.
-Wildcards and redirection are handle as usual in the shell."
-  (if (eq system-type 'vax-vms)
-      (apply 'start-process name buffer args)
-    (start-process name buffer shell-file-name "-c"
-                  (concat "exec " (mapconcat 'identity args " ")))))
+Wildcards and redirection are handled as usual in the shell."
+  (cond
+   ((eq system-type 'vax-vms)
+    (apply 'start-process name buffer args))
+   ;; We used to use `exec' to replace the shell with the command,
+   ;; but that failed to handle (...) and semicolon, etc.
+   (t
+    (start-process name buffer shell-file-name shell-command-switch
+                  (mapconcat 'identity args " ")))))
 
 (defmacro save-match-data (&rest body)
   "Execute the BODY forms, restoring the global value of the match data."
   (let ((original (make-symbol "match-data")))
-    (list
-     'let (list (list original '(match-data)))
-     (list 'unwind-protect
-           (cons 'progn body)
-           (list 'store-match-data original)))))
+    (list 'let (list (list original '(match-data)))
+         (list 'unwind-protect
+               (cons 'progn body)
+               (list 'store-match-data original)))))
+
+(defun match-string (num &optional string)
+  "Return string of text matched by last search.
+NUM specifies which parenthesized expression in the last regexp.
+ Value is nil if NUMth pair didn't match, or there were less than NUM pairs.
+Zero means the entire text matched by the whole regexp or whole string.
+STRING should be given if the last search was by `string-match' on STRING."
+  (if (match-beginning num)
+      (if string
+         (substring string (match-beginning num) (match-end num))
+       (buffer-substring (match-beginning num) (match-end num)))))
+
+(defun shell-quote-argument (argument)
+  "Quote an argument for passing as argument to an inferior shell."
+  (if (eq system-type 'ms-dos)
+      ;; MS-DOS shells don't have quoting, so don't do any.
+      argument
+    (if (eq system-type 'windows-nt)
+       (concat "\"" argument "\"")
+      ;; Quote everything except POSIX filename characters.
+      ;; This should be safe enough even for really weird shells.
+      (let ((result "") (start 0) end)
+       (while (string-match "[^-0-9a-zA-Z_./]" argument start)
+         (setq end (match-beginning 0)
+               result (concat result (substring argument start end)
+                              "\\" (substring argument end (1+ end)))
+               start (1+ end)))
+       (concat result (substring argument start))))))
+
+(defun make-syntax-table (&optional oldtable)
+  "Return a new syntax table.
+It inherits all letters and control characters from the standard
+syntax table; other characters are copied from the standard syntax table."
+  (if oldtable
+      (copy-syntax-table oldtable)
+    (let ((table (copy-syntax-table))
+         i)
+      (setq i 0)
+      (while (<= i 31)
+       (aset table i nil)
+       (setq i (1+ i)))
+      (setq i ?A)
+      (while (<= i ?Z)
+       (aset table i nil)
+       (setq i (1+ i)))
+      (setq i ?a)
+      (while (<= i ?z)
+       (aset table i nil)
+       (setq i (1+ i)))
+      (setq i 128)
+      (while (<= i 255)
+       (aset table i nil)
+       (setq i (1+ i)))
+      table)))
+\f
+(defun global-set-key (key command)
+  "Give KEY a global binding as COMMAND.
+COMMAND is a symbol naming an interactively-callable function.
+KEY is a key sequence (a string or vector of characters or event types).
+Non-ASCII characters with codes above 127 (such as ISO Latin-1)
+can be included if you use a vector.
+Note that if KEY has a local binding in the current buffer
+that local binding will continue to shadow any global binding."
+  (interactive "KSet key globally: \nCSet key %s to command: ")
+  (or (vectorp key) (stringp key)
+      (signal 'wrong-type-argument (list 'arrayp key)))
+  (define-key (current-global-map) key command)
+  nil)
+
+(defun local-set-key (key command)
+  "Give KEY a local binding as COMMAND.
+COMMAND is a symbol naming an interactively-callable function.
+KEY is a key sequence (a string or vector of characters or event types).
+Non-ASCII characters with codes above 127 (such as ISO Latin-1)
+can be included if you use a vector.
+The binding goes in the current buffer's local map,
+which in most cases is shared with all other buffers in the same major mode."
+  (interactive "KSet key locally: \nCSet key %s locally to command: ")
+  (let ((map (current-local-map)))
+    (or map
+       (use-local-map (setq map (make-sparse-keymap))))
+    (or (vectorp key) (stringp key)
+       (signal 'wrong-type-argument (list 'arrayp key)))
+    (define-key map key command))
+  nil)
+
+(defun global-unset-key (key)
+  "Remove global binding of KEY.
+KEY is a string representing a sequence of keystrokes."
+  (interactive "kUnset key globally: ")
+  (global-set-key key nil))
+
+(defun local-unset-key (key)
+  "Remove local binding of KEY.
+KEY is a string representing a sequence of keystrokes."
+  (interactive "kUnset key locally: ")
+  (if (current-local-map)
+      (local-set-key key nil))
+  nil)
+\f
+;; We put this here instead of in frame.el so that it's defined even on
+;; systems where frame.el isn't loaded.
+(defun frame-configuration-p (object)
+  "Return non-nil if OBJECT seems to be a frame configuration.
+Any list whose car is `frame-configuration' is assumed to be a frame
+configuration."
+  (and (consp object)
+       (eq (car object) 'frame-configuration)))
 
 ;; now in fns.c
 ;(defun nth (n list)