;;; os2help.el --- invoke OS/2 on-line help, using an EPM index file

;; Copyright (C) 1992-1994 Eberhard Mattes

;; Author: Eberhard Mattes <mattes@azu.informatik.uni-stuttgart.de>
;; Keywords: emx

;; This file is part of GNU Emacs.

;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

;;; Commentary:
;;;
;;; Version 1.1b
;;;
;;; Usage:
;;;
;;; 1. Put the following code into your .emacs file:
;;;
;;;        (autoload 'os2help "os2help" "OS/2 on-line help" t)
;;;        (setq os2help "c:/toolkt20/book/epmkwhlp.ndx")
;;;        (global-set-key [C-f1] 'os2help)
;;;
;;;    Insert the correct directory in the 2nd line. The example above
;;;    uses the EPM index file of the IBM Developer's Toolkit for OS/2 2.0.
;;;    If you want to get on-line help for IBM C Set/2 as well, use the
;;;    following code instead:
;;;
;;;        (setq os2help '("c:/ibmc/help/dde4.ndx"
;;;                        "c:/toolkt20/book/epmkwhlp.ndx"))
;;;
;;;    You might want to add the emx index file:
;;;
;;;        (setq os2help '("c:/emx/book/emxdoc.ndx"
;;;                        "c:/toolkt20/book/epmkwhlp.ndx"))
;;;
;;;
;;; 2. Optionally byte-compile os2help.el.
;;;
;;; 3. Load your .emacs file (for instance by restarting Emacs).
;;;
;;; 4. Place the cursor on the function name you want to get help about
;;;    and press C-f1. Either enter a topic name or press RETURN to use
;;;    the default.
;;;
;;; History
;;;
;;; 1.0a     Initial release
;;;
;;; 1.1a     Renamed (original name: toolkt-online.el)
;;;          Bug fixed: os2help-get-word failed on word at start of buffer
;;;          Support for multiple index files
;;;          Support for templates not ending with *
;;;          Preprocess index files
;;;          Search is case-sensitive. On failure, try again with case ignored
;;;
;;; 1.1b     Emacs 19
;;;          GPL
;;;
;;; 1.1c     Turn defconst into defvar
;;;

;;; Code:

(provide 'os2help)

(defvar os2help '("g:/emx/book/emxdoc.ndx" "g:/toolkt20/book/epmkwhlp.ndx")
  "Name of the EPM index file for on-line help.
To use multiple index files, assign a list of file names to os2help.")

(defvar os2help-old nil
  "Value of the os2help variable for which os2help-alist has been built.")

(defvar os2help-alist nil
  "Contents of the EPM index files preprocessed into a list.")

(defun os2help (topic)
  "Request OS/2 on-line help for TOPIC.
Before using the os2help command, set the os2help variable to the name
of the index file or to a list of names of index files."
  (interactive (let* ((default (os2help-get-word))
                      (input (read-string
                              (if default (format "Topic (default %s): "
                                                  default)
                                "Topic: "))))
                 (list (if (string= input "")
                           default
                         input))))
  (let (tmp template command args)
    (if (equal os2help os2help-old)
        nil
      (message "Reading EPM index files...")
      (setq os2help-alist nil)
      (if (listp os2help)
          (mapcar 'os2help-parse-file os2help)
        (os2help-parse-file os2help))
      (message "")
      (setq os2help-old os2help))
    (let ((case-fold-search nil))
      (setq tmp (catch 'os2help-find
                  (mapcar 'os2help-find os2help-alist)
                  nil)))
    (or tmp
        (let ((case-fold-search t))
          (setq tmp (catch 'os2help-find
                      (mapcar 'os2help-find os2help-alist)
                      nil))))
    (or tmp
        (error "Topic not found"))
    (setq template (cdr tmp))
    (setq command
          (if (string-match "~" template)
              (concat
               (substring template 0 (match-beginning 0))
               topic
               (substring template (match-end 0)))
            template))
    (while (string-match "[ \t]+" command)
      (setq args
            (append args (list (substring
                                command 0 (match-beginning 0)))))
      (setq command (substring command (match-end 0))))
    (or (string= command "")
        (setq args (append args (list command))))
    (eval (append '(call-process "cmd.exe" nil 0 nil "/c" "start")
                  args))))

(defun os2help-find (node)
  "Examine NODE for OS/2 on-line help."
  (if (string-match (car node) topic)
      (throw 'os2help-find node)))

(defun os2help-parse-file (fname)
  "Parse EPM index file FNAME and add patterns to os2help-alist."
  (let (index-buffer limit prefix template (more t))
    (if (not (file-readable-p fname))
        (error "can't access EPM index file %s" fname))
    (setq index-buffer (get-buffer-create " *os2help-parse-file*"))
    (set-buffer index-buffer)
    (erase-buffer)
    (insert-file-contents fname nil)
    (set-buffer-modified-p nil)
    (while more
      (if (looking-at "^ *(")
          (progn
            (end-of-line)
            (setq limit (point))
            (beginning-of-line)
            (while (re-search-forward
                    " *(\\([^,)]+\\),[ \t]*\\([^)]+\\))" limit t)
              (setq prefix (buffer-substring (match-beginning 1)
                                             (match-end 1)))
              (setq template (buffer-substring (match-beginning 2)
                                               (match-end 2)))
              (setq prefix (concat "^"
                                   (if (string= (substring prefix -1) "*")
                                       (regexp-quote (substring prefix 0 -1))
                                     (concat (regexp-quote prefix) "$"))))
              (if os2help-alist
                  (nconc os2help-alist (list (cons prefix template)))
                (setq os2help-alist (list (cons prefix template)))))))
      (setq more (zerop (forward-line 1))))
    (kill-buffer index-buffer)))

(defun os2help-get-word ()
  "Get text for OS/2 online help."
  (let ((pos (point)) start)
    (if (looking-at "[A-Za-z_0-9]+")
        (setq end (match-end 0))
      (setq end pos))
    (goto-char end)
    (if (re-search-backward "[^A-Za-z_0-9]" nil t)
        (setq start (match-end 0))
      (setq start (point-min)))
    (goto-char pos)
    (if (< start end)
        (buffer-substring start end)
      nil)))

;;; os2help.el ends here
