]> code.delx.au - gnu-emacs/blobdiff - lisp/subr.el
Add "Package:" file headers to denote built-in packages.
[gnu-emacs] / lisp / subr.el
index ae19a644ee110f8df8f5cbd802232305f8f62461..67036ba641200844b9a1864101cd578c5c995f5a 100644 (file)
@@ -1,10 +1,11 @@
 ;;; subr.el --- basic lisp subroutines for Emacs
 
 ;; Copyright (C) 1985, 1986, 1992, 1994, 1995, 1999, 2000, 2001, 2002, 2003,
-;;   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+;;   2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: internal
+;; Package: emacs
 
 ;; This file is part of GNU Emacs.
 
@@ -62,11 +63,7 @@ set ARGLIST to `t'.  This is necessary because `nil' means an
 empty argument list, rather than an unspecified one.
 
 Note that for the purposes of `check-declare', this statement
-must be the first non-whitespace on a line, and everything up to
-the end of FILE must be all on the same line.  For example:
-
-\(declare-function c-end-of-defun \"progmodes/cc-cmds.el\"
-                  \(&optional arg))
+must be the first non-whitespace on a line.
 
 For more information, see Info node `(elisp)Declaring Functions'."
   ;; Does nothing - byte-compile-declare-function does the work.
@@ -119,13 +116,18 @@ BODY should be a list of Lisp expressions.
   ;; depend on backquote.el.
   (list 'function (cons 'lambda cdr)))
 
