slurp: handle short reads gracefully
[cl-slurp.git] / slurp.lisp
blobab3415fa356be50d88dc2e0492a428be06e3031a
1 (defpackage "SLURP"
2 (:use "CL")
3 (:export "SLURP"
4 "STREAM-LENGTH"))
6 (in-package "SLURP")
8 (defun stream-length (stream)
9 "Returns the length of STREAM, or NIL if the length can't be determined."
10 (check-type stream stream)
11 (handler-case (file-length stream)
12 (type-error () nil)))
14 (defgeneric slurp (arg &key element-type))
16 (defmethod slurp ((string string) &key (element-type 'character))
17 (slurp (parse-namestring string) :element-type element-type))
19 (defmethod slurp ((pathname pathname) &key (element-type 'character))
20 (with-open-file (stream pathname :direction :input :element-type element-type)
21 (slurp stream)))
23 (defmethod slurp ((stream stream) &key element-type)
24 (declare (ignore element-type))
25 (let ((stream-element-type (stream-element-type stream)))
26 (cond ((subtypep stream-element-type 'character)
27 (coerce (loop for c = (read-char stream nil nil)
28 while c
29 collect c) 'string))
31 ((subtypep stream-element-type 'unsigned-byte)
32 (let ((stream-length (stream-length stream)))
33 (if stream-length
34 (let* ((seq (make-array stream-length :element-type stream-element-type))
35 (seq-length (read-sequence seq stream)))
36 (if (= seq-length stream-length)
37 seq
38 (subseq seq 0 seq-length)))
39 (let ((byte-list (loop for b = (read-byte stream nil nil)
40 while b
41 collect b)))
42 (make-array (length byte-list) :element-type stream-element-type :initial-contents byte-list)))))
44 (t (error "Unexpected stream element type ~S." stream-element-type)))))