| 1 | (in-package "SPELL")
|
|---|
| 2 |
|
|---|
| 3 | (defparameter default-binary-dictionary #p"HOME:spell.bin")
|
|---|
| 4 |
|
|---|
| 5 | (defconstant +descriptor-bytes+ 10
|
|---|
| 6 | "The number of bytes a descriptor takes up on disk.")
|
|---|
| 7 |
|
|---|
| 8 | ;;; going for ease of writing on this first pass. later we'll pack things
|
|---|
| 9 | ;;; together a little bit more and document it.
|
|---|
| 10 | (defun read-descriptor (stream)
|
|---|
| 11 | (let ((hash-code (read-byte stream))
|
|---|
| 12 | (length (read-byte stream))
|
|---|
| 13 | (low-index (read-byte stream))
|
|---|
| 14 | (high-index (read-byte stream))
|
|---|
| 15 | (flags (read-byte stream)))
|
|---|
| 16 | (make-descriptor :hash-code hash-code
|
|---|
| 17 | :length length
|
|---|
| 18 | :char-index (dpb high-index +whole-index-high-byte+
|
|---|
| 19 | low-index)
|
|---|
| 20 | :flags flags)))
|
|---|
| 21 |
|
|---|
| 22 | (defun write-descriptor (descriptor stream)
|
|---|
| 23 | (write-byte (desc-hash-code descriptor) stream)
|
|---|
| 24 | (write-byte (desc-length descriptor) stream)
|
|---|
| 25 | (write-byte (ldb +whole-index-low-byte+ (desc-string-index descriptor))
|
|---|
| 26 | stream)
|
|---|
| 27 | (write-byte (ldb +whole-index-high-byte+ (desc-string-index descriptor))
|
|---|
| 28 | stream)
|
|---|
| 29 | (write-byte (desc-flags descriptor) stream)
|
|---|
| 30 | (values))
|
|---|
| 31 |
|
|---|
| 32 | (defun write-dictionary (filename dictionary entry-count string-table-length)
|
|---|
| 33 | (declare (fixnum string-table-length))
|
|---|
| 34 | (with-open-file (s filename
|
|---|
| 35 | :direction :output
|
|---|
| 36 | :element-type '(unsigned-byte 16)
|
|---|
| 37 | :if-exists :overwrite
|
|---|
| 38 | :if-does-not-exist :create)
|
|---|
| 39 | (write-byte +magic-file-id+ s)
|
|---|
| 40 | (write-byte +new-dictionary-size+ s)
|
|---|
| 41 | (write-byte entry-count s)
|
|---|
| 42 | (write-byte (ldb +whole-index-low-byte+ string-table-length) s)
|
|---|
| 43 | (write-byte (ldb +whole-index-high-byte+ string-table-length) s)
|
|---|
| 44 | (dotimes (i +new-dictionary-size+)
|
|---|
| 45 | (write-byte (aref (descriptor-table dictionary) i) s))
|
|---|
| 46 | (dotimes (i entry-count)
|
|---|
| 47 | ;; hack, because the 0th element goes unused. see if we can
|
|---|
| 48 | ;; fix this assumption in the code elsewhere
|
|---|
| 49 | (unless (zerop i)
|
|---|
| 50 | (write-descriptor (aref (descriptors dictionary) i) s)))
|
|---|
| 51 | (with-open-file (s filename
|
|---|
| 52 | :direction :output
|
|---|
| 53 | :element-type 'base-char
|
|---|
| 54 | :if-exists :append)
|
|---|
| 55 | (write-string (string-table dictionary)
|
|---|
| 56 | s :end string-table-length))))
|
|---|
| 57 |
|
|---|
| 58 | (defun read-dictionary (&optional (filename default-binary-dictionary))
|
|---|
| 59 | (with-open-file (stream filename
|
|---|
| 60 | :direction :input
|
|---|
| 61 | :if-does-not-exist :error
|
|---|
| 62 | :element-type '(unsigned-byte 16))
|
|---|
| 63 | (let* ((header (make-array 5 :element-type '(unsigned-byte 16)))
|
|---|
| 64 | (header-len (read-sequence header stream)))
|
|---|
| 65 | (unless (= header-len 5)
|
|---|
| 66 | (error "File is not a dictionary: ~S." filename))
|
|---|
| 67 | (unless (= (aref header 0) +magic-file-id+)
|
|---|
| 68 | (error "File is not a dictionary: ~S." filename))
|
|---|
| 69 | (let* ((dict-size (read-byte stream))
|
|---|
| 70 | (entry-count (read-byte stream))
|
|---|
| 71 | (string-table-length-low (read-byte stream))
|
|---|
| 72 | (string-table-length-high (read-byte stream))
|
|---|
| 73 | (string-table-length (dpb string-table-length-high
|
|---|
| 74 | +whole-index-high-byte+
|
|---|
| 75 | string-table-length-low))
|
|---|
| 76 | (word-table (make-array dict-size
|
|---|
| 77 | :element-type '(unsigned-byte 16)))
|
|---|
| 78 | (descriptors (make-array (1+ entry-count)
|
|---|
| 79 | :initial-element nil))
|
|---|
| 80 | (string-table (make-array string-table-length
|
|---|
| 81 | :element-type 'base-char)))
|
|---|
| 82 | (read-sequence word-table stream)
|
|---|
| 83 | (dotimes (i entry-count)
|
|---|
| 84 | (setf (aref descriptors (1+ i)) (read-descriptor stream)))
|
|---|
| 85 | (with-open-file (s filename
|
|---|
| 86 | :direction :input
|
|---|
| 87 | :if-does-not-exist :error
|
|---|
| 88 | :element-type 'base-char)
|
|---|
| 89 | ;; ??? is this portable?
|
|---|
| 90 | (file-position s (file-position stream))
|
|---|
| 91 | (read-sequence string-table s))
|
|---|
| 92 | (make-instance 'dictionary
|
|---|
| 93 | :string-table string-table
|
|---|
| 94 | :descriptors descriptors
|
|---|
| 95 | :descriptor-table word-table)))))
|
|---|