1 (eval-when (:load-toplevel
:compile-toplevel
:execute
)
2 (defpackage :db-doc
(:use
:cl
:asdf
#+sbcl
:sb-ext
#+cmu
:ext
)))
4 ;;; turn water into wine ^W^W^W lisp into HTML
9 1) The aim is to document the current package
, given a system.
10 2) The assumption is that the system is loaded
; this makes it easier to
11 do cross-references and stuff
12 3) We output HTML on
*standard-output
*
13 4) Hyperlink wherever useful
14 5) We
're allowed to intern symbols all over the place if we like
18 ;;; note: break badly on multiple packages
22 "List of external symbols to print; derived from parsing DEFPACKAGE form")
25 (defun worth-documenting-p (symbol)
27 (eql (symbol-package symbol
) *package
*)
28 (or (ignore-errors (find-class symbol
))
29 (boundp symbol
) (fboundp symbol
))))
31 (defun linkable-symbol-p (word)
32 (labels ((symbol-char (c) (or (upper-case-p c
) (digit-char-p c
)
34 (and (every #'symbol-char word
)
35 (some #'upper-case-p word
)
36 (worth-documenting-p (find-symbol word
)))))
38 (defun markup-word (w)
39 (if (symbolp w
) (setf w
(princ-to-string w
)))
40 (cond ((linkable-symbol-p w
)
41 (format nil
"<a href=\"#~A\">~A</a>"
43 ((and (> (length w
) 0)
45 (eql (elt w
(1- (length w
))) #\_
))
46 (format nil
"<b>~A</b>" (subseq w
1 (1- (length w
)))))
48 (defun markup-space (w)
49 (let ((para (search (coerce '(#\Newline
#\Newline
) 'string
) w
)))
52 (subseq w
0 (1+ para
))
53 (markup-space (subseq w
(1+ para
) nil
)))
56 (defun text-markup (text)
57 (let ((start-word 0) (end-word 0))
58 (labels ((read-word ()
61 (lambda (x) (member x
'(#\Space
#\
, #\.
#\Newline
)))
62 text
:start start-word
))
63 (subseq text start-word end-word
))
67 (lambda (x) (member x
'(#\Space
#\
, #\.
#\Newline
)))
68 text
:start end-word
))
69 (subseq text end-word start-word
)))
70 (with-output-to-string (o)
71 (loop for inword
= (read-word)
72 do
(princ (markup-word inword
) o
)
73 while
(and start-word end-word
)
74 do
(princ (markup-space (read-space)) o
)
75 while
(and start-word end-word
))))))
78 (defun do-defpackage (form stream
)
80 (destructuring-bind (defn name
&rest options
) form
81 (when (string-equal name
(package-name *package
*))
82 (format stream
"<h1>Package ~A</h1>~%" name
)
83 (when (documentation *package
* t
)
84 (princ (text-markup (documentation *package
* t
))))
85 (let ((exports (assoc :export options
)))
87 (setf *symbols
* (mapcar #'symbol-name
(cdr exports
)))))
90 (defun do-defclass (form stream
)
91 (destructuring-bind (defn name super slots
&rest options
) form
92 (when (interesting-name-p name
)
93 (let ((class (find-class name
)))
94 (format stream
"<p><a name=\"~A\"><i>Class: </i><b>~A</b></a>~%"
96 #+nil
(format stream
"<p><b>Superclasses: </b> ~{~A ~}~%"
97 (mapcar (lambda (x) (text-markup (class-name x
)))
98 (mop:class-direct-superclasses class
)))
99 (if (documentation class
'type
)
100 (format stream
"<blockquote>~A</blockquote>~%"
101 (text-markup (documentation class
'type
))))
103 (princ "<p><b>Slots:</b><ul>" stream
)
106 (name &key reader writer accessor initarg initform type
108 (if (consp slot
) slot
(list slot
))
109 (format stream
"<li>~A : ~A</li>~%" name
110 (if documentation
(text-markup documentation
) ""))))
111 (princ "</ul>" stream
))
115 (defun interesting-name-p (name)
117 (and (eql (car name
) 'setf
)
118 (interesting-name-p (cadr name
))))
119 (t (member (symbol-name name
) *symbols
* :test
#'string
=))))
121 (defun markup-lambdalist (l)
124 if
(eq '&key i
) do
(setf key-p t
)
126 if
(and (not key-p
) (consp i
))
127 collect
(list (car i
) (markup-word (cadr i
)))
130 (defun do-defunlike (form label stream
)
131 (destructuring-bind (defn name lambdalist
&optional doc
&rest code
) form
132 (when (interesting-name-p name
)
134 (setf *symbols
* (remove (symbol-name name
) *symbols
* :test
#'string
=)))
135 (format stream
"<p><a name=\"~A\"><table width=\"100%\"><tr><td width=\"80%\">(~A <i>~A</i>)</td><td align=right>~A</td></tr></table>~%"
136 name
(string-downcase (princ-to-string name
))
138 (format nil
"~{ ~A~}" (markup-lambdalist lambdalist
)))
141 (format stream
"<blockquote>~A</blockquote>~%"
145 (defun do-defun (form stream
) (do-defunlike form
"Function" stream
))
146 (defun do-defmethod (form stream
) (do-defunlike form
"Method" stream
))
147 (defun do-defgeneric (form stream
) (do-defunlike form
"Generic Function" stream
))
148 (defun do-boolean-sockopt (form stream
)
149 (destructuring-bind (type lisp-name level c-name
) form
150 (pushnew (symbol-name lisp-name
) *symbols
*)
152 (do-defunlike `(defun ,lisp-name
((socket socket
) argument
)
153 ,(format nil
"Return the value of the ~A socket option for SOCKET. This can also be updated with SETF." (symbol-name c-name
) ) 'empty
)
156 (defun do-form (form output-stream
)
157 (cond ((not (listp form
)) nil
)
158 ((string= (symbol-name (car form
)) "DEFINE-SOCKET-OPTION-BOOL")
159 (do-boolean-sockopt form output-stream
))
160 ((eq (car form
) 'defclass
)
161 (do-defclass form output-stream
))
162 ((eq (car form
) 'eval-when
)
163 (do-form (third form
) output-stream
))
164 ((eq (car form
) 'defpackage
)
165 (do-defpackage form output-stream
))
166 ((eq (car form
) 'defun
)
167 (do-defun form output-stream
))
168 ((eq (car form
) 'defmethod
)
169 (do-defmethod form output-stream
))
170 ((eq (car form
) 'defgeneric
)
171 (do-defgeneric form output-stream
))
174 (defun do-file (input-stream output-stream
)
175 "Read in a Lisp program on INPUT-STREAM and make semi-pretty HTML on OUTPUT-STREAM"
176 (let ((eof-marker (gensym)))
178 (loop for form
= (read input-stream nil eof-marker
)
179 until
(eq form eof-marker
)
180 if
(do-form form output-stream
)
182 do
(princ "<hr width=\"20%\">" output-stream
) |
# ))
183 (format output-stream
"<hr>"
186 (defvar *standard-sharpsign-reader
*
187 (get-dispatch-macro-character #\
# #\|
))
189 (defun document-system (system &key
190 (output-stream *standard-output
*)
192 "Produce HTML documentation for all files defined in SYSTEM, covering
193 symbols exported from PACKAGE"
194 (let ((*package
* (find-package package
))
195 (*readtable
* (copy-readtable))
196 (*standard-output
* output-stream
))
197 (set-dispatch-macro-character
200 (if (eql (peek-char nil s t nil t
) #\|
)
204 (loop with discard
= (read-char s t nil t
)
205 ;initially (princ "<P>")
206 for c
= (read-char s t nil t
)
207 until
(and (eql c
#\|
)
208 (eql (peek-char nil s t nil t
) #\
#))
210 finally
(read-char s t nil t
))
212 (funcall *standard-sharpsign-reader
* s c n
))))
213 (dolist (c (cclan:all-components
'sb-bsd-sockets
))
214 (when (and (typep c
'cl-source-file
)
215 (not (typep c
'sb-bsd-sockets-system
::constants-file
)))
216 (with-open-file (in (component-pathname c
) :direction
:input
)
217 (do-file in
*standard-output
*))))))
220 (with-open-file (*standard-output
* "index.html" :direction
:output
)
221 (format t
"<html><head><title>SBCL BSD-Sockets API Reference</title></head><body>~%")
222 (asdf:operate
'asdf
:load-op
'sb-bsd-sockets
)
223 (document-system 'sb-bsd-sockets
:package
:sb-bsd-sockets
)))