]> code.delx.au - gnu-emacs/blobdiff - lisp/man.el
*** empty log message ***
[gnu-emacs] / lisp / man.el
index 406085a094f428715abb9c54f42eb29e24604959..7222c1bad15428e35f0df3a21f552b43241d559c 100644 (file)
@@ -1,11 +1,11 @@
-;;; man.el --- browse UNIX manual pages
+;;; man.el --- browse UNIX manual pages -*- coding: iso-8859-1 -*-
 
 
-;; Copyright (C) 1993, 1994, 1996, 1997 Free Software Foundation, Inc.
+;; Copyright (C) 1993, 1994, 1996, 1997, 2001, 2003, 2004 Free Software Foundation, Inc.
 
 
-;; Author:             Barry A. Warsaw <bwarsaw@cen.com>
+;; Author: Barry A. Warsaw <bwarsaw@cen.com>
 ;; Maintainer: FSF
 ;; Maintainer: FSF
-;; Keywords:           help
-;; Adapted-By:         ESR, pot
+;; Keywords: help
+;; Adapted-By: ESR, pot
 
 ;; This file is part of GNU Emacs.
 
 
 ;; This file is part of GNU Emacs.
 
@@ -81,7 +81,7 @@
 ;;   footer).  A different algorithm should be used.  It is easy to
 ;;   compute how many blank lines there are before and after the page
 ;;   headers, and after the page footer.  But it is possible to compute
 ;;   footer).  A different algorithm should be used.  It is easy to
 ;;   compute how many blank lines there are before and after the page
 ;;   headers, and after the page footer.  But it is possible to compute
-;;   the number of blank lines before the page footer by euristhics
+;;   the number of blank lines before the page footer by heuristics
 ;;   only.  Is it worth doing?
 ;; - Allow a user option to mean that all the manpages should go in
 ;;   the same buffer, where they can be browsed with M-n and M-p.
 ;;   only.  Is it worth doing?
 ;; - Allow a user option to mean that all the manpages should go in
 ;;   the same buffer, where they can be browsed with M-n and M-p.
@@ -95,6 +95,7 @@
 ;;; Code:
 
 (require 'assoc)
 ;;; Code:
 
 (require 'assoc)
+(require 'button)
 
 ;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
 ;; empty defvars (keep the compiler quiet)
 
 ;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
 ;; empty defvars (keep the compiler quiet)
@@ -174,6 +175,17 @@ Any other value of `Man-notify-method' is equivalent to `meek'."
                (const polite) (const quiet) (const meek))
   :group 'man)
 
                (const polite) (const quiet) (const meek))
   :group 'man)
 
+(defcustom Man-width nil
+  "*Number of columns for which manual pages should be formatted.
+If nil, the width of the window selected at the moment of man
+invocation is used.  If non-nil, the width of the frame selected
+at the moment of man invocation is used.  The value also can be a
+positive integer."
+  :type '(choice (const :tag "Window width" nil)
+                 (const :tag "Frame width" t)
+                 (integer :tag "Specific width" :value 65))
+  :group 'man)
+
 (defcustom Man-frame-parameters nil
   "*Frame parameter list for creating a new frame for a manual page."
   :type 'sexp
 (defcustom Man-frame-parameters nil
   "*Frame parameter list for creating a new frame for a manual page."
   :type 'sexp
@@ -210,6 +222,12 @@ the associated section number."
                       (string :tag "Real Section")))
   :group 'man)
 
                       (string :tag "Real Section")))
   :group 'man)
 
+(defcustom Man-header-file-path
+  '("/usr/include" "/usr/local/include")
+  "C Header file search path used in Man."
+  :type '(repeat string)
+  :group 'man)
+
 (defvar manual-program "man"
   "The name of the program that produces man pages.")
 
 (defvar manual-program "man"
   "The name of the program that produces man pages.")
 
@@ -225,20 +243,6 @@ the associated section number."
 (defvar Man-awk-command "awk"
   "Command used for processing awk scripts.")
 
 (defvar Man-awk-command "awk"
   "Command used for processing awk scripts.")
 
-(defvar Man-mode-line-format
-  '("-"
-    mode-line-mule-info
-    mode-line-modified
-    mode-line-frame-identification
-    mode-line-buffer-identification "  "
-    global-mode-string
-    " " Man-page-mode-string
-    "  %[(" mode-name mode-line-process minor-mode-alist "%n)%]--"
-    (line-number-mode "L%l--")
-    (column-number-mode "C%c--")
-    (-3 . "%p") "-%-")
-  "Mode line format for manual mode buffer.")
-
 (defvar Man-mode-map nil
   "Keymap for Man mode.")
 
 (defvar Man-mode-map nil
   "Keymap for Man mode.")
 
@@ -248,7 +252,7 @@ the associated section number."
 (defvar Man-cooked-hook nil
   "Hook run after removing backspaces but before `Man-mode' processing.")
 
 (defvar Man-cooked-hook nil
   "Hook run after removing backspaces but before `Man-mode' processing.")
 
