Anonymous avatar Anonymous committed 341dac7

Import from CVS: tag r21-0b55

Comments (0)

Files changed (50)

 							-*- indented-text -*-
+to 21.0 pre12 "Irish Goat"
+-- visual package installer from Darryl Okahata
+-- miscellaneous bug fixes from various people
+-- miscellaneous fixes from Hrvoje Niksic
+-- regexp docs from Karl Hegbloom
+
 to 21.0 pre11 "Finnish Landrace"
 -- Update of PROBLEMS by Marcus Thiessel
 -- startup fixes from Michael Sperber
+1998-09-05  SL Baur  <steve@altair.xemacs.org>
+
+	* XEmacs 21.0-pre12 is released.
+
+1998-09-05  SL Baur  <steve@altair.xemacs.org>
+
+	* etc/check_cygwin_setup.sh: grammar fix.
+
+1998-09-02  Andy Piper  <andyp@parallax.co.uk>
+
+	* etc/check_cygwin_setup.sh: fix a couple of buglets.
+
+1998-08-23  Adrian Aichner  <aichner@ecf.teradyne.com>
+
+	* etc/sample.emacs: Enable sound support on mswindows devices.
+
 1998-08-22  SL Baur  <steve@altair.xemacs.org>
 
 	* XEmacs 21.0-pre11 is released.
 This may be changed by specifying a different value with the
 --package-path configuration option.
 
+IMPORTANT NOTE: In a future version of XEmacs, the user-specific
+package hierarchy will move from ~/.xemacs to ~/.xemacs/packages.
+
 4) In the top level directory of the XEmacs distribution, run the
    program `configure' as follows:
 
 See the file `etc/PACKAGES' in the distribution for a partial list of
 packages available at the time of the 21.0 release.
 
+IMPORTANT NOTE: XEmacs currently expects the user-specific package
+hierarchy in ~/.xemacs.  This will probably change to
+~/.xemacs/packages in a future version of XEmacs.
+
 ** XEmacs is now supported under Microsoft Windows 95/98 and Windows
 NT operating systems.  For starters, look at the XEmacs on Windows FAQ
 at <URL:http://jagor.srce.hr/~hniksic/xemacs-on-windows-faq.txt>.  To
 distribution.
 
 Please note that XEmacs is a GPL'ed program and there are restrictions
-on what kinds of binaries can be distributed with it.  In particular,
+on what kinds of binaries that can be linked with it.  In particular,
 proprietary DLLs without source cannot be distributed.  See the file
-COPYING for more detail.s
+COPYING for more details.
 
 * Lisp and internal changes in XEmacs 21.0
 ==========================================
 
+** There is a new configure option '--with-clash-detection' to
+   enable/disable 'lockdir' based clash detection. (Actually, it has
+   been there since 20.4, but was not documented then). The
+   implementation based on a central locking directory can cause
+   severe slowdowns on networked file systems. Therefore the default
+   has been changed to build with clash detection disabled, pending
+   reimplementation of the feature (most likely compatible with the
+   new implementation in recent FSF verions and Interleaf) in an
+   upcoming version.
+
 ** It is now possible to build XEmacs with support for 31-bit Lisp
 integers (normally, Lisp integers are only 28 bits wide on 32-bit
 machines.)  Configure with --use-minimal-tagbits to test.  With this

etc/check_cygwin_setup.sh

 OSversion="`uname -v | sed 's/^\(.\).*$/\1/'`"
 
 shell=`type sh | sed 's/sh is //'`
-distdir=`dirname $shell`
+distdir=`dirname $shell | sed 's!^//\(.\)/\(.*\)!\1:/\2!'`
 
 echo "cygwin installed in $distdir"
 
 echo "checking paths ..."
 
 if [ ! -d "/bin" ]; then
-    echo "You don't have /bin would like to mount cygwin as /bin ?"
+    echo "You don't have a /bin directory.  Would you like to mount cygwin as /bin ?"
     if yorn; then
 	mkdir /bin
