Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
;;;; -*- Mode: Lisp; Syntax: Common-Lisp; Package: SYSTEM -*-
;;;;
;;;; Copyright (c) 2001, Juan Jose Garcia-Ripoll.
;;;; Copyright (c) 2012, Jean-Claude Beaudoin.
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public
;;;; License as published by the Free Software Foundation; either
;;;; version 3 of the License, or (at your option) any later version.
;;;;
;;;; See file '../../Copyright' for full details.
;;;;
(in-package "SYSTEM")
;;;;----------------------------------------------------------------------
;;;; Help files
;;;;
(defun read-help-file (path)
(let* ((*package* (find-package "CL"))
(file (open path :direction :input :external-format '(:utf-8 :lf))))
(do ((end nil)
(h (make-hash-table :size 1024 :test #'eql)))
(end h)
(do ((c (read-char file nil)))
((or (not c) (eq c #\^_))
(when (not c) (setq end t)))
)
(when (not end)
(let* ((key (read file))
(value (read file)))
(si::hash-set key h value))))))
(defun dump-help-file (hash-table path &optional (merge nil))
(let ((entries nil))
(when merge
(let ((old-hash (read-help-file path)))
(push old-hash *documentation-pool*)
(maphash #'(lambda (key doc)
(when doc
(do* ((list doc)
(doc-type (first list))
(string (second list)))
(list)
(set-documentation key doc-type string))))
hash-table)
(setq hash-table (pop *documentation-pool*))))
(maphash #'(lambda (key doc)
(when (and (symbolp key) doc)
(push (cons key doc) entries)))
hash-table)
(setq entries (sort entries #'string-lessp :key #'car))
(let* ((*package* (find-package "CL"))
(file (open path :direction :output :external-format '(:utf-8 :lf))))
(dolist (l entries)
(format file "~A~S~%~S~%" #\^_ (car l) (rest l)))
(close file)
path)))
(defun search-help-file (key path &aux (pos 0))
(labels ((bin-search (file start end &aux (delta 0) (middle 0) sym)
(declare (fixnum start end delta middle))
(when (<= start end)
(setq middle (round (+ start end) 2))
(file-position file middle)
(if (plusp (setq delta (scan-for #\^_ file)))
(if (equal key (setq sym (read file)))
t
(if (string< key sym)
(bin-search file start (1- middle))
(bin-search file (+ middle delta) end)))
(bin-search file start (1- middle)))))
(scan-for (char file)
(declare (ignore char))
(do ((v #\space (read-char file nil nil))
(n 0 (1+ n)))
((or (eql v #\^_) (not v)) (if v n -1))
(declare (fixnum n)))))
(when (not (mkcl:probe-file-p path))
(return-from search-help-file nil))
(ignore-errors
(let* ((*package* (find-package "CL"))
(file (open path :direction :input :external-format '(:utf-8 :lf)))
output)
(when (and
(not (consp key)) ;; we cannot yet handle (setf foo) as function name. JCB
(let ((result (bin-search file 0 (file-length file))))
result)
)
(setq output (read file))) ;; What if this read blows up! JCB
(close file)
output))))
;;;;----------------------------------------------------------------------
;;;; Documentation system
;;;;
#+mkcl-min
(progn
(*make-special '*documentation-pool*)
(setq *documentation-pool* nil)
(*make-special '*keep-documentation*)
(setq *keep-documentation* t))
#-mkcl-min
(progn
(defvar *documentation-pool*
(list (make-hash-table :test #'eq :size 128) #P"SYS:HELP.DOC")) ;; should be #'equal for (setf foo) handling
(defvar *keep-documentation* t))
(defun get-documentation (object doc-type &aux output doc-plist)
(unless (symbolp object) (return-from get-documentation nil))
(dolist (dict *documentation-pool*)
(cond ((hash-table-p dict)
(when (and (setq doc-plist (gethash object dict))
(setq output (getf doc-plist doc-type)))
(return-from get-documentation output))
)
((and (or (pathnamep dict) (stringp dict))
#-(and) (or (symbolp object) (functionp object)))
(when (and (setq doc-plist (search-help-file object dict))
(setq output (getf doc-plist doc-type)))
(return-from get-documentation output))
)
#-(and)
(t (format t "~&get-documentation: looking for documentation in unknown source: ~S" dict)(finish-output)) ;; debug JCB
)))
(defun set-documentation (object doc-type string)
(when (not (or (stringp string) (null string)))
(error "~S is not a valid documentation string" string))
(unless (symbolp object)
(if (si::valid-function-name-p object)
;; we silently ignore (setf foobar) function names until we implement proper support. JCB
(return-from set-documentation string)
(error "In set-documentation: first argument ~S must be a symbol" object)))
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
(let ((dict (first *documentation-pool*)))
(when (hash-table-p dict)
(let ((plist (gethash object dict)))
(setq plist (if string
(put-f plist string doc-type)
(rem-f plist doc-type)))
(if plist
(si::hash-set object dict plist)
(remhash object dict)))))
string)
(defun expand-set-documentation (symbol doc-type string)
(when (and *keep-documentation* string)
(when (not (stringp string))
(error "~S is not a valid documentation string" string))
`((set-documentation ',symbol ',doc-type ,string))))
(defun new-documentation-pool (&optional (size 1024))
"Args: (&optional hash-size)
Sets up a new hash table for storing documentation strings."
(push (make-hash-table :test #'eql :size size)
*documentation-pool*))
(defun dump-documentation (file &optional (merge nil))
"Args: (filespec &optional (merge nil))
Saves the current hash table for documentation strings to the specificed file.
If MERGE is true, merges the contents of this table with the original values in
the help file."
(let ((dict (first *documentation-pool*)))
(when (hash-table-p dict)
(dump-help-file dict file merge)
(rplaca *documentation-pool* file))))
#|
;; This stuff is CLTL1 at best. JCB
#-clos
(defun documentation (object type)
"Args: (symbol doc-type)
Returns the DOC-TYPE doc-string of SYMBOL; NIL if none exists. Possible doc-
types are:
FUNCTION (special forms, macros, and functions)
VARIABLE (global variables)
TYPE (type specifiers)
STRUCTURE (structures)
SETF (SETF methods)
All built-in special forms, macros, functions, and variables have their doc-
strings."
(cond ((member type '(function type variable setf structure))
(when (not (symbolp object))
(error "~S is not a symbol." object))
(si::get-documentation object type))
(t
(error "~S is an unknown documentation type" type))))
|#
#+mkcl-min
(when (null *documentation-pool*) (new-documentation-pool 1024))