-(defvar Man-name-regexp "[-a-zA-Z0-9_][-a-zA-Z0-9_.]*"
+(defvar Man-name-regexp "[-a-zA-Z0-9_­+][-a-zA-Z0-9_.­+]*"
   "Regular expression describing the name of a manpage (without section).")
 
 (defvar Man-section-regexp "[0-9][a-zA-Z+]*\\|[LNln]"
   "Regular expression describing the name of a manpage (without section).")
 
 (defvar Man-section-regexp "[0-9][a-zA-Z+]*\\|[LNln]"
@@ -263,7 +267,7 @@ the associated section number."
            "(\\(" Man-section-regexp "\\))\\).*\\1"))
   "Regular expression describing the heading of a page.")
 
            "(\\(" Man-section-regexp "\\))\\).*\\1"))
   "Regular expression describing the heading of a page.")
 
-(defvar Man-heading-regexp "^\\([A-Z][A-Z ]+\\)$"
+(defvar Man-heading-regexp "^\\([A-Z][A-Z -]+\\)$"
   "Regular expression describing a manpage heading entry.")
 
 (defvar Man-see-also-regexp "SEE ALSO"
   "Regular expression describing a manpage heading entry.")
 
 (defvar Man-see-also-regexp "SEE ALSO"
@@ -276,10 +280,47 @@ This regular expression should start with a `^' character.")
 
 (defvar Man-reference-regexp
   (concat "\\(" Man-name-regexp "\\)(\\(" Man-section-regexp "\\))")
 
 (defvar Man-reference-regexp
   (concat "\\(" Man-name-regexp "\\)(\\(" Man-section-regexp "\\))")
+  "Regular expression describing a reference to another manpage.")
+
+(defvar Man-synopsis-regexp "SYNOPSIS"
+  "Regular expression for SYNOPSIS heading (or your equivalent).
+This regexp should not start with a `^' character.")
+
+(defvar Man-files-regexp "FILES"
+  "Regular expression for FILES heading (or your equivalent).
+This regexp should not start with a `^' character.")
+
+(defvar Man-include-regexp "#[ \t]*include[ \t]*"
+  "Regular expression describing the #include (directive of cpp).")
+
+(defvar Man-file-name-regexp "[^<>\" \t\n]+"
+  "Regular expression describing <> in #include line (directive of cpp).")
+
+(defvar Man-normal-file-prefix-regexp "[/~$]"
+  "Regular expression describing a file path appeared in FILES section.")
+
+(defvar Man-header-regexp
+  (concat "\\(" Man-include-regexp "\\)"
+          "[<\"]"
+          "\\(" Man-file-name-regexp "\\)"
+          "[>\"]")
+  "Regular expression describing references to header files.")
+
+(defvar Man-normal-file-regexp
+  (concat Man-normal-file-prefix-regexp Man-file-name-regexp)
+  "Regular expression describing references to normal files.")
+
+;; This includes the section as an optional part to catch hyphenated
+;; refernces to manpages.
+(defvar Man-hyphenated-reference-regexp
+  (concat "\\(" Man-name-regexp "\\)\\((\\(" Man-section-regexp "\\))\\)?")
   "Regular expression describing a reference in the SEE ALSO section.")
 
 (defvar Man-switches ""
   "Regular expression describing a reference in the SEE ALSO section.")
 
 (defvar Man-switches ""
-  "Switches passed to the man command, as a single string.")
+  "Switches passed to the man command, as a single string.
+
+If you want to be able to see all the manpages for a subject you type,
+make -a one of the switches, if your `man' program supports it.")
 
 (defvar Man-specified-section-option
   (if (string-match "-solaris[0-9.]*$" system-configuration)
 
 (defvar Man-specified-section-option
   (if (string-match "-solaris[0-9.]*$" system-configuration)
@@ -287,6 +328,12 @@ This regular expression should start with a `^' character.")
     "")
   "Option that indicates a specified a manual section name.")
 
     "")
   "Option that indicates a specified a manual section name.")
 
+(defvar Man-support-local-filenames 'auto-detect
+  "Internal cache for the value of the function `Man-support-local-filenames'.
+`auto-detect' means the value is not yet determined.
+Otherwise, the value is whatever the function
+`Man-support-local-filenames' should return.")
+
 ;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 ;; end user variables
 \f
 ;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 ;; end user variables
 \f
@@ -338,7 +385,7 @@ This regular expression should start with a `^' character.")
 
 (if Man-mode-map
     nil
 
 (if Man-mode-map
     nil
-  (setq Man-mode-map (make-keymap))
+  (setq Man-mode-map (copy-keymap button-buffer-map))
   (suppress-keymap Man-mode-map)
   (define-key Man-mode-map " "    'scroll-up)
   (define-key Man-mode-map "\177" 'scroll-down)
   (suppress-keymap Man-mode-map)
   (define-key Man-mode-map " "    'scroll-up)
   (define-key Man-mode-map "\177" 'scroll-down)
@@ -355,10 +402,32 @@ This regular expression should start with a `^' character.")
   (define-key Man-mode-map "k"    'Man-kill)
   (define-key Man-mode-map "q"    'Man-quit)
   (define-key Man-mode-map "m"    'man)
   (define-key Man-mode-map "k"    'Man-kill)
   (define-key Man-mode-map "q"    'Man-quit)
   (define-key Man-mode-map "m"    'man)
-  (define-key Man-mode-map "\r"   'man-follow)
   (define-key Man-mode-map "?"    'describe-mode)
   )
 
   (define-key Man-mode-map "?"    'describe-mode)
   )
 
+;; buttons
+(define-button-type 'Man-xref-man-page
+  'action (lambda (button) (man-follow (button-label button)))
+  'help-echo "RET, mouse-2: display this man page")
+
+(define-button-type 'Man-xref-header-file
+    'action (lambda (button)
+              (let ((w (button-get button 'Man-target-string)))
+                (unless (Man-view-header-file w)
+                  (error "Cannot find header file: %s" w))))
+    'help-echo "mouse-2: display this header file")
+
+(define-button-type 'Man-xref-normal-file
+  'action (lambda (button)
+           (let ((f (substitute-in-file-name
+                     (button-get button 'Man-target-string))))
+             (if (file-exists-p f)
+                 (if (file-readable-p f)
+                     (view-file f)
+                   (error "Cannot read a file: %s" f))
+               (error "Cannot find a file: %s" f))))
+  'help-echo "mouse-2: mouse-2: display this file")
+
 \f
 ;; ======================================================================
 ;; utilities
 \f
 ;; ======================================================================
 ;; utilities
@@ -373,9 +442,9 @@ This is necessary if one wants to dump man.el with Emacs."
          (cond
           (Man-fontify-manpage-flag
            nil)
          (cond
           (Man-fontify-manpage-flag
            nil)
-          ((= 0 (call-process Man-sed-command nil nil nil Man-sysv-sed-script))
+          ((eq 0 (call-process Man-sed-command nil nil nil Man-sysv-sed-script))
            Man-sysv-sed-script)
            Man-sysv-sed-script)
-          ((= 0 (call-process Man-sed-command nil nil nil Man-berkeley-sed-script))
+          ((eq 0 (call-process Man-sed-command nil nil nil Man-berkeley-sed-script))
            Man-berkeley-sed-script)
           (t
            nil))))
            Man-berkeley-sed-script)
           (t
            nil))))
@@ -423,16 +492,6 @@ This is necessary if one wants to dump man.el with Emacs."
           )))
 )
 
           )))
 )
 
-(defsubst Man-match-substring (&optional n string)
-  "Return the substring matched by the last search.
-Optional arg N means return the substring matched by the Nth paren
-grouping.  Optional second arg STRING means return a substring from
-that string instead of from the current buffer."
-  (if (null n) (setq n 0))
-  (if string
-      (substring string (match-beginning n) (match-end n))
-    (buffer-substring (match-beginning n) (match-end n))))
-
 (defsubst Man-make-page-mode-string ()
   "Formats part of the mode line for Man mode."
   (format "%s page %d of %d"
 (defsubst Man-make-page-mode-string ()
   "Formats part of the mode line for Man mode."
   (format "%s page %d of %d"
@@ -444,13 +503,15 @@ that string instead of from the current buffer."
 (defsubst Man-build-man-command ()
   "Builds the entire background manpage and cleaning command."
   (let ((command (concat manual-program " " Man-switches
 (defsubst Man-build-man-command ()
   "Builds the entire background manpage and cleaning command."
   (let ((command (concat manual-program " " Man-switches
-                        ; Stock MS-DOS shells cannot redirect stderr;
-                        ; `call-process' below sends it to /dev/null,
-                        ; so we don't need `2>' even with DOS shells
-                        ; which do support stderr redirection.
-                        (if (not (fboundp 'start-process))
-                            " %s"
-                          (concat " %s 2>" null-device))))
+                         (cond
+                          ;; Already has %s
+                          ((string-match "%s" manual-program) "")
+                          ;; Stock MS-DOS shells cannot redirect stderr;
+                          ;; `call-process' below sends it to /dev/null,
+                          ;; so we don't need `2>' even with DOS shells
+                          ;; which do support stderr redirection.
+                          ((not (fboundp 'start-process)) " %s")
+                          ((concat " %s 2>" null-device)))))
        (flist Man-filter-list))
     (while (and flist (car flist))
       (let ((pcom (car (car flist)))
        (flist Man-filter-list))
     (while (and flist (car flist))
       (let ((pcom (car (car flist)))
@@ -462,27 +523,40 @@ that string instead of from the current buffer."
                                       (error "Malformed Man-filter-list"))
                                   phrase)
                                 pargs " ")))
                                       (error "Malformed Man-filter-list"))
                                   phrase)
                                 pargs " ")))
-       (setq flist (cdr flist))))
+        (setq flist (cdr flist))))
     command))
 
     command))
 
+
+(defun Man-translate-cleanup (string)
+  "Strip leading, trailing and middle spaces."
+  (when (stringp string)
+    ;;  Strip leading and trailing
+    (if (string-match "^[ \t\f\r\n]*\\(.+[^ \t\f\r\n]\\)" string)
+        (setq string (match-string 1 string)))
+    ;; middle spaces
+    (setq string (replace-regexp-in-string "[\t\r\n]" " " string))
+    (setq string (replace-regexp-in-string "  +" " " string))
+    string))
+
 (defun Man-translate-references (ref)
   "Translates REF from \"chmod(2V)\" to \"2v chmod\" style.
 Leave it as is if already in that style.  Possibly downcase and
 translate the section (see the Man-downcase-section-letters-flag
 and the Man-section-translations-alist variables)."
   (let ((name "")
 (defun Man-translate-references (ref)
   "Translates REF from \"chmod(2V)\" to \"2v chmod\" style.
 Leave it as is if already in that style.  Possibly downcase and
 translate the section (see the Man-downcase-section-letters-flag
 and the Man-section-translations-alist variables)."
   (let ((name "")
-       (section "")
-       (slist Man-section-translations-alist))
+        (section "")
+        (slist Man-section-translations-alist))
+    (setq ref (Man-translate-cleanup ref))
     (cond
      ;; "chmod(2V)" case ?
      ((string-match (concat "^" Man-reference-regexp "$") ref)
     (cond
      ;; "chmod(2V)" case ?
      ((string-match (concat "^" Man-reference-regexp "$") ref)
-      (setq name (Man-match-substring 1 ref)
-           section (Man-match-substring 2 ref)))
+      (setq name (match-string 1 ref)
+           section (match-string 2 ref)))
      ;; "2v chmod" case ?
      ((string-match (concat "^\\(" Man-section-regexp
                            "\\) +\\(" Man-name-regexp "\\)$") ref)
      ;; "2v chmod" case ?
      ((string-match (concat "^\\(" Man-section-regexp
                            "\\) +\\(" Man-name-regexp "\\)$") ref)
-      (setq name (Man-match-substring 2 ref)
-           section (Man-match-substring 1 ref))))
+      (setq name (match-string 2 ref)
+           section (match-string 1 ref))))
     (if (string= name "")
        ref                             ; Return the reference as is
       (if Man-downcase-section-letters-flag
     (if (string= name "")
        ref                             ; Return the reference as is
       (if Man-downcase-section-letters-flag
@@ -500,6 +574,31 @@ and the Man-section-translations-alist variables)."
                  slist nil))))
       (concat Man-specified-section-option section " " name))))
 
                  slist nil))))
       (concat Man-specified-section-option section " " name))))
 
+(defun Man-support-local-filenames ()
+  "Check the availability of `-l' option of the man command.
+This option allows `man' to interpret command line arguments
+as local filenames.
+Return the value of the variable `Man-support-local-filenames'
+if it was set to nil or t before the call of this function.
+If t, the man command supports `-l' option.  If nil, it don't.
+Otherwise, if the value of `Man-support-local-filenames'
+is neither t nor nil, then determine a new value, set it
+to the variable `Man-support-local-filenames' and return
+a new value."
+  (if (or (not Man-support-local-filenames)
+          (eq Man-support-local-filenames t))
+      Man-support-local-filenames
+    (setq Man-support-local-filenames
+          (with-temp-buffer
+            (and (equal (condition-case nil
+                            (call-process manual-program nil t nil "--help")
+                          (error nil))
+                        0)
+                 (progn
+                   (goto-char (point-min))
+                   (search-forward "--local-file" nil t))
+                 t)))))
+
 \f
 ;; ======================================================================
 ;; default man entry: get word under point
 \f
 ;; ======================================================================
 ;; default man entry: get word under point
@@ -511,19 +610,21 @@ This guess is based on the text surrounding the cursor."
     (save-excursion
       ;; Default man entry title is any word the cursor is on, or if
       ;; cursor not on a word, then nearest preceding word.
     (save-excursion
       ;; Default man entry title is any word the cursor is on, or if
       ;; cursor not on a word, then nearest preceding word.
-      (setq word (current-word))
+      (skip-chars-backward "-a-zA-Z0-9._+:")
+      (let ((start (point)))
+       (skip-chars-forward "-a-zA-Z0-9._+:")
+       (setq word (buffer-substring-no-properties start (point))))
       (if (string-match "[._]+$" word)
          (setq word (substring word 0 (match-beginning 0))))
       (if (string-match "[._]+$" word)
          (setq word (substring word 0 (match-beginning 0))))
+      ;; If looking at something like *strcat(... , remove the '*'
+      (if (string-match "^*" word)
+         (setq word (substring word 1)))
       ;; If looking at something like ioctl(2) or brc(1M), include the
       ;; section number in the returned value.  Remove text properties.
       ;; If looking at something like ioctl(2) or brc(1M), include the
       ;; section number in the returned value.  Remove text properties.
-      (forward-word 1)
-      ;; Use `format' here to clear any text props from `word'.
-      (format "%s%s"
-             word
+      (concat word
              (if (looking-at
                   (concat "[ \t]*([ \t]*\\(" Man-section-regexp "\\)[ \t]*)"))
              (if (looking-at
                   (concat "[ \t]*([ \t]*\\(" Man-section-regexp "\\)[ \t]*)"))
-                 (format "(%s)" (Man-match-substring 1))
-               "")))))
+                 (format "(%s)" (match-string-no-properties 1)))))))
 
 \f
 ;; ======================================================================
 
 \f
 ;; ======================================================================
