From: Kumar Balachandran
Subject: Streams and IO (long)
Date: 
Message-ID: <02pvgwyc9p.fsf@rtp.ericsson.se>
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
From: Kumar Balachandran
Subject: Re: Streams and IO (long)
Date: 
Message-ID: <02ogwgybhb.fsf@rtp.ericsson.se>
I forgot to mention that I'm using CMUCL, but I'd like portable code.

-- Kumar