Date: Tuesday, October 12, 2010 @ 17:52:44 Author: rtoy Path: /project/cmucl/cvsroot/src
Modified: code/fd-stream-extfmt.lisp code/fd-stream.lisp code/struct.lisp code/sysmacs.lisp compiler/dump.lisp
Make read-char and read-byte signal errors when given the wrong kind of streams. This is a change from current 20a and 20b behavior which didn't signal errors, but matches the behavior for releases 19f and earlier.
But allow them to work on binary-text-streams. This is the same behavior as before for binary-text-stream streams.
However, read-sequence no longer allows reading from streams into arbitrary objects, unless the stream is a binary-text-stream stream.
code/fd-stream-extfmt.lisp: o In %SET-FD-STREAM-EXTERNAL-FORMAT, only update fd-stream-in/fd-stream-out if we have a character or binary-text-stream stream. o Don't update the fd-stream-string-buffer or lisp-stream-in-buffer if we have a binary-text-stream because that will mess up how fast-read-char and fast-read-byte dispatch to do the right thing for binary-text-stream streams.
code/fd-stream.lisp: o Set the fd-stream-in and fd-stream-bin slots appropriately depending on whether we have a character, binary, or binary-text-stream stream. o Only create the lisp-stream-in-buffer if we do NOT have a binary-text-stream. (Binary streams didn't use the lisp-stream-buffer previously, so no change there. Character streams use the lisp-stream-buffer and/or lisp-string-buffer.) o Set the fd-stream-flags appropriately for the kind of stream this is. Checking a fixnum is faster than checking the type of a stream.
code/struct.lisp: o Add FLAGS slot to LISP-STREAM so we can tell what kind of stream (character, binary, binary-text-stream) we have.
code/sysmacs.lisp: o Change FAST-READ-CHAR so that if we have a have a binary or binary-text-stream stream, we dispatch to the fast-read-char methods to do the right thing, including signaling an error for the wrong kind of stream. o Change FAST-READ-BYTE so that if we do not have a binary stream, we dispatch to the fast-read-char method to do the right thing.
compiler/dump.lisp: o With the above changes, we can no longer write characters to a binary stream, like a FASL file. Make the fasl file a binary-text-stream so that we can. (Alternatively, we could create the FASL header as a string, convert to octets and dump the octest to the file. This is easier, and should still be fast for writing fasls.)
----------------------------+ code/fd-stream-extfmt.lisp | 178 ++++++++++++++++++++++--------------------- code/fd-stream.lisp | 61 ++++++++++---- code/struct.lisp | 16 +++ code/sysmacs.lisp | 24 +++-- compiler/dump.lisp | 5 - 5 files changed, 170 insertions(+), 114 deletions(-)
Index: src/code/fd-stream-extfmt.lisp diff -u src/code/fd-stream-extfmt.lisp:1.13 src/code/fd-stream-extfmt.lisp:1.14 --- src/code/fd-stream-extfmt.lisp:1.13 Thu Sep 23 20:36:03 2010 +++ src/code/fd-stream-extfmt.lisp Tue Oct 12 17:52:44 2010 @@ -5,7 +5,7 @@ ;;; domain. ;;; (ext:file-comment - "$Header: /project/cmucl/cvsroot/src/code/fd-stream-extfmt.lisp,v 1.13 2010-09-24 00:36:03 rtoy Rel $") + "$Header: /project/cmucl/cvsroot/src/code/fd-stream-extfmt.lisp,v 1.14 2010-10-12 21:52:44 rtoy Exp $") ;;; ;;; ********************************************************************** ;;; @@ -70,101 +70,113 @@ (stream::ef-name (stream::find-external-format extfmt)) (fd-stream-oc-state stream) nil (fd-stream-co-state stream) nil) - (when (fd-stream-ibuf-sap stream) ; input stream + ;; Set fd-stream-in only if we have an input stream for a + ;; character stream or binary-text-stream. + (when (and (fd-stream-ibuf-sap stream) + (plusp (logand #b101 (lisp-stream-flags stream)))) (setf (fd-stream-in stream) (ef-cin extfmt))) - (when (fd-stream-obuf-sap stream) ; output stream + ;; Set fd-stream-in only if we have an input stream for a + ;; character stream or binary-text-stream. + (when (and (fd-stream-obuf-sap stream) + (plusp (logand #b101 (lisp-stream-flags stream)))) (setf (fd-stream-out stream) (ef-cout extfmt) ;;@@ (fd-stream-sout stream) (ef-sout extfmt) )) + ;; The following handles the case of setting the external format ;; for input streams where we need to handle the various buffering - ;; strategies. - ;; - (cond - ((eq old-format (fd-stream-external-format stream)) - ;; Nothing to do if the new and old formats are the same. - ) - ((and lisp::*enable-stream-buffer-p* updatep - (lisp-stream-string-buffer stream)) - ;; We want to reconvert any octets that haven't been converted - ;; yet. So, we need to figure out which octet to start with. - ;; This is done by converting (the previously converted) octets - ;; until we've converted the right number of characters. Or, - ;; since we have the octet-count, just sum up them up to figure - ;; out how many octets we've already consumed. - (let* ((ibuf (lisp-stream-in-buffer stream)) - (sindex (lisp-stream-string-index stream)) - (octet-count (fd-stream-octet-count stream)) - (oc (make-array in-buffer-length :element-type '(unsigned-byte 8))) - (index (loop for k of-type fixnum from 0 below (1- sindex) - summing (aref octet-count k)))) - ;; We now know the last octet that was used. Now convert the - ;; rest of the octets using the new format. The new - ;; characters are placed in the string buffer at the point - ;; just after the last character that we've already read. - (multiple-value-bind (s pos count new-state) - (stream::octets-to-string-counted ibuf - oc - :start index - :end (fd-stream-in-length stream) - :external-format (fd-stream-external-format stream) - :string (lisp-stream-string-buffer stream) - :s-start sindex - :error (fd-stream-octets-to-char-error stream)) - (replace octet-count oc :start1 index :end2 pos) - (cond ((eq (fd-stream-external-format stream) :iso8859-1) - ;; ISO8859-1 doesn't use the string-buffer, so we - ;; need to copy the string to the in-buffer and then - ;; set the string-buffer to nil to indicate we're not - ;; using the string buffer anymore. - (let ((index (- in-buffer-length count))) - (dotimes (k count) - (setf (aref ibuf (+ k index)) - (char-code (aref s (+ k sindex))))) - (setf (lisp-stream-in-index stream) index) - (setf (lisp-stream-string-buffer stream) nil) - (setf (lisp-stream-string-buffer-len stream) 0) - (setf (lisp-stream-string-index stream) 0))) - (t - (setf (lisp-stream-string-index stream) sindex) - (setf (lisp-stream-string-buffer-len stream) pos) - (setf (lisp-stream-in-index stream) (+ index count)) - (setf (fd-stream-oc-state stream) new-state)))))) - ((and updatep (lisp-stream-in-buffer stream)) - ;; This means the external format was ISO8859-1 and we're - ;; switching to something else. If so, we need to convert all - ;; the octets that haven't been processed yet and place them in - ;; the string buffer. We also need to adjust the in-buffer to - ;; put those octets in the expected place at the beginning of - ;; in-buffer. - (let ((index (lisp-stream-in-index stream)) - (ibuf (lisp-stream-in-buffer stream))) - (setf (lisp-stream-string-buffer stream) - (make-string (1+ in-buffer-length))) - (setf (lisp-stream-string-index stream) 1) - ;; Set the unread char to be the last read octet. - (setf (aref (lisp-stream-string-buffer stream) 0) - (code-char (aref ibuf (1- index)))) - - (let ((oc (or (fd-stream-octet-count stream) - (setf (fd-stream-octet-count stream) - (make-array in-buffer-length :element-type '(unsigned-byte 8)))))) + ;; strategies. But don't change anything if we have a + ;; binary-text-stream. In that case, we don't want to set the + ;; lisp-stream-in-buffer or lisp-stream-string-buffer which would + ;; cause the FAST-READ-CHAR/FAST-READ-BYTE functions to bypass the + ;; methods. + + (unless (typep stream 'binary-text-stream) + (cond + ((eq old-format (fd-stream-external-format stream)) + ;; Nothing to do if the new and old formats are the same. + ) + ((and lisp::*enable-stream-buffer-p* updatep + (lisp-stream-string-buffer stream)) + ;; We want to reconvert any octets that haven't been converted + ;; yet. So, we need to figure out which octet to start with. + ;; This is done by converting (the previously converted) octets + ;; until we've converted the right number of characters. Or, + ;; since we have the octet-count, just sum up them up to figure + ;; out how many octets we've already consumed. + (let* ((ibuf (lisp-stream-in-buffer stream)) + (sindex (lisp-stream-string-index stream)) + (octet-count (fd-stream-octet-count stream)) + (oc (make-array in-buffer-length :element-type '(unsigned-byte 8))) + (index (loop for k of-type fixnum from 0 below (1- sindex) + summing (aref octet-count k)))) + ;; We now know the last octet that was used. Now convert the + ;; rest of the octets using the new format. The new + ;; characters are placed in the string buffer at the point + ;; just after the last character that we've already read. (multiple-value-bind (s pos count new-state) (stream::octets-to-string-counted ibuf oc :start index + :end (fd-stream-in-length stream) :external-format (fd-stream-external-format stream) :string (lisp-stream-string-buffer stream) - :s-start 1 + :s-start sindex :error (fd-stream-octets-to-char-error stream)) - (declare (ignore s)) - (setf (lisp-stream-string-buffer-len stream) pos) - (setf (fd-stream-oc-state stream) new-state) - ;; Move the octets from the end of the in-buffer to the - ;; beginning. Set the index to the number of octets we've - ;; processed. - (replace ibuf ibuf :start2 index) - (setf (lisp-stream-in-index stream) count)))))) + (replace octet-count oc :start1 index :end2 pos) + (cond ((eq (fd-stream-external-format stream) :iso8859-1) + ;; ISO8859-1 doesn't use the string-buffer, so we + ;; need to copy the string to the in-buffer and then + ;; set the string-buffer to nil to indicate we're not + ;; using the string buffer anymore. + (let ((index (- in-buffer-length count))) + (dotimes (k count) + (setf (aref ibuf (+ k index)) + (char-code (aref s (+ k sindex))))) + (setf (lisp-stream-in-index stream) index) + (setf (lisp-stream-string-buffer stream) nil) + (setf (lisp-stream-string-buffer-len stream) 0) + (setf (lisp-stream-string-index stream) 0))) + (t + (setf (lisp-stream-string-index stream) sindex) + (setf (lisp-stream-string-buffer-len stream) pos) + (setf (lisp-stream-in-index stream) (+ index count)) + (setf (fd-stream-oc-state stream) new-state)))))) + ((and updatep (lisp-stream-in-buffer stream)) + ;; This means the external format was ISO8859-1 and we're + ;; switching to something else. If so, we need to convert all + ;; the octets that haven't been processed yet and place them in + ;; the string buffer. We also need to adjust the in-buffer to + ;; put those octets in the expected place at the beginning of + ;; in-buffer. + (let ((index (lisp-stream-in-index stream)) + (ibuf (lisp-stream-in-buffer stream))) + (setf (lisp-stream-string-buffer stream) + (make-string (1+ in-buffer-length))) + (setf (lisp-stream-string-index stream) 1) + ;; Set the unread char to be the last read octet. + (setf (aref (lisp-stream-string-buffer stream) 0) + (code-char (aref ibuf (1- index)))) + + (let ((oc (or (fd-stream-octet-count stream) + (setf (fd-stream-octet-count stream) + (make-array in-buffer-length :element-type '(unsigned-byte 8)))))) + (multiple-value-bind (s pos count new-state) + (stream::octets-to-string-counted ibuf + oc + :start index + :external-format (fd-stream-external-format stream) + :string (lisp-stream-string-buffer stream) + :s-start 1 + :error (fd-stream-octets-to-char-error stream)) + (declare (ignore s)) + (setf (lisp-stream-string-buffer-len stream) pos) + (setf (fd-stream-oc-state stream) new-state) + ;; Move the octets from the end of the in-buffer to the + ;; beginning. Set the index to the number of octets we've + ;; processed. + (replace ibuf ibuf :start2 index) + (setf (lisp-stream-in-index stream) count))))))) extfmt))
Index: src/code/fd-stream.lisp diff -u src/code/fd-stream.lisp:1.120 src/code/fd-stream.lisp:1.121 --- src/code/fd-stream.lisp:1.120 Wed Sep 15 07:32:49 2010 +++ src/code/fd-stream.lisp Tue Oct 12 17:52:44 2010 @@ -5,7 +5,7 @@ ;;; Carnegie Mellon University, and has been placed in the public domain. ;;; (ext:file-comment - "$Header: /project/cmucl/cvsroot/src/code/fd-stream.lisp,v 1.120 2010-09-15 11:32:49 rtoy Rel $") + "$Header: /project/cmucl/cvsroot/src/code/fd-stream.lisp,v 1.121 2010-10-12 21:52:44 rtoy Exp $") ;;; ;;; ********************************************************************** ;;; @@ -1402,9 +1402,16 @@ (setf (fd-stream-ibuf-sap stream) (next-available-buffer)) (setf (fd-stream-ibuf-length stream) bytes-per-buffer) (setf (fd-stream-ibuf-tail stream) 0) + + ;; Set the in and bin methods. Normally put an illegal input + ;; function in, but if we have a binary text stream, pick an + ;; appropriate input routine. (if (subtypep type 'character) (setf (fd-stream-in stream) routine - (fd-stream-bin stream) #'ill-bin) + (fd-stream-bin stream) (if (and binary-stream-p + (eql size 1)) + (pick-input-routine '(unsigned-byte 8)) + #'ill-bin)) (setf (fd-stream-in stream) (if (and binary-stream-p (eql size 1)) (pick-input-routine 'character) @@ -1423,17 +1430,17 @@ (or (eq 'unsigned-byte (and (consp type) (car type))) (eq type :default)) (eq type 'character))) - ;; We only create this buffer for streams of type - ;; (unsigned-byte 8) or character streams with an external - ;; format of :iso8859-1. Because there's no buffer, the - ;; other element-types will dispatch to the appropriate - ;; input (output) routine in fast-read-byte/fast-read-char. (when *enable-stream-buffer-p* - (setf (lisp-stream-in-buffer stream) - (make-array in-buffer-length - :element-type '(unsigned-byte 8))) + (when (and (not binary-stream-p) + (eq type 'character)) + ;; Create the in-buffer for any character (only) + ;; stream. Don't want one for binary-text-streams! + (setf (lisp-stream-in-buffer stream) + (make-array in-buffer-length + :element-type '(unsigned-byte 8)))) #+unicode - (when (and (eq type 'character) + (when (and (not binary-stream-p) + (eq type 'character) (not (eq :iso8859-1 (fd-stream-external-format stream)))) ;; For character streams, we create the string-buffer so ;; we can convert all available octets at once instead @@ -1444,6 +1451,7 @@ ;; For ISO8859-1, we don't want this because it's very ;; easy and quick to convert octets to iso8859-1. (See ;; FAST-READ-CHAR.) + (setf (lisp-stream-string-buffer stream) (make-string (1+ in-buffer-length))) (setf (fd-stream-octet-count stream) @@ -1464,15 +1472,23 @@ (setf (fd-stream-obuf-sap stream) (next-available-buffer)) (setf (fd-stream-obuf-length stream) bytes-per-buffer) (setf (fd-stream-obuf-tail stream) 0) + ;; Normally signal errors for reading from a stream with the + ;; wrong element type, but allow binary-text-streams to read + ;; from either. (if (subtypep type 'character) - (setf (fd-stream-out stream) routine - (fd-stream-bout stream) #'ill-bout) - (setf (fd-stream-out stream) - (or (if (eql size 1) + (setf (fd-stream-out stream) routine + (fd-stream-bout stream) + (if (and binary-stream-p + (eql size 1)) + (pick-output-routine '(unsigned-byte 8) + (fd-stream-buffering stream)) + #'ill-bout)) + (setf (fd-stream-out stream) + (if (and binary-stream-p (eql size 1)) (pick-output-routine 'base-char - (fd-stream-buffering stream))) - #'ill-out) - (fd-stream-bout stream) routine)) + (fd-stream-buffering stream)) + #'ill-out) + (fd-stream-bout stream) routine)) (setf (fd-stream-sout stream) (if (eql size 1) #'fd-sout #'ill-out)) (setf (fd-stream-char-pos stream) 0) @@ -1880,6 +1896,15 @@ :timeout timeout :char-to-octets-error e :octets-to-char-error d))))) + ;; Set the lisp-stream flags appropriately for the kind of stream + ;; we have (character, binary, binary-text-stream). + (cond ((typep stream 'binary-text-stream) + (setf (fd-stream-flags stream) #b100)) + ((subtypep element-type 'character) + (setf (fd-stream-flags stream) #b001)) + (t + (setf (fd-stream-flags stream) #b010))) + ;; FIXME: setting the external format here should be better ;; integrated into set-routines. We do it before so that ;; set-routines can create an in-buffer if appropriate. But we Index: src/code/struct.lisp diff -u src/code/struct.lisp:1.25 src/code/struct.lisp:1.26 --- src/code/struct.lisp:1.25 Sun Aug 15 08:04:44 2010 +++ src/code/struct.lisp Tue Oct 12 17:52:44 2010 @@ -5,7 +5,7 @@ ;;; Carnegie Mellon University, and has been placed in the public domain. ;;; (ext:file-comment - "$Header: /project/cmucl/cvsroot/src/code/struct.lisp,v 1.25 2010-08-15 12:04:44 rtoy Rel $") + "$Header: /project/cmucl/cvsroot/src/code/struct.lisp,v 1.26 2010-10-12 21:52:44 rtoy Exp $") ;;; ;;; ********************************************************************** ;;; @@ -61,7 +61,19 @@ ;; in string-buffer. This is basically unused, except by ;; FILE-POSITION so that we can get the correct file position. #+unicode - (octet-count nil :type (or null (simple-array (unsigned-byte 8) (*))))) + (octet-count nil :type (or null (simple-array (unsigned-byte 8) (*)))) + ;; + ;; Flags indicating if the stream is a character stream, binary + ;; stream or binary-text-stream. This is somewhat redundant because + ;; binary-text-stream is its own type (defstruct). But we can't + ;; easily distinguish a character stream from a binary stream. + ;; + ;; #b001 - character (only) stream + ;; #b010 - binary (only) stream + ;; #b100 - binary-text-stream (supports character and binary) + ;; + ;; It is an error if both character and binary bits are set. + (flags 0 :type fixnum))
(declaim (inline streamp)) (defun streamp (stream) Index: src/code/sysmacs.lisp diff -u src/code/sysmacs.lisp:1.34 src/code/sysmacs.lisp:1.35 --- src/code/sysmacs.lisp:1.34 Sun Jul 4 23:40:02 2010 +++ src/code/sysmacs.lisp Tue Oct 12 17:52:44 2010 @@ -5,7 +5,7 @@ ;;; Carnegie Mellon University, and has been placed in the public domain. ;;; (ext:file-comment - "$Header: /project/cmucl/cvsroot/src/code/sysmacs.lisp,v 1.34 2010-07-05 03:40:02 rtoy Rel $") + "$Header: /project/cmucl/cvsroot/src/code/sysmacs.lisp,v 1.35 2010-10-12 21:52:44 rtoy Exp $") ;;; ;;; ********************************************************************** ;;; @@ -184,6 +184,9 @@ ;;; (defmacro fast-read-char (&optional (eof-errorp t) (eof-value ())) `(cond + ((/= (lisp-stream-flags %frc-stream%) 1) + ;; Call the method if we're doing a read-char on a character stream. + (funcall %frc-method% %frc-stream% ,eof-errorp ,eof-value)) #+unicode (%frc-string-buffer% (cond ((>= %frc-string-index% %frc-string-length%) @@ -231,14 +234,17 @@ `(truly-the ,(if (and (eq eof-errorp 't) (not any-type)) '(unsigned-byte 8) 't) (cond - ((not %frc-buffer%) - (funcall %frc-method% %frc-stream% ,eof-errorp ,eof-value)) - ((= %frc-index% in-buffer-length) - (prog1 (fast-read-byte-refill %frc-stream% ,eof-errorp ,eof-value) - (setq %frc-index% (lisp-stream-in-index %frc-stream%)))) - (t - (prog1 (aref %frc-buffer% %frc-index%) - (incf %frc-index%)))))) + ((or (not %frc-buffer%) (/= (lisp-stream-flags %frc-stream%) #b10)) + ;; Call the method if we're doing a read-byte on a stream that + ;; is has no in-buffer (a binary-text-stream) or is not a + ;; binary stream (flags /= #b10). + (funcall %frc-method% %frc-stream% ,eof-errorp ,eof-value)) + ((= %frc-index% in-buffer-length) + (prog1 (fast-read-byte-refill %frc-stream% ,eof-errorp ,eof-value) + (setq %frc-index% (lisp-stream-in-index %frc-stream%)))) + (t + (prog1 (aref %frc-buffer% %frc-index%) + (incf %frc-index%)))))) ;;; (defmacro done-with-fast-read-byte () `(progn Index: src/compiler/dump.lisp diff -u src/compiler/dump.lisp:1.87 src/compiler/dump.lisp:1.88 --- src/compiler/dump.lisp:1.87 Tue Jun 1 16:27:09 2010 +++ src/compiler/dump.lisp Tue Oct 12 17:52:44 2010 @@ -5,7 +5,7 @@ ;;; Carnegie Mellon University, and has been placed in the public domain. ;;; (ext:file-comment - "$Header: /project/cmucl/cvsroot/src/compiler/dump.lisp,v 1.87 2010-06-01 20:27:09 rtoy Rel $") + "$Header: /project/cmucl/cvsroot/src/compiler/dump.lisp,v 1.88 2010-10-12 21:52:44 rtoy Exp $") ;;; ;;; ********************************************************************** ;;; @@ -383,7 +383,8 @@ (declare (type pathname name)) (let* ((stream (open name :direction :output :if-exists :rename-and-delete - :element-type '(unsigned-byte 8))) + :element-type '(unsigned-byte 8) + :class 'binary-text-stream)) (res (make-fasl-file :stream stream))) (multiple-value-bind (version f-vers f-imp)