source: tags/init/example/clhs.lisp

Last change on this file was 2, checked in by Erik Enge, 21 years ago

Initial revision

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.1 KB
Line 
1;;;; $Id: clhs.lisp 2 2004-01-05 14:13:03Z eenge $
2;;;; $Source$
3
4;;;; clhs.lisp - an example IRC bot for net-nittin-irc
5
6;;; clhs is an example IRC bot for net-nittin-irc. It runs on
7;;; irc.freenode.net in the channels #lisp and #clhs (preferred for
8;;; testing). It responds to queries of the form "clhs symbol" for
9;;; symbols in the spec, "clhs 3.1.2.1.2.1" for sections, and "clhs
10;;; format:A" for format control args. You will want to edit
11;;; *hyperspec-pathname* to point to where you have the HyperSpec
12;;; unpacked. You should also check out Mop_Sym.txt and put it in the
13;;; directory where you will be running the bot from.
14
15;;; To use it, load the net-nittin-irc system, load clhs.lisp, and
16;;; invoke (clhs::start-clhs-bot "desirednickname" "desiredserver"
17;;; "#channel1" "#channel2" "#channel3" ...)
18
19(defpackage :clhs (:use :common-lisp :irc))
20(in-package :clhs)
21
22;;; CLHS. This will be the default lookup.
23(defparameter *hyperspec-pathname* #p"/Users/chandler/Sites/HyperSpec/")
24
25(defparameter *hyperspec-map-file* (merge-pathnames "Data/Map_Sym.txt" *hyperspec-pathname*))
26
27(defparameter *hyperspec-root* "http://www.lispworks.com/reference/HyperSpec/")
28
29;;; AMOP.
30(defparameter *mop-map-file* #p"Mop_Sym.txt")
31
32(defparameter *mop-root* "http://www.alu.org/mop/")
33
34(defvar *table* (make-hash-table :test 'equalp))
35                                                   
36(defun add-clhs-section-to-table (&rest numbers)
37  (let ((key (format nil "~{~d~^.~}" numbers))
38        (target (concatenate 'string *hyperspec-root* (format nil "Body/~2,'0d_~(~{~36r~}~).htm" (car numbers) (mapcar #'(lambda (x) (+ x 9)) (cdr numbers))))))
39    (setf (gethash key *table*) target)))
40
41(defun valid-target (&rest numbers)
42  (probe-file (format nil "Body/~2,'0d_~(~{~36r~}~).htm" (car numbers) (mapcar #'(lambda (x) (+ x 9)) (cdr numbers)))))
43
44(defun populate-table ()
45  ;; Hyperspec
46  (with-open-file (s *hyperspec-map-file*)
47    ;; populate the table with the symbols from the Map file
48    ;; this bit is easy and portable.
49    (do ((symbol-name (read-line s nil s) (read-line s nil s))
50         (url (read-line s nil s) (read-line s nil s)))
51        ((eq url s) 'done)
52      (setf (gethash symbol-name *table*) (concatenate 'string *hyperspec-root* (subseq url 3))))
53    ;; add in section references.
54    (let ((*default-pathname-defaults* *hyperspec-pathname*))
55      ;; Yuk. I know. Fixes welcome.
56      (loop for section from 0 to 27
57            do (add-clhs-section-to-table section)
58            do (loop named s for s1 from 1 to 17
59                     unless (valid-target section s1)
60                       do (return-from s nil)
61                     do (add-clhs-section-to-table section s1)
62                       do (loop named ss for s2 from 1 to 17
63                                unless (valid-target section s1 s2)
64                                  do (return-from ss nil)
65                                do (add-clhs-section-to-table section s1 s2)
66                                do (loop named sss for s3 from 1 to 17
67                                         unless (valid-target section s1 s2 s3)
68                                           do (return-from sss nil)
69                                         do (add-clhs-section-to-table section s1 s2 s3)
70                                         do (loop named ssss for s4 from 1 to 17
71                                                  unless (valid-target section s1 s2 s3 s4)
72                                                    do (return-from ssss nil)
73                                                  do (add-clhs-section-to-table section s1 s2 s3 s4)
74                                                  do (loop named sssss for s5 from 1 to 17
75                                                           unless (valid-target section s1 s2 s3 s4 s5)
76                                                             do (return-from sssss nil)
77                                                           do (add-clhs-section-to-table section s1 s2 s3 s4 s5))))))))
78    ;; format directives
79    (loop for code from 32 to 127
80          do (setf (gethash (format nil "format:~A" (code-char code)) *table*)
81                   (concatenate 'string
82                    *hyperspec-root*
83                    (case (code-char code)
84                      ((#\c #\C) "Body/22_caa.htm")
85                      ((#\%) "Body/22_cab.htm")
86                      ((#\&) "Body/22_cac.htm")
87                      ((#\|) "Body/22_cad.htm")
88                      ((#\~) "Body/22_cae.htm")
89                      ((#\r #\R) "Body/22_cba.htm")
90                      ((#\d #\D) "Body/22_cbb.htm")
91                      ((#\b #\B) "Body/22_cbc.htm")
92                      ((#\o #\O) "Body/22_cbd.htm")
93                      ((#\x #\X) "Body/22_cbe.htm")
94                      ((#\f #\F) "Body/22_cca.htm")
95                      ((#\e #\E) "Body/22_ccb.htm")
96                      ((#\g #\G) "Body/22_ccc.htm")
97                      ((#\$) "Body/22_ccd.htm")
98                      ((#\a #\A) "Body/22_cda.htm")
99                      ((#\s #\S) "Body/22_cdb.htm")
100                      ((#\w #\W) "Body/22_cdc.htm")
101                      ((#\_) "Body/22_cea.htm")
102                      ((#\<) "Body/22_ceb.htm")
103                      ((#\i #\I) "Body/22_cec.htm")
104                      ((#\/) "Body/22_ced.htm")
105                      ((#\t #\T) "Body/22_cfa.htm")
106                      ;; FIXME
107                      ((#\<) "Body/22_cfb.htm")
108                      ((#\>) "Body/22_cfc.htm")
109                      ((#\*) "Body/22_cga.htm")
110                      ((#\[) "Body/22_cgb.htm")
111                      ((#\]) "Body/22_cgc.htm")
112                      ((#\{) "Body/22_cgd.htm")
113                      ((#\}) "Body/22_cge.htm")
114                      ((#\?) "Body/22_cgf.htm")
115                      ((#\() "Body/22_cha.htm")
116                      ((#\)) "Body/22_chb.htm")
117                      ((#\p #\P) "Body/22_chc.htm")
118                      ((#\;) "Body/22_cia.htm")
119                      ((#\^) "Body/22_cib.htm")
120                      ((#\Newline) "Body/22_cic.htm")
121                      (t "Body/22_c.htm")))))
122    ;; glossary.
123    )
124  ;; MOP
125  (with-open-file (s *mop-map-file*)
126    (do ((symbol-name (read-line s nil s) (read-line s nil s))
127         (url (read-line s nil s) (read-line s nil s)))
128        ((eq url s) 'done)
129      (setf (gethash (concatenate 'string "MOP:" symbol-name) *table*) (concatenate 'string *mop-root* url)))))
130
131(defvar *clhs-connection*)
132(defvar *clhs-nickname*)
133
134(defmacro aif (test conseq &optional (else nil))
135  `(let ((it ,test))
136     (if it ,conseq
137       (symbol-macrolet ((it ,test))
138         ,else))))
139
140(defun spec-lookup (str)
141  (aif (gethash str *table*)
142       it
143       (format nil "Nothing was found for: ~A" str)))
144
145(defparameter *clhs-attention-prefixes* '("clhs " "clhs: "))
146
147(defun valid-clhs-message-1 (message prefix)
148  (if (eql (search prefix (trailing-argument message) :test #'char-equal) 0)
149      (and (not (find #\space (trailing-argument message) :start (length prefix)))
150           (length prefix))
151      nil))
152
153(defun valid-clhs-message (message)
154  (some #'(lambda (e) (valid-clhs-message-1 message e)) *clhs-attention-prefixes*))
155
156(defun msg-hook (message)
157  (if (string-equal (first (arguments message)) *clhs-nickname*)
158      (aif (valid-clhs-message message)
159          (privmsg *clhs-connection* (source message) (spec-lookup (subseq (trailing-argument message) it)))
160        (privmsg *clhs-connection* (source message) (spec-lookup (trailing-argument message))))
161    (aif (valid-clhs-message message)
162        (privmsg *clhs-connection* (first (arguments message)) (spec-lookup (subseq (trailing-argument message) it))))))
163
164(defun start-clhs-bot (nick server &rest channels)
165  (populate-table)
166  (setf *clhs-nickname* nick)
167  (setf *clhs-connection* (connect :nickname *clhs-nickname* :server server))
168  (mapcar #'(lambda (channel) (join *clhs-connection* channel)) channels)
169  (add-hook *clhs-connection* 'irc::irc-privmsg-message 'msg-hook)
170  #+sbcl (start-background-message-handler *clhs-connection*)
171  #-sbcl (read-message-loop *clhs-connection*))
172
173(defun shuffle-hooks ()
174  (irc::remove-hooks *clhs-connection* 'irc::irc-privmsg-message)
175  (add-hook *clhs-connection* 'irc::irc-privmsg-message 'msg-hook))
Note: See TracBrowser for help on using the repository browser.