comparison lisp/packages/man.el @ 4:b82b59fe008d r19-15b3

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