-	mount -b /bin $distdir
+	mount -b $distdir /bin
     fi
 elif [ "$distdir" != "/bin" ]; then
     echo "Warning: you have /bin but it's not the cygwin installation."
        (setq ispell-extra-args '("-W" "3"))
 
        (cond ((or (not (fboundp 'device-type))
-		  (equal (device-type) 'x))
-	      ;; Code which applies only when running emacs under X goes here.
-	      ;; (We check whether the function `device-type' exists
-	      ;; before using it.  In versions before 19.12, there
-	      ;; was no such function.  If it doesn't exist, we
-	      ;; simply assume we're running under X -- versions before
-	      ;; 19.12 only supported X.)
+		  (equal (device-type) 'x)
+		  (equal (device-type) 'mswindows))
+	      ;; Code which applies only when running emacs under X or
+	      ;; MicroSoft Windows goes here.  (We check whether the
+	      ;; function `device-type' exists before using it.  In
+	      ;; versions before 19.12, there was no such function.
+	      ;; If it doesn't exist, we simply assume we're running
+	      ;; under X -- versions before 19.12 only supported X.)
 
 	      ;; Remove the binding of C-x C-c, which normally exits emacs.
 	      ;; It's easy to hit this by mistake, and that can be annoying.
 	      ;; standard beep only works with some X servers; many servers
 	      ;; completely ignore those parameters.)
 	      ;;
-	      (cond ((string-match ":0" (getenv "DISPLAY"))
+	      (cond ((or (and (getenv "DISPLAY") 
+			      (string-match ":0" (getenv "DISPLAY")))
+			 (and (eq (console-type) 'mswindows)
+			      (device-sound-enabled-p)))
 		     (load-default-sounds))
 		    (t
 		     (setq bell-volume 40)

lib-src/ChangeLog

+1998-09-05  SL Baur  <steve@altair.xemacs.org>
+
+	* XEmacs 21.0-pre12 is released.
+
 1998-08-22  SL Baur  <steve@altair.xemacs.org>
 
 	* XEmacs 21.0-pre11 is released.
+1998-09-05  SL Baur  <steve@altair.xemacs.org>
+
+	* XEmacs 21.0-pre12 is released.
+
+1998-09-03  Darryl Okahata  <darrylo@sr.hp.com>
+
+	* list-mode.el: `display-completion-list': added new/optional
+	  keyword `:completion-string', which allows the programmer to
+	  change the "Possible completions are:" prompt.
+
+	* menubar-items.el: Added new pulldown menu-pick to start up the 
+	  visual package browser/installer:
+
+		Options->Customize->List Packages
+
+	* package-admin.el: Added hooks for installing under both Unix
+	  and MS Windows.  Does additional error checking.  No longer
+	  calls "add-big-package.sh" to install packages under Unix; now 
+	  calls gunzip & tar directly.
+
+	* package-get.el: Added ability to install packages from files
+	  on a local disk/CDROM.  Now deletes any existing package lisp
+	  directory.  Does completion on available packages when
+	  querying for package names.  Will also search for .tgz files
+	  in addition for .tar.gz files.  Tries to reload
+	  auto-autoloads, as a convenience when loading new packages,
+	  and also tries to add any new package paths to `load-path'.
+ 	  Changed all occurences of `concat' to use `expand-file-name'.
+
+	* package-ui.el: New file which implements the main visual
+	  package browser/installer, which is started via a menu pick or 
+	  M-x pui-list packages.
+
+1998-09-03  Hrvoje Niksic  <hniksic@srce.hr>
+
+	* startup.el (load-init-file): spelling fix.
+
+1998-09-02  Michael Sperber [Mr. Preprocessor]  <sperber@informatik.uni-tuebingen.de>
+
+	* startup.el (normal-top-level): Load auto-autoload files
+	covariantly with their precedence.
+
+1998-08-26  Jan Vroonhof  <vroonhof@math.ethz.ch>
+
+	* menubar-items.el (default-menubar): Remove "Font Weight"
+	option, there is currently no custom equivalent.. Customize-faces
+	is "Edit faces".
+
+	* x-font-menu.el (font-menu-set-font): Use customize to set
+	default face.
+
+	* faces.el (face-spec-update-all-matching): New function.
+
+	* cus-face.el (custom-set-face-update-spec): New function.
+	Interface to customize faces from elisp.
+
+	(custom-face-value-create): Show the customized settings if set
+	but not saved.
+
+1998-08-26  Jan Vroonhof  <vroonhof@math.ethz.ch>
+
+	(custom-face-value-create): Show the customized settings if set
+	but not saved.
+
+1998-08-31  Hrvoje Niksic  <hniksic@srce.hr>
+
+	* keydefs.el (global-map): Add FSF 20.3 binding of
+	query-replace-regexp.
+
+1998-08-26  SL Baur  <steve@altair.xemacs.org>
+
+	* obsolete.el (column-number-start-at-one): Make obsolete.
+
 1998-08-22  SL Baur  <steve@altair.xemacs.org>
 
 	* XEmacs 21.0-pre11 is released.

lisp/auto-autoloads.el

 Uses `package-get-base' to determine just what is required and what
 package provides that functionality.  If VERSION is nil, retrieves
 latest version.  Optional argument FETCHED-PACKAGES is used to keep
-track of packages already fetched." t nil)
+track of packages already fetched.
+
+Returns nil upon error." t nil)
 
 (autoload 'package-get "package-get" "\
 Fetch PACKAGE from remote site.
 package is already installed.  Valid values for CONFLICT are:
 'always	always retrieve the package even if it is already installed
 'never	do not retrieve the package if it is installed.
+INSTALL-DIR, if non-nil, specifies the package directory where
+fetched packages should be installed.
 
 The value of `package-get-base' is used to determine what files should 
 be retrieved.  The value of `package-get-remote' is used to determine
 
 Once the package is retrieved, its md5 checksum is computed.  If that
 sum does not match that stored in `package-get-base' for this version
-of the package, an error is signalled." t nil)
+of the package, an error is signalled.
+
+Returns `t' upon success, the symbol `error' if the package was
+successfully installed but errors occurred during initialization, or
+`nil' upon error." t nil)
 
 (autoload 'package-get-package-provider "package-get" "\
 Search for a package that provides SYM and return the name and
 
 ;;;***
 
+;;;### (autoloads (pui-list-packages pui-add-install-directory) "package-ui" "lisp/package-ui.el")
+
+(autoload 'pui-add-install-directory "package-ui" "\
+Add a new package binary directory to the head of `package-get-remote'.
+Note that no provision is made for saving any changes made by this function.
+It exists mainly as a convenience for one-time package installations from
+disk." t nil)
+
+(autoload 'pui-list-packages "package-ui" "\
+List all packages and package information.
+The package name, version, and description are displayed.  From the displayed
+buffer, the user can see which packages are installed, which are not, and
+which are out-of-date (a newer version is available).  The user can then
+select packages for installation via the keyboard or mouse." t nil)
+
+;;;***
+
 ;;;### (autoloads (picture-mode) "picture" "lisp/picture.el")
 
 (autoload 'picture-mode "picture" "\
 	     (unless (widget-get widget :custom-form)
 		 (widget-put widget :custom-form custom-face-default-form))
 	     (let* ((symbol (widget-value widget))
-		    (spec (or (get symbol 'saved-face)
+		    (spec (or (get symbol 'customized-face)
+			      (get symbol 'saved-face)
 			      (get symbol 'face-defface-spec)
 			      ;; Attempt to construct it.
 			      (list (list t (face-custom-attributes-get
 	(error nil)))
     result))
 
+(defsubst custom-face-get-spec (symbol)
+  (or (get symbol 'customized-face)
+      (get symbol 'saved-face)
+      (get symbol 'face-defface-spec)
+      ;; Attempt to construct it.
+      (list (list t (face-custom-attributes-get
+		     symbol (selected-frame))))))
+
 (defun custom-set-face-bold (face value &optional frame)
   "Set the bold property of FACE to VALUE."
   (if value
 	 (fontobj (font-create-object font)))
     (font-family fontobj)))
 
+(defun custom-set-face-update-spec (face display plist)
+  "Customize the FACE for display types matching DISPLAY, merging
+  in the new items from PLIST"
+  (let ((spec (face-spec-update-all-matching (custom-face-get-spec face)
+					     display plist)))
+    (put face 'customized-face spec)
+    (face-spec-set face spec)))
+
 ;;; Initializing.
 
 ;;;###autoload

lisp/custom-load.el

 (custom-add-loads 'isearch '("isearch-mode"))
 (custom-add-loads 'font-lock-faces '("font-lock"))
 (custom-add-loads 'modeline '("modeline"))
-(custom-add-loads 'editing '("simple" "abbrev" "fill" "mouse" "dragdrop" "cus-edit"))
+(custom-add-loads 'packages '("package-get-custom"))
+(custom-add-loads 'editing '("simple" "abbrev" "fill" "mouse" "cus-edit" "dragdrop"))
 (custom-add-loads 'matching '("simple" "isearch-mode" "hyper-apropos"))
 (custom-add-loads 'i18n '("cus-edit"))
 (custom-add-loads 'info '("toolbar-items" "info"))
 	 (setq default-custom-frame-properties
 	       (extract-custom-frame-properties (selected-frame))))))
 
+(defun face-spec-update-all-matching (spec display plist)
+  "Update all entries in the face spec that could match display to
+have the entries from the new plist and return the new spec"
+  (mapcar
+   (lambda (e)
+     (let ((entries (car e))
+	   (options (cadr e))
+	   (match t)
+	   dplist
+	   (new-options plist)
+	   )
+       (unless (eq display t)
+	 (mapc (lambda (arg)
+		 (setq dplist (plist-put dplist (car arg) (cadr arg))))
+	       display))
+       (unless (eq entries t)
+	 (mapc (lambda (arg)
+		 (setq match (and match (eq (cadr arg)
+					    (plist-get
+					      dplist (car arg)
+					      (cadr arg))))))
+	       entries))
+       (if (not match)
+	   e
+	 (while new-options
+	   (setq options
+		 (plist-put options (car new-options) (cadr new-options)))
+	   (setq new-options (cddr new-options)))
+	 (list entries options))))
+   (copy-sequence spec)))
+       
+		    
+
 (defun face-spec-set-match-display (display &optional frame)
   "Return non-nil if DISPLAY matches FRAME.
 DISPLAY is part of a spec such as can be used in `defface'.
 
 
 
+(define-key global-map "\M-%" 'query-replace)
 
-
-
-(define-key global-map "\M-%" 'query-replace)
+;; FSF v20 binding
+(define-key global-map [(control meta %)] 'query-replace-regexp)
 
 
 ; autoloaded

lisp/list-mode.el

        :user-data
        :reference-buffer
        (:help-string completion-default-help-string)
+       (:completion-string "Possible completions are:")
        :window-width)
       ()
     (let ((old-buffer (current-buffer))
 			      (if (/= (% count cols) 0) ; want ceiling...
 				  (1+ (/ count cols))
                                 (/ count cols)))))))
-	      (princ (gettext "Possible completions are:"))
+	      (if (stringp cl-completion-string)
+		  (princ (gettext cl-completion-string)))
 	      (let ((tail completions)
 		    (r 0)
 		    (regexp-string

lisp/menubar-items.el

        ["Set..." customize-customized]
        ["Apropos..." customize-apropos]
        ["Browse..." customize-browse]
+       ["List Packages" pui-list-packages]
        ["Update Packages" package-get-custom])
       ("Editing Options"
        ["Overstrike"
 		     (fboundp 'browse-url-grail))]
        )
       "-----"
-      ["Browse Faces..." (customize-face nil)]
+      ["Edit Faces..." (customize-face nil)]
       ("Font"   :filter font-menu-family-constructor)
       ("Size"	:filter font-menu-size-constructor)
-      ("Weight"	:filter font-menu-weight-constructor)
+;      ("Weight"	:filter font-menu-weight-constructor)
       "-----"
       ["Save Options" customize-save-customized]
       )

lisp/package-admin.el

 (defvar package-admin-temp-buffer "*Package Output*"
   "Temporary buffer where output of backend commands is saved.")
 
+(defvar package-admin-install-function 'package-admin-default-install-function
+  "The function to call to install a package.
+Three args are passed: FILENAME PKG-DIR BUF
+Install package FILENAME into directory PKG-DIR, with any messages output
+to buffer BUF.")
+
+(defvar package-admin-error-messages '(
+				       "No space left on device"
+				       "No such file or directory"
+				       "Filename too long"
+				       "Read-only file system"
+				       "File too large"
+				       "Too many open files"
+				       "Not enough space"
+				       "Permission denied"
+				       "Input/output error"
+				       "Out of memory"
+				       "Unable to create directory"
+				       "Directory checksum error"
+				       "Cannot exclusively open file"
+				       "corrupted file"
+				       "incomplete .* tree"
+				       "Bad table"
+				       "corrupt input"
+				       "invalid compressed data"
+				       "too many leaves in Huffman tree"
+				       "not a valid zip file"
+				       "first entry not deflated or stored"
+				       "encrypted file --"
+				       "unexpected end of file"
+				       )
+  "Regular expressions of possible error messages.
+After each package extraction, the `package-admin-temp-buffer' buffer is
+scanned for these messages.  An error code is returned if one of these are
+found.
+
+This is awful, but it exists because error return codes aren't reliable
+under MS Windows.")
+
 ;;;###autoload
 (defun package-admin-add-single-file-package (file destdir &optional pkg-dir)
   "Install a single file Lisp package into XEmacs package hierarchy.
 		  ;; rest of command line follows
 		  package-admin-xemacs file destination)))
 
-;;;###autoload
-(defun package-admin-add-binary-package (file &optional pkg-dir)
-  "Install a pre-bytecompiled XEmacs package into package hierarchy."
-  (interactive "fPackage tarball: ")
+(defun package-admin-install-function-mswindows (file pkg-dir buf)
+  "Install function for mswindows"
+  (let ( (default-directory pkg-dir) )
+    (call-process "djtar" nil buf t "-x" file)
+    ))
+
+(defun package-admin-default-install-function (file pkg-dir buf)
+  "Default function to install a package.
+Install package FILENAME into directory PKG-DIR, with any messages output
+to buffer BUF."
+  (let (filename)
+    (setq filename (expand-file-name file pkg-dir))
+    (if (shell-command (concat "gunzip -c " filename " | tar xvf -") buf)
+	0
+      1)
+    ))
+
+;  (call-process "add-big-package.sh"
+;		nil
+;		buf
+;		t
+;		;; rest of command line follows
+;		package-admin-xemacs file pkg-dir))
+
+(defun package-admin-get-install-dir (pkg-dir)
   (when (null pkg-dir)
     (when (or (not (listp late-packages))
 	      (not late-packages))
       (error "No package path"))
     (setq pkg-dir (car (last late-packages))))
+  pkg-dir
+  )
 
-  (let ((buf (get-buffer-create package-admin-temp-buffer)))
-    (call-process "add-big-package.sh"
-		  nil
-		  buf
-		  t
-		  ;; rest of command line follows
-		  package-admin-xemacs file pkg-dir)))
+;;;###autoload
+(defun package-admin-add-binary-package (file &optional pkg-dir)
+  "Install a pre-bytecompiled XEmacs package into package hierarchy."
+  (interactive "fPackage tarball: ")
+  (setq pkg-dir (package-admin-get-install-dir pkg-dir))
+  (let ((buf (get-buffer-create package-admin-temp-buffer))
+	(status 1)
+	start err-list
+	)
+    ;; Insure that the current directory doesn't change
+    (save-excursion
+      (set-buffer buf)
+      (setq default-directory pkg-dir)
+      (setq case-fold-search t)
+      (buffer-disable-undo)
+      (goto-char (setq start (point-max)))
+      (if (= 0 (setq status (funcall package-admin-install-function
+				     file pkg-dir buf)))
+	  (catch 'done
+	    (goto-char start)
+	    (setq err-list package-admin-error-messages)
+	    (while err-list
+	      (if (re-search-forward (car err-list) nil t)
+		  (progn
+		    (setq status 1)
+		    (throw 'done nil)
+		    ))
+	      (setq err-list (cdr err-list))
+	      )
+	    ))
+      )
+    status
+    ))
 
 (provide 'package-admin)
 

lisp/package-get.el

     ("ftp.xemacs.org" "/pub/xemacs/package"))
   "*List of remote sites to contact for downloading packages.
 List format is '(site-name directory-on-site).  Each site is tried in
-order until the package is found.")
+order until the package is found.  As a special case, `site-name' can be
+`nil', in which case `directory-on-site' is treated as a local directory.")
 
 (defvar package-get-remove-copy nil
   "*After copying and installing a package, if this is T, then remove the
 copy.  Otherwise, keep it around.")
 
+(defun package-get-rmtree (directory)
+  "Delete a directory and all of its contents, recursively.
+This is a feeble attempt at making a portable rmdir."
+  (let ( (orig-default-directory default-directory) files dirs dir)
+    (unwind-protect
+	(progn
+	  (setq directory (file-name-as-directory directory))
+	  (setq files (directory-files directory nil nil nil t))
+	  (setq dirs (directory-files directory nil nil nil 'dirs))
+	  (while dirs
+	    (setq dir (car dirs))
+	    (if (file-symlink-p dir)	;; just in case, handle symlinks
+		(delete-file dir)
+	      (if (not (or (string-equal dir ".") (string-equal dir "..")))
+		  (package-get-rmtree (expand-file-name dir directory))))
+	    (setq dirs (cdr dirs))
+	    )
+	  (setq default-directory directory)
+	  (condition-case err
+	      (progn
+		(while files
+		  (delete-file (car files))
+		  (setq files (cdr files))
+		  )
+		(delete-directory directory)
+		)
+	    (file-error
+	     (message "%s: %s: \"%s\"" (nth 1 err) (nth 2 err) (nth 3 err)))
+	    )
+	  )
+      (progn
+	(setq default-directory orig-default-directory)
+	))
+    ))
+
 ;;;###autoload
 (defun package-get-update-all ()
   "Fetch and install the latest versions of all currently installed packages."
   (interactive)
   ;; Load a fresh copy
-  (mapcar (lambda (pkg)
-	    (package-get (car pkg) nil 'never))
-          packages-package-list))
+  (catch 'exit
+    (mapcar (lambda (pkg)
+	      (if (not (package-get (car pkg) nil 'never))
+		  (throw 'exit nil)		;; Bail out if error detected
+		  ))
+	    packages-package-list)))
+
+(defun package-get-interactive-package-query (get-version package-symbol)
+  "Perform interactive querying for package and optional version.
+Query for a version if GET-VERSION is non-nil.  Return package name as
+a symbol instead of a string if PACKAGE-SYMBOL is non-nil.
+The return value is suitable for direct passing to `interactive'."
+  (let ( (table (mapcar '(lambda (item)
+			   (let ( (name (symbol-name (car item))) )
+			     (cons name name)
+			     ))
+			package-get-base)) 
+	 package package-symbol default-version version)
+    (save-window-excursion
+      (setq package (completing-read "Package: " table nil t))
+      (setq package-symbol (intern package))
+      (if get-version
+	  (progn
+	    (setq default-version 
+		  (package-get-info-prop 
+		   (package-get-info-version
+		    (package-get-info-find-package package-get-base
+						   package-symbol) nil)
+		   'version))
+	    (while (string=
+		    (setq version (read-string "Version: " default-version))
+		    "")
+	      )
+	    (if package-symbol
+		(list package-symbol version)
+	      (list package version))
+	    )
+	(if package-symbol
+	    (list package-symbol)
+	  (list package)))
+      )))
 
 ;;;###autoload
 (defun package-get-all (package version &optional fetched-packages)
 Uses `package-get-base' to determine just what is required and what
 package provides that functionality.  If VERSION is nil, retrieves
 latest version.  Optional argument FETCHED-PACKAGES is used to keep
-track of packages already fetched."
-  (interactive "sPackage: \nsVersion: ")
+track of packages already fetched.
+
+Returns nil upon error."
+  (interactive (package-get-interactive-package-query t nil))
   (let* ((the-package (package-get-info-find-package package-get-base
 						     package))
 	 (this-package (package-get-info-version
 			the-package version))
 	 (this-requires (package-get-info-prop this-package 'requires))
 	 )
-    (setq version (package-get-info-prop this-package 'version))
-    (unless (package-get-installedp package version)
-      (package-get package version))
-    (setq fetched-packages
-	  (append (list package)
-		  (package-get-info-prop this-package 'provides)
-		  fetched-packages))
-    ;; grab everything that this package requires plus recursively
-    ;; grab everything that the requires require.  Keep track
-    ;; in `fetched-packages' the list of things provided -- this
-    ;; keeps us from going into a loop
-    (while this-requires
-      (if (not (member (car this-requires) fetched-packages))
-	  (let* ((reqd-package (package-get-package-provider
-				(car this-requires)))
-		 (reqd-version (cadr reqd-package))
-		 (reqd-name (car reqd-package)))
-	    (if (null reqd-name)
-		(error "Unable to find a provider for %s" (car this-requires)))
-	    (setq fetched-packages
-		  (package-get-all reqd-name reqd-version fetched-packages)))
-	)
-      (setq this-requires (cdr this-requires)))
+    (catch 'exit
+      (setq version (package-get-info-prop this-package 'version))
+      (unless (package-get-installedp package version)
+	(if (not (package-get package version))
+	    (progn
+	      (setq fetched-packages nil)
+	      (throw 'exit nil))))
+      (setq fetched-packages
+	    (append (list package)
+		    (package-get-info-prop this-package 'provides)
+		    fetched-packages))
+      ;; grab everything that this package requires plus recursively
+      ;; grab everything that the requires require.  Keep track
+      ;; in `fetched-packages' the list of things provided -- this
+      ;; keeps us from going into a loop
+      (while this-requires
+	(if (not (member (car this-requires) fetched-packages))
+	    (let* ((reqd-package (package-get-package-provider
+				  (car this-requires)))
+		   (reqd-version (cadr reqd-package))
+		   (reqd-name (car reqd-package)))
+	      (if (null reqd-name)
+		  (error "Unable to find a provider for %s"
+			 (car this-requires)))
+	      (if (not (setq fetched-packages
+			     (package-get-all reqd-name reqd-version
+					      fetched-packages)))
+		  (throw 'exit nil)))
+	  )
+	(setq this-requires (cdr this-requires)))
+      )
     fetched-packages
     ))
 
+(defun package-get-load-package-file (lispdir file)
+  (let (pathname)
+    (setq pathname (expand-file-name file lispdir))
+    (condition-case err
+	(progn
+	  (load pathname t)
+	  t)
+      (t
+       (message "Error loading package file \"%s\" %s!" pathname err)
+       nil))
+    ))
+
+(defun package-get-init-package (lispdir)
+  "Initialize the package.
+This really assumes that the package has never been loaded.  Updating
+a newer package can cause problems, due to old, obsolete functions in
+the old package.
+
+Return `t' upon complete success, `nil' if any errors occurred."
+  (progn
+    (if (and lispdir
+	     (file-accessible-directory-p lispdir))
+	(progn
+	  ;; Add lispdir to load-path if it doesn't already exist.
+	  ;; NOTE: this does not take symlinks, etc., into account.
+	  (if (let ( (dirs load-path) )
+		(catch 'done
+		  (while dirs
+		    (if (string-equal (car dirs) lispdir)
+			(throw 'done nil))
+		    (setq dirs (cdr dirs))
+		    )
+		  t))
+	      (setq load-path (cons lispdir load-path)))
+	  (package-get-load-package-file lispdir "auto-autoloads")
+	  t)
+      nil)
+    ))
+
 ;;;###autoload
 (defun package-get (package &optional version conflict install-dir)
   "Fetch PACKAGE from remote site.
 
 Once the package is retrieved, its md5 checksum is computed.  If that
 sum does not match that stored in `package-get-base' for this version
-of the package, an error is signalled."
-  (interactive "xPackage List: ")
+of the package, an error is signalled.
+
+Returns `t' upon success, the symbol `error' if the package was
+successfully installed but errors occurred during initialization, or
+`nil' upon error."
+  (interactive (package-get-interactive-package-query nil t))
   (let* ((this-package
 	  (package-get-info-version
 	   (package-get-info-find-package package-get-base
 					  package) version))
 	 (found nil)
 	 (search-dirs package-get-remote)
-	 (filename (package-get-info-prop this-package 'filename)))
+	 (base-filename (package-get-info-prop this-package 'filename))
+	 (package-status t)
+	 filenames full-package-filename package-lispdir)
     (if (null this-package)
 	(error "Couldn't find package %s with version %s"
 	       package version))
-    (if (null filename)
+    (if (null base-filename)
 	(error "No filename associated with package %s, version %s"
 	       package version))
+    (if (null install-dir)
+	(setq install-dir (package-admin-get-install-dir nil)))
+
+    ;; Contrive a list of possible package filenames.
+    ;; Ugly.  Is there a better way to do this?
+    (setq filenames (cons base-filename nil))
+    (if (string-match "^\\(..*\\)\.tar\.gz$" base-filename)
+	(setq filenames (cons (concat (match-string 1 base-filename) ".tgz")
+			      filenames)))
+
     (setq version (package-get-info-prop this-package 'version))
     (unless (and (eq conflict 'never)
 		 (package-get-installedp package version))
-      ;; Find the package from search list in package-get-remote
+      ;; Find the package from the search list in package-get-remote
       ;; and copy it into the staging directory.  Then validate
       ;; the checksum.  Finally, install the package.
-      (while (and search-dirs
-		  (not (file-exists-p (package-get-staging-dir filename))))
-	(if (file-exists-p (package-get-remote-filename
-			    (car search-dirs) filename))
-	    (copy-file (package-get-remote-filename (car search-dirs) filename)
-		       (package-get-staging-dir filename))
-	  (setq search-dirs (cdr search-dirs))
+      (catch 'done
+	(let (search-filenames current-dir-entry host dir current-filename)
+	  ;; In each search directory ...
+	  (while search-dirs
+	    (setq current-dir-entry (car search-dirs)
+		  host (car current-dir-entry)
+		  dir (car (cdr current-dir-entry))
+		  search-filenames filenames)
+
+	    ;; Look for one of the possible package filenames ...
+	    (while search-filenames
+	      (setq current-filename (car search-filenames))
+	      (if (null host)
+		  (progn
+		    ;; No host means look on the current system.
+		    (setq full-package-filename
+			  (substitute-in-file-name
+			   (expand-file-name current-filename
+					     (file-name-as-directory dir))))
+		    )
+		;; If the file exists on the remote system ...
+		(if (file-exists-p (package-get-remote-filename
+				    current-dir-entry current-filename))
+		    (progn
+		      ;; Get it
+		      (setq full-package-filename
+			    (package-get-staging-dir current-filename))
+		      (message "Retrieving package `%s' ..." 
+			       current-filename)
+		      (sit-for 0)
+		      (copy-file (package-get-remote-filename current-dir-entry
+							      current-filename)
+				 ))))
+	      ;; If we found it, we're done.
+	      (if (file-exists-p full-package-filename)
+		  (throw 'done nil))
+	      ;; Didn't find it.  Try the next possible filename.
+	      (setq search-filenames (cdr search-filenames))
+	      )
+	    ;; Try looking in the next possible directory ...
+	    (setq search-dirs (cdr search-dirs))
+	    )
 	  ))
-      (if (not (file-exists-p (package-get-staging-dir filename)))
-	  (error "Unable to find file %s" filename))
+
+      (if (or (not full-package-filename)
+	      (not (file-exists-p full-package-filename)))
+	  (error "Unable to find file %s" base-filename))
       ;; Validate the md5 checksum
       ;; Doing it with XEmacs removes the need for an external md5 program
+      (message "Validating checksum for `%s'..." package) (sit-for 0)
       (with-temp-buffer
 	;; What ever happened to i-f-c-literally
 	(let (file-name-handler-alist)
-	  (insert-file-contents-internal (package-get-staging-dir filename)))
+	  (insert-file-contents-internal full-package-filename))
 	(if (not (string= (md5 (current-buffer))
 			  (package-get-info-prop this-package
 						 'md5sum)))
-	    (error "Package %s does not match md5 checksum" filename)))
-      (message "Retrieved package %s" filename) (sit-for 0)
+	    (error "Package %s does not match md5 checksum" base-filename)))
+
+      ;; Now delete old lisp directory, if any
+      ;;
+      ;; Gads, this is ugly.  However, we're not supposed to use `concat'
+      ;; in the name of portability.
+      (if (and (setq package-lispdir (expand-file-name "lisp" install-dir))
+	       (setq package-lispdir (expand-file-name (symbol-name package)
+						       package-lispdir))
+	       (file-accessible-directory-p package-lispdir))
+	  (progn
+	    (message "Removing old lisp directory \"%s\" ..." package-lispdir)
+	    (sit-for 0)
+	    (package-get-rmtree package-lispdir)
+	    ))
+
+      (message "Installing package `%s' ..." package) (sit-for 0)
       (let ((status
-	     (package-admin-add-binary-package
-	      (package-get-staging-dir filename)
-              install-dir)))
-	(when (not (= status 0))
-	  (message "Package failed.")
-	  (switch-to-buffer package-admin-temp-buffer)))
-      (sit-for 0)
-      (message "Added package") (sit-for 0)
+	     (package-admin-add-binary-package full-package-filename
+					       install-dir)))
+	(if (= status 0)
+	    (progn
+	      ;; clear messages so that only messages from
+	      ;; package-get-init-package are seen, below.
+	      (clear-message)
+	      (if (package-get-init-package package-lispdir)
+		  (progn
+		    (message "Added package `%s'" package)
+		    (sit-for 0)
+		    )
+		(progn
+		  ;; display message only if there isn't already one.
+		  (if (not (current-message))
+		      (progn
+			(message "Added package `%s' (errors occurred)"
+				 package)
+			(sit-for 0)
+			))
+		  (if package-status
+		      (setq package-status 'errors))
+		  ))
+	      )
+	  (message "Installation of package %s failed." base-filename)
+	  (sit-for 0)
+	  (switch-to-buffer package-admin-temp-buffer)
+	  (setq package-status nil)
+	  ))
       (setq found t))
     (if (and found package-get-remove-copy)
-	(delete-file (package-get-staging-dir filename)))
+	(delete-file full-package-filename))
+    package-status
     ))
 
 (defun package-get-info-find-package (which name)
   `package-get-info-find-package'.  If VERSION is nil, then return the 
   first (aka most recent) version.  Use `package-get-info-find-prop'
   to retrieve a particular property from the value returned by this."
-  (interactive "xPackage Info: \nsVersion: ")
+  (interactive (package-get-interactive-package-query t t))
   (while (and version package (not (string= (plist-get (car package) 'version) version)))
     (setq package (cdr package)))
   (if package (car package)))
   (interactive "FPackage filename: ")
   (if (not (file-exists-p package-get-dir))
       (make-directory package-get-dir))
-  (concat 
-   (file-name-as-directory package-get-dir)
-   (file-name-nondirectory (or (nth 2 (efs-ftp-path filename)) filename))))
+  (expand-file-name
+   (file-name-nondirectory (or (nth 2 (efs-ftp-path filename)) filename))
+   (file-name-as-directory package-get-dir)))
        
 
 (defun package-get-remote-filename (search filename)
   (let ((custom-buffer (find-file-noselect 
 			(or (package-get-file-installed-p 
 			     "package-get-custom.el")
-			    (concat (file-name-directory 
-				     (package-get-file-installed-p 
-				      "package-get-base.el"))
-				    "package-get-custom.el"))))
+			    (expand-file-name
+			     "package-get-custom.el"
+			     (file-name-directory 
+			      (package-get-file-installed-p 
+			       "package-get-base.el"))
+			     ))))
 	(pkg-groups nil))
 
     ;; clear existing stuff

lisp/package-ui.el

+;;; package-ui.el ---
+
+;; Copyright (C) 1998 by Darryl Okahata
+
+;; Author: Darryl Okahata <darrylo@sr.hp.com>
+;; Keywords: internal
+
+;; This file is part of XEmacs.
+
+;; XEmacs 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 2, or (at your option)
+;; any later version.
+
+;; XEmacs 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 XEmacs; see the file COPYING.  If not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+;; 02111-1307, USA.
+
+;;; Synched up with: Not in FSF
+
+(require 'package-get)		;; which, in turn, requires 'package-admin
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; User-changeable variables:
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar pui-up-to-date-package-face nil
+  "The face to use for packages that are up-to-date.")
+
+(defvar pui-selected-package-face (get-face 'bold)
+  "The face to use for selected packages.
+Set this to `nil' to use the `default' face.")
+
+(defvar pui-outdated-package-face (get-face 'red)
+  "The face to use for outdated packages.
+Set this to `nil' to use the `default' face.")
+
+(defvar pui-uninstalled-package-face (get-face 'italic)
+  "The face to use for uninstalled packages.
+Set this to `nil' to use the `default' face.")
+
+(defvar pui-list-verbose t
+  "If non-nil, display verbose info in the package list buffer.")
+
+(defvar pui-info-buffer "*Packages*"
+  "Buffer to use for displaying package information.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; End of user-changeable variables.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar pui-selected-packages nil
+  "The list of user-selected packages to install.")
+
+(defvar pui-display-keymap
+  (let ((m (make-keymap)))
+    (suppress-keymap m)
+    (set-keymap-name m 'pui-display-keymap)
+    (define-key m "q" 'pui-quit)
+    (define-key m "g" 'pui-list-packages)
+    (define-key m " " 'pui-display-info)
+    (define-key m "?" 'pui-help)
+    (define-key m "v" 'pui-toggle-verbosity-redisplay)
+    (define-key m "d" 'pui-toggle-verbosity-redisplay)
+    (define-key m [return] 'pui-toggle-package-key)
+    (define-key m "x" 'pui-install-selected-packages)
+    (define-key m "I" 'pui-install-selected-packages)
+    (define-key m "n" 'next-line)
+    (define-key m "+" 'next-line)
+    (define-key m "p" 'previous-line)
+    (define-key m "-" 'previous-line)
+    m)
+  "Keymap to use in the `pui-info-buffer' buffer")
+
+(defvar pui-package-keymap
+  (let ((m (make-sparse-keymap)))
+    (set-keymap-name m 'pui-package-keymap)
+    (define-key m 'button2 'pui-toggle-package-event)
+    (define-key m 'button3 'pui-toggle-package-event)
+    m)
+  "Keymap to use over package names/descriptions.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; End of variables
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuration routines
+
+(defun pui-directory-exists (dir)
+  "Check to see if DIR exists in `package-get-remote'."
+  (let (found)
+    (mapcar '(lambda (item)
+	       (if (and (null (car item))
+			(string-equal (file-name-as-directory (car (cdr item)))
+				      (file-name-as-directory dir)))
+		   (setq found t))
+	       ) package-get-remote)
+    found
+    ))
+
+(defun pui-package-dir-list (buffer)
+  "In BUFFER, format the list of package binary paths."
+  (let ( (count 1) paths sys dir)
+    (set-buffer buffer)
+    (buffer-disable-undo buffer)
+    (erase-buffer buffer)
+    (insert "Existing package binary paths:\n\n")
+    (setq paths package-get-remote)
+    (while paths
+      (setq sys (car (car paths))
+	    dir (car (cdr (car paths))))
+      (insert (format "%2s. " count))
+      (if (null sys)
+	  (insert dir)
+	(insert sys ":" dir))
+      (insert "\n")
+      (setq count (1+ count))
+      (setq paths (cdr paths))
+      )
+    (insert "\nThese are the places that will be searched for package binaries.\n")
+    (goto-char (point-min))
+    ))
+
+;;;###autoload
+(defun pui-add-install-directory (dir)
+  "Add a new package binary directory to the head of `package-get-remote'.
+Note that no provision is made for saving any changes made by this function.
+It exists mainly as a convenience for one-time package installations from
+disk."
+  (interactive (let ( (tmpbuf (get-buffer-create
+			       "*Existing Package Binary Paths*"))
+		      dir)
+		 (save-window-excursion
+		   (save-excursion
+		     (unwind-protect
+			 (progn
+			   (pui-package-dir-list tmpbuf)
+			   (display-buffer tmpbuf)
+			   (setq dir (read-directory-name
+				      "New package binary directory to add? "
+				      nil nil t))
+			   )
+		       (kill-buffer tmpbuf)
+		       )))
+		 (list dir)
+		 ))
+  (progn
+    (if (not (pui-directory-exists dir))
+	(progn
+	  (setq package-get-remote (cons (list nil dir) package-get-remote))
+	  (message "Package directory \"%s\" added." dir)
+	  )
+      (message "Directory \"%s\" already exists in `package-get-remote'." dir))
+    ))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Package list/installer routines
+
+(defun pui-quit ()
+  (interactive)
+  (kill-buffer nil))
+
+(defun pui-help ()
+  (interactive)
+  (let ( (help-buffer (get-buffer-create "*Help*")) )
+    (display-buffer help-buffer t)
+    (save-window-excursion
+      (set-buffer help-buffer)
+      (buffer-disable-undo help-buffer)
+      (erase-buffer help-buffer)
+      (insert (pui-help-string))
+      )
+    ))
+
+(defun pui-package-symbol-char (pkg-sym version)
+  (progn
+    (if (package-get-info-find-package packages-package-list pkg-sym)
+	(if (package-get-installedp pkg-sym version)
+	    (list " " pui-up-to-date-package-face)
+	  (list "*" pui-outdated-package-face))
+      (list "-" pui-uninstalled-package-face))
+    ))
+
+(defun pui-update-package-display (extent &optional pkg-sym version)
+  "Update the package status for EXTENT.
+If PKG-SYM or VERSION are not given, they are read from the extent.
+These are used to determine whether or not the package is installed,
+and whether or not it is up-to-date."
+  (let (buffer-read-only disp sym-char)
+    (if (not pkg-sym)
+	(setq pkg-sym (extent-property extent 'pui-package)))
+    (if (not version)
+	(setq version (package-get-info-prop (extent-property extent 'pui-info)
+					     'version)))
+    (if (member pkg-sym pui-selected-packages)
+	(progn
+	  (if pui-selected-package-face
+	      (set-extent-face extent (get-face pui-selected-package-face))
+	    (set-extent-face extent (get-face 'default)))
+	  (setq sym-char "+")
+	  )
+      (progn
+	(setq disp (pui-package-symbol-char pkg-sym version))
+	(setq sym-char (car disp))
+	(if (cdr disp)
+	    (set-extent-face extent (car (cdr disp)))
+	  (set-extent-face extent (get-face 'default)))
+	))
+    (save-excursion
+      (goto-char (extent-start-position extent))
+      (delete-char 1)
+      (insert sym-char)
+      (set-buffer-modified-p nil)
+      )
+    ))
+
+(defun pui-toggle-package (extent)
+  (let (pkg-sym)
+    (setq pkg-sym (extent-property extent 'pui-package))
+    (if (member pkg-sym pui-selected-packages)
+	(setq pui-selected-packages
+	      (delete pkg-sym pui-selected-packages))
+      (setq pui-selected-packages
+	    (cons pkg-sym pui-selected-packages)))
+    (pui-update-package-display extent pkg-sym)
+    ))
+
+(defun pui-toggle-package-key ()
+  "Select/unselect package for installation, using the keyboard."
+  (interactive)
+  (let (extent)
+    (if (setq extent (extent-at (point) (current-buffer) 'pui))
+	(progn
+	  (pui-toggle-package extent)
+	  (forward-line 1)
+	  )
+      (error "No package under cursor!"))
+    ))
+
+(defun pui-toggle-package-event (event)
+  "Select/unselect package for installation, using the mouse."
+  (interactive "e")
+  (let* ( (ep (event-point event))
+          (buffer (window-buffer (event-window event)))
+          (extent (extent-at ep buffer 'pui-package))
+          )
+    (pui-toggle-package extent)
+    ))
+
+(defun pui-toggle-verbosity-redisplay ()
+  "Toggle verbose package info."
+  (interactive)
+  (progn
+    (setq pui-list-verbose (not pui-list-verbose))
+    (pui-list-packages)
+    ))
+
+(defun pui-install-selected-packages ()
+  "Install selected packages."
+  (interactive)
+  (let ( (tmpbuf "*Packages-To-Install*") do-install)
+    (if pui-selected-packages
+	(progn
+	  ;; Don't change window config when asking the user if he really
+	  ;; wants to install the packages.  We do this to avoid messing up
+	  ;; the window configuration if errors occur (we don't want to
+	  ;; display random buffers in addition to the error buffer, if
+	  ;; errors occur, which would normally be caused by display-buffer).
+	  (save-window-excursion
+	    (with-output-to-temp-buffer tmpbuf
+	      (display-completion-list (sort
+					(mapcar '(lambda (pkg)
+						   (symbol-name pkg)
+						   )
+						pui-selected-packages)
+					'string<)
+				       :activate-callback nil
+				       :help-string "Packages selected for installation:\n"
+				       :completion-string t
+				       ))
+	    (setq tmpbuf (get-buffer-create tmpbuf))
+	    (display-buffer tmpbuf)
+	    (setq do-install (y-or-n-p "Install these packages? "))
+	    (kill-buffer tmpbuf)
+	    )
+	  (if do-install
+	      (progn
+		(save-excursion
+		  ;; Clear old temp buffer history
+		  (set-buffer (get-buffer-create package-admin-temp-buffer))
+		  (buffer-disable-undo package-admin-temp-buffer)
+		  (erase-buffer package-admin-temp-buffer)
+		  )
+		(message "Installing selected packages ...") (sit-for 0)
+		(if (catch 'done
+		      (mapcar (lambda (pkg)
+				(if (not (package-get-all pkg nil))
+				    (throw 'done nil)))
+			      pui-selected-packages)
+		      t)
+		    (progn
+		      (pui-list-packages)
+		      (message "Packages installed")
+		      ))
+		)
+	      (clear-message)
+	      )
+	  )
+      (error "No packages have been selected!"))
+    ))
+
+(defun pui-help-echo (extent &optional force-update)
+  "Display additional package info in the modeline.
+EXTENT determines the package to display (the package information is
+attached to the extent as properties)."
+  (let (pkg-sym info inst-ver auth-ver date maintainer)
+    (if (or force-update (not (current-message))
+	    (string-match ".*: .*: " (current-message))
+	    )
+	(progn
+	  (setq pkg-sym (extent-property extent 'pui-package)
+		info (extent-property extent 'pui-info)
+		inst-ver (package-get-key pkg-sym :version)
+		auth-ver (package-get-info-prop info 'author-version)
+		date (package-get-info-prop info 'date)
+		maintainer (package-get-info-prop info 'maintainer))
+	  (if (not inst-ver)
+	      (setq inst-ver ""))
+	  (if pui-list-verbose
+	      (format "Author version: %-8s %11s: %s"
+		      auth-ver date maintainer)
+	    (format "%-6s: %-8s %11s: %s"
+		    inst-ver auth-ver date maintainer))
+	  ))
+    ))
+
+(defun pui-display-info (&optional no-error)
+  "Display additional package info in the modeline.
+Designed to be called interactively (from a keypress)."
+  (interactive)
+  (let (extent)
+    (save-excursion
+      (beginning-of-line)
+      (if (setq extent (extent-at (point) (current-buffer) 'pui))
+	  (message (pui-help-echo extent t))
+	(if no-error
+	    (clear-message nil)
+	  (error "No package under cursor!")))
+      )))
+
+(defun pui-help-string ()
+  "Return the help string for the package-info buffer.
+This is not a defconst because of the call to substitute-command-keys."
+  (save-excursion
+    (set-buffer (get-buffer pui-info-buffer))
+    (substitute-command-keys
+"Symbols in the leftmost column:
+
+  +	The package is marked for installation.
+  -     The package has not been installed.
+  *     The currently installed package is old, and a newer version is
+	available.
+
+Useful keys:
+
+  `\\[pui-toggle-package-key]' to select/unselect the current package for installation.
+  `\\[pui-install-selected-packages]' to install selected packages.
+  `\\[pui-display-info]' to display additional information about the package in the modeline.
+  `\\[pui-list-packages]' to refresh the package list.
+  `\\[pui-toggle-verbosity-redisplay]' to toggle between a verbose and non-verbose display.
+  `\\[pui-quit]' to kill this buffer.
+")
+    ))
+
+;;;###autoload
+(defun pui-list-packages ()
+  "List all packages and package information.
+The package name, version, and description are displayed.  From the displayed
+buffer, the user can see which packages are installed, which are not, and
+which are out-of-date (a newer version is available).  The user can then
+select packages for installation via the keyboard or mouse."
+  (interactive)
+  (let ( (outbuf (get-buffer-create pui-info-buffer))
+	 (sep-string "===============================================================================\n")
+	 start )
+    (message "Creating package list ...") (sit-for 0)
+    (set-buffer outbuf)
+    (setq buffer-read-only nil)
+    (buffer-disable-undo outbuf)
+    (erase-buffer outbuf)
+    (use-local-map pui-display-keymap)
+    (if pui-list-verbose
+	(insert "                 Latest Installed
+  Package name   Vers.  Vers.   Description
+")
+      (insert "                 Latest
+  Package name   Vers.  Description
+"))
+    (insert sep-string)
+    (setq start (point))
+    (mapcar '(lambda (pkg)
+	       (let (pkg-sym info version desc
+			     b e extent current-vers disp)
+		 (setq pkg-sym (car pkg)
+		       info (package-get-info-version (cdr pkg) nil))
+		 (setq version (package-get-info-prop info 'version)
+		       desc (package-get-info-prop info 'description))
+
+		 (setq disp (pui-package-symbol-char pkg-sym
+						     version))
+		 (setq b (point))
+		 (if pui-list-verbose
+		     (progn
+		       (setq current-vers (package-get-key pkg-sym :version))
+		       (if (not current-vers)
+			   (setq current-vers "-----"))
+		       (insert
+			(format "%s %-15s %-5s  %-5s  %s\n"
+				(car disp) pkg-sym version current-vers desc))
+;;		       (insert
+;;			(format "\t\t  %-12s  %s\n"
+;;				(package-get-info-prop info 'author-version)
+;;				(package-get-info-prop info 'date)
+;;				))
+		       )
+		   (insert (format "%s %-15s %-5s %s\n"
+				   (car disp)
+				   pkg-sym version desc)))
+		 (save-excursion
+		   (setq e (progn
+			     (forward-line -1)
+			     (end-of-line)
+			     (point)))
+		   )
+		 (setq extent (make-extent b e))
+		 (if (cdr disp)
+		     (set-extent-face extent (car (cdr disp)))
+		   (set-extent-face extent (get-face 'default)))
+		 (set-extent-property extent 'highlight t)
+		 (set-extent-property extent 'pui t)
+		 (set-extent-property extent 'pui-package pkg-sym)
+		 (set-extent-property extent 'pui-info info)
+		 (set-extent-property extent 'help-echo 'pui-help-echo)
+		 (set-extent-property extent 'keymap pui-package-keymap)
+		 )) (sort (copy-sequence package-get-base)
+			  '(lambda (a b)
+			     (string< (symbol-name (car a))
+				      (symbol-name (car b)))
+			       )))
+    (insert sep-string)
+    (insert (pui-help-string))
+    (set-buffer-modified-p nil)
+    (setq buffer-read-only t)
+    (pop-to-buffer outbuf)
+    (delete-other-windows)
+    (goto-char start)
+    (setq pui-selected-packages nil)	; Reset list
+    (clear-message)
+;    (message (substitute-command-keys "Press `\\[pui-help]' for help."))
+    ))
+
+(provide 'package-ui)
+
+;;; package-ui.el ends here
     
     (if (not inhibit-autoloads)
 	(progn
-	  (packages-load-package-auto-autoloads last-package-load-path)
+	  (if (not inhibit-early-packages)
+	      (packages-load-package-auto-autoloads early-package-load-path))
 	  (packages-load-package-auto-autoloads late-package-load-path)
-	  (if (not inhibit-early-packages)
-	      (packages-load-package-auto-autoloads early-package-load-path))))
+	  (packages-load-package-auto-autoloads last-package-load-path)))
 
     (unwind-protect
 	(command-line)
 	   (message "Error in init file: %s" (error-message-string error))
 	   (display-warning 'initialization
 	     (format "\
-An error has occured while loading %s:
+An error has occurred while loading %s:
 
 %s
 

lisp/x-font-menu.el

 	 (from-size   (aref font-data 2))
 	 (from-weight (aref font-data 3))
 	 (from-slant  (aref font-data 4))
-	 new-default-face-font)
+	 new-default-face-font
+	 new-props)
     (unless from-family
       (signal 'error '("couldn't parse font name for default face")))
-    (setq new-default-face-font
-	  (font-menu-load-font (or family from-family)
-			       (or weight from-weight)
-			       (or size   from-size)
-			       from-slant
-			       font-menu-preferred-resolution))
+    (when weight
+      (signal 'error '("Setting weight currently not supported")))
+;    (setq new-default-face-font
+;	  (font-menu-load-font (or family from-family)
+;			       (or weight from-weight)
+;			       (or size   from-size)
+;			       from-slant
+;			       font-menu-preferred-resolution))
     (dolist (face (delq 'default (face-list)))
       (when (face-font-instance face)
 	(message "Changing font of `%s'..." face)
 	   (sit-for 1)))))
     ;; Set the default face's font after hacking the other faces, so that
     ;; the frame size doesn't change until we are all done.
-
-    ;;; WMP - we need to honor font-menu-this-frame-only-p here!
-    (set-face-font 'default new-default-face-font
-		   (and font-menu-this-frame-only-p (selected-frame)))
+    
+    (when (and family (not (equal family from-family)))
+      (setq new-props (append (list :family family) new-props)))
+    (when (and size (not (equal size from-size)))
+      (setq new-props (append (list :size (int-to-string
+					  (/ size 10))) new-props)))
+    (custom-set-face-update-spec 'default '((type x)) new-props)
+    ;;; WMP - we need to honor font-menu-this-frame-only-p here!      
+;    (set-face-font 'default new-default-face-font
+;		   (and font-menu-this-frame-only-p (selected-frame)))
     (message "Font %s" (face-font-name 'default))))
 
 
+1998-09-05  SL Baur  <steve@altair.xemacs.org>
+
+	* XEmacs 21.0-pre12 is released.
+
+1998-09-03  Darryl Okahata  <darrylo@sr.hp.com>
+
+	* xemacs/packages.texi: Correct and update package documentation.
+	  Updated the package installation section to mention the visual 
+	  package browser/installer.
+
 1998-08-22  SL Baur  <steve@altair.xemacs.org>
 
 	* XEmacs 21.0-pre11 is released.

man/lispref/commands.texi

 also specify the modifier keys that were held down at the time.
 
 @item misc-user event
-  A menu item was selected, the scrollbar was used, or a drag or a drop occured.
+  A menu item was selected, the scrollbar was used, or a drag or a drop occurred.
 
 @item process event
   Input is available on a process.
 @end group
 
 @group
-;; @r{Create a simmilar button-release event.}
+;; @r{Create a similar button-release event.}
 (make-event 'button-release `(button 1 modifiers (meta) x ,x y ,x))
      @result{} #<buttonup-event meta-button1up>
 @end group

man/lispref/display.texi

 across several lines.  Here is an example of how a warning is displayed:
 
 @example
-(1) (initialization/error) An error has occured while loading ~/.emacs:
+(1) (initialization/error) An error has occurred while loading ~/.emacs:
 
 Symbol's value as variable is void: bogus-variable
 
 
 @table @code
 @item @var{atom}
-A character is invisible if its @code{invisible} propery value
+A character is invisible if its @code{invisible} property value
 is @var{atom} or if it is a list with @var{atom} as a member.
 
 @item (@var{atom} . t)
-A character is invisible if its @code{invisible} propery value
+A character is invisible if its @code{invisible} property value
 is @var{atom} or if it is a list with @var{atom} as a member.
 Moreover, if this character is at the end of a line and is followed
 by a visible newline, it displays an ellipsis.

man/lispref/dragndrop.texi

 interface may change! The current implementation is considered experimental.
 
   Drag'n'drop is a way to transfer information between multiple applications.
-To do this serveral GUIs define their own protocols. Examples are OffiX, CDE,
+To do this several GUIs define their own protocols. Examples are OffiX, CDE,
 Motif, KDE, MSWindows, GNOME, and many more. To catch all these protocols,
 XEmacs provides a generic API.
 
 @section Supported Protocols
 
 The current release of XEmacs only support a small set of Drag'n'drop
-protocols. Some of these only support limited options avaiable in the API.
+protocols. Some of these only support limited options available in the API.
 
 @menu
 * OffiX DND::           A generic X based protocol.
 XEmacs supports both MIME and URL drags and drops using this API. No application 
 interaction is possible while dragging is in progress.
 
-For infomation about the OffiX project have a look at http://leb.net/~offix/
+For information about the OffiX project have a look at http://leb.net/~offix/
 
 @node CDE dt
 @subsection CDE dt
 @code{experimental-dragdrop-drop-functions} for a function that can handle the 
 dropped data.
 
-To modify the drop behaviour, the user can modify the variable
+To modify the drop behavior, the user can modify the variable
 @code{experimental-dragdrop-drop-functions}. Each element of this list
 specifies a possible handler for dropped data. The first one that can handle
 the data will return @code{t} and exit. Another possibility is to set a

man/lispref/edebug-inc.texi

 is instrumented.  It does this by calling @code{edebug-on-entry} and
 then switching to @code{go} mode.
 
-Although the automatic instrumentating is convenient, it is not
+Although the automatic instrumentation is convenient, it is not
 later automatically uninstrumented.
 
 @item h
 @cindex backquote (Edebug)
 Backquote (@kbd{`}) is a macro that results in an expression that may or
 may not be evaluated.  It is often used to simplify the definition of a
-macro to return an expression that is evaluted, but Edebug does not know
+macro to return an expression that is evaluated, but Edebug does not know
 when this is the case.  However, the forms inside unquotes (@code{,} and
 @code{,@@}) are evaluated and Edebug instruments them.
 

man/lispref/edebug.texi

 sometimes.
 
 There is a bug in window updating when there is both a trace buffer
-and an evaluation list - the source buffer doesnt get displayed.
+and an evaluation list - the source buffer doesn't get displayed.
 
 @item 
 Killing and reinserting an instrumented definition or parts of

man/lispref/errors.texi

 
 @item setting-constant
 @code{"Attempt to set a constant symbol"}@* 
-The values of the symbols @code{nil} and @code{t}
-may not be changed.@*
 @xref{Constant Variables, , Variables that Never Change}.
 
 @c XEmacs feature
 @item undefined-keystroke-sequence
 @code{"Undefined keystroke sequence"}@*
 
-@c XEmacs feature
-@item underflow-error
-@code{"Arithmetic underflow error"}@*
-
 @ignore FSF Emacs only
 @item undefined-color
 @code{"Undefined color"}@*

man/lispref/menus.texi

 way that should be familiar to users of any of a certain family of popular PC
 operating systems.
 
-This behaviour can be changed by modifying the bindings in
+This behavior can be changed by modifying the bindings in
 menu-accelerator-map.  At this point, the online help is your best bet
 for more information about how to modify the menu traversal keys.
 
 @defvar menu-accelerator-modifiers
 A list of modifier keys which must be pressed in addition to a valid menu
 accelerator in order for the top level menu to be activated in response to
-a keystroke.  The default value of @code{(meta)} mirrors the useage of the alt key
+a keystroke.  The default value of @code{(meta)} mirrors the usage of the alt key
 as a menu accelerator in popular PC operating systems.
 
 The modifier keys in @var{menu-accelerator-modifiers} must match exactly the

man/lispref/modes.texi

 @end defvar
 
 @defvar interpreter-mode-alist
-This variable specifes major modes to use for scripts that specify a
+This variable specifies major modes to use for scripts that specify a
 command interpreter in an @samp{#!} line.  Its value is a list of
 elements of the form @code{(@var{interpreter} . @var{mode})}; for
 example, @code{("perl" . perl-mode)} is one element present by default.

man/lispref/objects.texi

 
 NOTE: Under XEmacs 19, characters are really just integers, and thus
 characters and integers are @code{eq}.  Under XEmacs 20, it was
-necessary to preserve remants of this in function such as @code{old-eq}
+necessary to preserve remnants of this in function such as @code{old-eq}
 in order to maintain byte-code compatibility.  Byte code compiled
 under any Emacs 19 will automatically have calls to @code{eq} mapped
 to @code{old-eq} when executed under XEmacs 20.

man/lispref/os.texi

 This function is used to open a @dfn{termscript file} that will record
 all the characters sent by XEmacs to the terminal. (If there are
 multiple tty or stream devices, all characters sent to all such devices
-are recorded.) The funcion returns @code{nil}.  Termscript files are
+are recorded.) The function returns @code{nil}.  Termscript files are
 useful for investigating problems where XEmacs garbles the screen,
 problems that are due to incorrect Termcap entries or to undesirable
 settings of terminal options more often than to actual XEmacs bugs.

man/lispref/positions.texi

 
 If @var{body} changes the current buffer, @code{save-restriction} still
 restores the restrictions on the original buffer (the buffer whose
-restructions it saved from), but it does not restore the identity of the
+restrictions it saved from), but it does not restore the identity of the
 current buffer.
 
 @code{save-restriction} does @emph{not} restore point and the mark; use

man/lispref/searching.texi

   A @dfn{regular expression} (@dfn{regexp}, for short) is a pattern that
 denotes a (possibly infinite) set of strings.  Searching for matches for
 a regexp is a very powerful operation.  This section explains how to write
-regexps; the following section says how to search for them.
+regexps; the following section says how to search using them.
 
  To gain a thorough understanding of regular expressions and how to use
 them to best advantage, we recommend that you study @cite{Mastering
 1997}. (It's known as the "Hip Owls" book, because of the picture on its
 cover.)  You might also read the manuals to @ref{(gawk)Top},
 @ref{(ed)Top}, @cite{sed}, @cite{grep}, @ref{(perl)Top},
-@ref{(regex)Top}, @ref{(rx)Top}, @cite{pcre}, and @ref{(flex)Top}, which
-also make good use of regular expressions.
+@ref{(regex)Top}, @ref{(rx)Top}, @cite{pcre}, and @ref{(flex)Top}.  All
+of these programs and libraries make effective use of regular
+expressions.
 
  The XEmacs regular expression syntax most closely resembles that of
 @cite{ed}, or @cite{grep}, the GNU versions of which all utilize the GNU
 @cite{regex} library.  XEmacs' version of @cite{regex} has recently been
-extended with some Perl--like capabilities, described in the next
-section.
+extended with some Perl--like capabilities, which are described in the
+next section.
 
 @menu
 * Syntax of Regexps::       Rules for writing regular expressions.
 @cindex @samp{?} in regexp
 is a quantifying suffix operator similar to @samp{*}, except that the
 preceding expression can match either once or not at all.  For example,
-@samp{ca?r} matches @samp{car} or @samp{cr}, but does not match anyhing
+@samp{ca?r} matches @samp{car} or @samp{cr}, but does not match anything
 else.
 
 @item *?
 @dfn{non-greedy} quantifier, a regexp construct borrowed from Perl.
 @c Did perl get this from somewhere?  What's the real history of *? ?
 
-This construct very useful for when you want to match the text inside a
-pair of delimiters.  For instance, @samp{/\*.*?\*/} will match C
-comments in a string.  This could not be achieved without the use of
-greedy quantifier.
+This construct is very useful for when you want to match the text inside
+a pair of delimiters.  For instance, @samp{/\*.*?\*/} will match C
+comments in a string.  This could not be so elegantly achieved without
+the use of a nongreedy quantifier.
 
 This construct has not been available prior to XEmacs 20.4.  It is not
 available in FSF Emacs.
 the same exact text.
 
 @item \(?: @dots{} \)
-@cindex @samp{\(?:} in regexp
+@cindex @samp{(?:} in regexp
 @cindex regexp grouping
 is called a @dfn{shy} grouping operator, and it is used just like
-@samp{\( @dots{} \)}, except that it does not cause the matched
+@samp{\( @dots{} \)}, except that it does not cause the match
 substring to be recorded for future reference.
 
-This is useful when you need a lot of grouping @samp{\( @dots{} \)}
-constructs, but only want to remember one or two.  Then you can use 
-not want to remember them for later use with @code{match-string}.
+This is useful when you need to use a lot of nested grouping @samp{\(
+@dots{} \)} constructs to express complex alternation, but only want to
+memoize, or capture, one or two of the subexpression matches.  Since
+@samp{\(?: @dots{} \)} doesn't capture a submatch, it also doesn't need
+to be counted when you count @samp{\( @dots{} \)} groups to figure the
+@samp{match-string} index.  That turns out to be a very convenient
+characteristic.
 
-Using @samp{\(?: @dots{} \)} rather than @samp{\( @dots{} \)} when you
-don't need the captured substrings ought to speed up your programs some,
-since it shortens the code path followed by the regular expression
-engine, as well as the amount of memory allocation and string copying it
-must do.  The actual performance gain to be observed has not been
-measured or quantified as of this writing.
-@c This is used to good advantage by the font-locking code, and by
-@c `regexp-opt.el'.  ... It will be.  It's not yet, but will be.
+This situtation occurs where parts of a regular expression have been
+automaticly generated by a program that builds them from lists of
+strings, and the static code following the matching operation must
+access a specific match number.  Here's an example that shows this:
+
+@example
+@group
+;; Assume that:
+(require 'regexp-opt) ;; gets executed at toplevel
+;;; `regexp-opt.el' is part of the "xemacs-devel" package.
+;; ... and that VARNAMES is a list of strings holding the name of some
+;; variables extracted from the program source you are editting and
+;; running this function on.  For this example, it will just be bound
+;; in the let* expression.
+(let* ((varnames '("k" "n" "i" "j" "varname"))
+       (keys-regexp (regexp-opt
+		     (mapcar #'symbol-name
+			     '(if then else elif
+			       case in of do while
+			       with for next unless
+			       cond begin end))))
+      (varname-regexp (regexp-opt varnames))
+      (contrived-regexp (concat "\\(" keys-regexp "\\)"
+				"\\s-(\\s-\\("
+				varname-regexp
+				"\\)\\s-)"))
+      (keyname "")
+      (varname ""))
+  ;; In the body of this particular defun, we:
+  (re-search-forward contrived-regexp nil t)
+  ;; ... and it finds a match.  Now we want to extract the text that
+  ;; it matched on, and save it into KEYNAME and VARNAME.
+  (setq keyname (match-string 1)
+	varname (match-string 2))
+  ;; ... and then do something with those values.
+  (list keyname varname))
+
+;; Here's something for it to match, so you can try it with `C-x C-e'.
+;; while ( j ) do ...
+@end group
+@end example
+
+Here you can see that if the regular expression returned by
+@samp{regexp-opt} did not use @samp{\(?: @dots{} \)} for grouping, and
+instead used @samp{\( @dots{} \)}, it would be necessary to count the
+number of opening parentheses in the @samp{keys-regexp} and to use that
+figure to calculate which match number is matched by the
+@code{varname-regexp}.  It is much more convienient to be able to just
+ask for the second match string.
+
+@c This is used to good advantage by the font-locking code....
+@c ... It will be.  It's not yet, but will be.
 
 The shy grouping operator has been borrowed from Perl, and has not been
 available prior to XEmacs 20.3, nor is it available in FSF Emacs.

man/lispref/tooltalk.texi

 
 @defun create-tooltalk-message
 Create a new ToolTalk message.  The message's session attribute is
-initialized to the default session.  Other attributes can be intialized
+initialized to the default session.  Other attributes can be initialized
 with @code{set-tooltalk-message-attribute}.
 @code{make-tooltalk-message} is the preferred way to create and
 initialize a message.

man/lispref/variables.texi

 @vindex t
 @kindex setting-constant
 
-  XEmacs Lisp has two special symbols, @code{nil} and @code{t}, that
-always evaluate to themselves.  These symbols cannot be rebound, nor can
-their value cells be changed.  An attempt to change the value of
-@code{nil} or @code{t} signals a @code{setting-constant} error.
+In XEmacs Lisp, some symbols always evaluate to themselves: the two
+special symbols @code{nil} and @code{t}, as well as @dfn{keyword
+symbols}, that is, symbols whose name begins with the character
+@samp{@code{:}}.  These symbols cannot be rebound, nor can their value
+cells be changed.  An attempt to change the value of @code{nil} or
+@code{t} signals a @code{setting-constant} error.
 
 @example
 @group
 
 If the first character of @var{doc-string} is @samp{*}, it means that
 this variable is considered a user option.  This lets users set the
-variable conventiently using the commands @code{set-variable} and
+variable conveniently using the commands @code{set-variable} and
 @code{edit-options}.
 
 For example, this form defines @code{foo} but does not set its value:

man/xemacs/packages.texi

 number.)  The core distribution contains the sources of XEmacs and a
 minimal set of Emacs Lisp files, which are in the subdirectory named
 @file{lisp}.  This subdirectory used to contain all Emacs Lisp files
-distributed with XEmacs.
+distributed with XEmacs.  Now, to conserve disk space, most
+non-essential packages were made optional.
 
 @subsection Choosing the Packages You Need
 
 The available packages can currently be found in the same ftp directory
 where you grabbed the core distribition from, and are located in the
-subdirectory @file{binary-packages}. Package file names follow the
-naming convention @file{<package-name>-<version>-pkg.tar.gz}.
+subdirectory @file{packages/binary-packages}.  Package file names follow
+the naming convention @file{<package-name>-<version>-pkg.tar.gz}.
+
+If you have EFS @ref{(EFS)}, packages can be installed over the network.
+Alternatively, if you have copies of the packages locally, you can
+install packages from a local disk or CDROM.
 
 The file @file{etc/PACKAGES} in the core distribution contains a list of
 the packages available at the time of the XEmacs release.  Packages are
 	Options->Customize->Emacs->Packages
 @end example
 
-If you have EFS @ref{(EFS)}, installed and configured packages can be
-installed completely from the menubar.
+However, don't select any of these menu picks unless you actually want 
+to install the given package (and have properly configured your system 
+to do so).
+
+You can also get a list of available packages, and whether or not they
+are installed, using the visual package browser and installer.  You can
+access it via the menus:
+
+@example
+	Options->Customize->List Packages
+@end example
+
+Or, you can get to it via the keyboard:
+
+@example
+M-x pui-list-packages
+@end example
 
 Hint to system administrators of multi-user systems: it might be a good
-idea to install all packages and not to interfer with the wishes of your
+idea to install all packages and not interfere with the wishes of your
 users.
 
-@subsection Installing packages and XEmacs
+@subsection XEmacs and Installing Packages
 
-The easiest and most correct way to install a package is to do:
+Normally, packages are installed over the network, using EFS
+@ref{(EFS)}.  However, you may not have network access, or you may
+already have some or all of the packages on a local disk, such as a
+CDROM.  If you want to install from a local disk, you must first tell
+XEmacs where to find the package binaries.  This is done by adding a line
+like the following to your @file{.emacs} file:
 
 @example
-M-x package-admin-add-binary-package <return>
+(setq package-get-remote (cons (list nil "/my/path/to/package/binaries")
+                               package-get-remote))
 @end example
 
-input the location of the package tarball and XEmacs will do the rest
-for you.  If you have the EFS package installed and configured you can
-select package from the customize menu, set their state to on and then
-do:
+Here, you'd change @code{"/my/path/to/package/binaries"} to be the path
+to your local package binaries.  Next, restart XEmacs, and you're ready
+to go (advanced users can just re-evaluate the sexp).
+
+If you're going to install over the network, you only have to insure
+that EFS @ref{(EFS)} works, and that it can get outside a firewall, if
+you happen to be behind one.  You shouldn't have to do anything else;
+XEmacs already knows where to go.
+
+The easiest way to install a package is to use the visual package
+browser and installer, using the menu pick:
+
+@example
+	Options->Customize->List Packages
+@end example
+
+You can also access it using the keyboard:
+
+@example
+M-x pui-list-packages
+@end example
+
+The visual package browser will then display a list of all packages.
+Help information will be displayed at the very bottom of the buffer; you
+may have to scroll down to see it.  You can also press @kbd{?} to get
+the same help.  From this buffer, you can tell the package status by the
+character in the first column:
+
+@table @kbd
+@item -
+The package has not been installed.
+@item *
+The package has been installed, but a newer version is available.  The
+current version is out-of-date.
+@item +
+The package has been marked for installation/update.
+@end table
+
+If there is no character in the first column, the package has been
+installed and is up-to-date.
+
+From here, you can select or unselect packages for installation using
+the @key{RET} key, or using the @kbd{Mouse-2} or @kbd{Mouse-3} buttons.
+Once you've finished selecting the packages, you can press the @kbd{x}
+key to actually install the packages.  Note that you will have to
+restart XEmacs for XEmacs to recognize any new packages.
+
+Key summary:
+
+@table @kbd
+@item ?
+Display simple help.
+@item @key{RET}
+@itemx @key{Mouse-2}
+@itemx @key{Mouse-3}
+Toggle between selecting and unselecting a package for installation.
+@item x
+Install selected packages.
+@item @key{SPC}
+View, in the minibuffer, additional information about the package, such
+as the package date (not the build date) and the package author.  Moving 
+the mouse over a package name will also do the same thing.
+@item v
+Toggle between verbose and non-verbose package display.
+@item g
+Refresh the package display.
+@item q
+Kill the package buffer.
+@end table
+
+Moving the mouse over a package will also cause additional information
+about the package to be displayed in the minibuffer.
+
+@subsection Other package installation interfaces
+
+For an alternative package interface, you can select packages from the
+customize menus, under:
+
+@example
+	Options->Customize->Emacs->Packages-> ...
+@end example
+
+Set their state to on, and then do:
 
 @example
 	Options->Customize->Update Packages
 @end example
 
 This will automatically retrieve the packages you have selected from the
-XEmacs ftp site and install them into XEmacs. Additionally it will
-update any packages you already have installed to the newest version.
-Note that if a package is newly installed you will have to restart