diff lisp/packages/man.el @ 72:b9518feda344 r20-0b31

Import from CVS: tag r20-0b31
author cvs
date Mon, 13 Aug 2007 09:03:46 +0200
parents 131b0175ea99
children 54cc21c15cbb
line wrap: on
line diff
--- a/lisp/packages/man.el	Mon Aug 13 09:03:07 2007 +0200
+++ b/lisp/packages/man.el	Mon Aug 13 09:03:46 2007 +0200
@@ -1,8 +1,11 @@
 ;;; man.el --- browse UNIX manual pages
-;; Keywords: help
+
+;; Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc.
 
-;; Copyright (C) 1985, 1993, 1994 Free Software Foundation, Inc.
-;;
+;; Author:		Barry A. Warsaw <bwarsaw@cen.com>
+;; Keywords:		help
+;; Adapted-By:		ESR, pot
+
 ;; This file is part of XEmacs.
 
 ;; XEmacs is free software; you can redistribute it and/or modify it
@@ -16,1211 +19,1046 @@
 ;; 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.
+;; 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 synched with FSF.
-;;; ICK!  This file is almost completely different from FSF.
-;;; Someone clarify please.
+;;; Synched up with: FSF 19.34.
 
-;; Mostly rewritten by Alan K. Stebbens <aks@hub.ucsb.edu> 11-apr-90.
-;;
-;;  o  Match multiple man pages using TOPIC as a simple pattern
-;;  o  Search unformatted pages, even when formatted matches are found
-;;  o  Query the user as to which pages are desired
-;;  o  Use of the prefix arg to toggle/bypass the above features
-;;  o  Buffers named by the first topic in the buffer
-;;  o  Automatic uncompress for compressed man pages (.Z, .z, and .gz)
-;;  o  View the resulting buffer using M-x view mode
-;;
-;; Modified 16-mar-91 by Jamie Zawinski <jwz@lucid.com> to default the 
-;; manual topic to the symbol at point, just like find-tag does.
-;;
-;; Modified 22-mar-93 by jwz to use multiple fonts and follow xrefs with mouse.
-;;
-;; Modified 16-apr-93 by Dave Gillespie <daveg@synaptics.com> to make
-;; apropos work nicely; work correctly when bold or italic is unavailable; 
-;; reuse old buffer if topic is re-selected (in Manual-topic-buffer mode).
-;;
-;; Modified 4-apr-94 by jwz: merged in Tibor Polgar's code for manpath.conf.
-;;
-;; Modified 19-apr-94 by Tibor Polgar <tlp00@spg.amdahl.com> to add support for
-;; $PAGER variable to be emacsclient and properly process man pages (assuming
-;; the man pages were built by man in /tmp.  also fixed bug with man list being
-;; backwards.
-;;
-;; Modified 23-aug-94 by Tibor Polgar <tlp00@spg.amdahl.com> to add support for
-;; displaying only one instance of a man page (Manual-unique-man-sections-only)
-;; Fixed some more man page ordering bugs, bug with Manual-query-multiple-pages.
+;;; Commentary:
+
+;; This code provides a function, `man', with which you can browse
+;; UNIX manual pages.  Formatting is done in background so that you
+;; can continue to use your Emacs while processing is going on.
 ;;
-;; Modified 29-nov-94 by Ben Wing <wing@spg.amdahl.com>: small fixes
-;; that should hopefully make things work under HPUX and IRIX.; 
-;;
-;; Modified 15-jul-95 by Dale Atems <atems@physics.wayne.edu>:
-;; some extensive rewriting to make things work right (more or less)
-;; under IRIX.
-;;
-;; Modified 08-mar-96 by Hubert Palme <palme@wrcs3.urz.uni-wuppertal.de>:
-;; added /usr/share/catman to the manual directory list for IRIX (5.3)
-;; 
-;; This file defines "manual-entry", and the remaining definitions all
-;; begin with "Manual-".  This makes the autocompletion on "M-x man" work.
-;;
-;; Variables of interest:
-;;
-;;	Manual-program
-;;	Manual-topic-buffer
-;;	Manual-buffer-view-mode
-;;	Manual-directory-list
-;;	Manual-formatted-directory-list
-;;	Manual-match-topic-exactly
-;;	Manual-query-multiple-pages
-;;	Manual-page-history
-;;	Manual-subdirectory-list
-;;	Manual-man-page-section-ids
-;;	Manual-formatted-page-prefix
-;;	Manual-unformatted-page-prefix
-;;	Manual-use-full-section-ids
+;; The mode also supports hypertext-like following of manual page SEE
+;; ALSO references, and other features.  See below or do `?' in a
+;; manual page buffer for details.
+
+;; ========== Credits and History ========== 
+;; In mid 1991, several people posted some interesting improvements to
+;; man.el from the standard emacs 18.57 distribution.  I liked many of
+;; these, but wanted everything in one single package, so I decided
+;; to incorporate them into a single manual browsing mode.  While
+;; much of the code here has been rewritten, and some features added,
+;; these folks deserve lots of credit for providing the initial
+;; excellent packages on which this one is based.
+
+;; Nick Duffek <duffek@chaos.cs.brandeis.edu>, posted a very nice
+;; improvement which retrieved and cleaned the manpages in a
+;; background process, and which correctly deciphered such options as
+;; man -k.
+
+;; Eric Rose <erose@jessica.stanford.edu>, submitted manual.el which
+;; provided a very nice manual browsing mode.
+
+;; This package was available as `superman.el' from the LCD package
+;; for some time before it was accepted into Emacs 19.  The entry
+;; point and some other names have been changed to make it a drop-in
+;; replacement for the old man.el package.
+
+;; Francesco Potorti` <pot@cnuce.cnr.it> cleaned it up thoroughly,
+;; making it faster, more robust and more tolerant of different
+;; systems' man idiosyncrasies.
+
+;; ========== Features ==========
+;; + Runs "man" in the background and pipes the results through a
+;;   series of sed and awk scripts so that all retrieving and cleaning
+;;   is done in the background. The cleaning commands are configurable.
+;; + Syntax is the same as Un*x man
+;; + Functionality is the same as Un*x man, including "man -k" and
+;;   "man <section>", etc.
+;; + Provides a manual browsing mode with keybindings for traversing
+;;   the sections of a manpage, following references in the SEE ALSO
+;;   section, and more.
+;; + Multiple manpages created with the same man command are put into
+;;   a narrowed buffer circular list.
 
-(defvar Manual-program "man" "\
-*Name of the program to invoke in order to format the source man pages.")
+;; ============= TODO ===========
+;; - Add a command for printing.
+;; - The awk script deletes multiple blank lines.  This behaviour does
+;;   not allow to understand if there was indeed a blank line at the
+;;   end or beginning of a page (after the header, or before the
+;;   footer).  A different algorithm should be used.  It is easy to
+;;   compute how many blank lines there are before and after the page
+;;   headers, and after the page footer.  But it is possible to compute
+;;   the number of blank lines before the page footer by euristhics
+;;   only.  Is it worth doing?
+;; - Allow a user option to mean that all the manpages should go in
+;;   the same buffer, where they can be browsed with M-n and M-p.
+;; - Allow completion on the manpage name when calling man.  This
+;;   requires a reliable list of places where manpages can be found.  The
+;;   drawback would be that if the list is not complete, the user might
+;;   be led to believe that the manpages in the missing directories do
+;;   not exist.
+
+
+;;; Code:
+
+(require 'assoc)
+
+;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+;; empty defvars (keep the compiler quiet)
 
-(defvar Manual-section-switch (if (eq system-type 'usg-unix-v) "-s" nil)
-  "SysV needs this to work right.")
+(defvar Man-notify)
+(defvar Man-current-page)
+(defvar Man-page-list)
+(defvar Man-filter-list nil
+  "*Manpage cleaning filter command phrases.
+This variable contains a list of the following form:
+
+'((command-string phrase-string*)*)
+
+Each phrase-string is concatenated onto the command-string to form a
+command filter.  The (standard) output (and standard error) of the Un*x
+man command is piped through each command filter in the order the
+commands appear in the association list.  The final output is placed in
+the manpage buffer.")
 
-(defvar Manual-topic-buffer t "\
-*Non-nil means \\[Manual-entry] should output the manual entry for TOPIC into
-a buffer named *man TOPIC*, otherwise, it should name the buffer
-*Manual Entry*.")
+(defvar Man-original-frame)
+(defvar Man-arguments)
+(defvar Man-sections-alist)
+(defvar Man-refpages-alist)
+(defvar Man-uses-untabify-flag t
+  "When non-nil use `untabify' instead of Man-untabify-command.")
+(defvar Man-page-mode-string)
+(defvar Man-sed-script nil
+  "Script for sed to nuke backspaces and ANSI codes from manpages.")
+
+;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+;; user variables
+
+(defvar Man-fontify-manpage-flag t
+  "*Make up the manpage with fonts.")
+
+(defvar Man-overstrike-face 'bold
+  "*Face to use when fontifying overstrike.")
 
-(defvar Manual-buffer-view-mode t "\
-*Whether manual buffers should be placed in view-mode.
-nil means leave the buffer in fundamental-mode in another window.
-t means use `view-buffer' to display the man page in the current window.
-Any other value means use `view-buffer-other-window'.")
+(defvar Man-underline-face 'underline
+  "*Face to use when fontifying underlining.")
+
+;; Use the value of the obsolete user option Man-notify, if set.
+(defvar Man-notify-method (if (boundp 'Man-notify) Man-notify 'friendly)
+  "*Selects the behavior when manpage is ready.
+This variable may have one of the following values, where (sf) means
+that the frames are switched, so the manpage is displayed in the frame
+where the man command was called from:
 
-(defvar Manual-match-topic-exactly t "\
-*Non-nil means that \\[manual-entry] will match the given TOPIC exactly, rather
-apply it as a pattern.  When this is nil, and \"Manual-query-multiple-pages\"
-is non-nil, then \\[manual-entry] will query you for all matching TOPICs.
-This variable only has affect on the preformatted man pages (the \"cat\" files),
-since the \"man\" command always does exact topic matches.")
+newframe   -- put the manpage in its own frame (see `Man-frame-parameters')
+pushy      -- make the manpage the current buffer in the current window
+bully      -- make the manpage the current buffer and only window (sf)
+aggressive -- make the manpage the current buffer in the other window (sf)
+friendly   -- display manpage in the other window but don't make current (sf)
+polite     -- don't display manpage, but prints message and beep when ready
+quiet      -- like `polite', but don't beep
+meek       -- make no indication that the manpage is ready
 
-(defvar Manual-query-multiple-pages nil "\
-*Non-nil means that \\[manual-entry] will query the user about multiple man
-pages which match the given topic.  The query is done using the function 
-\"y-or-n-p\".  If this variable is nil, all man pages with topics matching the
-topic given to \\[manual-entry] will be inserted into the temporary buffer.
-See the variable \"Manual-match-topic-exactly\" to control the matching.")
+Any other value of `Man-notify-method' is equivalent to `meek'.")
+
+(defvar Man-frame-parameters nil
+  "*Frame parameter list for creating a new frame for a manual page.")
 
-(defvar Manual-unique-man-sections-only nil
-  "*Only present one man page per section.  This variable is useful if the same or
-up/down level man pages for the same entry are present in mulitple man paths.
-When set to t, only the first entry found in a section is displayed, the others
-are ignored without any messages or warnings.  Note that duplicates can occur if
-the system has both formatted and unformatted version of the same page.")
+(defvar Man-downcase-section-letters-flag t
+  "*Letters in sections are converted to lower case.
+Some Un*x man commands can't handle uppercase letters in sections, for
+example \"man 2V chmod\", but they are often displayed in the manpage
+with the upper case letter.  When this variable is t, the section
+letter (e.g., \"2V\") is converted to lowercase (e.g., \"2v\") before
+being sent to the man background process.")
 
-(defvar Manual-mode-hook nil
-  "Function or functions run on entry to Manual-mode.")
+(defvar Man-circular-pages-flag t
+  "*If t, the manpage list is treated as circular for traversal.")
 
-(defvar Manual-directory-list nil "\
-*A list of directories used with the \"man\" command, where each directory
-contains a set of \"man?\" and \"cat?\" subdirectories.  If this variable is nil,
-it is initialized by \\[Manual-directory-list-init].")
+(defvar Man-section-translations-alist
+  (list
+   '("3C++" . "3")
+   ;; Some systems have a real 3x man section, so let's comment this.
+   ;; '("3X" . "3")                        ; Xlib man pages
+   '("3X11" . "3")
+   '("1-UCB" . ""))
+  "*Association list of bogus sections to real section numbers.
+Some manpages (e.g. the Sun C++ 2.1 manpages) have section numbers in
+their references which Un*x `man' does not recognize.  This
+association list is used to translate those sections, when found, to
+the associated section number.")
 
-(defvar Manual-formatted-directory-list nil "\
-A list of directories containing formatted man pages.  Initialized by
-\\[Manual-directory-list-init].")
+(defvar manual-program "man"
+  "The name of the program that produces man pages.")
 
-(defvar Manual-unformatted-directory-list nil "\
-A list of directories containing the unformatted (source) man pages.  
-Initialized by \\[Manual-directory-list-init].")
+(defvar Man-untabify-command "pr"
+  "Command used for untabifying.")
+
+(defvar Man-untabify-command-args (list "-t" "-e")
+  "List of arguments to be passed to Man-untabify-command (which see).")
 
-(defvar Manual-page-history nil "\
-A list of names of previously visited man page buffers.")
+(defvar Man-sed-command "sed"
+  "Command used for processing sed scripts.")
 
-(defvar Manual-manpath-config-file "/usr/lib/manpath.config"
-  "*Location of the manpath.config file, if any.")
-
-(defvar Manual-apropos-switch "-k"
-  "*Man apropos switch")
+(defvar Man-awk-command "awk"
+  "Command used for processing awk scripts.")
 
-;; New variables.
+(defvar Man-mode-line-format
+  '("" mode-line-modified
+       mode-line-buffer-identification "  "
+       global-mode-string
+       " " Man-page-mode-string
+       "  %[(" mode-name mode-line-process minor-mode-alist ")%]----"
+       (-3 . "%p") "-%-")
+  "Mode line format for manual mode buffer.")
 
-(defvar Manual-subdirectory-list nil "\
-A list of all the subdirectories in which man pages may be found.
-Iniialized by Manual-directory-list-init.")
+(defvar Man-mode-map nil
+  "Keymap for Man mode.")
+
+(defvar Man-mode-hook nil
+  "Hook run when Man mode is enabled.")
 
-;; This is for SGI systems; don't know what it should be otherwise.
-(defvar Manual-man-page-section-ids "1nl6823457poD" "\
-String containing all suffix characters for \"cat\" and \"man\"
-that identify valid sections of the Un*x manual.") 
+(defvar Man-cooked-hook nil
+  "Hook run after removing backspaces but before Man-mode processing.")
+
+(defvar Man-name-regexp "[-a-zA-Z0-9_][-a-zA-Z0-9_.]*"
+  "Regular expression describing the name of a manpage (without section).")
 
-(defvar Manual-formatted-page-prefix "cat" "\
-Prefix for directories where formatted man pages are to be found.
-Defaults to \"cat\".")
+(defvar Man-section-regexp "[0-9][a-zA-Z+]*\\|[LNln]"
+  "Regular expression describing a manpage section within parentheses.")
 
-(defvar Manual-unformatted-page-prefix "man" "\
-Prefix for directories where unformatted man pages are to be found.
-Defaults to \"man\".")
+(defvar Man-page-header-regexp
+  (concat "^[ \t]*\\(" Man-name-regexp
+	  "(\\(" Man-section-regexp "\\))\\).*\\1")
+  "Regular expression describing the heading of a page.")
 
-(defvar Manual-leaf-signature "" "\
-Regexp for identifying \"leaf\" subdirectories in the search path.
-If empty, initialized by Manual-directory-list-init.")
+(defvar Man-heading-regexp "^\\([A-Z][A-Z ]+\\)$"
+  "Regular expression describing a manpage heading entry.")
+
+(defvar Man-see-also-regexp "SEE ALSO"
+  "Regular expression for SEE ALSO heading (or your equivalent).
+This regexp should not start with a `^' character.")
 
-(defvar Manual-use-full-section-ids t "\
-If non-nil, pass full section ids to Manual-program, otherwise pass
-only the first character. Defaults to 't'.")
+(defvar Man-first-heading-regexp "^[ \t]*NAME$\\|^[ \t]*No manual entry fo.*$"
+  "Regular expression describing first heading on a manpage.
+This regular expression should start with a `^' character.")
+
+(defvar Man-reference-regexp
+  (concat "\\(" Man-name-regexp "\\)(\\(" Man-section-regexp "\\))")
+  "Regular expression describing a reference in the SEE ALSO section.")
 
-(defvar Manual-use-subdirectory-list (eq system-type 'irix) "\
-This makes manual-entry work correctly on SGI machines but it
-imposes a large startup cost which is why it is not simply on by
-default on all systems.")
+(defvar Man-switches ""
+  "Switches passed to the man command, as a single string.")
 
-(defvar Manual-use-rosetta-man (not (null (locate-file "rman" exec-path))) "\
-If non-nil, use RosettaMan (rman) to filter man pages.
-This makes man-page cleanup virtually instantaneous, instead of
-potentially taking a long time.
+(defvar Man-specified-section-option
+  (if (string-match "-solaris[0-9.]*$" system-configuration)
+      "-s"
+    "")
+  "Option that indicates a specified a manual section name.")
 
-Here is information on RosettaMan, from Neal.Becker@comsat.com (Neal Becker):
+;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+;; end user variables
+
+;; other variables and keymap initializations
+(make-variable-buffer-local 'Man-sections-alist)
+(make-variable-buffer-local 'Man-refpages-alist)
+(make-variable-buffer-local 'Man-page-list)
+(make-variable-buffer-local 'Man-current-page)
+(make-variable-buffer-local 'Man-page-mode-string)
+(make-variable-buffer-local 'Man-original-frame)
+(make-variable-buffer-local 'Man-arguments)
 
-RosettaMan is a filter for UNIX manual pages.  It takes as input man
-pages formatted for a variety of UNIX flavors (not [tn]roff source)
-and produces as output a variety of file formats.  Currently
-RosettaMan accepts man pages as formatted by the following flavors of
-UNIX: Hewlett-Packard HP-UX, AT&T System V, SunOS, Sun Solaris, OSF/1,
-DEC Ultrix, SGI IRIX, Linux, SCO; and produces output for the following
-formats: printable ASCII only (stripping page headers and footers),
-section and subsection headers only, TkMan, [tn]roff, Ensemble, RTF,
-SGML (soon--I finally found a DTD), HTML, MIME, LaTeX, LaTeX 2e, Perl 5's pod.
+(setq-default Man-sections-alist nil)
+(setq-default Man-refpages-alist nil)
+(setq-default Man-page-list nil)
+(setq-default Man-current-page 0)
+(setq-default Man-page-mode-string "1 of 1")
 
-RosettaMan improves on other man page filters in several ways: (1) its
-analysis recognizes the structural pieces of man pages, enabling high
-quality output, (2) its modular structure permits easy augmentation of
-output formats, (3) it accepts man pages formatted with the varient
-macros of many different flavors of UNIX, and (4) it doesn't require
-modification or cooperation with any other program.
+(defconst Man-sysv-sed-script "\
+/\b/ {	s/_\b//g
+	s/\b_//g
+        s/o\b+/o/g
+        s/+\bo/o/g
+	:ovstrk
+	s/\\(.\\)\b\\1/\\1/g
+	t ovstrk
+	}
+/\e\\[[0-9][0-9]*m/ s///g"
+  "Script for sysV-like sed to nuke backspaces and ANSI codes from manpages.")
 
-RosettaMan is a rewrite of TkMan's man page filter, called bs2tk.  (If
-you haven't heard about TkMan, a hypertext man page browser, you
-should grab it via anonymous ftp from ftp.cs.berkeley.edu:
-/ucb/people/phelps/tkman.tar.Z.)  Whereas bs2tk generated output only for
-TkMan, RosettaMan generalizes the process so that the analysis can be
-leveraged to new output formats.  A single analysis engine recognizes
-section heads, subsection heads, body text, lists, references to other
-man pages, boldface, italics, bold italics, special characters (like
-bullets), tables (to a degree) and strips out page headers and
-footers.  The engine sends signals to the selected output functions so
-that an enhancement in the engine improves the quality of output of
-all of them.  Output format functions are easy to add, and thus far
-average about about 75 lines of C code each.
-
-
-
-*** NOTES ON CURRENT VERSION ***
+(defconst Man-berkeley-sed-script "\
+/\b/ {	s/_\b//g\\
+	s/\b_//g\\
+        s/o\b+/o/g\\
+        s/+\bo/o/g\\
+	:ovstrk\\
+	s/\\(.\\)\b\\1/\\1/g\\
+	t ovstrk\\
+	}\\
+/\e\\[[0-9][0-9]*m/ s///g"
+  "Script for berkeley-like sed to nuke backspaces and ANSI codes from manpages.")
 
-Help!  I'm looking for people to help with the following projects.
-\(1) Better RTF output format.  The current one works, but could be
-made better.  (2) Roff macros that produce text that is easily
-parsable.  RosettaMan handles a great variety, but some things, like
-H-P's tables, are intractable.  If you write an output format or
-otherwise improve RosettaMan, please send in your code so that I may
-share the wealth in future releases.
-
-This version can try to identify tables (turn this on with the -T
-switch) by looking for lines with a large amount of interword spacing,
-reasoning that this is space between columns of a table.  This
-heuristic doesn't always work and sometimes misidentifies ordinary
-text as tables.  In general I think it is impossible to perfectly
-identify tables from nroff formatted text.  However, I do think the
-heuristics can be tuned, so if you have a collection of manual pages
-with unrecognized tables, send me the lot, in formatted form (i.e.,
-after formatting with nroff -man), and uuencode them to preserve the
-control characters.  Better, if you can think of heuristics that
-distinguish tables from ordinary text, I'd like to hear them.
-
+(if Man-mode-map
+    nil
+  (setq Man-mode-map (make-keymap))
+  (suppress-keymap Man-mode-map)
+  (define-key Man-mode-map " "    'scroll-up)
+  (define-key Man-mode-map "\177" 'scroll-down)
+  (define-key Man-mode-map "n"    'Man-next-section)
+  (define-key Man-mode-map "p"    'Man-previous-section)
+  (define-key Man-mode-map "\en"  'Man-next-manpage)
+  (define-key Man-mode-map "\ep"  'Man-previous-manpage)
+  (define-key Man-mode-map ">"    'end-of-buffer)
+  (define-key Man-mode-map "<"    'beginning-of-buffer)
+  (define-key Man-mode-map "."    'beginning-of-buffer)
+  (define-key Man-mode-map "r"    'Man-follow-manual-reference)
+  (define-key Man-mode-map "g"    'Man-goto-section)
+  (define-key Man-mode-map "s"    'Man-goto-see-also-section)
+  (define-key Man-mode-map "k"    'Man-kill)
+  (define-key Man-mode-map "q"    'Man-quit)
+  (define-key Man-mode-map "m"    'man)
+  (define-key Man-mode-map "?"    'describe-mode)
+  )
 
-Notes for HTML consumers: This filter does real (heuristic)
-parsing--no <PRE>!  Man page references are turned into hypertext links.")
+
+;; ======================================================================
+;; utilities
 
-(make-face 'man-italic)
-(or (face-differs-from-default-p 'man-italic)
-    (copy-face 'italic 'man-italic))
-;; XEmacs (from Darrell Kindred): underlining is annoying due to
-;; large blank spaces in this face.
-;; (or (face-differs-from-default-p 'man-italic)
-;;    (set-face-underline-p 'man-italic t))
+(defun Man-init-defvars ()
+  "Used for initialising variables based on the value of window-system.
+This is necessary if one wants to dump man.el with emacs."
 
-(make-face 'man-bold)
-(or (face-differs-from-default-p 'man-bold)
-    (copy-face 'bold 'man-bold))
-(or (face-differs-from-default-p 'man-bold)
-    (copy-face 'man-italic 'man-bold))
+  ;; The following is necessary until fonts are implemented on
+  ;; terminals.
+  (setq Man-fontify-manpage-flag (and Man-fontify-manpage-flag
+				      window-system))
 
-(make-face 'man-heading)
-(or (face-differs-from-default-p 'man-heading)
-    (copy-face 'man-bold 'man-heading))
-
-(make-face 'man-xref)
-(or (face-differs-from-default-p 'man-xref)
-    (set-face-underline-p 'man-xref t))
+  (setq Man-sed-script
+	(cond
+	 (Man-fontify-manpage-flag
+	  nil)
+	 ((= 0 (call-process Man-sed-command nil nil nil Man-sysv-sed-script))
+	  Man-sysv-sed-script)
+	 ((= 0 (call-process Man-sed-command nil nil nil Man-berkeley-sed-script))
+	  Man-berkeley-sed-script)
+	 (t
+	  nil)))
 
-;; Manual-directory-list-init
-;; Initialize the directory lists.
+  (setq Man-filter-list
+	(list
+	 (cons
+	  Man-sed-command
+	  (list
+	   (if Man-sed-script
+	       (concat "-e '" Man-sed-script "'")
+	     "")
+	   "-e '/^[\001-\032][\001-\032]*$/d'"
+	   "-e '/\e[789]/s///g'"
+	   "-e '/Reformatting page.  Wait/d'"
+	   "-e '/Reformatting entry.  Wait/d'"
+	   "-e '/^[ \t]*Hewlett-Packard[ \t]Company[ \t]*-[ \t][0-9]*[ \t]-/d'"
+	   "-e '/^[ \t]*Hewlett-Packard[ \t]*-[ \t][0-9]*[ \t]-.*$/d'"
+	   "-e '/^[ \t][ \t]*-[ \t][0-9]*[ \t]-[ \t]*Formatted:.*[0-9]$/d'"
+	   "-e '/^[ \t]*Page[ \t][0-9]*.*(printed[ \t][0-9\\/]*)$/d'"
+	   "-e '/^Printed[ \t][0-9].*[0-9]$/d'"
+	   "-e '/^[ \t]*X[ \t]Version[ \t]1[01].*Release[ \t][0-9]/d'"
+	   "-e '/^[A-za-z].*Last[ \t]change:/d'"
+	   "-e '/^Sun[ \t]Release[ \t][0-9].*[0-9]$/d'"
+	   "-e '/[ \t]*Copyright [0-9]* UNIX System Laboratories, Inc.$/d'"
+	   "-e '/^[ \t]*Rev\\..*Page [0-9][0-9]*$/d'"
+	   ))
+	 (cons
+	  Man-awk-command
+	  (list
+	   "'\n"
+	   "BEGIN { blankline=0; anonblank=0; }\n"
+	   "/^$/ { if (anonblank==0) next; }\n"
+	   "{ anonblank=1; }\n"
+	   "/^$/ { blankline++; next; }\n"
+	   "{ if (blankline>0) { print \"\"; blankline=0; } print $0; }\n"
+	   "'"
+	   ))
+	 (if (not Man-uses-untabify-flag)
+	     (cons
+	      Man-untabify-command
+	      Man-untabify-command-args)
+	   )))
+)
+
+(defsubst Man-match-substring (&optional n string)
+  "Return the substring matched by the last search.
+Optional arg N means return the substring matched by the Nth paren
+grouping.  Optional second arg STRING means return a substring from
+that string instead of from the current buffer."
+  (if (null n) (setq n 0))
+  (if string
+      (substring string (match-beginning n) (match-end n))
+    (buffer-substring (match-beginning n) (match-end n))))
+
+(defsubst Man-make-page-mode-string ()
+  "Formats part of the mode line for Man mode."
+  (format "%s page %d of %d"
+	  (or (nth 2 (nth (1- Man-current-page) Man-page-list))
+	      "")
+	  Man-current-page
+	  (length Man-page-list)))
+
+(defsubst Man-build-man-command ()
+  "Builds the entire background manpage and cleaning command."
+  (let ((command (concat manual-program " " Man-switches " %s 2>/dev/null"))
+	(flist Man-filter-list))
+    (while (and flist (car flist))
+      (let ((pcom (car (car flist)))
+	    (pargs (cdr (car flist))))
+	(setq command
+	      (concat command " | " pcom " "
+		      (mapconcat '(lambda (phrase)
+				    (if (not (stringp phrase))
+					(error "Malformed Man-filter-list"))
+				    phrase)
+				 pargs " ")))
+	(setq flist (cdr flist))))
+    command))
 
-(defun Manual-directory-list-init (&optional arg) 
-  "Initialize the Manual-directory-list variable from $MANPATH
-if it is not already set, or if a prefix argument is provided."
-  (interactive "P")
-  (if arg (setq Manual-directory-list nil))
-  (if (null Manual-directory-list)
-      (let ((manpath (getenv "MANPATH"))
-	    (global (Manual-manpath-config-contents))
-	    (dirlist nil)
-	    dir)
-	(cond ((and manpath global)
-	       (setq manpath (concat manpath ":" global)))
-	      (global
-	       (setq manpath global))
-	      ((not manpath)
-	       ;; XEmacs - (bpw/stig) Unix-specifix hack for lusers w/ no manpath
-	       (setq manpath "/usr/local/man:/usr/share/man:/usr/share/catman:/usr/contrib/man:/usr/X11/man:/usr/man:/usr/catman")))
-	;; Make sure that any changes we've made internally are seen by man.
-	(setenv "MANPATH" manpath)
-	(while (string-match "\\`:*\\([^:]+\\)" manpath)
-	  (setq dir (substring manpath (match-beginning 1) (match-end 1)))
-	  (and (not (member dir dirlist))
-	       (setq dirlist (cons dir dirlist)))
-	  (setq manpath (substring manpath (match-end 0))))
-	(setq dirlist (nreverse dirlist))
-	(setq Manual-directory-list dirlist)
-	(setq Manual-subdirectory-list nil)
-	(setq Manual-formatted-directory-list nil)
-	(setq Manual-unformatted-directory-list nil)))
-  (if (string-equal Manual-leaf-signature "")
-      (setq Manual-leaf-signature
-	    (concat "/\\("
-		    Manual-formatted-page-prefix
-		    "\\|" Manual-unformatted-page-prefix
-		    "\\)"
-		    "[" Manual-man-page-section-ids
-		    "].?/.")))
-  (if Manual-use-subdirectory-list
-      (progn
-	(if (null Manual-subdirectory-list)
-	    (setq Manual-subdirectory-list
-		  (Manual-all-subdirectories Manual-directory-list
-					     Manual-leaf-signature nil)))
-	(if (null Manual-formatted-directory-list)
-	    (setq Manual-formatted-directory-list
-		  (Manual-filter-subdirectories Manual-subdirectory-list
-						Manual-formatted-page-prefix)))
-	(if (null Manual-unformatted-directory-list)
-	    (setq Manual-unformatted-directory-list
-		  (Manual-filter-subdirectories Manual-subdirectory-list
-						Manual-unformatted-page-prefix))))
-    (if (null Manual-formatted-directory-list)
-        (setq Manual-formatted-directory-list
-	      (Manual-select-subdirectories Manual-directory-list
-					    Manual-formatted-page-prefix)))
-    (if (null Manual-unformatted-directory-list)
-        (setq Manual-unformatted-directory-list
-	      (Manual-select-subdirectories Manual-directory-list
-					    Manual-unformatted-page-prefix)))))
+(defun Man-translate-references (ref)
+  "Translates REF from \"chmod(2V)\" to \"2v chmod\" style.
+Leave it as is if already in that style.  Possibly downcase and
+translate the section (see the Man-downcase-section-letters-flag
+and the Man-section-translations-alist variables)."
+  (let ((name "")
+	(section "")
+	(slist Man-section-translations-alist))
+    (cond
+     ;; "chmod(2V)" case ?
+     ((string-match (concat "^" Man-reference-regexp "$") ref)
+      (setq name (Man-match-substring 1 ref)
+	    section (Man-match-substring 2 ref)))
+     ;; "2v chmod" case ?
+     ((string-match (concat "^\\(" Man-section-regexp
+			    "\\) +\\(" Man-name-regexp "\\)$") ref)
+      (setq name (Man-match-substring 2 ref)
+	    section (Man-match-substring 1 ref))))
+    (if (string= name "")
+	ref				; Return the reference as is
+      (if Man-downcase-section-letters-flag
+	  (setq section (downcase section)))
+      (while slist
+	(let ((s1 (car (car slist)))
+	      (s2 (cdr (car slist))))
+	  (setq slist (cdr slist))
+	  (if Man-downcase-section-letters-flag
+	      (setq s1 (downcase s1)))
+	  (if (not (string= s1 section)) nil
+	    (setq section (if Man-downcase-section-letters-flag
+			      (downcase s2)
+			    s2)
+		  slist nil))))
+      (concat Man-specified-section-option section " " name))))
 
+
+;; ======================================================================
+;; default man entry: get word under point
 
-(defun Manual-manpath-config-contents ()
-  "Parse the `Manual-manpath-config-file' file, if any.
-Returns a string like in $MANPATH."
-  (if (and Manual-manpath-config-file
-	   (file-readable-p Manual-manpath-config-file))
-      (let ((buf (get-buffer-create " *Manual-config*"))
-	    path)
-	(set-buffer buf)
-	(buffer-disable-undo buf)
-	(erase-buffer)
-	(insert-file-contents Manual-manpath-config-file)
-	(while (re-search-forward "^\\(MANDATORY_MANPATH\\|MANPATH_MAP\\)"
-				  nil t)
-	  (and (re-search-forward "\\(/[^ \t\n]+\\)[ \t]*$")
-	       (setq path (concat path (buffer-substring (match-beginning 1)
-							 (match-end 1))
-				  ":"))))
-	(kill-buffer buf)
-	path)))
-;;
-;; manual-entry  -- The "main" user function
-;;
+(defsubst Man-default-man-entry ()
+  "Make a guess at a default manual entry.
+This guess is based on the text surrounding the cursor, and the
+default section number is selected from `Man-auto-section-alist'."
+  (let (default-title)
+    (save-excursion
+      
+      ;; Default man entry title is any word the cursor is on, or if
+      ;; cursor not on a word, then nearest preceding word.  Cannot
+      ;; use the current-word function because it skips the dots.
+      (if (not (looking-at "[-a-zA-Z_.]"))
+	  (skip-chars-backward "^a-zA-Z"))
+      (skip-chars-backward "-(a-zA-Z_0-9_.")
+      (if (looking-at "(") (forward-char 1))
+      (setq default-title
+	    (buffer-substring
+	     (point)
+	     (progn (skip-chars-forward "-a-zA-Z0-9_.") (point))))
+      
+      ;; If looking at something like ioctl(2) or brc(1M), include the
+      ;; section number in the returned value.  Remove text properties.
+      (let ((result (concat
+		     default-title
+		     (if (looking-at
+			  (concat "[ \t]*([ \t]*\\("
+				  Man-section-regexp "\\)[ \t]*)"))
+			 (format "(%s)" (Man-match-substring 1))))))
+	(set-text-properties 0 (length result) nil result)
+	result))))
+
+
+;; ======================================================================
+;; Top level command and background process sentinel
+
+;; For compatibility with older versions.
+;;;###autoload
+(defalias 'manual-entry 'man)
 
 ;;;###autoload
-(defun manual-entry (topic &optional arg silent)
-  "Display the Unix manual entry (or entries) for TOPIC.
-If prefix arg is given, modify the search according to the value:
-  2 = complement default exact matching of the TOPIC name;
-      exact matching default is specified by `Manual-match-topic-exactly'
-  3 = force a search of the unformatted man directories
-  4 = both 2 and 3
-The manual entries are searched according to the variable
-Manual-directory-list, which should be a list of directories.  If
-Manual-directory-list is nil, \\[Manual-directory-list-init] is
-invoked to create this list from the MANPATH environment variable.
-See the variable Manual-topic-buffer which controls how the buffer
-is named.  See also the variables Manual-match-topic-exactly,
-Manual-query-multiple-pages, and Manual-buffer-view-mode."
+(defun man (man-args)
+  "Get a Un*x manual page and put it in a buffer.
+This command is the top-level command in the man package.  It runs a Un*x
+command to retrieve and clean a manpage in the background and places the
+results in a Man mode (manpage browsing) buffer.  See variable
+`Man-notify-method' for what happens when the buffer is ready.
+If a buffer already exists for this man page, it will display immediately."
   (interactive
-   (list (let* ((fmh "-A-Za-z0-9_.")
-		(default (save-excursion
-			   (buffer-substring
-			    (progn
-			      (re-search-backward "\\sw" nil t)
-			      (skip-chars-backward fmh) (point))
-			    (progn (skip-chars-forward fmh) (point)))))
-		(thing (read-string
-			(if (equal default "") "Manual entry: "
-			  (concat "Manual entry: (default " default ") ")))))
-	   (if (equal thing "") default thing))
-	 (prefix-numeric-value current-prefix-arg)))
-  ;;(interactive "sManual entry (topic): \np")
-  (or arg (setq arg 1))
-  (Manual-directory-list-init nil)
-  (let ((exact (if (or (= arg 2) (= arg 4))
-		   (not Manual-match-topic-exactly)
-		 Manual-match-topic-exactly))
-	(force (if (>= arg 3)
-                   t
-                   nil))
-	section fmtlist manlist apropos-mode)
-    (let ((case-fold-search nil))
-      (if (and (null section)
-	       (string-match
-		"\\`[ \t]*\\([^( \t]+\\)[ \t]*(\\(.+\\))[ \t]*\\'" topic))
-	  (setq section (substring topic (match-beginning 2)
-				   (match-end 2))
-		topic (substring topic (match-beginning 1)
-				 (match-end 1)))
-	(if (string-match "\\`[ \t]*-k[ \t]+\\([^ \t]+\\)\\'" topic)
-	    (setq section "-k"
-		  topic (substring topic (match-beginning 1))))))
-    (if (equal section "-k")
-	(setq apropos-mode t)
-      (or silent
-	  (message "Looking for formatted entry for %s%s..."
-		   topic (if section (concat "(" section ")") "")))
-      (setq fmtlist (Manual-select-man-pages
-                      Manual-formatted-directory-list
-                      topic section exact '()))
-      (if (or force (not section) (null fmtlist))
-	  (progn
-	    (or silent
-		(message "%sooking for unformatted entry for %s%s..."
-			 (if fmtlist "L" "No formatted entry, l")
-			 topic (if section (concat "(" section ")") "")))
-	    (setq manlist (Manual-select-man-pages
-                            Manual-unformatted-directory-list
-                            topic section exact (if force '() fmtlist))))))
-
-    ;; Delete duplicate man pages (a file of the same name in multiple
-    ;; directories.)
-    (or nil ;force
-        (let ((rest (append fmtlist manlist)))
-          (while rest
-            (let ((rest2 (cdr rest)))
-              (while rest2
-                (if (equal (file-name-nondirectory (car rest))
-                           (file-name-nondirectory (car rest2)))
-                    (setq fmtlist (delq (car rest2) fmtlist)
-                          manlist (delq (car rest2) manlist)))
-                (setq rest2 (cdr rest2))))
-            (setq rest (cdr rest)))))
-
-    (if (not (or fmtlist manlist apropos-mode))
-        (progn
-          (message "No entries found for %s%s" topic
-                   (if section (concat "(" section ")") ""))
-          nil)
-      (let ((bufname (cond ((not Manual-topic-buffer)
-                            ;; What's the point of retaining this?
-                            (if apropos-mode
-                                "*Manual Apropos*"
-                                "*Manual Entry*"))
-                           (apropos-mode
-                            (concat "*man apropos " topic "*"))
-                           (t
-                            (concat "*man "
-                                    (cond (exact
-                                           (if section
-                                               (concat topic "." section)
-                                               topic))
-                                          ((or (cdr fmtlist) (cdr manlist)
-                                               (and fmtlist manlist))
-                                           ;; more than one entry found
-                                           (concat topic "..."))
-                                          (t
-                                           (file-name-nondirectory
-                                            (car (or fmtlist manlist)))))
-                                    "*"))))
-            (temp-buffer-show-function 
-             (cond ((eq 't Manual-buffer-view-mode) 'view-buffer)
-                   ((eq 'nil Manual-buffer-view-mode)
-                    temp-buffer-show-function)
-                   (t 'view-buffer-other-window))))
-
-        (if apropos-mode
-            (setq manlist (list (format "%s.%s" topic section))))
+   (list (let* ((default-entry (Man-default-man-entry))
+		(input (read-string
+			(format "Manual entry%s: "
+				(if (string= default-entry "")
+				    ""
+				  (format " (default %s)" default-entry))))))
+	   (if (string= input "")
+	       (if (string= default-entry "")
+		   (error "No man args given")
+		 default-entry)
+	     input))))
 
-        (cond
-          ((and Manual-topic-buffer (get-buffer bufname))
-           ;; reselect an old man page buffer if it exists already.
-           (save-excursion
-             (set-buffer (get-buffer bufname))
-             (Manual-mode))
-           (if temp-buffer-show-function
-               (funcall temp-buffer-show-function (get-buffer bufname))
-               (display-buffer bufname)))
-          (t
-           (with-output-to-temp-buffer bufname
-             (buffer-disable-undo standard-output)
-             (save-excursion
-               (set-buffer standard-output)
-               (setq buffer-read-only nil)
-               (erase-buffer)
-	       (Manual-insert-pages fmtlist manlist apropos-mode)
-               (set-buffer-modified-p nil)
-               (Manual-mode)
-               ))))
-        (setq Manual-page-history
-              (cons (buffer-name)
-                    (delete (buffer-name) Manual-page-history)))
-        (message nil)
-        t))))
-
-(defun Manpage-apropos (topic &optional arg silent)
-  "Apropos on Unix manual pages for TOPIC.
-It calls the function `manual-entry'. Look at this function for
-further description. Look also at the variable `Manual-apropos-switch',
-if this function doesn't work on your system."
-  (interactive
-   (list (let* ((fmh "-A-Za-z0-9_.")
-		(default (save-excursion
-			   (buffer-substring
-			    (progn
-			      (re-search-backward "\\sw" nil t)
-			      (skip-chars-backward fmh) (point))
-			    (progn (skip-chars-forward fmh) (point)))))
-		(thing (read-string
-			(if (equal default "") "Manual entry: "
-			  (concat "Manual entry: (default " default ") ")))))
-	   (if (equal thing "") default thing))
-	 (prefix-numeric-value current-prefix-arg)))
-  (manual-entry (concat Manual-apropos-switch " " topic) arg silent))
+  ;; Possibly translate the "subject(section)" syntax into the
+  ;; "section subject" syntax and possibly downcase the section.
+  (setq man-args (Man-translate-references man-args))
 
-(defun Manual-insert-pages (fmtlist manlist apropos-mode)
-  (let ((sep (make-string 65 ?-))
-	name start end topic section)
-    (while fmtlist			; insert any formatted files
-      (setq name (car fmtlist))
-      (goto-char (point-max))
-      (setq start (point))
-      ;; In case the file can't be read or uncompressed or
-      ;; something like that.
-      (condition-case ()
-	  (Manual-insert-man-file name)
-	(file-error nil))
-      (goto-char (point-max))
-      (setq end (point))
-      (save-excursion
-	(save-restriction
-	  (message "Cleaning manual entry for %s..."
-		   (file-name-nondirectory name))
-	  (narrow-to-region start end)
-	  (Manual-nuke-nroff-bs)
-	  (goto-char (point-min))
-	  (insert "File: " name "\n")
-	  (goto-char (point-max))
-	  ))
-      (if (or (cdr fmtlist) manlist)
-	  (insert "\n\n" sep "\n"))
-      (setq fmtlist (cdr fmtlist)))
-
-    (while manlist			; process any unformatted files
-      (setq name (car manlist))
-      (or (string-match "\\([^/]+\\)\\.\\([^./]+\\)\\(\\.gz\\'\\)" name)
-	  (string-match "\\([^/]+\\)\\.\\([^./]+\\)\\'" name))
-      (setq topic (substring name (match-beginning 1) (match-end 1)))
-      (setq section (substring name (match-beginning 2) (match-end 2)))
-      ;; This won't work under IRIX, because SGI man accepts only the
-      ;; "main" (one-character) section id, not full section ids
-      ;; like 1M, 3X, etc. Put (setq Manual-use-full-section-ids nil)
-      ;; in your .emacs to work around this problem.
-      (if (not (or Manual-use-full-section-ids (string-equal section "")))
-	  (setq section (substring section 0 1)))
-      (message "Invoking man %s%s %s..."
-	       (if Manual-section-switch
-		   (concat Manual-section-switch " ")
-		 "")
-	       section topic)
-      (setq start (point))
-      (Manual-run-formatter name topic section)
-      (setq end (point))
-      (save-excursion
-	(save-restriction
-	  (message "Cleaning manual entry for %s(%s)..." topic section)
-	  (narrow-to-region start end)
-	  (Manual-nuke-nroff-bs apropos-mode)
-	  (goto-char (point-min))
-	  (insert "File: " name "\n")
-	  (goto-char (point-max))
-	  ))
-      (if (cdr manlist)
-	  (insert "\n\n" sep "\n"))
-      (setq manlist (cdr manlist))))
-  (if (< (buffer-size) 200)
-      (progn
-	(goto-char (point-min))
-	(if (looking-at "^File: ")
-	    (forward-line 1))
-	(error (buffer-substring (point) (progn (end-of-line) (point))))))
-  nil)
-
-
-(defun Manual-run-formatter (name topic section)
-  (cond
-   ((string-match "roff\\'" Manual-program)
-    ;; kludge kludge
-    (call-process Manual-program nil t nil "-Tman" "-man" name))
-
-   (t
-    (call-process Manual-program nil t nil
-                  (concat Manual-section-switch section) topic))))
-
-   ;(Manual-use-rosetta-man
-   ; (call-process "/bin/sh" nil t nil "-c"
-   ;               (format "man %s %s | rman" section topic)))
+  (Man-getpage-in-background man-args))
 
 
-(defvar Manual-mode-map
-  (let ((m (make-sparse-keymap)))
-    (set-keymap-name m 'Manual-mode-map)
-    (define-key m "l" 'Manual-last-page)
-    (define-key m 'button2 'Manual-follow-xref)
-    (define-key m 'button3 'Manual-popup-menu)
-    m))
+(defun Man-getpage-in-background (topic)
+  "Uses TOPIC to build and fire off the manpage and cleaning command."
+  (let* ((man-args topic)
+	 (bufname (concat "*Man " man-args "*"))
+	 (buffer  (get-buffer bufname)))
+    (if buffer
+	(Man-notify-when-ready buffer)
+      (require 'env)
+      (message "Invoking %s %s in the background" manual-program man-args)
+      (setq buffer (generate-new-buffer bufname))
+      (save-excursion
+	(set-buffer buffer)
+	(setq Man-original-frame (selected-frame))
+	(setq Man-arguments man-args))
+      (let ((process-environment (copy-sequence process-environment)))
+	;; Prevent any attempt to use display terminal fanciness.
+	(setenv "TERM" "dumb")
+	(set-process-sentinel
+	 (start-process manual-program buffer "sh" "-c"
+			(format (Man-build-man-command) man-args))
+	 'Man-bgproc-sentinel)))))
 
-(defun Manual-mode ()
-  (kill-all-local-variables)
-  (setq buffer-read-only t)
-  (use-local-map Manual-mode-map)
-  (setq major-mode 'Manual-mode
-	mode-name "Manual")
-  ;; man pages with long lines are buggy!
-  ;; This looks slightly better if they only
-  ;; overran by a couple of chars.
-  (setq truncate-lines t)
-  (if (featurep 'scrollbar)
-      ;; turn off horizontal scrollbars in this buffer
-      (set-specifier scrollbar-height (cons (current-buffer) 0)))
-  (run-hooks 'Manual-mode-hook))
+(defun Man-notify-when-ready (man-buffer)
+  "Notify the user when MAN-BUFFER is ready.
+See the variable `Man-notify-method' for the different notification behaviors."
+  (let ((saved-frame (save-excursion
+		       (set-buffer man-buffer)
+		       Man-original-frame)))
+    (cond
+     ((eq Man-notify-method 'newframe)
+      ;; Since we run asynchronously, perhaps while Emacs is waiting
+      ;; for input, we must not leave a different buffer current.  We
+      ;; can't rely on the editor command loop to reselect the
+      ;; selected window's buffer.
+      (save-excursion
+	(set-buffer man-buffer)
+	(make-frame Man-frame-parameters)))
+     ((eq Man-notify-method 'pushy)
+      (switch-to-buffer man-buffer))
+     ((eq Man-notify-method 'bully)
+      (and window-system
+	   (frame-live-p saved-frame)
+	   (select-frame saved-frame))
+      (pop-to-buffer man-buffer)
+      (delete-other-windows))
+     ((eq Man-notify-method 'aggressive)
+      (and window-system
+	   (frame-live-p saved-frame)
+	   (select-frame saved-frame))
+      (pop-to-buffer man-buffer))
+     ((eq Man-notify-method 'friendly)
+      (and window-system
+	   (frame-live-p saved-frame)
+	   (select-frame saved-frame))
+      (display-buffer man-buffer 'not-this-window))
+     ((eq Man-notify-method 'polite)
+      (beep)
+      (message "Manual buffer %s is ready" (buffer-name man-buffer)))
+     ((eq Man-notify-method 'quiet)
+      (message "Manual buffer %s is ready" (buffer-name man-buffer)))
+     ((or (eq Man-notify-method 'meek)
+	  t)
+      (message ""))
+     )))
 
-(defun Manual-last-page ()
+(defun Man-fontify-manpage ()
+  "Convert overstriking and underlining to the correct fonts.
+Same for the ANSI bold and normal escape sequences."
   (interactive)
-  (while (or (not (get-buffer (car (or Manual-page-history
-				       (error "No more history.")))))
-	     (eq (get-buffer (car Manual-page-history)) (current-buffer)))
-    (setq Manual-page-history (cdr Manual-page-history)))
-  (switch-to-buffer (car Manual-page-history)))
-
-
-;; Manual-select-subdirectories
-;; Given a DIRLIST and a SUBDIR name, return all subdirectories of the former which
-;; match the latter.
-
-(defun Manual-select-subdirectories (dirlist subdir)
-  (let ((dirs '())
-        (case-fold-search nil)
-        (match (concat "\\`" (regexp-quote subdir)))
-        d)
-    (while dirlist
-      (setq d (car dirlist) dirlist (cdr dirlist))
-      (if (file-directory-p d)
-          (let ((files (directory-files d t match nil 'dirs-only))
-		(dir-temp '()))
-            (while files
-              (if (file-executable-p (car files))
-                  (setq dir-temp (cons (file-name-as-directory (car files))
-                                   dir-temp)))
-              (setq files (cdr files)))
-	    (and dir-temp
-		 (setq dirs (append dirs (nreverse dir-temp)))))))
-    dirs))
-
+  (message "Please wait: making up the %s man page..." Man-arguments)
+  (goto-char (point-min))
+  (while (search-forward "\e[1m" nil t)
+    (delete-backward-char 4)
+    (put-text-property (point)
+		       (progn (if (search-forward "\e[0m" nil 'move)
+				  (delete-backward-char 4))
+			      (point))
+		       'face Man-overstrike-face))
+  (goto-char (point-min))
+  (while (search-forward "_\b" nil t)
+    (backward-delete-char 2)
+    (put-text-property (point) (1+ (point)) 'face Man-underline-face))
+  (goto-char (point-min))
+  (while (search-forward "\b_" nil t)
+    (backward-delete-char 2)
+    (put-text-property (1- (point)) (point) 'face Man-underline-face))
+  (goto-char (point-min))
+  (while (re-search-forward "\\(.\\)\\(\b\\1\\)+" nil t)
+    (replace-match "\\1")
+    (put-text-property (1- (point)) (point) 'face Man-overstrike-face))
+  (goto-char (point-min))
+  (while (re-search-forward "o\b\\+\\|\\+\bo" nil t)
+    (replace-match "o")
+    (put-text-property (1- (point)) (point) 'face 'bold))
+  (goto-char (point-min))
+  (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t)
+    (replace-match "+")
+    (put-text-property (1- (point)) (point) 'face 'bold))
+  ;; \255 is some kind of dash in Latin-1.
+  (goto-char (point-min))
+  (while (search-forward "\255" nil t) (replace-match "-"))
+  (message "%s man page made up" Man-arguments))
 
-;; Manual-filter-subdirectories
-;; Given a DIRLIST and a SUBDIR name, return all members of the former
-;; which match the latter.
+(defun Man-cleanup-manpage ()
+  "Remove overstriking and underlining from the current buffer."
+  (interactive)
+  (message "Please wait: cleaning up the %s man page..."
+	   Man-arguments)
+  (if (or (interactive-p) (not Man-sed-script))
+      (progn
+	(goto-char (point-min))
+	(while (search-forward "_\b" nil t) (backward-delete-char 2))
+	(goto-char (point-min))
+	(while (search-forward "\b_" nil t) (backward-delete-char 2))
+	(goto-char (point-min))
+	(while (re-search-forward "\\(.\\)\\(\b\\1\\)+" nil t)
+	  (replace-match "\\1"))
+	(goto-char (point-min))
+	(while (re-search-forward "\e\\[[0-9]+m" nil t) (replace-match ""))
+	(goto-char (point-min))
+	(while (re-search-forward "o\b\\+\\|\\+\bo" nil t) (replace-match "o"))
+	))
+  (goto-char (point-min))
+  (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t) (replace-match "+"))
+  ;; \255 is some kind of dash in Latin-1.
+  (goto-char (point-min))
+  (while (search-forward "\255" nil t) (replace-match "-"))
+  (message "%s man page cleaned up" Man-arguments))
+
+(defun Man-bgproc-sentinel (process msg)
+  "Manpage background process sentinel."
+  (let ((Man-buffer (process-buffer process))
+	(delete-buff nil)
+	(err-mess nil))
+
+    (if (null (buffer-name Man-buffer)) ;; deleted buffer
+	(set-process-buffer process nil)
 
-(defun Manual-filter-subdirectories (dirlist subdir)
-  (let ((match (concat
-		"/"
-		(regexp-quote subdir)
-		"[" Manual-man-page-section-ids "]"))
-	slist dir)
-    (while dirlist
-      (setq dir (car dirlist) dirlist (cdr dirlist))
-      (if (and (file-executable-p dir) (string-match match dir))
-	    (setq slist (cons dir slist))))
-    (nreverse slist)))
+      (save-excursion
+	(set-buffer Man-buffer)
+	(let ((case-fold-search nil))
+	  (goto-char (point-min))
+	  (cond ((or (looking-at "No \\(manual \\)*entry for")
+		     (looking-at "[^\n]*: nothing appropriate$"))
+		 (setq err-mess (buffer-substring (point)
+						  (progn
+						    (end-of-line) (point)))
+		       delete-buff t))
+		((not (and (eq (process-status process) 'exit)
+			   (= (process-exit-status process) 0)))
+		 (setq err-mess
+		       (concat (buffer-name Man-buffer)
+			       ": process "
+			       (let ((eos (1- (length msg))))
+				 (if (= (aref msg eos) ?\n)
+				     (substring msg 0 eos) msg))))
+		 (goto-char (point-max))
+		 (insert (format "\nprocess %s" msg))
+		 ))
+	  (if delete-buff
+	      (kill-buffer Man-buffer)
+	    (if Man-fontify-manpage-flag
+		(Man-fontify-manpage)
+	      (Man-cleanup-manpage))
+	    (run-hooks 'Man-cooked-hook)
+	    (Man-mode)
+	    (set-buffer-modified-p nil)
+	    ))
+	;; Restore case-fold-search before calling
+	;; Man-notify-when-ready because it may switch buffers.
 
-
-(defun Manual-all-subdirectories (dirlist leaf-signature dirs &optional silent) "\
-Given a DIRLIST, return a backward-sorted list of all subdirectories
-thereof, prepended to DIRS if non-nil. This function calls itself
-recursively until subdirectories matching LEAF-SIGNATURE are reached,
-or the hierarchy has been thoroughly searched. This code is a modified
-version of a function written by Tim Bradshaw (tfb@ed.ac.uk)."
-  (Manual-all-subdirectories-noloop dirlist leaf-signature dirs nil silent))
+	(if (not delete-buff)
+	    (Man-notify-when-ready Man-buffer))
 
-(defun Manual-all-subdirectories-noloop (dirlist leaf-signature dirs been &optional silent) "\
-Does the job of manual-all-subdirectories and keeps track of where it
-has been to avoid loops."
-  (let (dir)
-    (while dirlist
-      (setq dir (car dirlist) dirlist (cdr dirlist))
-      (if (file-directory-p dir)
-	  (let ((dir-temp (cons (file-name-as-directory dir) dirs)))
-	    ;; Without feedback the user might wonder about the delay!
-	    (or silent (message
-			"Building list of search directories... %s"
-			(car dir-temp)))
-	    (if (member (file-truename dir) been)
-		()		 ; Ignore. We have been here before
-	      (setq been (cons (file-truename dir) been))
-	      (setq dirs
-		    (if (string-match leaf-signature dir)
-			dir-temp
-		      (Manual-all-subdirectories-noloop
-		       (directory-files dir t "[^.]$" nil 'dirs-only)
-		       leaf-signature dir-temp been silent))))))))
-  dirs)
+	(if err-mess
+	    (error err-mess))
+	))))
+
+
+;; ======================================================================
+;; set up manual mode in buffer and build alists
+
+(defun Man-mode ()
+  "A mode for browsing Un*x manual pages.
+
+The following man commands are available in the buffer. Try
+\"\\[describe-key] <key> RET\" for more information:
+
+\\[man]       Prompt to retrieve a new manpage.
+\\[Man-follow-manual-reference]       Retrieve reference in SEE ALSO section.
+\\[Man-next-manpage]   Jump to next manpage in circular list.
+\\[Man-previous-manpage]   Jump to previous manpage in circular list.
+\\[Man-next-section]       Jump to next manpage section.
+\\[Man-previous-section]       Jump to previous manpage section.
+\\[Man-goto-section]       Go to a manpage section.
+\\[Man-goto-see-also-section]       Jumps to the SEE ALSO manpage section.
+\\[Man-quit]       Deletes the manpage window, bury its buffer.
+\\[Man-kill]       Deletes the manpage window, kill its buffer.
+\\[describe-mode]       Prints this help text.
+
+The following variables may be of some use. Try
+\"\\[describe-variable] <variable-name> RET\" for more information:
 
-
-(defvar Manual-bogus-file-pattern "\\.\\(lpr\\|ps\\|PS\\)\\'"
-  "Some systems have files in the man/man*/ directories which aren't man pages.
-This pattern is used to prune those files.")
+Man-notify-method               What happens when manpage formatting is done.
+Man-downcase-section-letters-flag  Force section letters to lower case.
+Man-circular-pages-flag         Treat multiple manpage list as circular.
+Man-auto-section-alist          List of major modes and their section numbers.
+Man-section-translations-alist  List of section numbers and their Un*x equiv.
+Man-filter-list                 Background manpage filter command.
+Man-mode-line-format            Mode line format for Man mode buffers.
+Man-mode-map                    Keymap bindings for Man mode buffers.
+Man-mode-hook                   Normal hook run on entry to Man mode.
+Man-section-regexp              Regexp describing manpage section letters.
+Man-heading-regexp              Regexp describing section headers.
+Man-see-also-regexp             Regexp for SEE ALSO section (or your equiv).
+Man-first-heading-regexp        Regexp for first heading on a manpage.
+Man-reference-regexp            Regexp matching a references in SEE ALSO.
+Man-switches			Background `man' command switches.
 
-;; Manual-select-man-pages
-;;
-;; Given a DIRLIST, discover all filenames which complete given the TOPIC
-;; and SECTION.
+The following key bindings are currently in effect in the buffer:
+\\{Man-mode-map}"
+  (interactive)
+  (setq major-mode 'Man-mode
+	mode-name "Man"
+	buffer-auto-save-file-name nil
+	mode-line-format Man-mode-line-format
+	truncate-lines t
+	buffer-read-only t)
+  (buffer-disable-undo (current-buffer))
+  (auto-fill-mode -1)
+  (use-local-map Man-mode-map)
+  (Man-build-page-list)
+  (Man-strip-page-headers)
+  (Man-unindent)
+  (Man-goto-page 1)
+  (run-hooks 'Man-mode-hook))
 
-;; ## Note: BSD man looks for .../man1/foo.1 and .../man1/$MACHINE/foo.1
+(defsubst Man-build-section-alist ()
+  "Build the association list of manpage sections."
+  (setq Man-sections-alist nil)
+  (goto-char (point-min))
+  (let ((case-fold-search nil))
+    (while (re-search-forward Man-heading-regexp (point-max) t)
+      (aput 'Man-sections-alist (Man-match-substring 1))
+      (forward-line 1))))
 
-;; ## Fixed for SGI IRIX 5.x on Sat Jul 15 1995 by Dale Atems
-;; (atems@physics.wayne.edu).
+(defsubst Man-build-references-alist ()
+  "Build the association list of references (in the SEE ALSO section)."
+  (setq Man-refpages-alist nil)
+  (save-excursion
+    (if (Man-find-section Man-see-also-regexp)
+	(let ((start (progn (forward-line 1) (point)))
+	      (end (progn
+		     (Man-next-section 1)
+		     (point)))
+	      hyphenated
+	      (runningpoint -1))
+	  (save-restriction
+	    (narrow-to-region start end)
+	    (goto-char (point-min))
+	    (back-to-indentation)
+	    (while (and (not (eobp)) (/= (point) runningpoint))
+	      (setq runningpoint (point))
+	      (if (re-search-forward Man-reference-regexp end t)
+		  (let* ((word (Man-match-substring 0))
+			 (len (1- (length word))))
+		    (if hyphenated
+			(setq word (concat hyphenated word)
+			      hyphenated nil))
+		    (if (= (aref word len) ?-)
+			(setq hyphenated (substring word 0 len))
+		      (aput 'Man-refpages-alist word))))
+	      (skip-chars-forward " \t\n,")))))))
+
+(defun Man-build-page-list ()
+  "Build the list of separate manpages in the buffer."
+  (setq Man-page-list nil)
+  (let ((page-start (point-min))
+	(page-end (point-max))
+	(header ""))
+    (goto-char page-start)
+    ;; (switch-to-buffer (current-buffer))(debug)
+    (while (not (eobp))
+      (setq header
+	    (if (looking-at Man-page-header-regexp)
+		(Man-match-substring 1)
+	      nil))
+      ;; Go past both the current and the next Man-first-heading-regexp
+      (if (re-search-forward Man-first-heading-regexp nil 'move 2)
+	  (let ((p (progn (beginning-of-line) (point))))
+	    ;; We assume that the page header is delimited by blank
+	    ;; lines and that it contains at most one blank line.  So
+	    ;; if we back by three blank lines we will be sure to be
+	    ;; before the page header but not before the possible
+	    ;; previous page header.
+	    (search-backward "\n\n" nil t 3)
+	    (if (re-search-forward Man-page-header-regexp p 'move)
+		(beginning-of-line))))
+      (setq page-end (point))
+      (setq Man-page-list (append Man-page-list
+				  (list (list (copy-marker page-start)
+					      (copy-marker page-end)
+					      header))))
+      (setq page-start page-end)
+      )))
 
-(defun Manual-select-man-pages (dirlist topic section exact shadow)
-  (let ((case-fold-search nil))
-    (and section
-      (let ((l '())
-	    ;;(match (concat (substring section 0 1) "/?\\'"))
-	    ;;                                          ^^^
-	    ;; We'll lose any pages inside subdirectories of the "standard"
-	    ;; ones if we insist on this! The following regexp should
-	    ;; match any directory ending with the full section id or
-	    ;; its first character, or any direct subdirectory thereof:
-	    (match (concat "\\("
-			   (regexp-quote section)
-			   "\\|"
-			   (substring section 0 1)
-			   "\\)/?"))
-	    d)
-	(while dirlist
-	  (setq d (car dirlist) dirlist (cdr dirlist))
-	  (if (string-match match d)
-	      (setq l (cons d l))))
-	(setq dirlist l)))
-    (if shadow
-        (setq shadow (concat "/\\("
-                             (mapconcat #'(lambda (n)
-                                            (regexp-quote
-                                             (file-name-nondirectory n)))
-                                        shadow
-                                        "\\|")
-                             "\\)\\'")))
-    (let ((manlist '())
-          (match (concat "\\`"
-                           (regexp-quote topic)
-			    ;; **Note: on IRIX the preformatted pages
-			    ;; are packed, so they end with ".z". This
-			    ;; way you miss them if you specify a
-			    ;; section. I don't see any point to it here
-			    ;; even on BSD systems since we're looking
-			    ;; one level down already, but I can't test
-			    ;; this. More thought needed (???)
+(defun Man-strip-page-headers ()
+  "Strip all the page headers but the first from the manpage."
+  (let ((buffer-read-only nil)
+	(case-fold-search nil)
+	(page-list Man-page-list)
+	(page ())
+	(header ""))
+    (while page-list
+      (setq page (car page-list))
+      (and (nth 2 page)
+	   (goto-char (car page))
+	   (re-search-forward Man-first-heading-regexp nil t)
+	   (setq header (buffer-substring (car page) (match-beginning 0)))
+	   ;; Since the awk script collapses all successive blank
+	   ;; lines into one, and since we don't want to get rid of
+	   ;; the fast awk script, one must choose between adding
+	   ;; spare blank lines between pages when there were none and
+	   ;; deleting blank lines at page boundaries when there were
+	   ;; some.  We choose the first, so we comment the following
+	   ;; line.
+	   ;; (setq header (concat "\n" header)))
+	   (while (search-forward header (nth 1 page) t)
+	     (replace-match "")))
+      (setq page-list (cdr page-list)))))
+
+(defun Man-unindent ()
+  "Delete the leading spaces that indent the manpage."
+  (let ((buffer-read-only nil)
+	(case-fold-search nil)
+	(page-list Man-page-list))
+    (while page-list
+      (let ((page (car page-list))
+	    (indent "")
+	    (nindent 0))
+	(narrow-to-region (car page) (car (cdr page)))
+	(if Man-uses-untabify-flag
+	    (untabify (point-min) (point-max)))
+	(if (catch 'unindent
+	      (goto-char (point-min))
+	      (if (not (re-search-forward Man-first-heading-regexp nil t))
+		  (throw 'unindent nil))
+	      (beginning-of-line)
+	      (setq indent (buffer-substring (point)
+					     (progn
+					       (skip-chars-forward " ")
+					       (point))))
+	      (setq nindent (length indent))
+	      (if (zerop nindent)
+		  (throw 'unindent nil))
+	      (setq indent (concat indent "\\|$"))
+	      (goto-char (point-min))
+	      (while (not (eobp))
+		(if (looking-at indent)
+		    (forward-line 1)
+		  (throw 'unindent nil)))
+	      (goto-char (point-min)))
+	    (while (not (eobp))
+	      (or (eolp)
+		  (delete-char nindent))
+	      (forward-line 1)))
+	(setq page-list (cdr page-list))
+	))))
+
+
+;; ======================================================================
+;; Man mode commands
 
-			   (cond ((and section
-				       (not Manual-use-subdirectory-list))
-				  (concat "\\." (regexp-quote section)))
-                                 (exact
-                                  ;; If Manual-match-topic-exactly is
-                                  ;; set, then we must make sure the
-                                  ;; completions are exact, except for
-                                  ;; trailing weird characters after
-                                  ;; the section.
-                                  "\\.")
-                                 (t
-                                  ""))))
-          dir)
-      (while dirlist
-        (setq dir (car dirlist) dirlist (cdr dirlist))
-        (if (not (file-directory-p dir))
-            (progn
-              (message "warning: %s is not a directory" dir)
-              ;;(sit-for 1)
-              )
-            (let ((files (directory-files dir t match nil t))
-                  f)
-              (while files
-                (setq f (car files) files (cdr files))
-                (cond ((string-match Manual-bogus-file-pattern f)
-		       ;(message "Bogus fule %s" f) (sit-for 2)
-                       )
-		      ((and shadow (string-match shadow f))
-                       ;(message "Shadowed %s" f) (sit-for 2)
-                       )
-                      ((not (file-readable-p f))
-                       ;(message "Losing with %s" f) (sit-for 2)
-                       )
-                      (t
-                       (setq manlist (cons f manlist))))))))
-      (setq manlist (nreverse manlist))
-      (and Manual-unique-man-sections-only
-	   (setq manlist (Manual-clean-to-unique-pages-only manlist)))
-      (if (and manlist Manual-query-multiple-pages)
-          (apply #'append
-                 (mapcar #'(lambda (page)
-                             (and page 
-                                  (y-or-n-p (format "Read %s? " page))
-				  (list page)))
-                         manlist))
-          manlist))))
+(defun Man-next-section (n)
+  "Move point to Nth next section (default 1)."
+  (interactive "p")
+  (let ((case-fold-search nil))
+    (if (looking-at Man-heading-regexp)
+	(forward-line 1))
+    (if (re-search-forward Man-heading-regexp (point-max) t n)
+	(beginning-of-line)
+      (goto-char (point-max)))))
+
+(defun Man-previous-section (n)
+  "Move point to Nth previous section (default 1)."
+  (interactive "p")
+  (let ((case-fold-search nil))
+    (if (looking-at Man-heading-regexp)
+	(forward-line -1))
+    (if (re-search-backward Man-heading-regexp (point-min) t n)
+	(beginning-of-line)
+      (goto-char (point-min)))))
+
+(defun Man-find-section (section)
+  "Move point to SECTION if it exists, otherwise don't move point.
+Returns t if section is found, nil otherwise."
+  (let ((curpos (point))
+	(case-fold-search nil))
+    (goto-char (point-min))
+    (if (re-search-forward (concat "^" section) (point-max) t)
+	(progn (beginning-of-line) t)
+      (goto-char curpos)
+      nil)
+    ))
+
+(defun Man-goto-section ()
+  "Query for section to move point to."
+  (interactive)
+  (aput 'Man-sections-alist
+	(let* ((default (aheadsym Man-sections-alist))
+	       (completion-ignore-case t)
+	       chosen
+	       (prompt (concat "Go to section: (default " default ") ")))
+	  (setq chosen (completing-read prompt Man-sections-alist))
+	  (if (or (not chosen)
+		  (string= chosen ""))
+	      default
+	    chosen)))
+  (Man-find-section (aheadsym Man-sections-alist)))
+
+(defun Man-goto-see-also-section ()
+  "Move point the the \"SEE ALSO\" section.
+Actually the section moved to is described by `Man-see-also-regexp'."
+  (interactive)
+  (if (not (Man-find-section Man-see-also-regexp))
+      (error (concat "No " Man-see-also-regexp
+		     " section found in the current manpage"))))
 
-(defun Manual-clean-to-unique-pages-only (manlist)
-  "Prune the current list of pages down to a unique set."
-  (let (page-name unique-pages)
-    (apply 'append
-	   (mapcar '(lambda (page)
-		      (cond (page
-			     (and (string-match ".*/\\(.*\\)" page)
-				  (setq page-name (substring page (match-beginning 1)
-							     (match-end 1)))
-				  ;; try to clip off .Z, .gz suffixes
-				  (and (string-match "\\(.*\\)\\.\\(.+\\)\\.\\(.+\\)"
-						     page-name)
-				       (setq page-name
-					     (substring page-name (match-beginning 1)
-							(match-end 2)))))
-			     ;; add Manual-unique-pages if it isn't there
-			     ;;  and return file
-			     (if (and unique-pages
-				      page-name
-				      (string-match (concat "\\b" page-name "\\b")
-						    unique-pages))
-				 nil
-			       (setq unique-pages (concat unique-pages
-								 page-name
-								 " "))
-			       (list page)))))
-		   manlist))))
-			    
+(defun Man-follow-manual-reference (reference)
+  "Get one of the manpages referred to in the \"SEE ALSO\" section.
+Specify which reference to use; default is based on word at point."
+  (interactive
+   (if (not Man-refpages-alist)
+       (error "There are no references in the current man page")
+     (list (let* ((default (or
+			     (car (all-completions
+				   (save-excursion
+				     (skip-syntax-backward "w()")
+				     (skip-chars-forward " \t")
+				     (let ((word (current-word)))
+				       ;; strip a trailing '-':
+				       (if (string-match "-$" word)
+					   (substring word 0
+						      (match-beginning 0))
+					 word)))
+				   Man-refpages-alist))
+			     (aheadsym Man-refpages-alist)))
+		   chosen
+		   (prompt (concat "Refer to: (default " default ") ")))
+	      (setq chosen (completing-read prompt Man-refpages-alist nil t))
+	      (if (or (not chosen)
+		      (string= chosen ""))
+		  default
+		chosen)))))
+  (if (not Man-refpages-alist)
+      (error "Can't find any references in the current manpage")
+    (aput 'Man-refpages-alist reference)
+    (Man-getpage-in-background
+     (Man-translate-references (aheadsym Man-refpages-alist)))))
+
+(defun Man-kill ()
+  "Kill the buffer containing the manpage."
+  (interactive)
+  (let ((buff (current-buffer)))
+    (delete-windows-on buff)
+    (kill-buffer buff))
+  (if (and window-system
+	   (or (eq Man-notify-method 'newframe)
+	       (and pop-up-frames
+		    (eq Man-notify-method 'bully))))
+      (delete-frame)))
+
+(defun Man-quit ()
+  "Bury the buffer containing the manpage."
+  (interactive)
+  (let ((buff (current-buffer)))
+    (delete-windows-on buff)
+    (bury-buffer buff))
+  (if (and window-system
+	   (or (eq Man-notify-method 'newframe)
+	       (and pop-up-frames
+		    (eq Man-notify-method 'bully))))
+      (delete-frame)))
+
+(defun Man-goto-page (page)
+  "Go to the manual page on page PAGE."
+  (interactive
+   (if (not Man-page-list)
+       (let ((args Man-arguments))
+	 (kill-buffer (current-buffer))
+	 (error "Can't find the %s manpage" args))
+     (if (= (length Man-page-list) 1)
+	 (error "You're looking at the only manpage in the buffer")
+       (list (read-minibuffer (format "Go to manpage [1-%d]: "
+				      (length Man-page-list)))))))
+  (if (not Man-page-list)
+      (let ((args Man-arguments))
+	(kill-buffer (current-buffer))
+	(error "Can't find the %s manpage" args)))
+  (if (or (< page 1)
+	  (> page (length Man-page-list)))
+      (error "No manpage %d found" page))
+  (let* ((page-range (nth (1- page) Man-page-list))
+	 (page-start (car page-range))
+	 (page-end (car (cdr page-range))))
+    (setq Man-current-page page
+	  Man-page-mode-string (Man-make-page-mode-string))
+    (widen)
+    (goto-char page-start)
+    (narrow-to-region page-start page-end)
+    (Man-build-section-alist)
+    (Man-build-references-alist)
+    (goto-char (point-min))))
 
 
-(defun Manual-insert-man-file (name)
-  ;; Insert manual file (unpacked as necessary) into buffer
-  (cond ((equal (substring name -3) ".gz")
-	 (call-process "gunzip" nil t nil "--stdout" name))
-        ((or (equal (substring name -2) ".Z")
-	     ;; HPUX uses directory names that end in .Z and compressed
-	     ;; files that don't.  How gratuitously random.
-             (let ((case-fold-search nil))
-               (string-match "\\.Z/" name)))
-	 (call-process "zcat" name t nil)) ;; XEmacs change for HPUX
-	((equal (substring name -2) ".z")
-	 (call-process "pcat" nil t nil name))
-	(t
-	 (insert-file-contents name))))
-
-(defmacro Manual-delete-char (n)
-  ;; in v19, delete-char is compiled as a function call, but delete-region
-  ;; is byte-coded, so it's much faster.
-  ;; (We were spending 40% of our time in delete-char alone.)
-  (list 'delete-region '(point) (list '+ '(point) n)))
-
-;; Hint: BS stands for more things than "back space"
-(defun Manual-nuke-nroff-bs (&optional apropos-mode)
-  (interactive "*")
-  (if Manual-use-rosetta-man
-      (call-process-region (point-min) (point-max) "rman" t t nil)
-    ;;
-    ;; turn underlining into italics
-    ;;
-    (goto-char (point-min))
-    (while (search-forward "_\b" nil t)
-      ;; searching for underscore-backspace and then comparing the following
-      ;; chars until the sequence ends turns out to be much faster than searching
-      ;; for a regexp which matches the whole sequence.
-      (let ((s (match-beginning 0)))
-	(goto-char s)
-	(while (and (= (following-char) ?_)
-		    (= (char-after (1+ (point))) ?\b))
-	  (Manual-delete-char 2)
-	  (forward-char 1))
-	(set-extent-face (make-extent s (point)) 'man-italic)))
-    ;;
-    ;; turn overstriking into bold
-    ;;
-    (goto-char (point-min))
-    (while (re-search-forward "\\([^\n]\\)\\(\b\\1\\)" nil t)
-      ;; Surprisingly, searching for the above regexp is faster than searching
-      ;; for a backspace and then comparing the preceding and following chars,
-      ;; I presume because there are many false matches, meaning more funcalls
-      ;; to re-search-forward.
-      (let ((s (match-beginning 0)))
-	(goto-char s)
-	;; Some systems (SGI) overstrike multiple times, eg, "M\bM\bM\bM".
-	(while (looking-at "\\([^\n]\\)\\(\b\\1\\)+")
-	  (delete-region (+ (point) 1) (match-end 0))
-	  (forward-char 1))
-	(set-extent-face (make-extent s (point)) 'man-bold)))
-    ;;
-    ;; hack bullets: o^H+ --> +
-    (goto-char (point-min))
-    (while (search-forward "\b" nil t)
-      (Manual-delete-char -2))
-
-    (if (> (buffer-size) 100) ; minor kludge
-	(Manual-nuke-nroff-bs-footers))
-    ) ;; not Manual-use-rosetta-man
-  ;;
-  ;; turn subsection header lines into bold
-  ;;
-  (goto-char (point-min))
-  (if apropos-mode
-      (while (re-search-forward "[a-zA-Z0-9] ([0-9]" nil t)
-	(forward-char -2)
-	(delete-backward-char 1))
-
-    ;;    (while (re-search-forward "^[^ \t\n]" nil t)
-    ;;      (set-extent-face (make-extent (match-beginning 0)
-    ;;                                   (progn (end-of-line) (point)))
-    ;;                      'man-heading))
-
-    ;; boldface the first line
-    (if (looking-at "[^ \t\n].*$")
-	(set-extent-face (make-extent (match-beginning 0) (match-end 0))
-			 'man-bold))
-
-    ;; boldface subsequent title lines
-    ;; Regexp to match section headers changed to match a non-indented
-    ;; line preceded by a blank line and followed by an indented line. 
-    ;; This seems to work ok for manual pages but gives better results
-    ;; with other nroff'd files
-    (while (re-search-forward "\n\n\\([^ \t\n].*\\)\n[ \t]+[^ \t\n]" nil t)
-      (goto-char (match-end 1))
-      (set-extent-face (make-extent (match-beginning 1) (match-end 1))
-		       'man-heading)
-      (forward-line 1))
-    )
-
-  (if Manual-use-rosetta-man
-      nil
-    ;; Zap ESC7,  ESC8, and ESC9
-    ;; This is for Sun man pages like "man 1 csh"
-    (goto-char (point-min))
-    (while (re-search-forward "\e[789]" nil t)
-      (replace-match "")))
-  
-  ;; Nuke blanks lines at start.
-  ;;  (goto-char (point-min))
-  ;;  (skip-chars-forward "\n")
-  ;;  (delete-region (point-min) (point))
-
-  (Manual-mouseify-xrefs)
-  )
-
-(fset 'nuke-nroff-bs 'Manual-nuke-nroff-bs) ; use old name
-
-
-(defun Manual-nuke-nroff-bs-footers ()
-  ;; Nuke headers and footers.
-  ;;
-  ;; nroff assumes pages are 66 lines high.  We assume that, and that the
-  ;; first and last line on each page is expendible.  There is no way to
-  ;; tell the difference between a page break in the middle of a paragraph
-  ;; and a page break between paragraphs (the amount of extra whitespace
-  ;; that nroff inserts is the same in both cases) so this might strip out
-  ;; a blank line were one should remain.  I think that's better than
-  ;; leaving in a blank line where there shouldn't be one.  (Need I say
-  ;; it: FMH.)
-  ;;
-  ;; Note that if nroff spits out error messages, pages will be more than
-  ;; 66 lines high, and we'll lose badly.  That's ok because standard
-  ;; nroff doesn't do any diagnostics, and the "gnroff" wrapper for groff
-  ;; turns off error messages for compatibility.  (At least, it's supposed
-  ;; to.)
-  ;; 
-  (goto-char (point-min))
-  ;; first lose the status output
-  (let ((case-fold-search t))
-    (if (and (not (looking-at "[^\n]*warning"))
-	     (looking-at "Reformatting.*\n"))
-	(delete-region (match-beginning 0) (match-end 0))))
-
-  ;; kludge around a groff bug where it won't keep quiet about some
-  ;; warnings even with -Wall or -Ww.
-  (cond ((looking-at "grotty:")
-	 (while (looking-at "grotty:")
-	   (delete-region (point) (progn (forward-line 1) (point))))
-	 (if (looking-at " *done\n")
-	     (delete-region (point) (match-end 0)))))
-
-  (let ((pages '())
-	p)
-    ;; collect the page boundary markers before we start deleting, to make
-    ;; it easier to strip things out without changing the page sizes.
-    (while (not (eobp))
-      (forward-line 66)
-      (setq pages (cons (point-marker) pages)))
-    (setq pages (nreverse pages))
-    (while pages
-      (goto-char (car pages))
-      (set-marker (car pages) nil)
-      ;;
-      ;; The lines are: 3 blank; footer; 6 blank; header; 3 blank.
-      ;; We're in between the previous footer and the following header,
-      ;;
-      ;; First lose 3 blank lines, the header, and then 3 more.
-      ;;
-      (setq p (point))
-      (skip-chars-forward "\n")
-      (delete-region p (point))
-      (and (looking-at "[^\n]+\n\n?\n?\n?")
-	   (delete-region (match-beginning 0) (match-end 0)))
-      ;;
-      ;; Next lose the footer, and the 3 blank lines after, and before it.
-      ;; But don't lose the last footer of the manual entry; that contains
-      ;; the "last change" date, so it's not completely uninteresting.
-      ;; (Actually lose all blank lines before it; sh(1) needs this.)
-      ;;
-      (skip-chars-backward "\n")
-      (beginning-of-line)
-      (if (null (cdr pages))
-	  nil
-	(and (looking-at "[^\n]+\n\n?\n?\n?")
-	     (delete-region (match-beginning 0) (match-end 0))))
-      (setq p (point))
-      (skip-chars-backward "\n")
-      (if (> (- p (point)) 4)
-	  (delete-region (+ 2 (point)) p)
-	(delete-region (1+ (point)) p))
-;      (and (looking-at "\n\n?\n?")
-;	   (delete-region (match-beginning 0) (match-end 0)))
+(defun Man-next-manpage ()
+  "Find the next manpage entry in the buffer."
+  (interactive)
+  (if (= (length Man-page-list) 1)
+      (error "This is the only manpage in the buffer"))
+  (if (< Man-current-page (length Man-page-list))
+      (Man-goto-page (1+ Man-current-page))
+    (if Man-circular-pages-flag
+	(Man-goto-page 1)
+      (error "You're looking at the last manpage in the buffer"))))
 
-      (setq pages (cdr pages)))
-    ;;
-    ;; Now nuke the extra blank lines at the beginning and end.
-    (goto-char (point-min))
-    (if (looking-at "\n+")
-	(delete-region (match-beginning 0) (match-end 0)))
-    (forward-line 1)
-    (if (looking-at "\n\n+")
-	(delete-region (1+ (match-beginning 0)) (match-end 0)))
-    (goto-char (point-max))
-    (skip-chars-backward "\n")
-    (delete-region (point) (point-max))
-    (beginning-of-line)
-    (forward-char -1)
-    (setq p (point))
-    (skip-chars-backward "\n")
-    (if (= ?\n (following-char)) (forward-char 1))
-    (if (> (point) (1+ p))
-	(delete-region (point) p))
-    ))
-
-;(defun Manual-nuke-nroff-bs-footers ()
-;  ;; Nuke headers: "MORE(1) UNIX Programmer's Manual MORE(1)"
-;  (goto-char (point-min))
-;  (while (re-search-forward "^ *\\([A-Za-z][-_A-Za-z0-9]*([0-9A-Za-z]+)\\).*\\1$" nil t)
-;    (replace-match ""))
-;  
-;  ;;
-;  ;; it would appear that we have a choice between sometimes introducing
-;  ;; an extra blank line when a paragraph was broken by a footer, and
-;  ;; sometimes not putting in a blank line between two paragraphs when
-;  ;; a footer appeared right between them.  FMH; I choose the latter.
-;  ;;
-;
-;  ;; Nuke footers: "Printed 12/3/85	27 April 1981	1"
-;  ;;    Sun appear to be on drugz:
-;  ;;     "Sun Release 3.0B  Last change: 1 February 1985     1"
-;  ;;    HP are even worse!
-;  ;;     "     Hewlett-Packard   -1- (printed 12/31/99)"  FMHWA12ID!!
-;  ;;    System V (well WICATs anyway):
-;  ;;     "Page 1			  (printed 7/24/85)"
-;  ;;    Who is administering PCP to these corporate bozos?
-;  (goto-char (point-min))
-;  (while (re-search-forward
-;	   (cond
-;	    ((eq system-type 'hpux)
-;	     "\n\n?[ \t]*Hewlett-Packard\\(\\| Company\\)[ \t]*- [0-9]* -.*\n")
-;	    ((eq system-type 'dgux-unix)
-;	     "\n\n?[ \t]*Licensed material--.*Page [0-9]*\n")
-;	    ((eq system-type 'usg-unix-v)
-;	     "\n\n? *Page [0-9]*.*(printed [0-9/]*)\n")
-;	    (t
-;	     "\n\n?\\(Printed\\|Sun Release\\) [0-9].*[0-9]\n"))
-;	   nil t)
-;    (replace-match ""))
-;
-;  ;;    Also, hack X footers:
-;  ;;     "X Version 11         Last change: Release 5         1"
-;  (goto-char (point-min))
-;  (while (re-search-forward "\n\n?X Version [^\n]+\n" nil t)
-;    (replace-match ""))
-;
-;  ;; Crunch blank lines
-;  (goto-char (point-min))
-;  (while (re-search-forward "\n\n\n\n*" nil t)
-;    (replace-match "\n\n"))
-;  )
+(defun Man-previous-manpage ()
+  "Find the previous manpage entry in the buffer."
+  (interactive)
+  (if (= (length Man-page-list) 1)
+      (error "This is the only manpage in the buffer"))
+  (if (> Man-current-page 1)
+      (Man-goto-page (1- Man-current-page))
+    (if Man-circular-pages-flag
+	(Man-goto-page (length Man-page-list))
+      (error "You're looking at the first manpage in the buffer"))))
+
+;; Init the man package variables, if not already done.
+(Man-init-defvars)
 
-(defun Manual-mouseify-xrefs ()
-  (goto-char (point-min))
-  (forward-line 1)
-  (let ((case-fold-search nil)
-	s e name extent)
-    ;; possibly it would be faster to rewrite this expression to search for
-    ;; a less common sequence first (like "([0-9]") and then back up to see
-    ;; if it's really a match.  This function is 15% of the total time, 13%
-    ;; of which is this call to re-search-forward.
-    (while (re-search-forward "[a-zA-Z_][-a-zA-Z0-9_.]*([0-9][a-zA-Z0-9]*)"
-			      nil t)
-      (setq s (match-beginning 0)
-	    e (match-end 0)
-	    name (buffer-substring s e))
-      (goto-char s)
-      (skip-chars-backward " \t")
-      (if (and (bolp)
-	       (progn (backward-char 1) (= (preceding-char) ?-)))
-	  (progn
-	    (setq s (point))
-	    (skip-chars-backward "-a-zA-Z0-9_.")
-	    (setq name (concat (buffer-substring (point) (1- s)) name))
-	    (setq s (point))))
-      ;; if there are upper case letters in the section, downcase them.
-      (if (string-match "(.*[A-Z]+.*)$" name)
-	  (setq name (concat (substring name 0 (match-beginning 0))
-			     (downcase (substring name (match-beginning 0))))))
-      ;; (setq already-fontified (extent-at s))
-      (setq extent (make-extent s e))
-      (set-extent-property extent 'man (list 'Manual-follow-xref name))
-      (set-extent-property extent 'highlight t)
-      ;; (if (not already-fontified)...
-      (set-extent-face extent 'man-xref)
-      (goto-char e))))
-
-(defun Manual-follow-xref (&optional name-or-event)
-  "Invoke `manual-entry' on the cross-reference under the mouse.
-When invoked noninteractively, the arg may be an xref string to parse instead."
-  (interactive "e")
-  (if (eventp name-or-event)
-      (let* ((p (event-point name-or-event))
-	     (extent (and p (extent-at p
-			     (event-buffer name-or-event)
-			     'highlight)))
-	     (data (and extent (extent-property extent 'man))))
-	(if (eq (car-safe data) 'Manual-follow-xref)
-	    (eval data)
-	  (error "no manual cross-reference there.")))
-    (let ((Manual-match-topic-exactly t)
-	  (Manual-query-multiple-pages nil))
-      (or (manual-entry name-or-event)
-	  ;; If that didn't work, maybe it's in a different section than the
-	  ;; man page writer expected.  For example, man pages tend assume
-	  ;; that all user programs are in section 1, but X tends to generate
-	  ;; makefiles that put things in section "n" instead...
-	  (and (string-match "[ \t]*([^)]+)\\'" name-or-event)
-	       (progn
-		 (message "No entries found for %s; checking other sections..."
-			  name-or-event)
-		 (manual-entry
-		  (substring name-or-event 0 (match-beginning 0))
-		  nil t)))))))
+(provide 'man)
 
-(defun Manual-popup-menu (&optional event)
-  "Pops up a menu of cross-references in this manual page.
-If there is a cross-reference under the mouse button which invoked this
-command, it will be the first item on the menu.  Otherwise, they are
-on the menu in the order in which they appear in the buffer."
-  (interactive "e")
-  (let ((buffer (current-buffer))
-	(sep "---")
-	(prefix "Show Manual Page for ")
-	xref items)
-    (cond (event
-	   (setq buffer (event-buffer event))
-	   (let* ((p (event-point event))
-		  (extent (and p (extent-at p buffer 'highlight)))
-		  (data (and extent (extent-property extent 'man))))
-	     (if (eq (car-safe data) 'Manual-follow-xref)
-		 (setq xref (nth 1 data))))))
-    (if xref (setq items (list sep xref)))
-    (map-extents #'(lambda (extent ignore)
-		     (let ((data (extent-property extent 'man)))
-		       (if (and (eq (car-safe data) 'Manual-follow-xref)
-				(not (member (nth 1 data) items)))
-			   (setq items (cons (nth 1 data) items)))
-		    nil))
-		 buffer)
-    (if (eq sep (car items)) (setq items (cdr items)))
-    (let ((popup-menu-titles nil))
-      (popup-menu
-       (cons "Manual Entry"
-	     (mapcar #'(lambda (item)
-			 (if (eq item sep)
-			     item
-                           (vector (concat prefix item)
-                                   (list 'Manual-follow-xref item) t)))
-		     (nreverse items)))))))
-
-(defun pager-cleanup-hook ()
-  "cleanup man page if called via $PAGER"
-  (let ((buf-name (or buffer-file-name (buffer-name))))
-	(if (and (or (string-match "^/tmp/man[0-9]+" buf-name)
-		     (string-match ".*/man/\\(man\\|cat\\)[1-9a-z]/" buf-name))
-		 (not (string-match Manual-bogus-file-pattern buf-name)))
-	    (let (buffer manpage)
-	      (require 'man)
-	      (goto-char (point-min))
-	      (setq buffer-read-only nil)
-	      (Manual-nuke-nroff-bs)
-	      (goto-char (point-min))
-	      (if (re-search-forward "[^ \t]")
-		  (goto-char (- (point) 1)))
-	      (if (looking-at "\\([a-zA-Z0-9]+\\)[ \t]*(")
-		  (setq manpage (buffer-substring (match-beginning 1) (match-end 1)))
-		(setq manpage "???"))
-	      (setq buffer
-		    (rename-buffer
-		     (generate-new-buffer-name (concat "*man " manpage "*"))))
-	      (setq buffer-file-name nil)
-	      (goto-char (point-min))
-	      (insert (format "%s\n" buf-name))
-	      (goto-char (point-min))
-	      (buffer-disable-undo buffer)
-	      (set-buffer-modified-p nil)
-	      (Manual-mode)
-	      ))))
-
-(add-hook 'server-visit-hook 'pager-cleanup-hook)
-(provide 'man)
+;;; man.el ends here