I want to read messages from a file stream that have varying
characteristics. As an example, say a file has two kinds of vectors
stored in it (integer and real) and a file can be ascii or binary. I
am trying to write a read function that returns a lisp vector
regardless of the file format.
The formats (please bear with me) are
1. Integer Ascii
2A
length
element
element
... (up to length)
2A
length
...
(up to EOF)
2. Real Ascii
1A
length
elements
3. Binary Integer
[2][B][length][element][...]
with storage
[1byte][1byte][4bytes][4bytes]...
4. Binary Real follows with single-float elements.
I have a function that can read an ascii file as follows:
(defun read-ascii-integer-vector (&optional
(input-stream nil)
(eof-error-p t)
(eof-value nil)
(recursive-p nil))
"
Given:
[1] input-stream default nil
[2] eof-error-p default t
[3] eof-value default nil
[4] recursive-p nil
Output:
[1] single array of fixnums
Read a single integer vector object from a stream. The format read is in ASCII and
reads as
2A
length
element
element
...
"
(let* ((sig-type (read-char input-stream
eof-error-p
eof-value
recursive-p))
(stream-type (read-char input-stream
eof-error-p
eof-value
recursive-p))
(num-elements (read input-stream
eof-error-p
eof-value
recursive-p))
(arr (make-array num-elements :element-type '(signed-byte 32))))
(declare (type character sig-type)
(type character stream-type)
(type (signed-byte 32) num-elements))
;; (format t "~a ~a ~%" stream-type num-elements)
(if (and (digit-char-p sig-type) (char= sig-type #\2) (char= stream-type #\A))
(loop for count below num-elements do
(let ((re (read input-stream
eof-error-p
eof-value
recursive-p)))
(declare (type (signed-byte 32) re))
(setf (aref arr count) re)))
(error "Error in read-integer-vector: Stream is not of
type integer vector or not ASCII, first character is ~c and second character is ~c~%"
sig-type stream-type ))
arr))
However, if I want to use a common function to read the binary format
and the ascii format, one method is to read the first two characters,
and redefine :element-type for the stream to be (unsigned-byte 32). I
could not find any way of doing this. Is there some way of defining a
stream that has a mutable element-type? Is there a better solution
for this problem? I am aware of the brute force solution of writing a
binary version of the reader. However, one has to read the first 2
characters to decide the stream type, and the usage is not transparent
to the user.
This is probably a simple question for a Lisp guru, but I am stunted
by the path I took to get to Lisp.
-- Kumar