+(if (null (featurep 'cl))
+    (progn
+  ;; If we reload subr.el after having loaded CL, be careful not to
+  ;; overwrite CL's extended definition of `dolist', `dotimes',
+  ;; `declare', `push' and `pop'.
 (defmacro push (newelt listname)
   "Add NEWELT to the list stored in the symbol LISTNAME.
 This is equivalent to (setq LISTNAME (cons NEWELT LISTNAME)).
 LISTNAME must be a symbol."
   (declare (debug (form sexp)))
   (list 'setq listname
-       (list 'cons newelt listname)))
+        (list 'cons newelt listname)))
 
 (defmacro pop (listname)
   "Return the first element of LISTNAME's value, and remove it from the list.
@@ -134,8 +136,9 @@ If the value is nil, `pop' returns nil but does not actually
 change the list."
   (declare (debug (sexp)))
   (list 'car
-       (list 'prog1 listname
-             (list 'setq listname (list 'cdr listname)))))
+        (list 'prog1 listname
+              (list 'setq listname (list 'cdr listname)))))
+))
 
 (defmacro when (cond &rest body)
   "If COND yields non-nil, do BODY, else return nil.
@@ -155,6 +158,11 @@ value of last one, or nil if there are none.
   (declare (indent 1) (debug t))
   (cons 'if (cons cond (cons nil body))))
 
+(if (null (featurep 'cl))
+    (progn
+  ;; If we reload subr.el after having loaded CL, be careful not to
+  ;; overwrite CL's extended definition of `dolist', `dotimes',
+  ;; `declare', `push' and `pop'.
 (defvar --dolist-tail-- nil
   "Temporary variable used in `dolist' expansion.")
 
@@ -207,10 +215,12 @@ the return value (nil if RESULT is omitted).
 Treated as a declaration when used at the right place in a
 `defmacro' form.  \(See Info anchor `(elisp)Definition of declare'.)"
   nil)
+))
 
 (defmacro ignore-errors (&rest body)
   "Execute BODY; if an error occurs, return nil.
 Otherwise, return result of last form in BODY."
+  (declare (debug t) (indent 0))
   `(condition-case nil (progn ,@body) (error nil)))
 \f
 ;;;; Basic Lisp functions.
@@ -221,15 +231,15 @@ This function accepts any number of arguments, but ignores them."
   (interactive)
   nil)
 
+;; Signal a compile-error if the first arg is missing.
 (defun error (&rest args)
   "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.
-
-\(fn STRING &rest ARGS)"
+for the sake of consistency."
   (while t
     (signal 'error (list (apply 'format args)))))
+(set-advertised-calling-convention 'error '(string &rest args))
 
 ;; We put this here instead of in frame.el so that it's defined even on
 ;; systems where frame.el isn't loaded.
@@ -726,8 +736,8 @@ in a cleaner way with command remapping, like this:
 \f
 ;;;; The global keymap tree.
 
-;;; global-map, esc-map, and ctl-x-map have their values set up in
-;;; keymap.c; we just give them docstrings here.
+;; global-map, esc-map, and ctl-x-map have their values set up in
+;; keymap.c; we just give them docstrings here.
 
 (defvar global-map nil
   "Default global keymap mapping Emacs keyboard input into commands.
@@ -1000,6 +1010,41 @@ and `event-end' functions."
 \f
 ;;;; Obsolescent names for functions.
 
+(define-obsolete-function-alias 'window-dot 'window-point "22.1")
+(define-obsolete-function-alias 'set-window-dot 'set-window-point "22.1")
+(define-obsolete-function-alias 'read-input 'read-string "22.1")
+(define-obsolete-function-alias 'show-buffer 'set-window-buffer "22.1")
+(define-obsolete-function-alias 'eval-current-buffer 'eval-buffer "22.1")
+(define-obsolete-function-alias 'string-to-int 'string-to-number "22.1")
+
+(make-obsolete 'char-bytes "now always returns 1." "20.4")
+(make-obsolete 'forward-point "use (+ (point) N) instead." "23.1")
+
+(defun insert-string (&rest args)
+  "Mocklisp-compatibility insert function.
+Like the function `insert' except that any argument that is a number
+is converted into a string by expressing it in decimal."
+  (dolist (el args)
+    (insert (if (integerp el) (number-to-string el) el))))
+(make-obsolete 'insert-string 'insert "22.1")
+
+(defun makehash (&optional test) (make-hash-table :test (or test 'eql)))
+(make-obsolete 'makehash 'make-hash-table "22.1")
+
+;; These are used by VM and some old programs
+(defalias 'focus-frame 'ignore "")
+(make-obsolete 'focus-frame "it does nothing." "22.1")
+(defalias 'unfocus-frame 'ignore "")
+(make-obsolete 'unfocus-frame "it does nothing." "22.1")
+(make-obsolete 'make-variable-frame-local
+              "explicitly check for a frame-parameter instead." "22.2")
+(make-obsolete 'interactive-p 'called-interactively-p "23.2")
+(set-advertised-calling-convention 'called-interactively-p '(kind))
+(set-advertised-calling-convention
+ 'all-completions '(string collection &optional predicate))
+\f
+;;;; Obsolescence declarations for variables, and aliases.
+
 ;; Special "default-FOO" variables which contain the default value of
 ;; the "FOO" variable are nasty.  Their implementation is brittle, and
 ;; slows down several unrelated variable operations; furthermore, they
@@ -1012,7 +1057,6 @@ and `event-end' functions."
 (make-obsolete-variable 'default-line-spacing 'line-spacing "23.2")
 (make-obsolete-variable 'default-abbrev-mode 'abbrev-mode "23.2")
 (make-obsolete-variable 'default-ctl-arrow 'ctl-arrow "23.2")
-(make-obsolete-variable 'default-direction-reversed 'direction-reversed "23.2")
 (make-obsolete-variable 'default-truncate-lines 'truncate-lines "23.2")
 (make-obsolete-variable 'default-left-margin 'left-margin "23.2")
 (make-obsolete-variable 'default-tab-width 'tab-width "23.2")
@@ -1039,43 +1083,6 @@ and `event-end' functions."
 (make-obsolete-variable 'default-enable-multibyte-characters
       "use enable-multibyte-characters or set-buffer-multibyte instead" "23.2")
 
-(define-obsolete-function-alias 'window-dot 'window-point "22.1")
-(define-obsolete-function-alias 'set-window-dot 'set-window-point "22.1")
-(define-obsolete-function-alias 'read-input 'read-string "22.1")
-(define-obsolete-function-alias 'show-buffer 'set-window-buffer "22.1")
-(define-obsolete-function-alias 'eval-current-buffer 'eval-buffer "22.1")
-(define-obsolete-function-alias 'string-to-int 'string-to-number "22.1")
-
-(make-obsolete 'char-bytes "now always returns 1." "20.4")
-(make-obsolete 'forward-point "use (+ (point) N) instead." "23.1")
-
-(defun insert-string (&rest args)
-  "Mocklisp-compatibility insert function.
-Like the function `insert' except that any argument that is a number
-is converted into a string by expressing it in decimal."
-  (dolist (el args)
-    (insert (if (integerp el) (number-to-string el) el))))
-(make-obsolete 'insert-string 'insert "22.1")
-
-(defun makehash (&optional test) (make-hash-table :test (or test 'eql)))
-(make-obsolete 'makehash 'make-hash-table "22.1")
-
-;; Some programs still use this as a function.
-(defun baud-rate ()
-  "Return the value of the `baud-rate' variable."
-  baud-rate)
-(make-obsolete 'baud-rate "use the `baud-rate' variable instead." "before 19.15")
-
-;; These are used by VM and some old programs
-(defalias 'focus-frame 'ignore "")
-(make-obsolete 'focus-frame "it does nothing." "22.1")
-(defalias 'unfocus-frame 'ignore "")
-(make-obsolete 'unfocus-frame "it does nothing." "22.1")
-(make-obsolete 'make-variable-frame-local
-              "explicitly check for a frame-parameter instead." "22.2")
-\f
-;;;; Obsolescence declarations for variables, and aliases.
-
 (make-obsolete-variable 'define-key-rebound-commands nil "23.2")
 (make-obsolete-variable 'redisplay-end-trigger-functions 'jit-lock-register "23.1")
 (make-obsolete 'window-redisplay-end-trigger nil "23.1")
@@ -1084,7 +1091,11 @@ is converted into a string by expressing it in decimal."
 (make-obsolete 'process-filter-multibyte-p nil "23.1")
 (make-obsolete 'set-process-filter-multibyte nil "23.1")
 
-(make-obsolete-variable 'directory-sep-char "do not use it." "21.1")
+(defconst directory-sep-char ?/
+  "Directory separator character for built-in functions that return file names.
+The value is always ?/.")
+(make-obsolete-variable 'directory-sep-char "do not use it, just use `/'." "21.1")
+
 (make-obsolete-variable
  'mode-line-inverse-video
  "use the appropriate faces instead."
@@ -1212,6 +1223,8 @@ function, it is changed to a list of functions."
       (setq hook-value (list hook-value)))
     ;; Do the actual addition if necessary
     (unless (member function hook-value)
+      (when (stringp function)
+       (setq function (purecopy function)))
       (setq hook-value
            (if append
                (append hook-value (list function))
@@ -1470,8 +1483,7 @@ If TOGGLE has a `:menu-tag', that is used for the menu item's label."
              (let ((rest (cdr found)))
                (setcdr found nil)
                (nconc found (list (list toggle name)) rest))
-           (setq minor-mode-alist (cons (list toggle name)
-                                        minor-mode-alist)))))))
+           (push (list toggle name) minor-mode-alist))))))
   ;; Add the toggle to the minor-modes menu if requested.
   (when (get toggle :included)
     (define-key mode-line-mode-menu
@@ -1500,8 +1512,7 @@ If TOGGLE has a `:menu-tag', that is used for the menu item's label."
              (let ((rest (cdr found)))
                (setcdr found nil)
                (nconc found (list (cons toggle keymap)) rest))
-           (setq minor-mode-map-alist (cons (cons toggle keymap)
-                                            minor-mode-map-alist))))))))
+           (push (cons toggle keymap) minor-mode-map-alist)))))))
 \f
 ;;; Load history
 
@@ -1591,22 +1602,6 @@ and the file name is displayed in the echo area."
 \f
 ;;;; Specifying things to do later.
 
-(defmacro eval-at-startup (&rest body)
-  "Make arrangements to evaluate BODY when Emacs starts up.
-If this is run after Emacs startup, evaluate BODY immediately.
-Always returns nil.
-
-This works by adding a function to `before-init-hook'.
-That function's doc string says which file created it."
-  `(progn
-     (if command-line-processed
-        (progn . ,body)
-       (add-hook 'before-init-hook
-                '(lambda () ,(concat "From " (or load-file-name "no file"))
-                   . ,body)
-                t))
-     nil))
-
 (defun load-history-regexp (file)
   "Form a regexp to find FILE in `load-history'.
 FILE, a string, is described in the function `eval-after-load'."
@@ -1670,14 +1665,14 @@ This function makes or adds to an entry on `after-load-alist'."
   ;; Add this FORM into after-load-alist (regardless of whether we'll be
   ;; evaluating it now).
   (let* ((regexp-or-feature
-         (if (stringp file) (load-history-regexp file) file))
+         (if (stringp file) (setq file (purecopy (load-history-regexp file))) file))
         (elt (assoc regexp-or-feature after-load-alist)))
     (unless elt
       (setq elt (list regexp-or-feature))
       (push elt after-load-alist))
     ;; Add FORM to the element unless it's already there.
     (unless (member form (cdr elt))
-      (nconc elt (list form)))
+      (nconc elt (purecopy (list form))))
 
     ;; Is there an already loaded file whose name (or `provide' name)
     ;; matches FILE?
@@ -1686,21 +1681,39 @@ This function makes or adds to an entry on `after-load-alist'."
          (featurep file))
        (eval form))))
 
+(defvar after-load-functions nil
+  "Special hook run after loading a file.
+Each function there is called with a single argument, the absolute
+name of the file just loaded.")
+
 (defun do-after-load-evaluation (abs-file)
   "Evaluate all `eval-after-load' forms, if any, for ABS-FILE.
-ABS-FILE, a string, should be the absolute true name of a file just loaded."
+ABS-FILE, a string, should be the absolute true name of a file just loaded.
+This function is called directly from the C code."
+  ;; Run the relevant eval-after-load forms.
   (mapc #'(lambda (a-l-element)
            (when (and (stringp (car a-l-element))
                       (string-match-p (car a-l-element) abs-file))
              ;; discard the file name regexp
              (mapc #'eval (cdr a-l-element))))
-       after-load-alist))
+       after-load-alist)
+  ;; Complain when the user uses obsolete files.
+  (when (string-match-p "/obsolete/[^/]*\\'" abs-file)
+    (run-with-timer 0 nil
+                    (lambda (file)
+                      (message "Package %s is obsolete!"
+                               (substring file 0
+                                          (string-match "\\.elc?\\>" file))))
+                    (file-name-nondirectory abs-file)))
+  ;; Finally, run any other hook.
+  (run-hook-with-args 'after-load-functions abs-file))
 
 (defun eval-next-after-load (file)
   "Read the following input sexp, and run it whenever FILE is loaded.
 This makes or adds to an entry on `after-load-alist'.
 FILE should be the name of a library, with no directory name."
   (eval-after-load file (read)))
+(make-obsolete 'eval-next-after-load `eval-after-load "23.2")
 \f
 ;;;; Process stuff.
 
@@ -1796,7 +1809,7 @@ Legitimate radix values are 8, 10 and 16."
 
 (defconst read-key-empty-map (make-sparse-keymap))
 
-(defvar read-key-delay 0.1)
+(defvar read-key-delay 0.01) ;Fast enough for 100Hz repeat rate, hopefully.
 
 (defun read-key (&optional prompt)
   "Read a key from the keyboard.
@@ -1807,6 +1820,7 @@ When there's an ambiguity because the key looks like the prefix of
 some sort of escape sequence, the ambiguity is resolved via `read-key-delay'."
   (let ((overriding-terminal-local-map read-key-empty-map)
        (overriding-local-map nil)
+        (echo-keystrokes 0)
        (old-global-map (current-global-map))
         (timer (run-with-idle-timer
                 ;; Wait long enough that Emacs has the time to receive and
@@ -1831,8 +1845,13 @@ some sort of escape sequence, the ambiguity is resolved via `read-key-delay'."
                       (throw 'read-key keys)))))))
     (unwind-protect
         (progn
-         (use-global-map read-key-empty-map)
-         (aref (catch 'read-key (read-key-sequence prompt nil t)) 0))
+         (use-global-map
+           (let ((map (make-sparse-keymap)))
+             ;; Don't hide the menu-bar and tool-bar entries.
+             (define-key map [menu-bar] (lookup-key global-map [menu-bar]))
+             (define-key map [tool-bar] (lookup-key global-map [tool-bar]))
+             map))
+         (aref (catch 'read-key (read-key-sequence-vector prompt nil t)) 0))
       (cancel-timer timer)
       (use-global-map old-global-map))))
 
@@ -1861,16 +1880,13 @@ any other non-digit terminates the character code and is then used as input."))
        (if inhibit-quit (setq quit-flag nil)))
       ;; Translate TAB key into control-I ASCII character, and so on.
       ;; Note: `read-char' does it using the `ascii-character' property.
-      ;; We could try and use read-key-sequence instead, but then C-q ESC
-      ;; or C-q C-x might not return immediately since ESC or C-x might be
-      ;; bound to some prefix in function-key-map or key-translation-map.
-      (setq translated
-           (if (integerp char)
-               (char-resolve-modifiers char)
-             char))
+      ;; We should try and use read-key instead.
       (let ((translation (lookup-key local-function-key-map (vector char))))
-       (if (arrayp translation)
-           (setq translated (aref translation 0))))
+       (setq translated (if (arrayp translation)
+                            (aref translation 0)
+                          char)))
+      (if (integerp translated)
+         (setq translated (char-resolve-modifiers translated)))
       (cond ((null translated))
            ((not (integerp translated))
             (setq unread-command-events (list char)
@@ -1879,11 +1895,13 @@ any other non-digit terminates the character code and is then used as input."))
             ;; Turn a meta-character into a character with the 0200 bit set.
             (setq code (logior (logand translated (lognot ?\M-\^@)) 128)
                   done t))
-           ((and (<= ?0 translated) (< translated (+ ?0 (min 10 read-quoted-char-radix))))
+           ((and (<= ?0 translated)
+                  (< translated (+ ?0 (min 10 read-quoted-char-radix))))
             (setq code (+ (* code read-quoted-char-radix) (- translated ?0)))
             (and prompt (setq prompt (message "%s %c" prompt translated))))
            ((and (<= ?a (downcase translated))
-                 (< (downcase translated) (+ ?a -10 (min 36 read-quoted-char-radix))))
+                 (< (downcase translated)
+                     (+ ?a -10 (min 36 read-quoted-char-radix))))
             (setq code (+ (* code read-quoted-char-radix)
                           (+ 10 (- (downcase translated) ?a))))
             (and prompt (setq prompt (message "%s %c" prompt translated))))
@@ -2020,9 +2038,7 @@ An obsolete, but still supported form is
 \(sit-for SECONDS &optional MILLISECONDS NODISP)
 where the optional arg MILLISECONDS specifies an additional wait period,
 in milliseconds; this was useful when Emacs was built without
-floating point support.
-
-\(fn SECONDS &optional NODISP)"
+floating point support."
   (if (numberp nodisp)
       (setq seconds (+ seconds (* 1e-3 nodisp))
             nodisp obsolete)
@@ -2047,6 +2063,7 @@ floating point support.
                (setq read (cons t read)))
            (push read unread-command-events)
            nil))))))
+(set-advertised-calling-convention 'sit-for '(seconds &optional nodisp))
 \f
 ;;; Atomic change groups.
 
@@ -2185,35 +2202,24 @@ 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 ?\s))
   (let ((ol (make-overlay pos pos))
-        (message (copy-sequence string)))
+        (str (copy-sequence string)))
     (unwind-protect
         (progn
           (save-excursion
-            (overlay-put ol 'after-string message)
+            (overlay-put ol 'after-string str)
             (goto-char pos)
             ;; To avoid trouble with out-of-bounds position
             (setq pos (point))
-            ;; If the message end is off screen, recenter now.
+            ;; If the string end is off screen, recenter now.
             (if (<= (window-end nil t) pos)
                 (recenter (/ (window-height) 2))))
           (message (or message "Type %s to continue editing.")
                    (single-key-description exit-char))
-          (let (char)
-            (if (integerp exit-char)
-                (condition-case nil
-                    (progn
-                      (setq char (read-char))
-                      (or (eq char exit-char)
-                          (setq unread-command-events (list char))))
-                  (error
-                   ;; `exit-char' is a character, hence it differs
-                   ;; from char, which is an event.
-                   (setq unread-command-events (list char))))
-              ;; `exit-char' can be an event, or an event description list.
-              (setq char (read-event))
-              (or (eq char exit-char)
-                  (eq char (event-convert-list exit-char))
-                  (setq unread-command-events (list char))))))
+         (let ((event (read-event)))
+           ;; `exit-char' can be an event, or an event description list.
+           (or (eq event exit-char)
+               (eq event (event-convert-list exit-char))
+               (setq unread-command-events (list event)))))
       (delete-overlay ol))))
 
 \f
@@ -2221,10 +2227,14 @@ If MESSAGE is nil, instructions to type EXIT-CHAR are displayed there."
 
 (defun copy-overlay (o)
   "Return a copy of overlay O."
-  (let ((o1 (make-overlay (overlay-start o) (overlay-end o)
-                         ;; FIXME: there's no easy way to find the
-                         ;; insertion-type of the two markers.
-                         (overlay-buffer o)))
+  (let ((o1 (if (overlay-buffer o)
+                (make-overlay (overlay-start o) (overlay-end o)
+                              ;; FIXME: there's no easy way to find the
+                              ;; insertion-type of the two markers.
+                              (overlay-buffer o))
+              (let ((o1 (make-overlay (point-min) (point-min))))
+                (delete-overlay o1)
+                o1)))
        (props (overlay-properties o)))
     (while props
       (overlay-put o1 (pop props) (pop props)))
@@ -2287,7 +2297,7 @@ On other systems, this variable is normally always nil.")
 ;; The `assert' macro from the cl package signals
 ;; `cl-assertion-failed' at runtime so always define it.
 (put 'cl-assertion-failed 'error-conditions '(error))
-(put 'cl-assertion-failed 'error-message "Assertion failed")
+(put 'cl-assertion-failed 'error-message (purecopy "Assertion failed"))
 
 (defconst user-emacs-directory
   (if (eq system-type 'ms-dos)
@@ -2427,7 +2437,11 @@ Otherwise, return nil."
   "Remove `yank-excluded-properties' between START and END positions.
 Replaces `category' properties with their defined properties."
   (let ((inhibit-read-only t))
-    ;; Replace any `category' property with the properties it stands for.
+    ;; Replace any `category' property with the properties it stands
+    ;; for.  This is to remove `mouse-face' properties that are placed
+    ;; on categories in *Help* buffers' buttons.  See
+    ;; http://lists.gnu.org/archive/html/emacs-devel/2002-04/msg00648.html
+    ;; for the details.
     (unless (memq yank-excluded-properties '(t nil))
       (save-excursion
        (goto-char start)
@@ -2571,24 +2585,24 @@ COMMAND is the shell command to run.
 
 An old calling convention accepted any number of arguments after COMMAND,
 which were just concatenated to COMMAND.  This is still supported but strongly
-discouraged.
-
-\(fn NAME BUFFER COMMAND)"
+discouraged."
    ;; We used to use `exec' to replace the shell with the command,
    ;; but that failed to handle (...) and semicolon, etc.
   (start-process name buffer shell-file-name shell-command-switch
                 (mapconcat 'identity args " ")))
+(set-advertised-calling-convention 'start-process-shell-command
+                                   '(name buffer command))
 
 (defun start-file-process-shell-command (name buffer &rest args)
   "Start a program in a subprocess.  Return the process object for it.
-Similar to `start-process-shell-command', but calls `start-file-process'.
-
-\(fn NAME BUFFER COMMAND)"
+Similar to `start-process-shell-command', but calls `start-file-process'."
   (start-file-process
    name buffer
    (if (file-remote-p default-directory) "/bin/sh" shell-file-name)
    (if (file-remote-p default-directory) "-c" shell-command-switch)
    (mapconcat 'identity args " ")))
+(set-advertised-calling-convention 'start-file-process-shell-command
+                                   '(name buffer command))
 
 (defun call-process-shell-command (command &optional infile buffer display
                                           &rest args)
@@ -3182,6 +3196,13 @@ and replace a sub-expression, e.g.
       (setq matches (cons (substring string start l) matches)) ; leftover
       (apply #'concat (nreverse matches)))))
 \f
+(defun string-prefix-p (str1 str2 &optional ignore-case)
+  "Return non-nil if STR1 is a prefix of STR2.
+If IGNORE-CASE is non-nil, the comparison is done without paying attention
+to case differences."
+  (eq t (compare-strings str1 nil nil
+                         str2 0 (length str1) ignore-case)))
+\f
 ;;;; invisibility specs
 
 (defun add-to-invisibility-spec (element)
@@ -3395,51 +3416,59 @@ The properties used on SYMBOL are `composefunc', `sendfunc',
 ;; digits of precision, it doesn't really matter here.  On the other
 ;; hand, it greatly simplifies the code.
 
-(defsubst progress-reporter-update (reporter value)
+(defsubst progress-reporter-update (reporter &optional value)
   "Report progress of an operation in the echo area.
-However, if the change since last echo area update is too small
-or not enough time has passed, then do nothing (see
-`make-progress-reporter' for details).
-
-First parameter, REPORTER, should be the result of a call to
-`make-progress-reporter'.  Second, VALUE, determines the actual
-progress of operation; it must be between MIN-VALUE and MAX-VALUE
-as passed to `make-progress-reporter'.
-
-This function is very inexpensive, you may not bother how often
-you call it."
-  (when (>= value (car reporter))
-    (progress-reporter-do-update reporter value)))
+REPORTER should be the result of a call to `make-progress-reporter'.
 
-(defun make-progress-reporter (message min-value max-value
-                                      &optional current-value
-                                      min-change min-time)
-  "Return progress reporter object to be used with `progress-reporter-update'.
-
-MESSAGE is shown in the echo area.  When at least 1% of operation
-is complete, the exact percentage will be appended to the
-MESSAGE.  When you call `progress-reporter-done', word \"done\"
-is printed after the MESSAGE.  You can change MESSAGE of an
-existing progress reporter with `progress-reporter-force-update'.
-
-MIN-VALUE and MAX-VALUE designate starting (0% complete) and
-final (100% complete) states of operation.  The latter should be
-larger; if this is not the case, then simply negate all values.
-Optional CURRENT-VALUE specifies the progress by the moment you
-call this function.  You should omit it or set it to nil in most
-cases since it defaults to MIN-VALUE.
-
-Optional MIN-CHANGE determines the minimal change in percents to
-report (default is 1%.)  Optional MIN-TIME specifies the minimal
-time before echo area updates (default is 0.2 seconds.)  If
-`float-time' function is not present, then time is not tracked
-at all.  If OS is not capable of measuring fractions of seconds,
-then this parameter is effectively rounded up."
+If REPORTER is a numerical progress reporter---i.e. if it was
+ made using non-nil MIN-VALUE and MAX-VALUE arguments to
+ `make-progress-reporter'---then VALUE should be a number between
+ MIN-VALUE and MAX-VALUE.
 
+If REPORTER is a non-numerical reporter, VALUE should be nil.
+
+This function is relatively inexpensive.  If the change since
+last update is too small or insufficient time has passed, it does
+nothing."
+  (when (or (not (numberp value))      ; For pulsing reporter
+           (>= value (car reporter))) ; For numerical reporter
+    (progress-reporter-do-update reporter value)))
+
+(defun make-progress-reporter (message &optional min-value max-value
+                                      current-value min-change min-time)
+  "Return progress reporter object for use with `progress-reporter-update'.
+
+MESSAGE is shown in the echo area, with a status indicator
+appended to the end.  When you call `progress-reporter-done', the
+word \"done\" is printed after the MESSAGE.  You can change the
+MESSAGE of an existing progress reporter by calling
+`progress-reporter-force-update'.
+
+MIN-VALUE and MAX-VALUE, if non-nil, are starting (0% complete)
+and final (100% complete) states of operation; the latter should
+be larger.  In this case, the status message shows the percentage
+progress.
+
+If MIN-VALUE and/or MAX-VALUE is omitted or nil, the status
+message shows a \"spinning\", non-numeric indicator.
+
+Optional CURRENT-VALUE is the initial progress; the default is
+MIN-VALUE.
+Optional MIN-CHANGE is the minimal change in percents to report;
+the default is 1%.
+CURRENT-VALUE and MIN-CHANGE do not have any effect if MIN-VALUE
+and/or MAX-VALUE are nil.
+
+Optional MIN-TIME specifies the minimum interval time between
+echo area updates (default is 0.2 seconds.)  If the function
+`float-time' is not present, time is not tracked at all.  If the
+OS is not capable of measuring fractions of seconds, this
+parameter is effectively rounded up."
   (unless min-time
     (setq min-time 0.2))
   (let ((reporter
-        (cons min-value ;; Force a call to `message' now
+        ;; Force a call to `message' now
+        (cons (or min-value 0)
               (vector (if (and (fboundp 'float-time)
                                (>= min-time 0.02))
                           (float-time) nil)
@@ -3451,12 +3480,11 @@ then this parameter is effectively rounded up."
     (progress-reporter-update reporter (or current-value min-value))
     reporter))
 
-(defun progress-reporter-force-update (reporter value &optional new-message)
+(defun progress-reporter-force-update (reporter &optional value new-message)
   "Report progress of an operation in the echo area unconditionally.
 
-First two parameters are the same as for
-`progress-reporter-update'.  Optional NEW-MESSAGE allows you to
-change the displayed message."
+The first two arguments are the same as in `progress-reporter-update'.
+NEW-MESSAGE, if non-nil, sets a new message for the reporter."
   (let ((parameters (cdr reporter)))
     (when new-message
       (aset parameters 3 new-message))
@@ -3464,15 +3492,15 @@ change the displayed message."
       (aset parameters 0 (float-time)))
     (progress-reporter-do-update reporter value)))
 
+(defvar progress-reporter--pulse-characters ["-" "\\" "|" "/"]
+  "Characters to use for pulsing progress reporters.")
+
 (defun progress-reporter-do-update (reporter value)
   (let* ((parameters   (cdr reporter))
+        (update-time  (aref parameters 0))
         (min-value    (aref parameters 1))
         (max-value    (aref parameters 2))
-        (one-percent  (/ (- max-value min-value) 100.0))
-        (percentage   (if (= max-value min-value)
-                          0
-                        (truncate (/ (- value min-value) one-percent))))
-        (update-time  (aref parameters 0))
+        (text         (aref parameters 3))
         (current-time (float-time))
         (enough-time-passed
          ;; See if enough time has passed since the last update.
@@ -3480,26 +3508,41 @@ change the displayed message."
              (when (>= current-time update-time)
                ;; Calculate time for the next update
                (aset parameters 0 (+ update-time (aref parameters 5)))))))
-    ;;
-    ;; Calculate NEXT-UPDATE-VALUE.  If we are not going to print
-    ;; message this time because not enough time has passed, then use
-    ;; 1 instead of MIN-CHANGE.  This makes delays between echo area
-    ;; updates closer to MIN-TIME.
-    (setcar reporter
-           (min (+ min-value (* (+ percentage
-                                   (if enough-time-passed
-                                       (aref parameters 4) ;; MIN-CHANGE
-                                     1))
-                                one-percent))
-                max-value))
-    (when (integerp value)
-      (setcar reporter (ceiling (car reporter))))
-    ;;
-    ;; Only print message if enough time has passed
-    (when enough-time-passed
-      (if (> percentage 0)
-         (message "%s%d%%" (aref parameters 3) percentage)
-       (message "%s" (aref parameters 3))))))
+    (cond ((and min-value max-value)
+          ;; Numerical indicator
+          (let* ((one-percent (/ (- max-value min-value) 100.0))
+                 (percentage  (if (= max-value min-value)
+                                  0
+                                (truncate (/ (- value min-value)
+                                             one-percent)))))
+            ;; Calculate NEXT-UPDATE-VALUE.  If we are not printing
+            ;; message because not enough time has passed, use 1
+            ;; instead of MIN-CHANGE.  This makes delays between echo
+            ;; area updates closer to MIN-TIME.
+            (setcar reporter
+                    (min (+ min-value (* (+ percentage
+                                            (if enough-time-passed
+                                                ;; MIN-CHANGE
+                                                (aref parameters 4)
+                                              1))
+                                         one-percent))
+                         max-value))
+            (when (integerp value)
+              (setcar reporter (ceiling (car reporter))))
+            ;; Only print message if enough time has passed
+            (when enough-time-passed
+              (if (> percentage 0)
+                  (message "%s%d%%" text percentage)
+                (message "%s" text)))))
+         ;; Pulsing indicator
+         (enough-time-passed
+          (let ((index (mod (1+ (car reporter)) 4))
+                (message-log-max nil))
+            (setcar reporter index)
+            (message "%s %s"
+                     text
+                     (aref progress-reporter--pulse-characters
+                           index)))))))
 
 (defun progress-reporter-done (reporter)
   "Print reporter's message followed by word \"done\" in echo area."
@@ -3535,23 +3578,23 @@ convenience wrapper around `make-progress-reporter' and friends.
 \f
 ;;;; Comparing version strings.
 
-(defvar version-separator "."
+(defconst version-separator "."
   "*Specify the string used to separate the version elements.
 
 Usually the separator is \".\", but it can be any other string.")
 
 
-(defvar version-regexp-alist
-  '(("^[-_+ ]?a\\(lpha\\)?$"   . -3)
+(defconst version-regexp-alist
+  '(("^[-_+ ]?alpha$"   . -3)
     ("^[-_+]$"                 . -3) ; treat "1.2.3-20050920" and "1.2-3" as alpha releases
     ("^[-_+ ]cvs$"             . -3)   ; treat "1.2.3-CVS" as alpha release
-    ("^[-_+ ]?b\\(eta\\)?$"    . -2)
-    ("^[-_+ ]?\\(pre\\|rc\\)$" . -1))
-  "*Specify association between non-numeric version part and a priority.
+    ("^[-_+ ]?beta$"    . -2)
+    ("^[-_+ ]?\\(pre\\|rcc\\)$" . -1))
+  "*Specify association between non-numeric version and its priority.
 
 This association is used to handle version string like \"1.0pre2\",
 \"0.9alpha1\", etc.  It's used by `version-to-list' (which see) to convert the
-non-numeric part to an integer.  For example:
+non-numeric part of a version string to an integer.  For example:
 
    String Version    Integer List Version
    \"1.0pre2\"         (1  0 -1 2)
@@ -3569,15 +3612,15 @@ Each element has the following form:
 Where:
 
 REGEXP         regexp used to match non-numeric part of a version string.
-               It should begin with a `^' anchor and end with a `$' to
+               It should begin with the `^' anchor and end with a `$' to
                prevent false hits.  Letter-case is ignored while matching
                REGEXP.
 
-PRIORITY       negative integer which indicate the non-numeric priority.")
+PRIORITY       a negative integer specifying non-numeric priority of REGEXP.")
 
 
 (defun version-to-list (ver)
-  "Convert version string VER into an integer list.
+  "Convert version string VER into a list of integers.
 
 The version syntax is given by the following EBNF:
 
@@ -3591,17 +3634,17 @@ The version syntax is given by the following EBNF:
 The NUMBER part is optional if SEPARATOR is a match for an element
 in `version-regexp-alist'.
 
-As an example of valid version syntax:
+Examples of valid version syntax:
 
    1.0pre2   1.0.7.5   22.8beta3   0.9alpha1   6.9.30Beta
 
-As an example of invalid version syntax:
+Examples of invalid version syntax:
 
    1.0prepre2   1.0..7.5   22.8X3   alpha3.2   .5
 
-As an example of version convertion:
+Examples of version conversion:
 
-   String Version    Integer List Version
+   Version String    Version as a List of Integers
    \"1.0.7.5\"         (1  0  7 5)
    \"1.0pre2\"         (1  0 -1 2)
    \"1.0PRE2\"         (1  0 -1 2)
@@ -3639,20 +3682,25 @@ See documentation for `version-separator' and `version-regexp-alist'."
            (setq al version-regexp-alist)
            (while (and al (not (string-match (caar al) s)))
              (setq al (cdr al)))
-           (or al (error "Invalid version syntax: '%s'" ver))
-           (setq lst (cons (cdar al) lst)))))
+           (cond (al
+                  (push (cdar al) lst))
+                 ;; Convert 22.3a to 22.3.1.
+                 ((string-match "^[-_+ ]?\\([a-zA-Z]\\)$" s)
+                  (push (- (aref (downcase (match-string 1 s)) 0) ?a -1)
+                        lst))
+                 (t (error "Invalid version syntax: '%s'" ver))))))
       (if (null lst)
          (error "Invalid version syntax: '%s'" ver)
        (nreverse lst)))))
 
 
 (defun version-list-< (l1 l2)
-  "Return t if integer list L1 is lesser than L2.
+  "Return t if L1, a list specification of a version, is lower than L2.
 
-Note that integer list (1) is equal to (1 0), (1 0 0), (1 0 0 0),
-etc.  That is, the trailing zeroes are irrelevant.  Also, integer
-list (1) is greater than (1 -1) which is greater than (1 -2)
-which is greater than (1 -3)."
+Note that a version specified by the list (1) is equal to (1 0),
+\(1 0 0), (1 0 0 0), etc.  That is, the trailing zeros are insignificant.
+Also, a version given by the list (1) is higher than (1 -1), which in
+turn is higher than (1 -2), which is higher than (1 -3)."
   (while (and l1 l2 (= (car l1) (car l2)))
     (setq l1 (cdr l1)
          l2 (cdr l2)))
@@ -3668,12 +3716,12 @@ which is greater than (1 -3)."
 
 
 (defun version-list-= (l1 l2)
-  "Return t if integer list L1 is equal to L2.
+  "Return t if L1, a list specification of a version, is equal to L2.
 
-Note that integer list (1) is equal to (1 0), (1 0 0), (1 0 0 0),
-etc.  That is, the trailing zeroes are irrelevant.  Also, integer
-list (1) is greater than (1 -1) which is greater than (1 -2)
-which is greater than (1 -3)."
+Note that a version specified by the list (1) is equal to (1 0),
+\(1 0 0), (1 0 0 0), etc.  That is, the trailing zeros are insignificant.
+Also, a version given by the list (1) is higher than (1 -1), which in
+turn is higher than (1 -2), which is higher than (1 -3)."
   (while (and l1 l2 (= (car l1) (car l2)))
     (setq l1 (cdr l1)
          l2 (cdr l2)))
@@ -3689,7 +3737,7 @@ which is greater than (1 -3)."
 
 
 (defun version-list-<= (l1 l2)
-  "Return t if integer list L1 is lesser than or equal to L2.
+  "Return t if L1, a list specification of a version, is lower or equal to L2.
 
 Note that integer list (1) is equal to (1 0), (1 0 0), (1 0 0 0),
 etc.  That is, the trailing zeroes are irrelevant.  Also, integer
@@ -3709,9 +3757,9 @@ which is greater than (1 -3)."
    (t  (<= 0 (version-list-not-zero l2)))))
 
 (defun version-list-not-zero (lst)
-  "Return the first non-zero element of integer list LST.
+  "Return the first non-zero element of LST, which is a list of integers.
 
-If all LST elements are zeroes or LST is nil, return zero."
+If all LST elements are zeros or LST is nil, return zero."
   (while (and lst (zerop (car lst)))
     (setq lst (cdr lst)))
   (if lst
@@ -3721,35 +3769,37 @@ If all LST elements are zeroes or LST is nil, return zero."
 
 
 (defun version< (v1 v2)
-  "Return t if version V1 is lesser than V2.
+  "Return t if version V1 is lower (older) than V2.
 
 Note that version string \"1\" is equal to \"1.0\", \"1.0.0\", \"1.0.0.0\",
-etc.  That is, the trailing \".0\"s are irrelevant.  Also, version string \"1\"
-is greater than \"1pre\" which is greater than \"1beta\" which is greater than
-\"1alpha\"."
+etc.  That is, the trailing \".0\"s are insignificant.  Also, version
+string \"1\" is higher (newer) than \"1pre\", which is higher than \"1beta\",
+which is higher than \"1alpha\"."
   (version-list-< (version-to-list v1) (version-to-list v2)))
 
 
 (defun version<= (v1 v2)
-  "Return t if version V1 is lesser than or equal to V2.
+  "Return t if version V1 is lower (older) than or equal to V2.
 
 Note that version string \"1\" is equal to \"1.0\", \"1.0.0\", \"1.0.0.0\",
-etc.  That is, the trailing \".0\"s are irrelevant.  Also, version string \"1\"
-is greater than \"1pre\" which is greater than \"1beta\" which is greater than
-\"1alpha\"."
+etc.  That is, the trailing \".0\"s are insignificant..  Also, version
+string \"1\" is higher (newer) than \"1pre\", which is higher than \"1beta\",
+which is higher than \"1alpha\"."
   (version-list-<= (version-to-list v1) (version-to-list v2)))
 
 (defun version= (v1 v2)
   "Return t if version V1 is equal to V2.
 
 Note that version string \"1\" is equal to \"1.0\", \"1.0.0\", \"1.0.0.0\",
-etc.  That is, the trailing \".0\"s are irrelevant.  Also, version string \"1\"
-is greater than \"1pre\" which is greater than \"1beta\" which is greater than
-\"1alpha\"."
+etc.  That is, the trailing \".0\"s are insignificant..  Also, version
+string \"1\" is higher (newer) than \"1pre\", which is higher than \"1beta\",
+which is higher than \"1alpha\"."
   (version-list-= (version-to-list v1) (version-to-list v2)))
 
 \f
 ;;; Misc.
+(defconst menu-bar-separator '("--")
+  "Separator for menus.")
 
 ;; The following statement ought to be in print.c, but `provide' can't
 ;; be used there.