@@ -533,6 +634,7 @@ This guess is based on the text surrounding the cursor."
 ;;;###autoload
 (defalias 'manual-entry 'man)
 
 ;;;###autoload
 (defalias 'manual-entry 'man)
 
+
 ;;;###autoload
 (defun man (man-args)
   "Get a Un*x manual page and put it in a buffer.
 ;;;###autoload
 (defun man (man-args)
   "Get a Un*x manual page and put it in a buffer.
@@ -543,18 +645,19 @@ results in a Man mode (manpage browsing) buffer.  See variable
 If a buffer already exists for this man page, it will display immediately.
 
 To specify a man page from a certain section, type SUBJECT(SECTION) or
 If a buffer already exists for this man page, it will display immediately.
 
 To specify a man page from a certain section, type SUBJECT(SECTION) or
-SECTION SUBJECT when prompted for a manual entry."
+SECTION SUBJECT when prompted for a manual entry.  To see manpages from
+all sections related to a subject, put something appropriate into the
+`Man-switches' variable, which see."
   (interactive
    (list (let* ((default-entry (Man-default-man-entry))
                (input (read-string
                        (format "Manual entry%s: "
                                (if (string= default-entry "")
                                    ""
   (interactive
    (list (let* ((default-entry (Man-default-man-entry))
                (input (read-string
                        (format "Manual entry%s: "
                                (if (string= default-entry "")
                                    ""
-                                 (format " (default %s)" default-entry))))))
+                                 (format " (default %s)" default-entry)))
+                       nil nil default-entry)))
           (if (string= input "")
           (if (string= input "")
-              (if (string= default-entry "")
-                  (error "No man args given")
-                default-entry)
+              (error "No man args given")
             input))))
 
   ;; Possibly translate the "subject(section)" syntax into the
             input))))
 
   ;; Possibly translate the "subject(section)" syntax into the
@@ -596,27 +699,54 @@ SECTION SUBJECT when prompted for a manual entry."
             (if default-enable-multibyte-characters
                 locale-coding-system 'raw-text-unix))
            ;; Avoid possible error by using a directory that always exists.
             (if default-enable-multibyte-characters
                 locale-coding-system 'raw-text-unix))
            ;; Avoid possible error by using a directory that always exists.
-           (default-directory "/"))
+           (default-directory
+             (if (and (file-directory-p default-directory)
+                      (not (find-file-name-handler default-directory
+                                                   'file-directory-p)))
+                 default-directory
+               "/")))
        ;; Prevent any attempt to use display terminal fanciness.
        (setenv "TERM" "dumb")
        ;; Prevent any attempt to use display terminal fanciness.
        (setenv "TERM" "dumb")
+       ;; In Debian Woody, at least, we get overlong lines under X
+       ;; unless COLUMNS or MANWIDTH is set.  This isn't a problem on
+       ;; a tty.  man(1) says:
+       ;;        MANWIDTH
+       ;;               If $MANWIDTH is set, its value is used as the  line
+       ;;               length  for which manual pages should be formatted.
+       ;;               If it is not set, manual pages  will  be  formatted
+       ;;               with  a line length appropriate to the current ter-
+       ;;               minal (using an ioctl(2) if available, the value of
+       ;;               $COLUMNS,  or falling back to 80 characters if nei-
+       ;;               ther is available).
+       (if window-system
+           (unless (or (getenv "MANWIDTH") (getenv "COLUMNS"))
+             ;; This isn't strictly correct, since we don't know how
+             ;; the page will actually be displayed, but it seems
+             ;; reasonable.
+             (setenv "COLUMNS" (number-to-string
+                                (cond
+                                 ((and (integerp Man-width) (> Man-width 0))
+                                  Man-width)
+                                 (Man-width (frame-width))
+                                 ((window-width)))))))
+       (setenv "GROFF_NO_SGR" "1")
        (if (fboundp 'start-process)
            (set-process-sentinel
             (start-process manual-program buffer "sh" "-c"
                            (format (Man-build-man-command) man-args))
             'Man-bgproc-sentinel)
        (if (fboundp 'start-process)
            (set-process-sentinel
             (start-process manual-program buffer "sh" "-c"
                            (format (Man-build-man-command) man-args))
             'Man-bgproc-sentinel)
-         (progn
-           (let ((exit-status
-                  (call-process shell-file-name nil (list buffer nil) nil "-c"
-                                (format (Man-build-man-command) man-args)))
-                 (msg ""))
-             (or (and (numberp exit-status)
-                      (= exit-status 0))
-                 (and (numberp exit-status)
-                      (setq msg
-                            (format "exited abnormally with code %d"
-                                    exit-status)))
-                 (setq msg exit-status))
-             (Man-bgproc-sentinel bufname msg))))))))
+         (let ((exit-status
+                (call-process shell-file-name nil (list buffer nil) nil "-c"
+                              (format (Man-build-man-command) man-args)))
+               (msg ""))
+           (or (and (numberp exit-status)
+                    (= exit-status 0))
+               (and (numberp exit-status)
+                    (setq msg
+                          (format "exited abnormally with code %d"
+                                  exit-status)))
+               (setq msg exit-status))
+           (Man-bgproc-sentinel bufname msg)))))))
 
 (defun Man-notify-when-ready (man-buffer)
   "Notify the user when MAN-BUFFER is ready.
 
 (defun Man-notify-when-ready (man-buffer)
   "Notify the user when MAN-BUFFER is ready.
@@ -662,7 +792,7 @@ See the variable `Man-notify-method' for the different notification behaviors."
      )))
 
 (defun Man-softhyphen-to-minus ()
      )))
 
 (defun Man-softhyphen-to-minus ()
-  ;; \255 is some kind of dash in Latin-N.  Versions of Debian man, at
+  ;; \255 is SOFT HYPHEN in Latin-N.  Versions of Debian man, at
   ;; least, emit it even when not in a Latin-N locale.
   (unless (eq t (compare-strings "latin-" 0 nil
                                 current-language-environment 0 6 t))
   ;; least, emit it even when not in a Latin-N locale.
   (unless (eq t (compare-strings "latin-" 0 nil
                                 current-language-environment 0 6 t))
@@ -676,7 +806,7 @@ See the variable `Man-notify-method' for the different notification behaviors."
   "Convert overstriking and underlining to the correct fonts.
 Same for the ANSI bold and normal escape sequences."
   (interactive)
   "Convert overstriking and underlining to the correct fonts.
 Same for the ANSI bold and normal escape sequences."
   (interactive)
-  (message "Please wait: making up the %s man page..." Man-arguments)
+  (message "Please wait: formatting the %s man page..." Man-arguments)
   (goto-char (point-min))
   (while (search-forward "\e[1m" nil t)
     (delete-backward-char 4)
   (goto-char (point-min))
   (while (search-forward "\e[1m" nil t)
     (delete-backward-char 4)
@@ -716,8 +846,47 @@ Same for the ANSI bold and normal escape sequences."
   (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t)
     (replace-match "+")
     (put-text-property (1- (point)) (point) 'face 'bold))
   (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t)
     (replace-match "+")
     (put-text-property (1- (point)) (point) 'face 'bold))
+  (goto-char (point-min))
+  ;; Try to recognize common forms of cross references.
+  (Man-highlight-references)
   (Man-softhyphen-to-minus)
   (Man-softhyphen-to-minus)
-  (message "%s man page made up" Man-arguments))
+  (goto-char (point-min))
+  (while (re-search-forward Man-heading-regexp nil t)
+    (put-text-property (match-beginning 0)
+                      (match-end 0)
+                      'face Man-overstrike-face))
+  (message "%s man page formatted" Man-arguments))
+
+(defun Man-highlight-references ()
+  "Highlight the references on mouse-over.
+references include items in the SEE ALSO section,
+header file(#include <foo.h>) and files in FILES"
+  (let ((dummy 0))
+    (Man-highlight-references0
+     Man-see-also-regexp Man-reference-regexp 1 dummy
+     'Man-xref-man-page)
+    (Man-highlight-references0
+     Man-synopsis-regexp Man-header-regexp 0 2
+     'Man-xref-header-file)
+    (Man-highlight-references0
+     Man-files-regexp Man-normal-file-regexp 0 0
+     'Man-xref-normal-file)))
+
+(defun Man-highlight-references0 (start-section regexp button-pos target-pos type)
+  ;; Based on `Man-build-references-alist'
+  (when (Man-find-section start-section)
+    (forward-line 1)
+    (let ((end (save-excursion
+                 (Man-next-section 1)
+                 (point))))
+      (back-to-indentation)
+      (while (re-search-forward regexp end t)
+       (make-text-button
+        (match-beginning button-pos)
+        (match-end button-pos)
+        'type type
+        'Man-target-string (match-string target-pos)
+        )))))
 
 (defun Man-cleanup-manpage ()
   "Remove overstriking and underlining from the current buffer."
 
 (defun Man-cleanup-manpage ()
   "Remove overstriking and underlining from the current buffer."
@@ -832,7 +1001,6 @@ The following variables may be of some use.  Try
 `Man-circular-pages-flag'      Treat multiple manpage list as circular.
 `Man-section-translations-alist' List of section numbers and their Un*x equiv.
 `Man-filter-list'              Background manpage filter command.
 `Man-circular-pages-flag'      Treat multiple manpage list as circular.
 `Man-section-translations-alist' List of section numbers and their Un*x equiv.
 `Man-filter-list'              Background manpage filter command.
-`Man-mode-line-format'         Mode line format for Man mode buffers.
 `Man-mode-map'                 Keymap bindings for Man mode buffers.
 `Man-mode-hook'                        Normal hook run on entry to Man mode.
 `Man-section-regexp'           Regexp describing manpage section letters.
 `Man-mode-map'                 Keymap bindings for Man mode buffers.
 `Man-mode-hook'                        Normal hook run on entry to Man mode.
 `Man-section-regexp'           Regexp describing manpage section letters.
@@ -848,13 +1016,18 @@ The following key bindings are currently in effect in the buffer:
   (setq major-mode 'Man-mode
        mode-name "Man"
        buffer-auto-save-file-name nil
   (setq major-mode 'Man-mode
        mode-name "Man"
        buffer-auto-save-file-name nil
-       mode-line-format Man-mode-line-format
+       mode-line-buffer-identification
+       (list (default-value 'mode-line-buffer-identification)
+             " {" 'Man-page-mode-string "}")
        truncate-lines t
        buffer-read-only t)
   (buffer-disable-undo (current-buffer))
   (auto-fill-mode -1)
   (use-local-map Man-mode-map)
   (set-syntax-table man-mode-syntax-table)
        truncate-lines t
        buffer-read-only t)
   (buffer-disable-undo (current-buffer))
   (auto-fill-mode -1)
   (use-local-map Man-mode-map)
   (set-syntax-table man-mode-syntax-table)
+  (setq imenu-generic-expression (list (list nil Man-heading-regexp 0)))
+  (set (make-local-variable 'outline-regexp) Man-heading-regexp)
+  (set (make-local-variable 'outline-level) (lambda () 1))
   (Man-build-page-list)
   (Man-strip-page-headers)
   (Man-unindent)
   (Man-build-page-list)
   (Man-strip-page-headers)
   (Man-unindent)
@@ -867,7 +1040,7 @@ The following key bindings are currently in effect in the buffer:
   (goto-char (point-min))
   (let ((case-fold-search nil))
     (while (re-search-forward Man-heading-regexp (point-max) t)
   (goto-char (point-min))
   (let ((case-fold-search nil))
     (while (re-search-forward Man-heading-regexp (point-max) t)
-      (aput 'Man-sections-alist (Man-match-substring 1))
+      (aput 'Man-sections-alist (match-string 1))
       (forward-line 1))))
 
 (defsubst Man-build-references-alist ()
       (forward-line 1))))
 
 (defsubst Man-build-references-alist ()
@@ -887,16 +1060,21 @@ The following key bindings are currently in effect in the buffer:
            (back-to-indentation)
            (while (and (not (eobp)) (/= (point) runningpoint))
              (setq runningpoint (point))
            (back-to-indentation)
            (while (and (not (eobp)) (/= (point) runningpoint))
              (setq runningpoint (point))
-             (if (re-search-forward Man-reference-regexp end t)
-                 (let* ((word (Man-match-substring 0))
+             (if (re-search-forward Man-hyphenated-reference-regexp end t)
+                 (let* ((word (match-string 0))
                         (len (1- (length word))))
                    (if hyphenated
                        (setq word (concat hyphenated word)
                         (len (1- (length word))))
                    (if hyphenated
                        (setq word (concat hyphenated word)
-                             hyphenated nil))
-                   (if (= (aref word len) ?-)
-                       (setq hyphenated (substring word 0 len))
-                     (aput 'Man-refpages-alist word))))
-             (skip-chars-forward " \t\n,")))))))
+                             hyphenated nil
+                             ;; Update len, in case a reference spans
+                             ;; more than two lines (paranoia).
+                             len (1- (length word))))
+                   (if (memq (aref word len) '(?- ?­))
+                       (setq hyphenated (substring word 0 len)))
+                   (if (string-match Man-reference-regexp word)
+                       (aput 'Man-refpages-alist word))))
+             (skip-chars-forward " \t\n,"))))))
+  (setq Man-refpages-alist (nreverse Man-refpages-alist)))
 
 (defun Man-build-page-list ()
   "Build the list of separate manpages in the buffer."
 
 (defun Man-build-page-list ()
   "Build the list of separate manpages in the buffer."
@@ -909,7 +1087,7 @@ The following key bindings are currently in effect in the buffer:
     (while (not (eobp))
       (setq header
            (if (looking-at Man-page-header-regexp)
     (while (not (eobp))
       (setq header
            (if (looking-at Man-page-header-regexp)
-               (Man-match-substring 1)
+               (match-string 1)
              nil))
       ;; Go past both the current and the next Man-first-heading-regexp
       (if (re-search-forward Man-first-heading-regexp nil 'move 2)
              nil))
       ;; Go past both the current and the next Man-first-heading-regexp
       (if (re-search-forward Man-first-heading-regexp nil 'move 2)
@@ -1045,13 +1223,33 @@ Returns t if section is found, nil otherwise."
   (Man-find-section (aheadsym Man-sections-alist)))
 
 (defun Man-goto-see-also-section ()
   (Man-find-section (aheadsym Man-sections-alist)))
 
 (defun Man-goto-see-also-section ()
-  "Move point the the \"SEE ALSO\" section.
+  "Move point to the \"SEE ALSO\" section.
 Actually the section moved to is described by `Man-see-also-regexp'."
   (interactive)
   (if (not (Man-find-section Man-see-also-regexp))
       (error (concat "No " Man-see-also-regexp
                     " section found in the current manpage"))))
 
 Actually the section moved to is described by `Man-see-also-regexp'."
   (interactive)
   (if (not (Man-find-section Man-see-also-regexp))
       (error (concat "No " Man-see-also-regexp
                     " section found in the current manpage"))))
 
+(defun Man-possibly-hyphenated-word ()
+  "Return a possibly hyphenated word at point.
+If the word starts at the first non-whitespace column, and the
+previous line ends with a hyphen, return the last word on the previous
+line instead.  Thus, if a reference to \"tcgetpgrp(3V)\" is hyphenated
+as \"tcgetp-grp(3V)\", and point is at \"grp(3V)\", we return
+\"tcgetp-\" instead of \"grp\"."
+  (save-excursion
+    (skip-syntax-backward "w()")
+    (skip-chars-forward " \t")
+    (let ((beg (point))
+         (word (current-word)))
+      (when (eq beg (save-excursion
+                     (back-to-indentation)
+                     (point)))
+       (end-of-line 0)
+       (if (eq (char-before) ?-)
+           (setq word (current-word))))
+      word)))
+
 (defun Man-follow-manual-reference (reference)
   "Get one of the manpages referred to in the \"SEE ALSO\" section.
 Specify which REFERENCE to use; default is based on word at point."
 (defun Man-follow-manual-reference (reference)
   "Get one of the manpages referred to in the \"SEE ALSO\" section.
 Specify which REFERENCE to use; default is based on word at point."
@@ -1059,21 +1257,18 @@ Specify which REFERENCE to use; default is based on word at point."
    (if (not Man-refpages-alist)
        (error "There are no references in the current man page")
      (list (let* ((default (or
    (if (not Man-refpages-alist)
        (error "There are no references in the current man page")
      (list (let* ((default (or
-                            (car (all-completions
-                                  (save-excursion
-                                    (skip-syntax-backward "w()")
-                                    (skip-chars-forward " \t")
-                                    (let ((word (current-word)))
-                                      ;; strip a trailing '-':
-                                      (if (string-match "-$" word)
-                                          (substring word 0
-                                                     (match-beginning 0))
-                                        word)))
-                                  Man-refpages-alist))
-                            (aheadsym Man-refpages-alist)))
+                           (car (all-completions
+                                 (let ((word (Man-possibly-hyphenated-word)))
+                                   ;; strip a trailing '-':
+                                   (if (string-match "-$" word)
+                                       (substring word 0
+                                                  (match-beginning 0))
+                                     word))
+                                 Man-refpages-alist))
+                           (aheadsym Man-refpages-alist)))
                   chosen
                   (prompt (concat "Refer to: (default " default ") ")))
                   chosen
                   (prompt (concat "Refer to: (default " default ") ")))
-             (setq chosen (completing-read prompt Man-refpages-alist nil t))
+             (setq chosen (completing-read prompt Man-refpages-alist))
              (if (or (not chosen)
                      (string= chosen ""))
                  default
              (if (or (not chosen)
                      (string= chosen ""))
                  default
@@ -1146,6 +1341,20 @@ Specify which REFERENCE to use; default is based on word at point."
     (if Man-circular-pages-flag
        (Man-goto-page (length Man-page-list))
       (error "You're looking at the first manpage in the buffer"))))
     (if Man-circular-pages-flag
        (Man-goto-page (length Man-page-list))
       (error "You're looking at the first manpage in the buffer"))))
+
+;; Header file support
+(defun Man-view-header-file (file)
+  "View a header file specified by FILE from `Man-header-file-path'."
+  (let ((path Man-header-file-path)
+        complete-path)
+    (while path
+      (setq complete-path (concat (car path) "/" file)
+            path (cdr path))
+      (if (file-readable-p complete-path)
+          (progn (view-file complete-path)
+                 (setq path nil))
+        (setq complete-path nil)))
+    complete-path))
 \f
 ;; Init the man package variables, if not already done.
 (Man-init-defvars)
 \f
 ;; Init the man package variables, if not already done.
 (Man-init-defvars)
@@ -1155,4 +1364,5 @@ Specify which REFERENCE to use; default is based on word at point."
 
 (provide 'man)
 
 
 (provide 'man)
 
+;;; arch-tag: 587cda76-8e23-4594-b1f3-89b6b09a0d47
 ;;; man.el ends here
 ;;; man.el ends here