comparison 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
comparison
equal deleted inserted replaced
71:bae944334fa4 72:b9518feda344
1 ;;; man.el --- browse UNIX manual pages 1 ;;; man.el --- browse UNIX manual pages
2 ;; Keywords: help 2
3 3 ;; Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc.
4 ;; Copyright (C) 1985, 1993, 1994 Free Software Foundation, Inc. 4
5 ;; 5 ;; Author: Barry A. Warsaw <bwarsaw@cen.com>
6 ;; Keywords: help
7 ;; Adapted-By: ESR, pot
8
6 ;; This file is part of XEmacs. 9 ;; This file is part of XEmacs.
7 10
8 ;; XEmacs is free software; you can redistribute it and/or modify it 11 ;; XEmacs is free software; you can redistribute it and/or modify it
9 ;; under the terms of the GNU General Public License as published by 12 ;; under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 2, or (at your option) 13 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; WITHOUT ANY WARRANTY; without even the implied warranty of 17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 ;; General Public License for more details. 19 ;; General Public License for more details.
17 20
18 ;; You should have received a copy of the GNU General Public License 21 ;; You should have received a copy of the GNU General Public License
19 ;; along with XEmacs; see the file COPYING. If not, write to the 22 ;; along with XEmacs; see the file COPYING. If not, write to the Free
20 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, 23 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 ;; Boston, MA 02111-1307, USA. 24 ;; 02111-1307, USA.
22 25
23 ;;; Synched up with: Not synched with FSF. 26 ;;; Synched up with: FSF 19.34.
24 ;;; ICK! This file is almost completely different from FSF. 27
25 ;;; Someone clarify please. 28 ;;; Commentary:
26 29
27 ;; Mostly rewritten by Alan K. Stebbens <aks@hub.ucsb.edu> 11-apr-90. 30 ;; This code provides a function, `man', with which you can browse
31 ;; UNIX manual pages. Formatting is done in background so that you
32 ;; can continue to use your Emacs while processing is going on.
28 ;; 33 ;;
29 ;; o Match multiple man pages using TOPIC as a simple pattern 34 ;; The mode also supports hypertext-like following of manual page SEE
30 ;; o Search unformatted pages, even when formatted matches are found 35 ;; ALSO references, and other features. See below or do `?' in a
31 ;; o Query the user as to which pages are desired 36 ;; manual page buffer for details.
32 ;; o Use of the prefix arg to toggle/bypass the above features 37
33 ;; o Buffers named by the first topic in the buffer 38 ;; ========== Credits and History ==========
34 ;; o Automatic uncompress for compressed man pages (.Z, .z, and .gz) 39 ;; In mid 1991, several people posted some interesting improvements to
35 ;; o View the resulting buffer using M-x view mode 40 ;; man.el from the standard emacs 18.57 distribution. I liked many of
36 ;; 41 ;; these, but wanted everything in one single package, so I decided
37 ;; Modified 16-mar-91 by Jamie Zawinski <jwz@lucid.com> to default the 42 ;; to incorporate them into a single manual browsing mode. While
38 ;; manual topic to the symbol at point, just like find-tag does. 43 ;; much of the code here has been rewritten, and some features added,
39 ;; 44 ;; these folks deserve lots of credit for providing the initial
40 ;; Modified 22-mar-93 by jwz to use multiple fonts and follow xrefs with mouse. 45 ;; excellent packages on which this one is based.
41 ;; 46
42 ;; Modified 16-apr-93 by Dave Gillespie <daveg@synaptics.com> to make 47 ;; Nick Duffek <duffek@chaos.cs.brandeis.edu>, posted a very nice
43 ;; apropos work nicely; work correctly when bold or italic is unavailable; 48 ;; improvement which retrieved and cleaned the manpages in a
44 ;; reuse old buffer if topic is re-selected (in Manual-topic-buffer mode). 49 ;; background process, and which correctly deciphered such options as
45 ;; 50 ;; man -k.
46 ;; Modified 4-apr-94 by jwz: merged in Tibor Polgar's code for manpath.conf. 51
47 ;; 52 ;; Eric Rose <erose@jessica.stanford.edu>, submitted manual.el which
48 ;; Modified 19-apr-94 by Tibor Polgar <tlp00@spg.amdahl.com> to add support for 53 ;; provided a very nice manual browsing mode.
49 ;; $PAGER variable to be emacsclient and properly process man pages (assuming 54
50 ;; the man pages were built by man in /tmp. also fixed bug with man list being 55 ;; This package was available as `superman.el' from the LCD package
51 ;; backwards. 56 ;; for some time before it was accepted into Emacs 19. The entry
52 ;; 57 ;; point and some other names have been changed to make it a drop-in
53 ;; Modified 23-aug-94 by Tibor Polgar <tlp00@spg.amdahl.com> to add support for 58 ;; replacement for the old man.el package.
54 ;; displaying only one instance of a man page (Manual-unique-man-sections-only) 59
55 ;; Fixed some more man page ordering bugs, bug with Manual-query-multiple-pages. 60 ;; Francesco Potorti` <pot@cnuce.cnr.it> cleaned it up thoroughly,
56 ;; 61 ;; making it faster, more robust and more tolerant of different
57 ;; Modified 29-nov-94 by Ben Wing <wing@spg.amdahl.com>: small fixes 62 ;; systems' man idiosyncrasies.
58 ;; that should hopefully make things work under HPUX and IRIX.; 63
59 ;; 64 ;; ========== Features ==========
60 ;; Modified 15-jul-95 by Dale Atems <atems@physics.wayne.edu>: 65 ;; + Runs "man" in the background and pipes the results through a
61 ;; some extensive rewriting to make things work right (more or less) 66 ;; series of sed and awk scripts so that all retrieving and cleaning
62 ;; under IRIX. 67 ;; is done in the background. The cleaning commands are configurable.
63 ;; 68 ;; + Syntax is the same as Un*x man
64 ;; Modified 08-mar-96 by Hubert Palme <palme@wrcs3.urz.uni-wuppertal.de>: 69 ;; + Functionality is the same as Un*x man, including "man -k" and
65 ;; added /usr/share/catman to the manual directory list for IRIX (5.3) 70 ;; "man <section>", etc.
66 ;; 71 ;; + Provides a manual browsing mode with keybindings for traversing
67 ;; This file defines "manual-entry", and the remaining definitions all 72 ;; the sections of a manpage, following references in the SEE ALSO
68 ;; begin with "Manual-". This makes the autocompletion on "M-x man" work. 73 ;; section, and more.
69 ;; 74 ;; + Multiple manpages created with the same man command are put into
70 ;; Variables of interest: 75 ;; a narrowed buffer circular list.
71 ;; 76
72 ;; Manual-program 77 ;; ============= TODO ===========
73 ;; Manual-topic-buffer 78 ;; - Add a command for printing.
74 ;; Manual-buffer-view-mode 79 ;; - The awk script deletes multiple blank lines. This behaviour does
75 ;; Manual-directory-list 80 ;; not allow to understand if there was indeed a blank line at the
76 ;; Manual-formatted-directory-list 81 ;; end or beginning of a page (after the header, or before the
77 ;; Manual-match-topic-exactly 82 ;; footer). A different algorithm should be used. It is easy to
78 ;; Manual-query-multiple-pages 83 ;; compute how many blank lines there are before and after the page
79 ;; Manual-page-history 84 ;; headers, and after the page footer. But it is possible to compute
80 ;; Manual-subdirectory-list 85 ;; the number of blank lines before the page footer by euristhics
81 ;; Manual-man-page-section-ids 86 ;; only. Is it worth doing?
82 ;; Manual-formatted-page-prefix 87 ;; - Allow a user option to mean that all the manpages should go in
83 ;; Manual-unformatted-page-prefix 88 ;; the same buffer, where they can be browsed with M-n and M-p.
84 ;; Manual-use-full-section-ids 89 ;; - Allow completion on the manpage name when calling man. This
85 90 ;; requires a reliable list of places where manpages can be found. The
86 (defvar Manual-program "man" "\ 91 ;; drawback would be that if the list is not complete, the user might
87 *Name of the program to invoke in order to format the source man pages.") 92 ;; be led to believe that the manpages in the missing directories do
88 93 ;; not exist.
89 (defvar Manual-section-switch (if (eq system-type 'usg-unix-v) "-s" nil) 94
90 "SysV needs this to work right.") 95
91 96 ;;; Code:
92 (defvar Manual-topic-buffer t "\ 97
93 *Non-nil means \\[Manual-entry] should output the manual entry for TOPIC into 98 (require 'assoc)
94 a buffer named *man TOPIC*, otherwise, it should name the buffer 99
95 *Manual Entry*.") 100 ;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
96 101 ;; empty defvars (keep the compiler quiet)
97 (defvar Manual-buffer-view-mode t "\ 102
98 *Whether manual buffers should be placed in view-mode. 103 (defvar Man-notify)
99 nil means leave the buffer in fundamental-mode in another window. 104 (defvar Man-current-page)
100 t means use `view-buffer' to display the man page in the current window. 105 (defvar Man-page-list)
101 Any other value means use `view-buffer-other-window'.") 106 (defvar Man-filter-list nil
102 107 "*Manpage cleaning filter command phrases.
103 (defvar Manual-match-topic-exactly t "\ 108 This variable contains a list of the following form:
104 *Non-nil means that \\[manual-entry] will match the given TOPIC exactly, rather 109
105 apply it as a pattern. When this is nil, and \"Manual-query-multiple-pages\" 110 '((command-string phrase-string*)*)
106 is non-nil, then \\[manual-entry] will query you for all matching TOPICs. 111
107 This variable only has affect on the preformatted man pages (the \"cat\" files), 112 Each phrase-string is concatenated onto the command-string to form a
108 since the \"man\" command always does exact topic matches.") 113 command filter. The (standard) output (and standard error) of the Un*x
109 114 man command is piped through each command filter in the order the
110 (defvar Manual-query-multiple-pages nil "\ 115 commands appear in the association list. The final output is placed in
111 *Non-nil means that \\[manual-entry] will query the user about multiple man 116 the manpage buffer.")
112 pages which match the given topic. The query is done using the function 117
113 \"y-or-n-p\". If this variable is nil, all man pages with topics matching the 118 (defvar Man-original-frame)
114 topic given to \\[manual-entry] will be inserted into the temporary buffer. 119 (defvar Man-arguments)
115 See the variable \"Manual-match-topic-exactly\" to control the matching.") 120 (defvar Man-sections-alist)
116 121 (defvar Man-refpages-alist)
117 (defvar Manual-unique-man-sections-only nil 122 (defvar Man-uses-untabify-flag t
118 "*Only present one man page per section. This variable is useful if the same or 123 "When non-nil use `untabify' instead of Man-untabify-command.")
119 up/down level man pages for the same entry are present in mulitple man paths. 124 (defvar Man-page-mode-string)
120 When set to t, only the first entry found in a section is displayed, the others 125 (defvar Man-sed-script nil
121 are ignored without any messages or warnings. Note that duplicates can occur if 126 "Script for sed to nuke backspaces and ANSI codes from manpages.")
122 the system has both formatted and unformatted version of the same page.") 127
123 128 ;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
124 (defvar Manual-mode-hook nil 129 ;; user variables
125 "Function or functions run on entry to Manual-mode.") 130
126 131 (defvar Man-fontify-manpage-flag t
127 (defvar Manual-directory-list nil "\ 132 "*Make up the manpage with fonts.")
128 *A list of directories used with the \"man\" command, where each directory 133
129 contains a set of \"man?\" and \"cat?\" subdirectories. If this variable is nil, 134 (defvar Man-overstrike-face 'bold
130 it is initialized by \\[Manual-directory-list-init].") 135 "*Face to use when fontifying overstrike.")
131 136
132 (defvar Manual-formatted-directory-list nil "\ 137 (defvar Man-underline-face 'underline
133 A list of directories containing formatted man pages. Initialized by 138 "*Face to use when fontifying underlining.")
134 \\[Manual-directory-list-init].") 139
135 140 ;; Use the value of the obsolete user option Man-notify, if set.
136 (defvar Manual-unformatted-directory-list nil "\ 141 (defvar Man-notify-method (if (boundp 'Man-notify) Man-notify 'friendly)
137 A list of directories containing the unformatted (source) man pages. 142 "*Selects the behavior when manpage is ready.
138 Initialized by \\[Manual-directory-list-init].") 143 This variable may have one of the following values, where (sf) means
139 144 that the frames are switched, so the manpage is displayed in the frame
140 (defvar Manual-page-history nil "\ 145 where the man command was called from:
141 A list of names of previously visited man page buffers.") 146
142 147 newframe -- put the manpage in its own frame (see `Man-frame-parameters')
143 (defvar Manual-manpath-config-file "/usr/lib/manpath.config" 148 pushy -- make the manpage the current buffer in the current window
144 "*Location of the manpath.config file, if any.") 149 bully -- make the manpage the current buffer and only window (sf)
145 150 aggressive -- make the manpage the current buffer in the other window (sf)
146 (defvar Manual-apropos-switch "-k" 151 friendly -- display manpage in the other window but don't make current (sf)
147 "*Man apropos switch") 152 polite -- don't display manpage, but prints message and beep when ready
148 153 quiet -- like `polite', but don't beep
149 ;; New variables. 154 meek -- make no indication that the manpage is ready
150 155
151 (defvar Manual-subdirectory-list nil "\ 156 Any other value of `Man-notify-method' is equivalent to `meek'.")
152 A list of all the subdirectories in which man pages may be found. 157
153 Iniialized by Manual-directory-list-init.") 158 (defvar Man-frame-parameters nil
154 159 "*Frame parameter list for creating a new frame for a manual page.")
155 ;; This is for SGI systems; don't know what it should be otherwise. 160
156 (defvar Manual-man-page-section-ids "1nl6823457poD" "\ 161 (defvar Man-downcase-section-letters-flag t
157 String containing all suffix characters for \"cat\" and \"man\" 162 "*Letters in sections are converted to lower case.
158 that identify valid sections of the Un*x manual.") 163 Some Un*x man commands can't handle uppercase letters in sections, for
159 164 example \"man 2V chmod\", but they are often displayed in the manpage
160 (defvar Manual-formatted-page-prefix "cat" "\ 165 with the upper case letter. When this variable is t, the section
161 Prefix for directories where formatted man pages are to be found. 166 letter (e.g., \"2V\") is converted to lowercase (e.g., \"2v\") before
162 Defaults to \"cat\".") 167 being sent to the man background process.")
163 168
164 (defvar Manual-unformatted-page-prefix "man" "\ 169 (defvar Man-circular-pages-flag t
165 Prefix for directories where unformatted man pages are to be found. 170 "*If t, the manpage list is treated as circular for traversal.")
166 Defaults to \"man\".") 171
167 172 (defvar Man-section-translations-alist
168 (defvar Manual-leaf-signature "" "\ 173 (list
169 Regexp for identifying \"leaf\" subdirectories in the search path. 174 '("3C++" . "3")
170 If empty, initialized by Manual-directory-list-init.") 175 ;; Some systems have a real 3x man section, so let's comment this.
171 176 ;; '("3X" . "3") ; Xlib man pages
172 (defvar Manual-use-full-section-ids t "\ 177 '("3X11" . "3")
173 If non-nil, pass full section ids to Manual-program, otherwise pass 178 '("1-UCB" . ""))
174 only the first character. Defaults to 't'.") 179 "*Association list of bogus sections to real section numbers.
175 180 Some manpages (e.g. the Sun C++ 2.1 manpages) have section numbers in
176 (defvar Manual-use-subdirectory-list (eq system-type 'irix) "\ 181 their references which Un*x `man' does not recognize. This
177 This makes manual-entry work correctly on SGI machines but it 182 association list is used to translate those sections, when found, to
178 imposes a large startup cost which is why it is not simply on by 183 the associated section number.")
179 default on all systems.") 184
180 185 (defvar manual-program "man"
181 (defvar Manual-use-rosetta-man (not (null (locate-file "rman" exec-path))) "\ 186 "The name of the program that produces man pages.")
182 If non-nil, use RosettaMan (rman) to filter man pages. 187
183 This makes man-page cleanup virtually instantaneous, instead of 188 (defvar Man-untabify-command "pr"
184 potentially taking a long time. 189 "Command used for untabifying.")
185 190
186 Here is information on RosettaMan, from Neal.Becker@comsat.com (Neal Becker): 191 (defvar Man-untabify-command-args (list "-t" "-e")
187 192 "List of arguments to be passed to Man-untabify-command (which see).")
188 RosettaMan is a filter for UNIX manual pages. It takes as input man 193
189 pages formatted for a variety of UNIX flavors (not [tn]roff source) 194 (defvar Man-sed-command "sed"
190 and produces as output a variety of file formats. Currently 195 "Command used for processing sed scripts.")
191 RosettaMan accepts man pages as formatted by the following flavors of 196
192 UNIX: Hewlett-Packard HP-UX, AT&T System V, SunOS, Sun Solaris, OSF/1, 197 (defvar Man-awk-command "awk"
193 DEC Ultrix, SGI IRIX, Linux, SCO; and produces output for the following 198 "Command used for processing awk scripts.")
194 formats: printable ASCII only (stripping page headers and footers), 199
195 section and subsection headers only, TkMan, [tn]roff, Ensemble, RTF, 200 (defvar Man-mode-line-format
196 SGML (soon--I finally found a DTD), HTML, MIME, LaTeX, LaTeX 2e, Perl 5's pod. 201 '("" mode-line-modified
197 202 mode-line-buffer-identification " "
198 RosettaMan improves on other man page filters in several ways: (1) its 203 global-mode-string
199 analysis recognizes the structural pieces of man pages, enabling high 204 " " Man-page-mode-string
200 quality output, (2) its modular structure permits easy augmentation of 205 " %[(" mode-name mode-line-process minor-mode-alist ")%]----"
201 output formats, (3) it accepts man pages formatted with the varient 206 (-3 . "%p") "-%-")
202 macros of many different flavors of UNIX, and (4) it doesn't require 207 "Mode line format for manual mode buffer.")
203 modification or cooperation with any other program. 208
204 209 (defvar Man-mode-map nil
205 RosettaMan is a rewrite of TkMan's man page filter, called bs2tk. (If 210 "Keymap for Man mode.")
206 you haven't heard about TkMan, a hypertext man page browser, you 211
207 should grab it via anonymous ftp from ftp.cs.berkeley.edu: 212 (defvar Man-mode-hook nil
208 /ucb/people/phelps/tkman.tar.Z.) Whereas bs2tk generated output only for 213 "Hook run when Man mode is enabled.")
209 TkMan, RosettaMan generalizes the process so that the analysis can be 214
210 leveraged to new output formats. A single analysis engine recognizes 215 (defvar Man-cooked-hook nil
211 section heads, subsection heads, body text, lists, references to other 216 "Hook run after removing backspaces but before Man-mode processing.")
212 man pages, boldface, italics, bold italics, special characters (like 217
213 bullets), tables (to a degree) and strips out page headers and 218 (defvar Man-name-regexp "[-a-zA-Z0-9_][-a-zA-Z0-9_.]*"
214 footers. The engine sends signals to the selected output functions so 219 "Regular expression describing the name of a manpage (without section).")
215 that an enhancement in the engine improves the quality of output of 220
216 all of them. Output format functions are easy to add, and thus far 221 (defvar Man-section-regexp "[0-9][a-zA-Z+]*\\|[LNln]"
217 average about about 75 lines of C code each. 222 "Regular expression describing a manpage section within parentheses.")
218 223
219 224 (defvar Man-page-header-regexp
220 225 (concat "^[ \t]*\\(" Man-name-regexp
221 *** NOTES ON CURRENT VERSION *** 226 "(\\(" Man-section-regexp "\\))\\).*\\1")
222 227 "Regular expression describing the heading of a page.")
223 Help! I'm looking for people to help with the following projects. 228
224 \(1) Better RTF output format. The current one works, but could be 229 (defvar Man-heading-regexp "^\\([A-Z][A-Z ]+\\)$"
225 made better. (2) Roff macros that produce text that is easily 230 "Regular expression describing a manpage heading entry.")
226 parsable. RosettaMan handles a great variety, but some things, like 231
227 H-P's tables, are intractable. If you write an output format or 232 (defvar Man-see-also-regexp "SEE ALSO"
228 otherwise improve RosettaMan, please send in your code so that I may 233 "Regular expression for SEE ALSO heading (or your equivalent).
229 share the wealth in future releases. 234 This regexp should not start with a `^' character.")
230 235
231 This version can try to identify tables (turn this on with the -T 236 (defvar Man-first-heading-regexp "^[ \t]*NAME$\\|^[ \t]*No manual entry fo.*$"
232 switch) by looking for lines with a large amount of interword spacing, 237 "Regular expression describing first heading on a manpage.
233 reasoning that this is space between columns of a table. This 238 This regular expression should start with a `^' character.")
234 heuristic doesn't always work and sometimes misidentifies ordinary 239
235 text as tables. In general I think it is impossible to perfectly 240 (defvar Man-reference-regexp
236 identify tables from nroff formatted text. However, I do think the 241 (concat "\\(" Man-name-regexp "\\)(\\(" Man-section-regexp "\\))")
237 heuristics can be tuned, so if you have a collection of manual pages 242 "Regular expression describing a reference in the SEE ALSO section.")
238 with unrecognized tables, send me the lot, in formatted form (i.e., 243
239 after formatting with nroff -man), and uuencode them to preserve the 244 (defvar Man-switches ""
240 control characters. Better, if you can think of heuristics that 245 "Switches passed to the man command, as a single string.")
241 distinguish tables from ordinary text, I'd like to hear them. 246
242 247 (defvar Man-specified-section-option
243 248 (if (string-match "-solaris[0-9.]*$" system-configuration)
244 Notes for HTML consumers: This filter does real (heuristic) 249 "-s"
245 parsing--no <PRE>! Man page references are turned into hypertext links.") 250 "")
246 251 "Option that indicates a specified a manual section name.")
247 (make-face 'man-italic) 252
248 (or (face-differs-from-default-p 'man-italic) 253 ;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
249 (copy-face 'italic 'man-italic)) 254 ;; end user variables
250 ;; XEmacs (from Darrell Kindred): underlining is annoying due to 255
251 ;; large blank spaces in this face. 256 ;; other variables and keymap initializations
252 ;; (or (face-differs-from-default-p 'man-italic) 257 (make-variable-buffer-local 'Man-sections-alist)
253 ;; (set-face-underline-p 'man-italic t)) 258 (make-variable-buffer-local 'Man-refpages-alist)
254 259 (make-variable-buffer-local 'Man-page-list)
255 (make-face 'man-bold) 260 (make-variable-buffer-local 'Man-current-page)
256 (or (face-differs-from-default-p 'man-bold) 261 (make-variable-buffer-local 'Man-page-mode-string)
257 (copy-face 'bold 'man-bold)) 262 (make-variable-buffer-local 'Man-original-frame)
258 (or (face-differs-from-default-p 'man-bold) 263 (make-variable-buffer-local 'Man-arguments)
259 (copy-face 'man-italic 'man-bold)) 264
260 265 (setq-default Man-sections-alist nil)
261 (make-face 'man-heading) 266 (setq-default Man-refpages-alist nil)
262 (or (face-differs-from-default-p 'man-heading) 267 (setq-default Man-page-list nil)
263 (copy-face 'man-bold 'man-heading)) 268 (setq-default Man-current-page 0)
264 269 (setq-default Man-page-mode-string "1 of 1")
265 (make-face 'man-xref) 270
266 (or (face-differs-from-default-p 'man-xref) 271 (defconst Man-sysv-sed-script "\
267 (set-face-underline-p 'man-xref t)) 272 /\b/ { s/_\b//g
268 273 s/\b_//g
269 ;; Manual-directory-list-init 274 s/o\b+/o/g
270 ;; Initialize the directory lists. 275 s/+\bo/o/g
271 276 :ovstrk
272 (defun Manual-directory-list-init (&optional arg) 277 s/\\(.\\)\b\\1/\\1/g
273 "Initialize the Manual-directory-list variable from $MANPATH 278 t ovstrk
274 if it is not already set, or if a prefix argument is provided." 279 }
275 (interactive "P") 280 /\e\\[[0-9][0-9]*m/ s///g"
276 (if arg (setq Manual-directory-list nil)) 281 "Script for sysV-like sed to nuke backspaces and ANSI codes from manpages.")
277 (if (null Manual-directory-list) 282
278 (let ((manpath (getenv "MANPATH")) 283 (defconst Man-berkeley-sed-script "\
279 (global (Manual-manpath-config-contents)) 284 /\b/ { s/_\b//g\\
280 (dirlist nil) 285 s/\b_//g\\
281 dir) 286 s/o\b+/o/g\\
282 (cond ((and manpath global) 287 s/+\bo/o/g\\
283 (setq manpath (concat manpath ":" global))) 288 :ovstrk\\
284 (global 289 s/\\(.\\)\b\\1/\\1/g\\
285 (setq manpath global)) 290 t ovstrk\\
286 ((not manpath) 291 }\\
287 ;; XEmacs - (bpw/stig) Unix-specifix hack for lusers w/ no manpath 292 /\e\\[[0-9][0-9]*m/ s///g"
288 (setq manpath "/usr/local/man:/usr/share/man:/usr/share/catman:/usr/contrib/man:/usr/X11/man:/usr/man:/usr/catman"))) 293 "Script for berkeley-like sed to nuke backspaces and ANSI codes from manpages.")
289 ;; Make sure that any changes we've made internally are seen by man. 294
290 (setenv "MANPATH" manpath) 295 (if Man-mode-map
291 (while (string-match "\\`:*\\([^:]+\\)" manpath) 296 nil
292 (setq dir (substring manpath (match-beginning 1) (match-end 1))) 297 (setq Man-mode-map (make-keymap))
293 (and (not (member dir dirlist)) 298 (suppress-keymap Man-mode-map)
294 (setq dirlist (cons dir dirlist))) 299 (define-key Man-mode-map " " 'scroll-up)
295 (setq manpath (substring manpath (match-end 0)))) 300 (define-key Man-mode-map "\177" 'scroll-down)
296 (setq dirlist (nreverse dirlist)) 301 (define-key Man-mode-map "n" 'Man-next-section)
297 (setq Manual-directory-list dirlist) 302 (define-key Man-mode-map "p" 'Man-previous-section)
298 (setq Manual-subdirectory-list nil) 303 (define-key Man-mode-map "\en" 'Man-next-manpage)
299 (setq Manual-formatted-directory-list nil) 304 (define-key Man-mode-map "\ep" 'Man-previous-manpage)
300 (setq Manual-unformatted-directory-list nil))) 305 (define-key Man-mode-map ">" 'end-of-buffer)
301 (if (string-equal Manual-leaf-signature "") 306 (define-key Man-mode-map "<" 'beginning-of-buffer)
302 (setq Manual-leaf-signature 307 (define-key Man-mode-map "." 'beginning-of-buffer)
303 (concat "/\\(" 308 (define-key Man-mode-map "r" 'Man-follow-manual-reference)
304 Manual-formatted-page-prefix 309 (define-key Man-mode-map "g" 'Man-goto-section)
305 "\\|" Manual-unformatted-page-prefix 310 (define-key Man-mode-map "s" 'Man-goto-see-also-section)
306 "\\)" 311 (define-key Man-mode-map "k" 'Man-kill)
307 "[" Manual-man-page-section-ids 312 (define-key Man-mode-map "q" 'Man-quit)
308 "].?/."))) 313 (define-key Man-mode-map "m" 'man)
309 (if Manual-use-subdirectory-list 314 (define-key Man-mode-map "?" 'describe-mode)
310 (progn 315 )
311 (if (null Manual-subdirectory-list) 316
312 (setq Manual-subdirectory-list 317
313 (Manual-all-subdirectories Manual-directory-list 318 ;; ======================================================================
314 Manual-leaf-signature nil))) 319 ;; utilities
315 (if (null Manual-formatted-directory-list) 320
316 (setq Manual-formatted-directory-list 321 (defun Man-init-defvars ()
317 (Manual-filter-subdirectories Manual-subdirectory-list 322 "Used for initialising variables based on the value of window-system.
318 Manual-formatted-page-prefix))) 323 This is necessary if one wants to dump man.el with emacs."
319 (if (null Manual-unformatted-directory-list) 324
320 (setq Manual-unformatted-directory-list 325 ;; The following is necessary until fonts are implemented on
321 (Manual-filter-subdirectories Manual-subdirectory-list 326 ;; terminals.
322 Manual-unformatted-page-prefix)))) 327 (setq Man-fontify-manpage-flag (and Man-fontify-manpage-flag
323 (if (null Manual-formatted-directory-list) 328 window-system))
324 (setq Manual-formatted-directory-list 329
325 (Manual-select-subdirectories Manual-directory-list 330 (setq Man-sed-script
326 Manual-formatted-page-prefix))) 331 (cond
327 (if (null Manual-unformatted-directory-list) 332 (Man-fontify-manpage-flag
328 (setq Manual-unformatted-directory-list 333 nil)
329 (Manual-select-subdirectories Manual-directory-list 334 ((= 0 (call-process Man-sed-command nil nil nil Man-sysv-sed-script))
330 Manual-unformatted-page-prefix))))) 335 Man-sysv-sed-script)
331 336 ((= 0 (call-process Man-sed-command nil nil nil Man-berkeley-sed-script))
332 337 Man-berkeley-sed-script)
333 (defun Manual-manpath-config-contents () 338 (t
334 "Parse the `Manual-manpath-config-file' file, if any. 339 nil)))
335 Returns a string like in $MANPATH." 340
336 (if (and Manual-manpath-config-file 341 (setq Man-filter-list
337 (file-readable-p Manual-manpath-config-file)) 342 (list
338 (let ((buf (get-buffer-create " *Manual-config*")) 343 (cons
339 path) 344 Man-sed-command
340 (set-buffer buf) 345 (list
341 (buffer-disable-undo buf) 346 (if Man-sed-script
342 (erase-buffer) 347 (concat "-e '" Man-sed-script "'")
343 (insert-file-contents Manual-manpath-config-file) 348 "")
344 (while (re-search-forward "^\\(MANDATORY_MANPATH\\|MANPATH_MAP\\)" 349 "-e '/^[\001-\032][\001-\032]*$/d'"
345 nil t) 350 "-e '/\e[789]/s///g'"
346 (and (re-search-forward "\\(/[^ \t\n]+\\)[ \t]*$") 351 "-e '/Reformatting page. Wait/d'"
347 (setq path (concat path (buffer-substring (match-beginning 1) 352 "-e '/Reformatting entry. Wait/d'"
348 (match-end 1)) 353 "-e '/^[ \t]*Hewlett-Packard[ \t]Company[ \t]*-[ \t][0-9]*[ \t]-/d'"
349 ":")))) 354 "-e '/^[ \t]*Hewlett-Packard[ \t]*-[ \t][0-9]*[ \t]-.*$/d'"
350 (kill-buffer buf) 355 "-e '/^[ \t][ \t]*-[ \t][0-9]*[ \t]-[ \t]*Formatted:.*[0-9]$/d'"
351 path))) 356 "-e '/^[ \t]*Page[ \t][0-9]*.*(printed[ \t][0-9\\/]*)$/d'"
352 ;; 357 "-e '/^Printed[ \t][0-9].*[0-9]$/d'"
353 ;; manual-entry -- The "main" user function 358 "-e '/^[ \t]*X[ \t]Version[ \t]1[01].*Release[ \t][0-9]/d'"
354 ;; 359 "-e '/^[A-za-z].*Last[ \t]change:/d'"
355 360 "-e '/^Sun[ \t]Release[ \t][0-9].*[0-9]$/d'"
361 "-e '/[ \t]*Copyright [0-9]* UNIX System Laboratories, Inc.$/d'"
362 "-e '/^[ \t]*Rev\\..*Page [0-9][0-9]*$/d'"
363 ))
364 (cons
365 Man-awk-command
366 (list
367 "'\n"
368 "BEGIN { blankline=0; anonblank=0; }\n"
369 "/^$/ { if (anonblank==0) next; }\n"
370 "{ anonblank=1; }\n"
371 "/^$/ { blankline++; next; }\n"
372 "{ if (blankline>0) { print \"\"; blankline=0; } print $0; }\n"
373 "'"
374 ))
375 (if (not Man-uses-untabify-flag)
376 (cons
377 Man-untabify-command
378 Man-untabify-command-args)
379 )))
380 )
381
382 (defsubst Man-match-substring (&optional n string)
383 "Return the substring matched by the last search.
384 Optional arg N means return the substring matched by the Nth paren
385 grouping. Optional second arg STRING means return a substring from
386 that string instead of from the current buffer."
387 (if (null n) (setq n 0))
388 (if string
389 (substring string (match-beginning n) (match-end n))
390 (buffer-substring (match-beginning n) (match-end n))))
391
392 (defsubst Man-make-page-mode-string ()
393 "Formats part of the mode line for Man mode."
394 (format "%s page %d of %d"
395 (or (nth 2 (nth (1- Man-current-page) Man-page-list))
396 "")
397 Man-current-page
398 (length Man-page-list)))
399
400 (defsubst Man-build-man-command ()
401 "Builds the entire background manpage and cleaning command."
402 (let ((command (concat manual-program " " Man-switches " %s 2>/dev/null"))
403 (flist Man-filter-list))
404 (while (and flist (car flist))
405 (let ((pcom (car (car flist)))
406 (pargs (cdr (car flist))))
407 (setq command
408 (concat command " | " pcom " "
409 (mapconcat '(lambda (phrase)
410 (if (not (stringp phrase))
411 (error "Malformed Man-filter-list"))
412 phrase)
413 pargs " ")))
414 (setq flist (cdr flist))))
415 command))
416
417 (defun Man-translate-references (ref)
418 "Translates REF from \"chmod(2V)\" to \"2v chmod\" style.
419 Leave it as is if already in that style. Possibly downcase and
420 translate the section (see the Man-downcase-section-letters-flag
421 and the Man-section-translations-alist variables)."
422 (let ((name "")
423 (section "")
424 (slist Man-section-translations-alist))
425 (cond
426 ;; "chmod(2V)" case ?
427 ((string-match (concat "^" Man-reference-regexp "$") ref)
428 (setq name (Man-match-substring 1 ref)
429 section (Man-match-substring 2 ref)))
430 ;; "2v chmod" case ?
431 ((string-match (concat "^\\(" Man-section-regexp
432 "\\) +\\(" Man-name-regexp "\\)$") ref)
433 (setq name (Man-match-substring 2 ref)
434 section (Man-match-substring 1 ref))))
435 (if (string= name "")
436 ref ; Return the reference as is
437 (if Man-downcase-section-letters-flag
438 (setq section (downcase section)))
439 (while slist
440 (let ((s1 (car (car slist)))
441 (s2 (cdr (car slist))))
442 (setq slist (cdr slist))
443 (if Man-downcase-section-letters-flag
444 (setq s1 (downcase s1)))
445 (if (not (string= s1 section)) nil
446 (setq section (if Man-downcase-section-letters-flag
447 (downcase s2)
448 s2)
449 slist nil))))
450 (concat Man-specified-section-option section " " name))))
451
452
453 ;; ======================================================================
454 ;; default man entry: get word under point
455
456 (defsubst Man-default-man-entry ()
457 "Make a guess at a default manual entry.
458 This guess is based on the text surrounding the cursor, and the
459 default section number is selected from `Man-auto-section-alist'."
460 (let (default-title)
461 (save-excursion
462
463 ;; Default man entry title is any word the cursor is on, or if
464 ;; cursor not on a word, then nearest preceding word. Cannot
465 ;; use the current-word function because it skips the dots.
466 (if (not (looking-at "[-a-zA-Z_.]"))
467 (skip-chars-backward "^a-zA-Z"))
468 (skip-chars-backward "-(a-zA-Z_0-9_.")
469 (if (looking-at "(") (forward-char 1))
470 (setq default-title
471 (buffer-substring
472 (point)
473 (progn (skip-chars-forward "-a-zA-Z0-9_.") (point))))
474
475 ;; If looking at something like ioctl(2) or brc(1M), include the
476 ;; section number in the returned value. Remove text properties.
477 (let ((result (concat
478 default-title
479 (if (looking-at
480 (concat "[ \t]*([ \t]*\\("
481 Man-section-regexp "\\)[ \t]*)"))
482 (format "(%s)" (Man-match-substring 1))))))
483 (set-text-properties 0 (length result) nil result)
484 result))))
485
486
487 ;; ======================================================================
488 ;; Top level command and background process sentinel
489
490 ;; For compatibility with older versions.
356 ;;;###autoload 491 ;;;###autoload
357 (defun manual-entry (topic &optional arg silent) 492 (defalias 'manual-entry 'man)
358 "Display the Unix manual entry (or entries) for TOPIC. 493
359 If prefix arg is given, modify the search according to the value: 494 ;;;###autoload
360 2 = complement default exact matching of the TOPIC name; 495 (defun man (man-args)
361 exact matching default is specified by `Manual-match-topic-exactly' 496 "Get a Un*x manual page and put it in a buffer.
362 3 = force a search of the unformatted man directories 497 This command is the top-level command in the man package. It runs a Un*x
363 4 = both 2 and 3 498 command to retrieve and clean a manpage in the background and places the
364 The manual entries are searched according to the variable 499 results in a Man mode (manpage browsing) buffer. See variable
365 Manual-directory-list, which should be a list of directories. If 500 `Man-notify-method' for what happens when the buffer is ready.
366 Manual-directory-list is nil, \\[Manual-directory-list-init] is 501 If a buffer already exists for this man page, it will display immediately."
367 invoked to create this list from the MANPATH environment variable.
368 See the variable Manual-topic-buffer which controls how the buffer
369 is named. See also the variables Manual-match-topic-exactly,
370 Manual-query-multiple-pages, and Manual-buffer-view-mode."
371 (interactive 502 (interactive
372 (list (let* ((fmh "-A-Za-z0-9_.") 503 (list (let* ((default-entry (Man-default-man-entry))
373 (default (save-excursion 504 (input (read-string
374 (buffer-substring 505 (format "Manual entry%s: "
375 (progn 506 (if (string= default-entry "")
376 (re-search-backward "\\sw" nil t) 507 ""
377 (skip-chars-backward fmh) (point)) 508 (format " (default %s)" default-entry))))))
378 (progn (skip-chars-forward fmh) (point))))) 509 (if (string= input "")
379 (thing (read-string 510 (if (string= default-entry "")
380 (if (equal default "") "Manual entry: " 511 (error "No man args given")
381 (concat "Manual entry: (default " default ") "))))) 512 default-entry)
382 (if (equal thing "") default thing)) 513 input))))
383 (prefix-numeric-value current-prefix-arg))) 514
384 ;;(interactive "sManual entry (topic): \np") 515 ;; Possibly translate the "subject(section)" syntax into the
385 (or arg (setq arg 1)) 516 ;; "section subject" syntax and possibly downcase the section.
386 (Manual-directory-list-init nil) 517 (setq man-args (Man-translate-references man-args))
387 (let ((exact (if (or (= arg 2) (= arg 4)) 518
388 (not Manual-match-topic-exactly) 519 (Man-getpage-in-background man-args))
389 Manual-match-topic-exactly)) 520
390 (force (if (>= arg 3) 521
391 t 522 (defun Man-getpage-in-background (topic)
392 nil)) 523 "Uses TOPIC to build and fire off the manpage and cleaning command."
393 section fmtlist manlist apropos-mode) 524 (let* ((man-args topic)
394 (let ((case-fold-search nil)) 525 (bufname (concat "*Man " man-args "*"))
395 (if (and (null section) 526 (buffer (get-buffer bufname)))
396 (string-match 527 (if buffer
397 "\\`[ \t]*\\([^( \t]+\\)[ \t]*(\\(.+\\))[ \t]*\\'" topic)) 528 (Man-notify-when-ready buffer)
398 (setq section (substring topic (match-beginning 2) 529 (require 'env)
399 (match-end 2)) 530 (message "Invoking %s %s in the background" manual-program man-args)
400 topic (substring topic (match-beginning 1) 531 (setq buffer (generate-new-buffer bufname))
401 (match-end 1)))
402 (if (string-match "\\`[ \t]*-k[ \t]+\\([^ \t]+\\)\\'" topic)
403 (setq section "-k"
404 topic (substring topic (match-beginning 1))))))
405 (if (equal section "-k")
406 (setq apropos-mode t)
407 (or silent
408 (message "Looking for formatted entry for %s%s..."
409 topic (if section (concat "(" section ")") "")))
410 (setq fmtlist (Manual-select-man-pages
411 Manual-formatted-directory-list
412 topic section exact '()))
413 (if (or force (not section) (null fmtlist))
414 (progn
415 (or silent
416 (message "%sooking for unformatted entry for %s%s..."
417 (if fmtlist "L" "No formatted entry, l")
418 topic (if section (concat "(" section ")") "")))
419 (setq manlist (Manual-select-man-pages
420 Manual-unformatted-directory-list
421 topic section exact (if force '() fmtlist))))))
422
423 ;; Delete duplicate man pages (a file of the same name in multiple
424 ;; directories.)
425 (or nil ;force
426 (let ((rest (append fmtlist manlist)))
427 (while rest
428 (let ((rest2 (cdr rest)))
429 (while rest2
430 (if (equal (file-name-nondirectory (car rest))
431 (file-name-nondirectory (car rest2)))
432 (setq fmtlist (delq (car rest2) fmtlist)
433 manlist (delq (car rest2) manlist)))
434 (setq rest2 (cdr rest2))))
435 (setq rest (cdr rest)))))
436
437 (if (not (or fmtlist manlist apropos-mode))
438 (progn
439 (message "No entries found for %s%s" topic
440 (if section (concat "(" section ")") ""))
441 nil)
442 (let ((bufname (cond ((not Manual-topic-buffer)
443 ;; What's the point of retaining this?
444 (if apropos-mode
445 "*Manual Apropos*"
446 "*Manual Entry*"))
447 (apropos-mode
448 (concat "*man apropos " topic "*"))
449 (t
450 (concat "*man "
451 (cond (exact
452 (if section
453 (concat topic "." section)
454 topic))
455 ((or (cdr fmtlist) (cdr manlist)
456 (and fmtlist manlist))
457 ;; more than one entry found
458 (concat topic "..."))
459 (t
460 (file-name-nondirectory
461 (car (or fmtlist manlist)))))
462 "*"))))
463 (temp-buffer-show-function
464 (cond ((eq 't Manual-buffer-view-mode) 'view-buffer)
465 ((eq 'nil Manual-buffer-view-mode)
466 temp-buffer-show-function)
467 (t 'view-buffer-other-window))))
468
469 (if apropos-mode
470 (setq manlist (list (format "%s.%s" topic section))))
471
472 (cond
473 ((and Manual-topic-buffer (get-buffer bufname))
474 ;; reselect an old man page buffer if it exists already.
475 (save-excursion
476 (set-buffer (get-buffer bufname))
477 (Manual-mode))
478 (if temp-buffer-show-function
479 (funcall temp-buffer-show-function (get-buffer bufname))
480 (display-buffer bufname)))
481 (t
482 (with-output-to-temp-buffer bufname
483 (buffer-disable-undo standard-output)
484 (save-excursion
485 (set-buffer standard-output)
486 (setq buffer-read-only nil)
487 (erase-buffer)
488 (Manual-insert-pages fmtlist manlist apropos-mode)
489 (set-buffer-modified-p nil)
490 (Manual-mode)
491 ))))
492 (setq Manual-page-history
493 (cons (buffer-name)
494 (delete (buffer-name) Manual-page-history)))
495 (message nil)
496 t))))
497
498 (defun Manpage-apropos (topic &optional arg silent)
499 "Apropos on Unix manual pages for TOPIC.
500 It calls the function `manual-entry'. Look at this function for
501 further description. Look also at the variable `Manual-apropos-switch',
502 if this function doesn't work on your system."
503 (interactive
504 (list (let* ((fmh "-A-Za-z0-9_.")
505 (default (save-excursion
506 (buffer-substring
507 (progn
508 (re-search-backward "\\sw" nil t)
509 (skip-chars-backward fmh) (point))
510 (progn (skip-chars-forward fmh) (point)))))
511 (thing (read-string
512 (if (equal default "") "Manual entry: "
513 (concat "Manual entry: (default " default ") ")))))
514 (if (equal thing "") default thing))
515 (prefix-numeric-value current-prefix-arg)))
516 (manual-entry (concat Manual-apropos-switch " " topic) arg silent))
517
518 (defun Manual-insert-pages (fmtlist manlist apropos-mode)
519 (let ((sep (make-string 65 ?-))
520 name start end topic section)
521 (while fmtlist ; insert any formatted files
522 (setq name (car fmtlist))
523 (goto-char (point-max))
524 (setq start (point))
525 ;; In case the file can't be read or uncompressed or
526 ;; something like that.
527 (condition-case ()
528 (Manual-insert-man-file name)
529 (file-error nil))
530 (goto-char (point-max))
531 (setq end (point))
532 (save-excursion 532 (save-excursion
533 (save-restriction 533 (set-buffer buffer)
534 (message "Cleaning manual entry for %s..." 534 (setq Man-original-frame (selected-frame))
535 (file-name-nondirectory name)) 535 (setq Man-arguments man-args))
536 (narrow-to-region start end) 536 (let ((process-environment (copy-sequence process-environment)))
537 (Manual-nuke-nroff-bs) 537 ;; Prevent any attempt to use display terminal fanciness.
538 (goto-char (point-min)) 538 (setenv "TERM" "dumb")
539 (insert "File: " name "\n") 539 (set-process-sentinel
540 (goto-char (point-max)) 540 (start-process manual-program buffer "sh" "-c"
541 )) 541 (format (Man-build-man-command) man-args))
542 (if (or (cdr fmtlist) manlist) 542 'Man-bgproc-sentinel)))))
543 (insert "\n\n" sep "\n")) 543
544 (setq fmtlist (cdr fmtlist))) 544 (defun Man-notify-when-ready (man-buffer)
545 545 "Notify the user when MAN-BUFFER is ready.
546 (while manlist ; process any unformatted files 546 See the variable `Man-notify-method' for the different notification behaviors."
547 (setq name (car manlist)) 547 (let ((saved-frame (save-excursion
548 (or (string-match "\\([^/]+\\)\\.\\([^./]+\\)\\(\\.gz\\'\\)" name) 548 (set-buffer man-buffer)
549 (string-match "\\([^/]+\\)\\.\\([^./]+\\)\\'" name)) 549 Man-original-frame)))
550 (setq topic (substring name (match-beginning 1) (match-end 1))) 550 (cond
551 (setq section (substring name (match-beginning 2) (match-end 2))) 551 ((eq Man-notify-method 'newframe)
552 ;; This won't work under IRIX, because SGI man accepts only the 552 ;; Since we run asynchronously, perhaps while Emacs is waiting
553 ;; "main" (one-character) section id, not full section ids 553 ;; for input, we must not leave a different buffer current. We
554 ;; like 1M, 3X, etc. Put (setq Manual-use-full-section-ids nil) 554 ;; can't rely on the editor command loop to reselect the
555 ;; in your .emacs to work around this problem. 555 ;; selected window's buffer.
556 (if (not (or Manual-use-full-section-ids (string-equal section "")))
557 (setq section (substring section 0 1)))
558 (message "Invoking man %s%s %s..."
559 (if Manual-section-switch
560 (concat Manual-section-switch " ")
561 "")
562 section topic)
563 (setq start (point))
564 (Manual-run-formatter name topic section)
565 (setq end (point))
566 (save-excursion 556 (save-excursion
567 (save-restriction 557 (set-buffer man-buffer)
568 (message "Cleaning manual entry for %s(%s)..." topic section) 558 (make-frame Man-frame-parameters)))
569 (narrow-to-region start end) 559 ((eq Man-notify-method 'pushy)
570 (Manual-nuke-nroff-bs apropos-mode) 560 (switch-to-buffer man-buffer))
571 (goto-char (point-min)) 561 ((eq Man-notify-method 'bully)
572 (insert "File: " name "\n") 562 (and window-system
573 (goto-char (point-max)) 563 (frame-live-p saved-frame)
574 )) 564 (select-frame saved-frame))
575 (if (cdr manlist) 565 (pop-to-buffer man-buffer)
576 (insert "\n\n" sep "\n")) 566 (delete-other-windows))
577 (setq manlist (cdr manlist)))) 567 ((eq Man-notify-method 'aggressive)
578 (if (< (buffer-size) 200) 568 (and window-system
569 (frame-live-p saved-frame)
570 (select-frame saved-frame))
571 (pop-to-buffer man-buffer))
572 ((eq Man-notify-method 'friendly)
573 (and window-system
574 (frame-live-p saved-frame)
575 (select-frame saved-frame))
576 (display-buffer man-buffer 'not-this-window))
577 ((eq Man-notify-method 'polite)
578 (beep)
579 (message "Manual buffer %s is ready" (buffer-name man-buffer)))
580 ((eq Man-notify-method 'quiet)
581 (message "Manual buffer %s is ready" (buffer-name man-buffer)))
582 ((or (eq Man-notify-method 'meek)
583 t)
584 (message ""))
585 )))
586
587 (defun Man-fontify-manpage ()
588 "Convert overstriking and underlining to the correct fonts.
589 Same for the ANSI bold and normal escape sequences."
590 (interactive)
591 (message "Please wait: making up the %s man page..." Man-arguments)
592 (goto-char (point-min))
593 (while (search-forward "\e[1m" nil t)
594 (delete-backward-char 4)
595 (put-text-property (point)
596 (progn (if (search-forward "\e[0m" nil 'move)
597 (delete-backward-char 4))
598 (point))
599 'face Man-overstrike-face))
600 (goto-char (point-min))
601 (while (search-forward "_\b" nil t)
602 (backward-delete-char 2)
603 (put-text-property (point) (1+ (point)) 'face Man-underline-face))
604 (goto-char (point-min))
605 (while (search-forward "\b_" nil t)
606 (backward-delete-char 2)
607 (put-text-property (1- (point)) (point) 'face Man-underline-face))
608 (goto-char (point-min))
609 (while (re-search-forward "\\(.\\)\\(\b\\1\\)+" nil t)
610 (replace-match "\\1")
611 (put-text-property (1- (point)) (point) 'face Man-overstrike-face))
612 (goto-char (point-min))
613 (while (re-search-forward "o\b\\+\\|\\+\bo" nil t)
614 (replace-match "o")
615 (put-text-property (1- (point)) (point) 'face 'bold))
616 (goto-char (point-min))
617 (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t)
618 (replace-match "+")
619 (put-text-property (1- (point)) (point) 'face 'bold))
620 ;; \255 is some kind of dash in Latin-1.
621 (goto-char (point-min))
622 (while (search-forward "\255" nil t) (replace-match "-"))
623 (message "%s man page made up" Man-arguments))
624
625 (defun Man-cleanup-manpage ()
626 "Remove overstriking and underlining from the current buffer."
627 (interactive)
628 (message "Please wait: cleaning up the %s man page..."
629 Man-arguments)
630 (if (or (interactive-p) (not Man-sed-script))
579 (progn 631 (progn
580 (goto-char (point-min)) 632 (goto-char (point-min))
581 (if (looking-at "^File: ") 633 (while (search-forward "_\b" nil t) (backward-delete-char 2))
582 (forward-line 1)) 634 (goto-char (point-min))
583 (error (buffer-substring (point) (progn (end-of-line) (point)))))) 635 (while (search-forward "\b_" nil t) (backward-delete-char 2))
584 nil) 636 (goto-char (point-min))
585 637 (while (re-search-forward "\\(.\\)\\(\b\\1\\)+" nil t)
586 638 (replace-match "\\1"))
587 (defun Manual-run-formatter (name topic section) 639 (goto-char (point-min))
588 (cond 640 (while (re-search-forward "\e\\[[0-9]+m" nil t) (replace-match ""))
589 ((string-match "roff\\'" Manual-program) 641 (goto-char (point-min))
590 ;; kludge kludge 642 (while (re-search-forward "o\b\\+\\|\\+\bo" nil t) (replace-match "o"))
591 (call-process Manual-program nil t nil "-Tman" "-man" name)) 643 ))
592 644 (goto-char (point-min))
593 (t 645 (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t) (replace-match "+"))
594 (call-process Manual-program nil t nil 646 ;; \255 is some kind of dash in Latin-1.
595 (concat Manual-section-switch section) topic)))) 647 (goto-char (point-min))
596 648 (while (search-forward "\255" nil t) (replace-match "-"))
597 ;(Manual-use-rosetta-man 649 (message "%s man page cleaned up" Man-arguments))
598 ; (call-process "/bin/sh" nil t nil "-c" 650
599 ; (format "man %s %s | rman" section topic))) 651 (defun Man-bgproc-sentinel (process msg)
600 652 "Manpage background process sentinel."
601 653 (let ((Man-buffer (process-buffer process))
602 (defvar Manual-mode-map 654 (delete-buff nil)
603 (let ((m (make-sparse-keymap))) 655 (err-mess nil))
604 (set-keymap-name m 'Manual-mode-map) 656
605 (define-key m "l" 'Manual-last-page) 657 (if (null (buffer-name Man-buffer)) ;; deleted buffer
606 (define-key m 'button2 'Manual-follow-xref) 658 (set-process-buffer process nil)
607 (define-key m 'button3 'Manual-popup-menu) 659
608 m)) 660 (save-excursion
609 661 (set-buffer Man-buffer)
610 (defun Manual-mode () 662 (let ((case-fold-search nil))
611 (kill-all-local-variables) 663 (goto-char (point-min))
612 (setq buffer-read-only t) 664 (cond ((or (looking-at "No \\(manual \\)*entry for")
613 (use-local-map Manual-mode-map) 665 (looking-at "[^\n]*: nothing appropriate$"))
614 (setq major-mode 'Manual-mode 666 (setq err-mess (buffer-substring (point)
615 mode-name "Manual") 667 (progn
616 ;; man pages with long lines are buggy! 668 (end-of-line) (point)))
617 ;; This looks slightly better if they only 669 delete-buff t))
618 ;; overran by a couple of chars. 670 ((not (and (eq (process-status process) 'exit)
619 (setq truncate-lines t) 671 (= (process-exit-status process) 0)))
620 (if (featurep 'scrollbar) 672 (setq err-mess
621 ;; turn off horizontal scrollbars in this buffer 673 (concat (buffer-name Man-buffer)
622 (set-specifier scrollbar-height (cons (current-buffer) 0))) 674 ": process "
623 (run-hooks 'Manual-mode-hook)) 675 (let ((eos (1- (length msg))))
624 676 (if (= (aref msg eos) ?\n)
625 (defun Manual-last-page () 677 (substring msg 0 eos) msg))))
678 (goto-char (point-max))
679 (insert (format "\nprocess %s" msg))
680 ))
681 (if delete-buff
682 (kill-buffer Man-buffer)
683 (if Man-fontify-manpage-flag
684 (Man-fontify-manpage)
685 (Man-cleanup-manpage))
686 (run-hooks 'Man-cooked-hook)
687 (Man-mode)
688 (set-buffer-modified-p nil)
689 ))
690 ;; Restore case-fold-search before calling
691 ;; Man-notify-when-ready because it may switch buffers.
692
693 (if (not delete-buff)
694 (Man-notify-when-ready Man-buffer))
695
696 (if err-mess
697 (error err-mess))
698 ))))
699
700
701 ;; ======================================================================
702 ;; set up manual mode in buffer and build alists
703
704 (defun Man-mode ()
705 "A mode for browsing Un*x manual pages.
706
707 The following man commands are available in the buffer. Try
708 \"\\[describe-key] <key> RET\" for more information:
709
710 \\[man] Prompt to retrieve a new manpage.
711 \\[Man-follow-manual-reference] Retrieve reference in SEE ALSO section.
712 \\[Man-next-manpage] Jump to next manpage in circular list.
713 \\[Man-previous-manpage] Jump to previous manpage in circular list.
714 \\[Man-next-section] Jump to next manpage section.
715 \\[Man-previous-section] Jump to previous manpage section.
716 \\[Man-goto-section] Go to a manpage section.
717 \\[Man-goto-see-also-section] Jumps to the SEE ALSO manpage section.
718 \\[Man-quit] Deletes the manpage window, bury its buffer.
719 \\[Man-kill] Deletes the manpage window, kill its buffer.
720 \\[describe-mode] Prints this help text.
721
722 The following variables may be of some use. Try
723 \"\\[describe-variable] <variable-name> RET\" for more information:
724
725 Man-notify-method What happens when manpage formatting is done.
726 Man-downcase-section-letters-flag Force section letters to lower case.
727 Man-circular-pages-flag Treat multiple manpage list as circular.
728 Man-auto-section-alist List of major modes and their section numbers.
729 Man-section-translations-alist List of section numbers and their Un*x equiv.
730 Man-filter-list Background manpage filter command.
731 Man-mode-line-format Mode line format for Man mode buffers.
732 Man-mode-map Keymap bindings for Man mode buffers.
733 Man-mode-hook Normal hook run on entry to Man mode.
734 Man-section-regexp Regexp describing manpage section letters.
735 Man-heading-regexp Regexp describing section headers.
736 Man-see-also-regexp Regexp for SEE ALSO section (or your equiv).
737 Man-first-heading-regexp Regexp for first heading on a manpage.
738 Man-reference-regexp Regexp matching a references in SEE ALSO.
739 Man-switches Background `man' command switches.
740
741 The following key bindings are currently in effect in the buffer:
742 \\{Man-mode-map}"
626 (interactive) 743 (interactive)
627 (while (or (not (get-buffer (car (or Manual-page-history 744 (setq major-mode 'Man-mode
628 (error "No more history."))))) 745 mode-name "Man"
629 (eq (get-buffer (car Manual-page-history)) (current-buffer))) 746 buffer-auto-save-file-name nil
630 (setq Manual-page-history (cdr Manual-page-history))) 747 mode-line-format Man-mode-line-format
631 (switch-to-buffer (car Manual-page-history))) 748 truncate-lines t
632 749 buffer-read-only t)
633 750 (buffer-disable-undo (current-buffer))
634 ;; Manual-select-subdirectories 751 (auto-fill-mode -1)
635 ;; Given a DIRLIST and a SUBDIR name, return all subdirectories of the former which 752 (use-local-map Man-mode-map)
636 ;; match the latter. 753 (Man-build-page-list)
637 754 (Man-strip-page-headers)
638 (defun Manual-select-subdirectories (dirlist subdir) 755 (Man-unindent)
639 (let ((dirs '()) 756 (Man-goto-page 1)
640 (case-fold-search nil) 757 (run-hooks 'Man-mode-hook))
641 (match (concat "\\`" (regexp-quote subdir))) 758
642 d) 759 (defsubst Man-build-section-alist ()
643 (while dirlist 760 "Build the association list of manpage sections."
644 (setq d (car dirlist) dirlist (cdr dirlist)) 761 (setq Man-sections-alist nil)
645 (if (file-directory-p d) 762 (goto-char (point-min))
646 (let ((files (directory-files d t match nil 'dirs-only))
647 (dir-temp '()))
648 (while files
649 (if (file-executable-p (car files))
650 (setq dir-temp (cons (file-name-as-directory (car files))
651 dir-temp)))
652 (setq files (cdr files)))
653 (and dir-temp
654 (setq dirs (append dirs (nreverse dir-temp)))))))
655 dirs))
656
657
658 ;; Manual-filter-subdirectories
659 ;; Given a DIRLIST and a SUBDIR name, return all members of the former
660 ;; which match the latter.
661
662 (defun Manual-filter-subdirectories (dirlist subdir)
663 (let ((match (concat
664 "/"
665 (regexp-quote subdir)
666 "[" Manual-man-page-section-ids "]"))
667 slist dir)
668 (while dirlist
669 (setq dir (car dirlist) dirlist (cdr dirlist))
670 (if (and (file-executable-p dir) (string-match match dir))
671 (setq slist (cons dir slist))))
672 (nreverse slist)))
673
674
675 (defun Manual-all-subdirectories (dirlist leaf-signature dirs &optional silent) "\
676 Given a DIRLIST, return a backward-sorted list of all subdirectories
677 thereof, prepended to DIRS if non-nil. This function calls itself
678 recursively until subdirectories matching LEAF-SIGNATURE are reached,
679 or the hierarchy has been thoroughly searched. This code is a modified
680 version of a function written by Tim Bradshaw (tfb@ed.ac.uk)."
681 (Manual-all-subdirectories-noloop dirlist leaf-signature dirs nil silent))
682
683 (defun Manual-all-subdirectories-noloop (dirlist leaf-signature dirs been &optional silent) "\
684 Does the job of manual-all-subdirectories and keeps track of where it
685 has been to avoid loops."
686 (let (dir)
687 (while dirlist
688 (setq dir (car dirlist) dirlist (cdr dirlist))
689 (if (file-directory-p dir)
690 (let ((dir-temp (cons (file-name-as-directory dir) dirs)))
691 ;; Without feedback the user might wonder about the delay!
692 (or silent (message
693 "Building list of search directories... %s"
694 (car dir-temp)))
695 (if (member (file-truename dir) been)
696 () ; Ignore. We have been here before
697 (setq been (cons (file-truename dir) been))
698 (setq dirs
699 (if (string-match leaf-signature dir)
700 dir-temp
701 (Manual-all-subdirectories-noloop
702 (directory-files dir t "[^.]$" nil 'dirs-only)
703 leaf-signature dir-temp been silent))))))))
704 dirs)
705
706
707 (defvar Manual-bogus-file-pattern "\\.\\(lpr\\|ps\\|PS\\)\\'"
708 "Some systems have files in the man/man*/ directories which aren't man pages.
709 This pattern is used to prune those files.")
710
711 ;; Manual-select-man-pages
712 ;;
713 ;; Given a DIRLIST, discover all filenames which complete given the TOPIC
714 ;; and SECTION.
715
716 ;; ## Note: BSD man looks for .../man1/foo.1 and .../man1/$MACHINE/foo.1
717
718 ;; ## Fixed for SGI IRIX 5.x on Sat Jul 15 1995 by Dale Atems
719 ;; (atems@physics.wayne.edu).
720
721 (defun Manual-select-man-pages (dirlist topic section exact shadow)
722 (let ((case-fold-search nil)) 763 (let ((case-fold-search nil))
723 (and section 764 (while (re-search-forward Man-heading-regexp (point-max) t)
724 (let ((l '()) 765 (aput 'Man-sections-alist (Man-match-substring 1))
725 ;;(match (concat (substring section 0 1) "/?\\'")) 766 (forward-line 1))))
726 ;; ^^^ 767
727 ;; We'll lose any pages inside subdirectories of the "standard" 768 (defsubst Man-build-references-alist ()
728 ;; ones if we insist on this! The following regexp should 769 "Build the association list of references (in the SEE ALSO section)."
729 ;; match any directory ending with the full section id or 770 (setq Man-refpages-alist nil)
730 ;; its first character, or any direct subdirectory thereof: 771 (save-excursion
731 (match (concat "\\(" 772 (if (Man-find-section Man-see-also-regexp)
732 (regexp-quote section) 773 (let ((start (progn (forward-line 1) (point)))
733 "\\|" 774 (end (progn
734 (substring section 0 1) 775 (Man-next-section 1)
735 "\\)/?")) 776 (point)))
736 d) 777 hyphenated
737 (while dirlist 778 (runningpoint -1))
738 (setq d (car dirlist) dirlist (cdr dirlist)) 779 (save-restriction
739 (if (string-match match d) 780 (narrow-to-region start end)
740 (setq l (cons d l)))) 781 (goto-char (point-min))
741 (setq dirlist l))) 782 (back-to-indentation)
742 (if shadow 783 (while (and (not (eobp)) (/= (point) runningpoint))
743 (setq shadow (concat "/\\(" 784 (setq runningpoint (point))
744 (mapconcat #'(lambda (n) 785 (if (re-search-forward Man-reference-regexp end t)
745 (regexp-quote 786 (let* ((word (Man-match-substring 0))
746 (file-name-nondirectory n))) 787 (len (1- (length word))))
747 shadow 788 (if hyphenated
748 "\\|") 789 (setq word (concat hyphenated word)
749 "\\)\\'"))) 790 hyphenated nil))
750 (let ((manlist '()) 791 (if (= (aref word len) ?-)
751 (match (concat "\\`" 792 (setq hyphenated (substring word 0 len))
752 (regexp-quote topic) 793 (aput 'Man-refpages-alist word))))
753 ;; **Note: on IRIX the preformatted pages 794 (skip-chars-forward " \t\n,")))))))
754 ;; are packed, so they end with ".z". This 795
755 ;; way you miss them if you specify a 796 (defun Man-build-page-list ()
756 ;; section. I don't see any point to it here 797 "Build the list of separate manpages in the buffer."
757 ;; even on BSD systems since we're looking 798 (setq Man-page-list nil)
758 ;; one level down already, but I can't test 799 (let ((page-start (point-min))
759 ;; this. More thought needed (???) 800 (page-end (point-max))
760 801 (header ""))
761 (cond ((and section 802 (goto-char page-start)
762 (not Manual-use-subdirectory-list)) 803 ;; (switch-to-buffer (current-buffer))(debug)
763 (concat "\\." (regexp-quote section))) 804 (while (not (eobp))
764 (exact 805 (setq header
765 ;; If Manual-match-topic-exactly is 806 (if (looking-at Man-page-header-regexp)
766 ;; set, then we must make sure the 807 (Man-match-substring 1)
767 ;; completions are exact, except for 808 nil))
768 ;; trailing weird characters after 809 ;; Go past both the current and the next Man-first-heading-regexp
769 ;; the section. 810 (if (re-search-forward Man-first-heading-regexp nil 'move 2)
770 "\\.") 811 (let ((p (progn (beginning-of-line) (point))))
771 (t 812 ;; We assume that the page header is delimited by blank
772 "")))) 813 ;; lines and that it contains at most one blank line. So
773 dir) 814 ;; if we back by three blank lines we will be sure to be
774 (while dirlist 815 ;; before the page header but not before the possible
775 (setq dir (car dirlist) dirlist (cdr dirlist)) 816 ;; previous page header.
776 (if (not (file-directory-p dir)) 817 (search-backward "\n\n" nil t 3)
777 (progn 818 (if (re-search-forward Man-page-header-regexp p 'move)
778 (message "warning: %s is not a directory" dir) 819 (beginning-of-line))))
779 ;;(sit-for 1) 820 (setq page-end (point))
780 ) 821 (setq Man-page-list (append Man-page-list
781 (let ((files (directory-files dir t match nil t)) 822 (list (list (copy-marker page-start)
782 f) 823 (copy-marker page-end)
783 (while files 824 header))))
784 (setq f (car files) files (cdr files)) 825 (setq page-start page-end)
785 (cond ((string-match Manual-bogus-file-pattern f) 826 )))
786 ;(message "Bogus fule %s" f) (sit-for 2) 827
787 ) 828 (defun Man-strip-page-headers ()
788 ((and shadow (string-match shadow f)) 829 "Strip all the page headers but the first from the manpage."
789 ;(message "Shadowed %s" f) (sit-for 2) 830 (let ((buffer-read-only nil)
790 ) 831 (case-fold-search nil)
791 ((not (file-readable-p f)) 832 (page-list Man-page-list)
792 ;(message "Losing with %s" f) (sit-for 2) 833 (page ())
793 ) 834 (header ""))
794 (t 835 (while page-list
795 (setq manlist (cons f manlist)))))))) 836 (setq page (car page-list))
796 (setq manlist (nreverse manlist)) 837 (and (nth 2 page)
797 (and Manual-unique-man-sections-only 838 (goto-char (car page))
798 (setq manlist (Manual-clean-to-unique-pages-only manlist))) 839 (re-search-forward Man-first-heading-regexp nil t)
799 (if (and manlist Manual-query-multiple-pages) 840 (setq header (buffer-substring (car page) (match-beginning 0)))
800 (apply #'append 841 ;; Since the awk script collapses all successive blank
801 (mapcar #'(lambda (page) 842 ;; lines into one, and since we don't want to get rid of
802 (and page 843 ;; the fast awk script, one must choose between adding
803 (y-or-n-p (format "Read %s? " page)) 844 ;; spare blank lines between pages when there were none and
804 (list page))) 845 ;; deleting blank lines at page boundaries when there were
805 manlist)) 846 ;; some. We choose the first, so we comment the following
806 manlist)))) 847 ;; line.
807 848 ;; (setq header (concat "\n" header)))
808 (defun Manual-clean-to-unique-pages-only (manlist) 849 (while (search-forward header (nth 1 page) t)
809 "Prune the current list of pages down to a unique set." 850 (replace-match "")))
810 (let (page-name unique-pages) 851 (setq page-list (cdr page-list)))))
811 (apply 'append 852
812 (mapcar '(lambda (page) 853 (defun Man-unindent ()
813 (cond (page 854 "Delete the leading spaces that indent the manpage."
814 (and (string-match ".*/\\(.*\\)" page) 855 (let ((buffer-read-only nil)
815 (setq page-name (substring page (match-beginning 1) 856 (case-fold-search nil)
816 (match-end 1))) 857 (page-list Man-page-list))
817 ;; try to clip off .Z, .gz suffixes 858 (while page-list
818 (and (string-match "\\(.*\\)\\.\\(.+\\)\\.\\(.+\\)" 859 (let ((page (car page-list))
819 page-name) 860 (indent "")
820 (setq page-name 861 (nindent 0))
821 (substring page-name (match-beginning 1) 862 (narrow-to-region (car page) (car (cdr page)))
822 (match-end 2))))) 863 (if Man-uses-untabify-flag
823 ;; add Manual-unique-pages if it isn't there 864 (untabify (point-min) (point-max)))
824 ;; and return file 865 (if (catch 'unindent
825 (if (and unique-pages 866 (goto-char (point-min))
826 page-name 867 (if (not (re-search-forward Man-first-heading-regexp nil t))
827 (string-match (concat "\\b" page-name "\\b") 868 (throw 'unindent nil))
828 unique-pages)) 869 (beginning-of-line)
829 nil 870 (setq indent (buffer-substring (point)
830 (setq unique-pages (concat unique-pages 871 (progn
831 page-name 872 (skip-chars-forward " ")
832 " ")) 873 (point))))
833 (list page))))) 874 (setq nindent (length indent))
834 manlist)))) 875 (if (zerop nindent)
835 876 (throw 'unindent nil))
836 877 (setq indent (concat indent "\\|$"))
837 878 (goto-char (point-min))
838 (defun Manual-insert-man-file (name) 879 (while (not (eobp))
839 ;; Insert manual file (unpacked as necessary) into buffer 880 (if (looking-at indent)
840 (cond ((equal (substring name -3) ".gz") 881 (forward-line 1)
841 (call-process "gunzip" nil t nil "--stdout" name)) 882 (throw 'unindent nil)))
842 ((or (equal (substring name -2) ".Z") 883 (goto-char (point-min)))
843 ;; HPUX uses directory names that end in .Z and compressed 884 (while (not (eobp))
844 ;; files that don't. How gratuitously random. 885 (or (eolp)
845 (let ((case-fold-search nil)) 886 (delete-char nindent))
846 (string-match "\\.Z/" name))) 887 (forward-line 1)))
847 (call-process "zcat" name t nil)) ;; XEmacs change for HPUX 888 (setq page-list (cdr page-list))
848 ((equal (substring name -2) ".z") 889 ))))
849 (call-process "pcat" nil t nil name)) 890
850 (t 891
851 (insert-file-contents name)))) 892 ;; ======================================================================
852 893 ;; Man mode commands
853 (defmacro Manual-delete-char (n) 894
854 ;; in v19, delete-char is compiled as a function call, but delete-region 895 (defun Man-next-section (n)
855 ;; is byte-coded, so it's much faster. 896 "Move point to Nth next section (default 1)."
856 ;; (We were spending 40% of our time in delete-char alone.) 897 (interactive "p")
857 (list 'delete-region '(point) (list '+ '(point) n))) 898 (let ((case-fold-search nil))
858 899 (if (looking-at Man-heading-regexp)
859 ;; Hint: BS stands for more things than "back space" 900 (forward-line 1))
860 (defun Manual-nuke-nroff-bs (&optional apropos-mode) 901 (if (re-search-forward Man-heading-regexp (point-max) t n)
861 (interactive "*") 902 (beginning-of-line)
862 (if Manual-use-rosetta-man 903 (goto-char (point-max)))))
863 (call-process-region (point-min) (point-max) "rman" t t nil) 904
864 ;; 905 (defun Man-previous-section (n)
865 ;; turn underlining into italics 906 "Move point to Nth previous section (default 1)."
866 ;; 907 (interactive "p")
908 (let ((case-fold-search nil))
909 (if (looking-at Man-heading-regexp)
910 (forward-line -1))
911 (if (re-search-backward Man-heading-regexp (point-min) t n)
912 (beginning-of-line)
913 (goto-char (point-min)))))
914
915 (defun Man-find-section (section)
916 "Move point to SECTION if it exists, otherwise don't move point.
917 Returns t if section is found, nil otherwise."
918 (let ((curpos (point))
919 (case-fold-search nil))
867 (goto-char (point-min)) 920 (goto-char (point-min))
868 (while (search-forward "_\b" nil t) 921 (if (re-search-forward (concat "^" section) (point-max) t)
869 ;; searching for underscore-backspace and then comparing the following 922 (progn (beginning-of-line) t)
870 ;; chars until the sequence ends turns out to be much faster than searching 923 (goto-char curpos)
871 ;; for a regexp which matches the whole sequence. 924 nil)
872 (let ((s (match-beginning 0)))
873 (goto-char s)
874 (while (and (= (following-char) ?_)
875 (= (char-after (1+ (point))) ?\b))
876 (Manual-delete-char 2)
877 (forward-char 1))
878 (set-extent-face (make-extent s (point)) 'man-italic)))
879 ;;
880 ;; turn overstriking into bold
881 ;;
882 (goto-char (point-min))
883 (while (re-search-forward "\\([^\n]\\)\\(\b\\1\\)" nil t)
884 ;; Surprisingly, searching for the above regexp is faster than searching
885 ;; for a backspace and then comparing the preceding and following chars,
886 ;; I presume because there are many false matches, meaning more funcalls
887 ;; to re-search-forward.
888 (let ((s (match-beginning 0)))
889 (goto-char s)
890 ;; Some systems (SGI) overstrike multiple times, eg, "M\bM\bM\bM".
891 (while (looking-at "\\([^\n]\\)\\(\b\\1\\)+")
892 (delete-region (+ (point) 1) (match-end 0))
893 (forward-char 1))
894 (set-extent-face (make-extent s (point)) 'man-bold)))
895 ;;
896 ;; hack bullets: o^H+ --> +
897 (goto-char (point-min))
898 (while (search-forward "\b" nil t)
899 (Manual-delete-char -2))
900
901 (if (> (buffer-size) 100) ; minor kludge
902 (Manual-nuke-nroff-bs-footers))
903 ) ;; not Manual-use-rosetta-man
904 ;;
905 ;; turn subsection header lines into bold
906 ;;
907 (goto-char (point-min))
908 (if apropos-mode
909 (while (re-search-forward "[a-zA-Z0-9] ([0-9]" nil t)
910 (forward-char -2)
911 (delete-backward-char 1))
912
913 ;; (while (re-search-forward "^[^ \t\n]" nil t)
914 ;; (set-extent-face (make-extent (match-beginning 0)
915 ;; (progn (end-of-line) (point)))
916 ;; 'man-heading))
917
918 ;; boldface the first line
919 (if (looking-at "[^ \t\n].*$")
920 (set-extent-face (make-extent (match-beginning 0) (match-end 0))
921 'man-bold))
922
923 ;; boldface subsequent title lines
924 ;; Regexp to match section headers changed to match a non-indented
925 ;; line preceded by a blank line and followed by an indented line.
926 ;; This seems to work ok for manual pages but gives better results
927 ;; with other nroff'd files
928 (while (re-search-forward "\n\n\\([^ \t\n].*\\)\n[ \t]+[^ \t\n]" nil t)
929 (goto-char (match-end 1))
930 (set-extent-face (make-extent (match-beginning 1) (match-end 1))
931 'man-heading)
932 (forward-line 1))
933 )
934
935 (if Manual-use-rosetta-man
936 nil
937 ;; Zap ESC7, ESC8, and ESC9
938 ;; This is for Sun man pages like "man 1 csh"
939 (goto-char (point-min))
940 (while (re-search-forward "\e[789]" nil t)
941 (replace-match "")))
942
943 ;; Nuke blanks lines at start.
944 ;; (goto-char (point-min))
945 ;; (skip-chars-forward "\n")
946 ;; (delete-region (point-min) (point))
947
948 (Manual-mouseify-xrefs)
949 )
950
951 (fset 'nuke-nroff-bs 'Manual-nuke-nroff-bs) ; use old name
952
953
954 (defun Manual-nuke-nroff-bs-footers ()
955 ;; Nuke headers and footers.
956 ;;
957 ;; nroff assumes pages are 66 lines high. We assume that, and that the
958 ;; first and last line on each page is expendible. There is no way to
959 ;; tell the difference between a page break in the middle of a paragraph
960 ;; and a page break between paragraphs (the amount of extra whitespace
961 ;; that nroff inserts is the same in both cases) so this might strip out
962 ;; a blank line were one should remain. I think that's better than
963 ;; leaving in a blank line where there shouldn't be one. (Need I say
964 ;; it: FMH.)
965 ;;
966 ;; Note that if nroff spits out error messages, pages will be more than
967 ;; 66 lines high, and we'll lose badly. That's ok because standard
968 ;; nroff doesn't do any diagnostics, and the "gnroff" wrapper for groff
969 ;; turns off error messages for compatibility. (At least, it's supposed
970 ;; to.)
971 ;;
972 (goto-char (point-min))
973 ;; first lose the status output
974 (let ((case-fold-search t))
975 (if (and (not (looking-at "[^\n]*warning"))
976 (looking-at "Reformatting.*\n"))
977 (delete-region (match-beginning 0) (match-end 0))))
978
979 ;; kludge around a groff bug where it won't keep quiet about some
980 ;; warnings even with -Wall or -Ww.
981 (cond ((looking-at "grotty:")
982 (while (looking-at "grotty:")
983 (delete-region (point) (progn (forward-line 1) (point))))
984 (if (looking-at " *done\n")
985 (delete-region (point) (match-end 0)))))
986
987 (let ((pages '())
988 p)
989 ;; collect the page boundary markers before we start deleting, to make
990 ;; it easier to strip things out without changing the page sizes.
991 (while (not (eobp))
992 (forward-line 66)
993 (setq pages (cons (point-marker) pages)))
994 (setq pages (nreverse pages))
995 (while pages
996 (goto-char (car pages))
997 (set-marker (car pages) nil)
998 ;;
999 ;; The lines are: 3 blank; footer; 6 blank; header; 3 blank.
1000 ;; We're in between the previous footer and the following header,
1001 ;;
1002 ;; First lose 3 blank lines, the header, and then 3 more.
1003 ;;
1004 (setq p (point))
1005 (skip-chars-forward "\n")
1006 (delete-region p (point))
1007 (and (looking-at "[^\n]+\n\n?\n?\n?")
1008 (delete-region (match-beginning 0) (match-end 0)))
1009 ;;
1010 ;; Next lose the footer, and the 3 blank lines after, and before it.
1011 ;; But don't lose the last footer of the manual entry; that contains
1012 ;; the "last change" date, so it's not completely uninteresting.
1013 ;; (Actually lose all blank lines before it; sh(1) needs this.)
1014 ;;
1015 (skip-chars-backward "\n")
1016 (beginning-of-line)
1017 (if (null (cdr pages))
1018 nil
1019 (and (looking-at "[^\n]+\n\n?\n?\n?")
1020 (delete-region (match-beginning 0) (match-end 0))))
1021 (setq p (point))
1022 (skip-chars-backward "\n")
1023 (if (> (- p (point)) 4)
1024 (delete-region (+ 2 (point)) p)
1025 (delete-region (1+ (point)) p))
1026 ; (and (looking-at "\n\n?\n?")
1027 ; (delete-region (match-beginning 0) (match-end 0)))
1028
1029 (setq pages (cdr pages)))
1030 ;;
1031 ;; Now nuke the extra blank lines at the beginning and end.
1032 (goto-char (point-min))
1033 (if (looking-at "\n+")
1034 (delete-region (match-beginning 0) (match-end 0)))
1035 (forward-line 1)
1036 (if (looking-at "\n\n+")
1037 (delete-region (1+ (match-beginning 0)) (match-end 0)))
1038 (goto-char (point-max))
1039 (skip-chars-backward "\n")
1040 (delete-region (point) (point-max))
1041 (beginning-of-line)
1042 (forward-char -1)
1043 (setq p (point))
1044 (skip-chars-backward "\n")
1045 (if (= ?\n (following-char)) (forward-char 1))
1046 (if (> (point) (1+ p))
1047 (delete-region (point) p))
1048 )) 925 ))
1049 926
1050 ;(defun Manual-nuke-nroff-bs-footers () 927 (defun Man-goto-section ()
1051 ; ;; Nuke headers: "MORE(1) UNIX Programmer's Manual MORE(1)" 928 "Query for section to move point to."
1052 ; (goto-char (point-min)) 929 (interactive)
1053 ; (while (re-search-forward "^ *\\([A-Za-z][-_A-Za-z0-9]*([0-9A-Za-z]+)\\).*\\1$" nil t) 930 (aput 'Man-sections-alist
1054 ; (replace-match "")) 931 (let* ((default (aheadsym Man-sections-alist))
1055 ; 932 (completion-ignore-case t)
1056 ; ;; 933 chosen
1057 ; ;; it would appear that we have a choice between sometimes introducing 934 (prompt (concat "Go to section: (default " default ") ")))
1058 ; ;; an extra blank line when a paragraph was broken by a footer, and 935 (setq chosen (completing-read prompt Man-sections-alist))
1059 ; ;; sometimes not putting in a blank line between two paragraphs when 936 (if (or (not chosen)
1060 ; ;; a footer appeared right between them. FMH; I choose the latter. 937 (string= chosen ""))
1061 ; ;; 938 default
1062 ; 939 chosen)))
1063 ; ;; Nuke footers: "Printed 12/3/85 27 April 1981 1" 940 (Man-find-section (aheadsym Man-sections-alist)))
1064 ; ;; Sun appear to be on drugz: 941
1065 ; ;; "Sun Release 3.0B Last change: 1 February 1985 1" 942 (defun Man-goto-see-also-section ()
1066 ; ;; HP are even worse! 943 "Move point the the \"SEE ALSO\" section.
1067 ; ;; " Hewlett-Packard -1- (printed 12/31/99)" FMHWA12ID!! 944 Actually the section moved to is described by `Man-see-also-regexp'."
1068 ; ;; System V (well WICATs anyway): 945 (interactive)
1069 ; ;; "Page 1 (printed 7/24/85)" 946 (if (not (Man-find-section Man-see-also-regexp))
1070 ; ;; Who is administering PCP to these corporate bozos? 947 (error (concat "No " Man-see-also-regexp
1071 ; (goto-char (point-min)) 948 " section found in the current manpage"))))
1072 ; (while (re-search-forward 949
1073 ; (cond 950 (defun Man-follow-manual-reference (reference)
1074 ; ((eq system-type 'hpux) 951 "Get one of the manpages referred to in the \"SEE ALSO\" section.
1075 ; "\n\n?[ \t]*Hewlett-Packard\\(\\| Company\\)[ \t]*- [0-9]* -.*\n") 952 Specify which reference to use; default is based on word at point."
1076 ; ((eq system-type 'dgux-unix) 953 (interactive
1077 ; "\n\n?[ \t]*Licensed material--.*Page [0-9]*\n") 954 (if (not Man-refpages-alist)
1078 ; ((eq system-type 'usg-unix-v) 955 (error "There are no references in the current man page")
1079 ; "\n\n? *Page [0-9]*.*(printed [0-9/]*)\n") 956 (list (let* ((default (or
1080 ; (t 957 (car (all-completions
1081 ; "\n\n?\\(Printed\\|Sun Release\\) [0-9].*[0-9]\n")) 958 (save-excursion
1082 ; nil t) 959 (skip-syntax-backward "w()")
1083 ; (replace-match "")) 960 (skip-chars-forward " \t")
1084 ; 961 (let ((word (current-word)))
1085 ; ;; Also, hack X footers: 962 ;; strip a trailing '-':
1086 ; ;; "X Version 11 Last change: Release 5 1" 963 (if (string-match "-$" word)
1087 ; (goto-char (point-min)) 964 (substring word 0
1088 ; (while (re-search-forward "\n\n?X Version [^\n]+\n" nil t) 965 (match-beginning 0))
1089 ; (replace-match "")) 966 word)))
1090 ; 967 Man-refpages-alist))
1091 ; ;; Crunch blank lines 968 (aheadsym Man-refpages-alist)))
1092 ; (goto-char (point-min)) 969 chosen
1093 ; (while (re-search-forward "\n\n\n\n*" nil t) 970 (prompt (concat "Refer to: (default " default ") ")))
1094 ; (replace-match "\n\n")) 971 (setq chosen (completing-read prompt Man-refpages-alist nil t))
1095 ; ) 972 (if (or (not chosen)
1096 973 (string= chosen ""))
1097 (defun Manual-mouseify-xrefs () 974 default
1098 (goto-char (point-min)) 975 chosen)))))
1099 (forward-line 1) 976 (if (not Man-refpages-alist)
1100 (let ((case-fold-search nil) 977 (error "Can't find any references in the current manpage")
1101 s e name extent) 978 (aput 'Man-refpages-alist reference)
1102 ;; possibly it would be faster to rewrite this expression to search for 979 (Man-getpage-in-background
1103 ;; a less common sequence first (like "([0-9]") and then back up to see 980 (Man-translate-references (aheadsym Man-refpages-alist)))))
1104 ;; if it's really a match. This function is 15% of the total time, 13% 981
1105 ;; of which is this call to re-search-forward. 982 (defun Man-kill ()
1106 (while (re-search-forward "[a-zA-Z_][-a-zA-Z0-9_.]*([0-9][a-zA-Z0-9]*)" 983 "Kill the buffer containing the manpage."
1107 nil t) 984 (interactive)
1108 (setq s (match-beginning 0) 985 (let ((buff (current-buffer)))
1109 e (match-end 0) 986 (delete-windows-on buff)
1110 name (buffer-substring s e)) 987 (kill-buffer buff))
1111 (goto-char s) 988 (if (and window-system
1112 (skip-chars-backward " \t") 989 (or (eq Man-notify-method 'newframe)
1113 (if (and (bolp) 990 (and pop-up-frames
1114 (progn (backward-char 1) (= (preceding-char) ?-))) 991 (eq Man-notify-method 'bully))))
1115 (progn 992 (delete-frame)))
1116 (setq s (point)) 993
1117 (skip-chars-backward "-a-zA-Z0-9_.") 994 (defun Man-quit ()
1118 (setq name (concat (buffer-substring (point) (1- s)) name)) 995 "Bury the buffer containing the manpage."
1119 (setq s (point)))) 996 (interactive)
1120 ;; if there are upper case letters in the section, downcase them. 997 (let ((buff (current-buffer)))
1121 (if (string-match "(.*[A-Z]+.*)$" name) 998 (delete-windows-on buff)
1122 (setq name (concat (substring name 0 (match-beginning 0)) 999 (bury-buffer buff))
1123 (downcase (substring name (match-beginning 0)))))) 1000 (if (and window-system
1124 ;; (setq already-fontified (extent-at s)) 1001 (or (eq Man-notify-method 'newframe)
1125 (setq extent (make-extent s e)) 1002 (and pop-up-frames
1126 (set-extent-property extent 'man (list 'Manual-follow-xref name)) 1003 (eq Man-notify-method 'bully))))
1127 (set-extent-property extent 'highlight t) 1004 (delete-frame)))
1128 ;; (if (not already-fontified)... 1005
1129 (set-extent-face extent 'man-xref) 1006 (defun Man-goto-page (page)
1130 (goto-char e)))) 1007 "Go to the manual page on page PAGE."
1131 1008 (interactive
1132 (defun Manual-follow-xref (&optional name-or-event) 1009 (if (not Man-page-list)
1133 "Invoke `manual-entry' on the cross-reference under the mouse. 1010 (let ((args Man-arguments))
1134 When invoked noninteractively, the arg may be an xref string to parse instead." 1011 (kill-buffer (current-buffer))
1135 (interactive "e") 1012 (error "Can't find the %s manpage" args))
1136 (if (eventp name-or-event) 1013 (if (= (length Man-page-list) 1)
1137 (let* ((p (event-point name-or-event)) 1014 (error "You're looking at the only manpage in the buffer")
1138 (extent (and p (extent-at p 1015 (list (read-minibuffer (format "Go to manpage [1-%d]: "
1139 (event-buffer name-or-event) 1016 (length Man-page-list)))))))
1140 'highlight))) 1017 (if (not Man-page-list)
1141 (data (and extent (extent-property extent 'man)))) 1018 (let ((args Man-arguments))
1142 (if (eq (car-safe data) 'Manual-follow-xref) 1019 (kill-buffer (current-buffer))
1143 (eval data) 1020 (error "Can't find the %s manpage" args)))
1144 (error "no manual cross-reference there."))) 1021 (if (or (< page 1)
1145 (let ((Manual-match-topic-exactly t) 1022 (> page (length Man-page-list)))
1146 (Manual-query-multiple-pages nil)) 1023 (error "No manpage %d found" page))
1147 (or (manual-entry name-or-event) 1024 (let* ((page-range (nth (1- page) Man-page-list))
1148 ;; If that didn't work, maybe it's in a different section than the 1025 (page-start (car page-range))
1149 ;; man page writer expected. For example, man pages tend assume 1026 (page-end (car (cdr page-range))))
1150 ;; that all user programs are in section 1, but X tends to generate 1027 (setq Man-current-page page
1151 ;; makefiles that put things in section "n" instead... 1028 Man-page-mode-string (Man-make-page-mode-string))
1152 (and (string-match "[ \t]*([^)]+)\\'" name-or-event) 1029 (widen)
1153 (progn 1030 (goto-char page-start)
1154 (message "No entries found for %s; checking other sections..." 1031 (narrow-to-region page-start page-end)
1155 name-or-event) 1032 (Man-build-section-alist)
1156 (manual-entry 1033 (Man-build-references-alist)
1157 (substring name-or-event 0 (match-beginning 0)) 1034 (goto-char (point-min))))
1158 nil t))))))) 1035
1159 1036
1160 (defun Manual-popup-menu (&optional event) 1037 (defun Man-next-manpage ()
1161 "Pops up a menu of cross-references in this manual page. 1038 "Find the next manpage entry in the buffer."
1162 If there is a cross-reference under the mouse button which invoked this 1039 (interactive)
1163 command, it will be the first item on the menu. Otherwise, they are 1040 (if (= (length Man-page-list) 1)
1164 on the menu in the order in which they appear in the buffer." 1041 (error "This is the only manpage in the buffer"))
1165 (interactive "e") 1042 (if (< Man-current-page (length Man-page-list))
1166 (let ((buffer (current-buffer)) 1043 (Man-goto-page (1+ Man-current-page))
1167 (sep "---") 1044 (if Man-circular-pages-flag
1168 (prefix "Show Manual Page for ") 1045 (Man-goto-page 1)
1169 xref items) 1046 (error "You're looking at the last manpage in the buffer"))))
1170 (cond (event 1047
1171 (setq buffer (event-buffer event)) 1048 (defun Man-previous-manpage ()
1172 (let* ((p (event-point event)) 1049 "Find the previous manpage entry in the buffer."
1173 (extent (and p (extent-at p buffer 'highlight))) 1050 (interactive)
1174 (data (and extent (extent-property extent 'man)))) 1051 (if (= (length Man-page-list) 1)
1175 (if (eq (car-safe data) 'Manual-follow-xref) 1052 (error "This is the only manpage in the buffer"))
1176 (setq xref (nth 1 data)))))) 1053 (if (> Man-current-page 1)
1177 (if xref (setq items (list sep xref))) 1054 (Man-goto-page (1- Man-current-page))
1178 (map-extents #'(lambda (extent ignore) 1055 (if Man-circular-pages-flag
1179 (let ((data (extent-property extent 'man))) 1056 (Man-goto-page (length Man-page-list))
1180 (if (and (eq (car-safe data) 'Manual-follow-xref) 1057 (error "You're looking at the first manpage in the buffer"))))
1181 (not (member (nth 1 data) items))) 1058
1182 (setq items (cons (nth 1 data) items))) 1059 ;; Init the man package variables, if not already done.
1183 nil)) 1060 (Man-init-defvars)
1184 buffer) 1061
1185 (if (eq sep (car items)) (setq items (cdr items)))
1186 (let ((popup-menu-titles nil))
1187 (popup-menu
1188 (cons "Manual Entry"
1189 (mapcar #'(lambda (item)
1190 (if (eq item sep)
1191 item
1192 (vector (concat prefix item)
1193 (list 'Manual-follow-xref item) t)))
1194 (nreverse items)))))))
1195
1196 (defun pager-cleanup-hook ()
1197 "cleanup man page if called via $PAGER"
1198 (let ((buf-name (or buffer-file-name (buffer-name))))
1199 (if (and (or (string-match "^/tmp/man[0-9]+" buf-name)
1200 (string-match ".*/man/\\(man\\|cat\\)[1-9a-z]/" buf-name))
1201 (not (string-match Manual-bogus-file-pattern buf-name)))
1202 (let (buffer manpage)
1203 (require 'man)
1204 (goto-char (point-min))
1205 (setq buffer-read-only nil)
1206 (Manual-nuke-nroff-bs)
1207 (goto-char (point-min))
1208 (if (re-search-forward "[^ \t]")
1209 (goto-char (- (point) 1)))
1210 (if (looking-at "\\([a-zA-Z0-9]+\\)[ \t]*(")
1211 (setq manpage (buffer-substring (match-beginning 1) (match-end 1)))
1212 (setq manpage "???"))
1213 (setq buffer
1214 (rename-buffer
1215 (generate-new-buffer-name (concat "*man " manpage "*"))))
1216 (setq buffer-file-name nil)
1217 (goto-char (point-min))
1218 (insert (format "%s\n" buf-name))
1219 (goto-char (point-min))
1220 (buffer-disable-undo buffer)
1221 (set-buffer-modified-p nil)
1222 (Manual-mode)
1223 ))))
1224
1225 (add-hook 'server-visit-hook 'pager-cleanup-hook)
1226 (provide 'man) 1062 (provide 'man)
1063
1064 ;;; man.el ends here