flexi-streams-cvs
  Threads by month 
                
            - ----- 2025 -----
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2024 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2023 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2022 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2021 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2020 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2019 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2018 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2017 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2016 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2015 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2014 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2013 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2012 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2011 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2010 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2009 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2008 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 
May 2008
- 2 participants
 - 61 discussions
 
                    
                        Author: eweitz
Date: Tue May 20 21:18:58 2008
New Revision: 41
Modified:
   branches/edi/CHANGELOG
   branches/edi/doc/index.html
   branches/edi/output.lisp
Log:
write-sequence
Modified: branches/edi/CHANGELOG
==============================================================================
--- branches/edi/CHANGELOG	(original)
+++ branches/edi/CHANGELOG	Tue May 20 21:18:58 2008
@@ -1,3 +1,5 @@
+Complete redesign, various additions, bugfixes, performance improvements (with the help of Hans H�bner)
+
 Version 0.14.0
 2007-12-30
 Some fixes for LispWorks (when the underlying stream is a character stream)
Modified: branches/edi/doc/index.html
==============================================================================
--- branches/edi/doc/index.html	(original)
+++ branches/edi/doc/index.html	Tue May 20 21:18:58 2008
@@ -1037,10 +1037,12 @@
 
 Thanks to David Lichteblau for numerous portability patches.  Thanks
 to Igor Plekhov for the KOI8-R code.  Thanks to Anton Vodonosov for
-numerous patches and additions.
+numerous patches and additions.  Thanks
+to <a href="http://netzhansa.blogspot.com/">Hans Hübner</a> for
+his work on making FLEXI-STREAMS faster.
 
 <p>
-$Header: /usr/local/cvsrep/flexi-streams/doc/index.html,v 1.105 2008/05/20 23:44:47 edi Exp $
+$Header: /usr/local/cvsrep/flexi-streams/doc/index.html,v 1.106 2008/05/21 01:06:45 edi Exp $
 <p><a href="http://weitz.de/index.html">BACK TO MY HOMEPAGE</a>
 
 </body>
Modified: branches/edi/output.lisp
==============================================================================
--- branches/edi/output.lisp	(original)
+++ branches/edi/output.lisp	Tue May 20 21:18:58 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/output.lisp,v 1.57 2008/05/21 00:04:58 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/output.lisp,v 1.59 2008/05/21 01:17:45 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -129,66 +129,71 @@
   ;; needed for AllegroCL - grrr...
   (stream-write-char stream #\Newline))
 
-(defmethod stream-write-sequence ((flexi-output-stream flexi-output-stream) sequence start end &key)
-  "Writes all elements of the sequence SEQUENCE from START to END
-to the underlying stream.  The elements can be either octets or
-characters.  Characters are output according to the current
-encoding \(external format) of the FLEXI-OUTPUT-STREAM object
-STREAM."
-  (declare #.*standard-optimize-settings*)
+(defmethod stream-write-sequence ((stream flexi-output-stream) sequence start end &key)
+;  (declare #.*standard-optimize-settings*)
   (declare (fixnum start end))
-  (with-accessors ((stream flexi-stream-stream)
-                   (column flexi-stream-column))
-      flexi-output-stream
-    (cond ((and (arrayp sequence)
-                (subtypep (array-element-type sequence) 'octet))
-           ;; set column to NIL because we don't know how to handle binary
-           ;; output mixed with character output
-           (setq column nil)
-           (write-sequence sequence stream :start start :end end))
-          (t (loop for index from start below end
-                   for element = (elt sequence index)
-                   when (characterp element) do
-                   (stream-write-char flexi-output-stream element)
-                   else do
-                   (stream-write-byte flexi-output-stream element))
-             sequence))))
-
-(defmethod stream-write-sequence ((stream flexi-output-stream) (sequence string) start end &key)
-  "Optimized method for the cases where SEQUENCE is a string.  Fills
-an internal buffer and uses repeated calls to WRITE-SEQUENCE to write
-to the underlying stream."
-  (declare #.*standard-optimize-settings*)
-  (declare (fixnum start end))
-  ;; don't use this optimized method for bivalent character streams on
-  ;; LispWorks, as it currently gets confused by the fill pointer
-  #+:lispworks
-  (unless (typep stream 'flexi-binary-output-stream)
-    (return-from stream-write-sequence
-      (call-next-method)))
-  (let ((buffer (make-array (+ +buffer-size+ 20)
-                            :element-type 'octet
-                            :fill-pointer 0))
-        (last-newline-pos (position #\Newline sequence
-                                    :test #'char=
-                                    :start start
-                                    :end end
-                                    :from-end t)))
-    (loop with format = (flexi-stream-external-format stream)
-          for index from start below end      
-          do (char-to-octets format
-                             (aref sequence index)
-                             (lambda (octet)
-                               (vector-push octet buffer)))
-          when (>= (fill-pointer buffer) +buffer-size+) do
-          (write-sequence buffer (flexi-stream-stream stream))
-          (setf (fill-pointer buffer) 0)
-          finally (when (>= (fill-pointer buffer) 0)
-                    (write-sequence buffer (flexi-stream-stream stream))))
-    (setf (flexi-stream-column stream)
-          (cond (last-newline-pos (- end last-newline-pos 1))
-                ((flexi-stream-column stream)
-                 (+ (flexi-stream-column stream) (- end start))))))
+  (with-accessors ((column flexi-stream-column)
+                   (external-format flexi-stream-external-format)
+                   (stream flexi-stream-stream))
+      stream
+    (let* ((octet-seen-p nil)
+           (buffer-pos 0)
+           ;; whether we might receive characters and thus the number
+           ;; of octets to output might not be equal to the number of
+           ;; sequence elements to write
+           (chars-p (or (listp sequence)
+                        (and (vectorp sequence)
+                             (not (subtypep (array-element-type sequence) 'integer)))))
+           (factor (if chars-p (encoding-factor external-format) 1))
+           (buffer-size (min +buffer-size+ (ceiling (* factor (- end start)))))
+           (buffer (make-octet-buffer buffer-size)))
+      (declare (fixnum buffer-pos buffer-size)
+               (boolean octet-seen-p)
+               (type (array octet *) buffer))
+      (labels ((flush-buffer ()
+                 (write-sequence buffer stream :end buffer-pos)
+                 (setq buffer-pos 0))
+               (write-octet (octet)
+                 (declare (octet octet))
+                 (when (>= buffer-pos buffer-size)
+                   (flush-buffer))
+                 (setf (aref buffer buffer-pos) octet)
+                 (incf buffer-pos))
+               (write-character (char)
+                 (char-to-octets external-format char #'write-octet))
+               (write-object (object)
+                 (etypecase object
+                   (octet (setq octet-seen-p t)
+                          (write-octet object))
+                   (character (write-character object)))))
+        (declare (dynamic-extent (function write-octet)))
+        (macrolet ((iterate (octets-p output-form)
+                     `(progn
+                        ,@(if octets-p '((setq octet-seen-p t)))
+                        (loop for index of-type fixnum from start below end
+                              do ,output-form
+                              finally (when (plusp buffer-pos)
+                                        (flush-buffer))))))
+          (etypecase sequence
+            (string (iterate nil (write-character (char sequence index))))
+            (array
+             (let ((array-element-type (array-element-type sequence)))
+               (cond ((type-equal array-element-type 'octet)
+                      (iterate t (write-octet (aref (the (array octet *) sequence) index))))
+                     ((subtypep array-element-type 'integer)
+                      (iterate t (write-octet (aref sequence index))))
+                     (t (iterate nil (write-object (aref sequence index)))))))
+            (list (iterate nil (write-object (nth index sequence)))))
+          (setq column
+                (cond (octet-seen-p nil)
+                      (t (let ((last-newline-pos (position #\Newline sequence
+                                                           :test #'char=
+                                                           :start start
+                                                           :end end
+                                                           :from-end t)))
+                           (cond (last-newline-pos (- end last-newline-pos 1))
+                                 (column (+ column (- end start))))))))))))
+          
   sequence)
 
 (defmethod stream-write-string ((stream flexi-output-stream) string
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        Author: eweitz
Date: Tue May 20 20:19:12 2008
New Revision: 40
Modified:
   branches/edi/conditions.lisp
   branches/edi/input.lisp
   branches/edi/output.lisp
Log:
read-sequence slightly improved for file streams
Modified: branches/edi/conditions.lisp
==============================================================================
--- branches/edi/conditions.lisp	(original)
+++ branches/edi/conditions.lisp	Tue May 20 20:19:12 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/conditions.lisp,v 1.6 2008/05/20 23:44:45 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/conditions.lisp,v 1.7 2008/05/21 00:05:42 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -51,6 +51,7 @@
 (define-condition flexi-stream-out-of-sync-error (flexi-stream-error)
   ()
   (:report (lambda (condition stream)
+             (declare (ignore condition))
              (format stream "Stream out of sync from previous
 lookahead, couldn't rewind.")))
   (:documentation "This can happen if you're trying to write to an IO
Modified: branches/edi/input.lisp
==============================================================================
--- branches/edi/input.lisp	(original)
+++ branches/edi/input.lisp	Tue May 20 20:19:12 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/input.lisp,v 1.68 2008/05/20 23:01:51 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/input.lisp,v 1.70 2008/05/21 00:18:35 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -217,23 +217,32 @@
            (buffer-pos 0)
            (buffer-end 0)
            (index start)
+           ;; whether we will deliver characters and thus the number
+           ;; of octets to read might not be equal to the number of
+           ;; sequence elements to fill
            (want-chars-p (or (stringp sequence)
                              (and (vectorp sequence)
                                   (not (subtypep (array-element-type sequence) 'integer)))
-                             (type-equal element-type 'octet)))
+                             (not (type-equal element-type 'octet))))
+           ;; whether we will later be able to rewind the stream if
+           ;; needed (to get rid of unused octets in the buffer)
+           (can-rewind-p (and want-chars-p (maybe-rewind stream 0)))
            (factor (if want-chars-p (encoding-factor external-format) 1))
            (integer-factor (floor factor))
            ;; it's an interesting question whether it makes sense
            ;; performance-wise to make RESERVE significantly bigger
            ;; (and thus put potentially a lot more octets into
            ;; OCTET-STACK), especially for UTF-8
-           (reserve (if (floatp factor) (* 2 integer-factor) 0)))
+           (reserve (cond ((not (floatp factor)) 0)
+                          ((not can-rewind-p) (* 2 integer-factor))
+                          (t (ceiling (* (- factor integer-factor) (- end start)))))))
       (declare (fixnum buffer-pos buffer-end index integer-factor reserve)
-               (boolean want-chars-p))
-      (flet ((compute-minimum ()
-               "Computes the minimum amount of octets we can savely
-read into the buffer without violating the stream's bound \(if there
-is one) and without potentially reading much more than we need."
+               (boolean want-chars-p can-rewind-p))
+      (flet ((compute-fill-amount ()
+               "Computes the amount of octets we can savely read into
+the buffer without violating the stream's bound \(if there is one) and
+without potentially reading much more than we need \(unless we can
+rewind afterwards)."
                (let ((minimum (min (the fixnum (+ (the fixnum (* integer-factor
                                                                  (the fixnum (- end index))))
                                                   reserve))
@@ -261,7 +270,7 @@
                ;; compare with BUFFER-POS
                (unless (zerop buffer-end)
                  (incf position buffer-end))))
-        (let ((minimum (compute-minimum)))
+        (let ((minimum (compute-fill-amount)))
           (declare (fixnum minimum))
           (setq buffer (make-octet-buffer minimum))
           ;; fill buffer for the first time or return immediately if
@@ -275,7 +284,7 @@
 stream."
                  (when (>= buffer-pos buffer-end)
                    (setq buffer-pos 0)
-                   (unless (fill-buffer (compute-minimum))
+                   (unless (fill-buffer (compute-fill-amount))
                      (return-from next-octet)))
                  (prog1
                      (aref (the (array octet *) buffer) buffer-pos)
@@ -306,12 +315,17 @@
                              (when (>= index end)
                                ;; check if there are octets in the
                                ;; buffer we didn't use - see
-                               ;; COMPUTE-MINIMUM above
-                               (loop
-                                (when (>= buffer-pos buffer-end)
-                                  (return))
-                                (decf buffer-end)
-                                (push (aref (the (array octet *) buffer) buffer-end) octet-stack))
+                               ;; COMPUTE-FILL-AMOUNT above
+                               (let ((rest (- buffer-end buffer-pos)))
+                                 (when (plusp rest)
+                                   (or (and can-rewind-p
+                                            (maybe-rewind stream rest))
+                                       (loop
+                                        (when (>= buffer-pos buffer-end)
+                                          (return))
+                                        (decf buffer-end)
+                                        (push (aref (the (array octet *) buffer) buffer-end)
+                                              octet-stack)))))
                                (leave))
                              (let ((next-thing ,(if octetp
                                                   '(next-octet)
Modified: branches/edi/output.lisp
==============================================================================
--- branches/edi/output.lisp	(original)
+++ branches/edi/output.lisp	Tue May 20 20:19:12 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/output.lisp,v 1.56 2008/05/20 23:44:45 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/output.lisp,v 1.57 2008/05/21 00:04:58 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -129,19 +129,6 @@
   ;; needed for AllegroCL - grrr...
   (stream-write-char stream #\Newline))
 
-;; TODO: file-position -> octet-stack (and others?)
-
-;; other way around: function "resync" trying to use File-position?
-
-;; "resync" independent function to empty octet-stack?
-;; (decrement-file-position) => success
-;; (resync ... &optional how-much (length octet-stack)) => success
-
-;; in stream-read-sequence: if file stream, read more into buffer,
-;; then resync with file-position?
-
-;; TODO: interaction between read and write
-
 (defmethod stream-write-sequence ((flexi-output-stream flexi-output-stream) sequence start end &key)
   "Writes all elements of the sequence SEQUENCE from START to END
 to the underlying stream.  The elements can be either octets or
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        Author: eweitz
Date: Tue May 20 19:46:57 2008
New Revision: 39
Added:
   branches/edi/io.lisp   (contents, props changed)
Log:
Forgot one...
Added: branches/edi/io.lisp
==============================================================================
--- (empty file)
+++ branches/edi/io.lisp	Tue May 20 19:46:57 2008
@@ -0,0 +1,110 @@
+;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
+;;; $Header: /usr/local/cvsrep/flexi-streams/io.lisp,v 1.2 2008/05/20 23:44:45 edi Exp $
+
+;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
+
+;;; Redistribution and use in source and binary forms, with or without
+;;; modification, are permitted provided that the following conditions
+;;; are met:
+
+;;;   * Redistributions of source code must retain the above copyright
+;;;     notice, this list of conditions and the following disclaimer.
+
+;;;   * Redistributions in binary form must reproduce the above
+;;;     copyright notice, this list of conditions and the following
+;;;     disclaimer in the documentation and/or other materials
+;;;     provided with the distribution.
+
+;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
+;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+;;; ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(in-package :flexi-streams)
+
+(defmethod reset-input-state ((flexi-io-stream flexi-io-stream))
+  "This method is used to clear any state associated with previous
+input before output is attempted on the stream.  It can fail if the
+octet stack is not empty and the stream can't be `rewound'."
+  (declare #.*standard-optimize-settings*)
+  (with-accessors ((last-char-code flexi-stream-last-char-code)
+                   (last-octet flexi-stream-last-octet)
+                   (octet-stack flexi-stream-octet-stack)
+                   (stream flexi-stream-stream))
+      flexi-io-stream
+    (when octet-stack
+      (unless (maybe-rewind stream (length octet-stack))
+        (error 'flexi-stream-out-of-sync-error
+               :stream flexi-io-stream))
+      (setq octet-stack nil))
+    (setq last-octet nil
+          last-char-code nil)))
+
+(defmethod stream-write-byte :before ((stream flexi-io-stream) byte)
+  (declare #.*standard-optimize-settings*)
+  (declare (ignore byte))
+  (reset-input-state stream))
+  
+(defmethod stream-write-char :before ((stream flexi-io-stream) char)
+  (declare #.*standard-optimize-settings*)
+  (declare (ignore char))
+  (reset-input-state stream))
+  
+(defmethod stream-write-sequence :before ((stream flexi-io-stream) sequence start end &key)
+  (declare #.*standard-optimize-settings*)
+  (declare (ignore sequence start end))
+  (reset-input-state stream))
+  
+(defmethod stream-clear-output :before ((stream flexi-io-stream))
+  (declare #.*standard-optimize-settings*)
+  (reset-input-state stream))
+
+(defmethod reset-output-state ((flexi-io-stream flexi-io-stream))
+  "This method is used to clear any state associated with previous
+output before the stream is used for input."
+  (declare #.*standard-optimize-settings*)
+  (with-accessors ((column flexi-stream-column))
+      flexi-io-stream
+    (setq column nil)))
+  
+(defmethod stream-read-byte :before ((stream flexi-io-stream))
+  (declare #.*standard-optimize-settings*)
+  (reset-output-state stream))
+  
+(defmethod stream-read-char :before ((stream flexi-io-stream))
+  (declare #.*standard-optimize-settings*)
+  (reset-output-state stream))
+
+(defmethod stream-read-sequence :before ((stream flexi-io-stream) sequence start end &key)
+  (declare #.*standard-optimize-settings*)
+  (declare (ignore sequence start end))
+  (reset-output-state stream))
+
+(defmethod stream-unread-char :before ((stream flexi-io-stream) char)
+  (declare #.*standard-optimize-settings*)
+  (declare (ignore char))
+  (reset-output-state stream))
+  
+(defmethod unread-byte :before (byte (stream flexi-io-stream))
+  (declare #.*standard-optimize-settings*)
+  (declare (ignore byte))
+  (reset-output-state stream))
+  
+(defmethod stream-clear-input :before ((stream flexi-io-stream))
+  (declare #.*standard-optimize-settings*)
+  (reset-output-state stream))
+
+(defmethod write-byte* :after (byte (stream flexi-io-stream))
+  "Keep POSITION slot up to date even when performing output."
+  (declare #.*standard-optimize-settings*)
+  (declare (ignore byte))
+  (with-accessors ((position flexi-stream-position))
+      stream
+    (incf position)))
\ No newline at end of file
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    20 May '08
                    
                        Author: eweitz
Date: Tue May 20 19:45:25 2008
New Revision: 38
Modified:
   branches/edi/conditions.lisp
   branches/edi/decode.lisp
   branches/edi/doc/index.html
   branches/edi/encode.lisp
   branches/edi/external-format.lisp
   branches/edi/flexi-streams.asd
   branches/edi/input.lisp
   branches/edi/mapping.lisp
   branches/edi/output.lisp
   branches/edi/packages.lisp
   branches/edi/specials.lisp
   branches/edi/test/test.lisp
   branches/edi/util.lisp
Log:
IO stream cleanup
Modified: branches/edi/conditions.lisp
==============================================================================
--- branches/edi/conditions.lisp	(original)
+++ branches/edi/conditions.lisp	Tue May 20 19:45:25 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/conditions.lisp,v 1.5 2008/05/19 07:57:07 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/conditions.lisp,v 1.6 2008/05/20 23:44:45 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -48,6 +48,15 @@
   (:documentation "Errors of this type are signalled if the flexi
 stream has a wrong element type."))
 
+(define-condition flexi-stream-out-of-sync-error (flexi-stream-error)
+  ()
+  (:report (lambda (condition stream)
+             (format stream "Stream out of sync from previous
+lookahead, couldn't rewind.")))
+  (:documentation "This can happen if you're trying to write to an IO
+stream which had prior to that `looked ahead' while reading and now
+can't `rewind' to the octet where you /should/ be."))
+
 (define-condition in-memory-stream-error (stream-error)
   ()
   (:documentation "Superclass for all errors related to
Modified: branches/edi/decode.lisp
==============================================================================
--- branches/edi/decode.lisp	(original)
+++ branches/edi/decode.lisp	Tue May 20 19:45:25 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/decode.lisp,v 1.15 2008/05/20 09:37:43 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/decode.lisp,v 1.16 2008/05/20 23:01:50 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -61,12 +61,12 @@
 whenever this function is called."))
 
 (defmethod octets-to-char-code ((format flexi-latin-1-format) reader)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (function reader))
   (funcall reader))
 
 (defmethod octets-to-char-code ((format flexi-ascii-format) reader)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (function reader))
   (when-let (octet (funcall reader))
     (if (> (the octet octet) 127)
@@ -75,7 +75,7 @@
       octet)))
 
 (defmethod octets-to-char-code ((format flexi-8-bit-format) reader)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (function reader))
   (with-accessors ((decoding-table external-format-decoding-table))
       format
@@ -89,7 +89,7 @@
           char-code)))))
 
 (defmethod octets-to-char-code ((format flexi-utf-8-format) reader)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (function reader))  
   (let (first-octet-seen)
     (declare (boolean first-octet-seen))
@@ -105,7 +105,7 @@
       (let ((octet (read-next-byte)))
         (declare (type octet octet))
         (multiple-value-bind (start count)
-            (cond ((zerop (logand octet #b10000000))
+            (cond ((not (logbitp 7 octet))
                    (values octet 0))
                   ((= #b11000000 (logand octet #b11100000))
                    (values (logand octet #b00011111) 1))
@@ -124,8 +124,8 @@
           (declare (fixnum count))
           ;; note that we currently don't check for "overlong"
           ;; sequences or other illegal values
-          (loop for result of-type (unsigned-byte 32)
-                = start then (+ (ash (the (unsigned-byte 26) result) 6)
+          (loop for result of-type code-point
+                = start then (+ (ash result 6)
                                 (logand octet #b111111))
                 repeat count
                 for octet of-type octet = (read-next-byte)
@@ -136,7 +136,7 @@
                 finally (return result)))))))
 
 (defmethod octets-to-char-code ((format flexi-utf-16-le-format) reader)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (function reader))
   (let (first-octet-seen)
     (declare (boolean first-octet-seen))
@@ -169,7 +169,7 @@
                 (t word)))))))
 
 (defmethod octets-to-char-code ((format flexi-utf-16-be-format) reader)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (function reader))
   (let (first-octet-seen)
     (declare (boolean first-octet-seen))
@@ -202,7 +202,7 @@
                 (t word)))))))
 
 (defmethod octets-to-char-code ((format flexi-utf-32-le-format) reader)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (function reader))
   (let (first-octet-seen)
     (declare (boolean first-octet-seen))
@@ -220,7 +220,7 @@
             sum (ash octet count)))))
 
 (defmethod octets-to-char-code ((format flexi-utf-32-be-format) reader)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (function reader))
   (let (first-octet-seen)
     (declare (boolean first-octet-seen))
@@ -238,7 +238,7 @@
             sum (ash octet count)))))
 
 (defmethod octets-to-char-code ((format flexi-cr-mixin) reader)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (ignore reader))
   (let ((char-code (call-next-method)))
     (case char-code
@@ -246,7 +246,7 @@
       (otherwise char-code))))
 
 (defmethod octets-to-char-code ((format flexi-crlf-mixin) reader)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (function *current-unreader*))
   (declare (ignore reader))
   (let ((char-code (call-next-method)))
Modified: branches/edi/doc/index.html
==============================================================================
--- branches/edi/doc/index.html	(original)
+++ branches/edi/doc/index.html	Tue May 20 19:45:25 2008
@@ -89,6 +89,7 @@
       <li><a href="#*substitution-char*"><code>*substitution-char*</code></a>
       <li><a href="#octet"><code>octet</code></a>
       <li><a href="#flexi-stream-error"><code>flexi-stream-error</code></a>
+      <li><a href="#flexi-stream-out-of-sync-error"><code>flexi-stream-out-of-sync-error</code></a>
       <li><a href="#flexi-stream-element-type-error"><code>flexi-stream-element-type-error</code></a>
       <li><a href="#flexi-stream-element-type-error-element-type"><code>flexi-stream-element-type-error-element-type</code></a>
       </ol>
@@ -804,6 +805,15 @@
 </blockquote>
 
 <p><br>[Condition]
+<br><a class=none name="flexi-stream-out-of-sync-error"><b>flexi-stream-out-of-sync-error</b></a>
+
+<blockquote><br> This can happen if you're trying to write to
+an <a href="#flexi-io-stream">IO stream</a> which had prior to that
+"looked ahead" while reading and now can't "rewind" to the octet where
+you <em>should</em> be.
+</blockquote>
+
+<p><br>[Condition]
 <br><a class=none name="flexi-stream-element-type-error"><b>flexi-stream-element-type-error</b></a>
 
 <blockquote><br>
@@ -1030,7 +1040,7 @@
 numerous patches and additions.
 
 <p>
-$Header: /usr/local/cvsrep/flexi-streams/doc/index.html,v 1.104 2008/05/20 06:55:21 edi Exp $
+$Header: /usr/local/cvsrep/flexi-streams/doc/index.html,v 1.105 2008/05/20 23:44:47 edi Exp $
 <p><a href="http://weitz.de/index.html">BACK TO MY HOMEPAGE</a>
 
 </body>
Modified: branches/edi/encode.lisp
==============================================================================
--- branches/edi/encode.lisp	(original)
+++ branches/edi/encode.lisp	Tue May 20 19:45:25 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/encode.lisp,v 1.11 2008/05/20 08:02:49 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/encode.lisp,v 1.12 2008/05/20 23:01:50 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -38,7 +38,7 @@
 unspecified."))
 
 (defmethod char-to-octets ((format flexi-latin-1-format) char writer)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (character char) (function writer))
   (let ((octet (char-code char)))
     (when (> octet 255)
@@ -46,7 +46,7 @@
     (funcall writer octet)))
 
 (defmethod char-to-octets ((format flexi-ascii-format) char writer)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (character char) (function writer))
   (let ((octet (char-code char)))
     (when (> octet 127)
@@ -54,7 +54,7 @@
     (funcall writer octet)))
 
 (defmethod char-to-octets ((format flexi-8-bit-format) char writer)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (character char) (function writer))
   (with-accessors ((encoding-hash external-format-encoding-hash))
       format
@@ -64,7 +64,7 @@
       (funcall writer octet))))
 
 (defmethod char-to-octets ((format flexi-utf-8-format) char writer)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (character char) (function writer))
   (let ((char-code (char-code char)))
     (tagbody
@@ -96,7 +96,7 @@
      zero)))
 
 (defmethod char-to-octets ((format flexi-utf-16-le-format) char writer)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (character char) (function writer))
   (flet ((write-word (word)
            (funcall writer (ldb (byte 8 0) word))
@@ -111,7 +111,7 @@
                (write-word (logior #xdc00 (ldb (byte 10 0) char-code))))))))
 
 (defmethod char-to-octets ((format flexi-utf-16-be-format) char writer)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (character char) (function writer))
   (flet ((write-word (word)
            (funcall writer (ldb (byte 8 8) word))
@@ -126,7 +126,7 @@
                (write-word (logior #xdc00 (ldb (byte 10 0) char-code))))))))
 
 (defmethod char-to-octets ((format flexi-utf-32-le-format) char writer)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (character char) (function writer))
   (let ((char-code (char-code char)))
     (funcall writer (ldb (byte 8 0) char-code))
@@ -135,7 +135,7 @@
     (funcall writer (ldb (byte 8 24) char-code))))
 
 (defmethod char-to-octets ((format flexi-utf-32-be-format) char writer)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (character char) (function writer))
   (let ((char-code (char-code char)))
     (funcall writer (ldb (byte 8 24) char-code))
@@ -144,14 +144,14 @@
     (funcall writer (ldb (byte 8 0) char-code))))
 
 (defmethod char-to-octets ((format flexi-cr-mixin) char writer)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (character char))
   (if (char= char #\Newline)
     (call-next-method format #\Return writer)
     (call-next-method)))
 
 (defmethod char-to-octets ((format flexi-crlf-mixin) char writer)
-  (declare #.*standard-optimize-settings*)
+  (declare #.*fixnum-optimize-settings*)
   (declare (character char))
   (cond ((char= char #\Newline)
          (call-next-method format #\Return writer)
Modified: branches/edi/external-format.lisp
==============================================================================
--- branches/edi/external-format.lisp	(original)
+++ branches/edi/external-format.lisp	Tue May 20 19:45:25 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/external-format.lisp,v 1.20 2008/05/20 08:02:50 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/external-format.lisp,v 1.21 2008/05/20 23:44:45 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -284,7 +284,7 @@
                                  'flexi-crlf-utf-32-be-format))))))))
                          
 (defun make-external-format% (name &key (little-endian *default-little-endian*)
-                                        id eol-style)
+                                   id eol-style)
   "Used internally by MAKE-EXTERNAL-FORMAT to default some of the
 keywords arguments and to determine the right subclass of
 EXTERNAL-FORMAT."
@@ -297,7 +297,9 @@
                  (list :eol-style (or eol-style *default-eol-style*)))
                 ((code-page-name-p real-name)
                  (list :id (or (known-code-page-id-p id)
-                               (error "Unknown code page ID ~S" id))
+                               (error 'external-format-error
+                                      :format-control "Unknown code page ID ~S"
+                                      :format-arguments (list id)))
                        ;; default EOL style for Windows code pages is :CRLF
                        :eol-style (or eol-style :crlf)))
                 (t (list :eol-style (or eol-style *default-eol-style*)
Modified: branches/edi/flexi-streams.asd
==============================================================================
--- branches/edi/flexi-streams.asd	(original)
+++ branches/edi/flexi-streams.asd	Tue May 20 19:45:25 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/flexi-streams.asd,v 1.63 2008/05/18 23:13:59 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/flexi-streams.asd,v 1.64 2008/05/20 23:01:51 edi Exp $
 
 ;;; Copyright (c) 2005-2007, Dr. Edmund Weitz.  All rights reserved.
 
@@ -54,6 +54,7 @@
                #+:lispworks (:file "lw-binary-stream")
                (:file "output")
                (:file "input")
+               (:file "io")
                (:file "strings"))
   :depends-on (:trivial-gray-streams))
 
Modified: branches/edi/input.lisp
==============================================================================
--- branches/edi/input.lisp	(original)
+++ branches/edi/input.lisp	Tue May 20 19:45:25 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/input.lisp,v 1.67 2008/05/20 09:38:07 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/input.lisp,v 1.68 2008/05/20 23:01:51 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -213,7 +213,7 @@
                    (element-type flexi-stream-element-type)
                    (stream flexi-stream-stream))
       flexi-input-stream
-    (let* ((buffer (make-octet-buffer))
+    (let* (buffer
            (buffer-pos 0)
            (buffer-end 0)
            (index start)
@@ -229,7 +229,7 @@
            ;; OCTET-STACK), especially for UTF-8
            (reserve (if (floatp factor) (* 2 integer-factor) 0)))
       (declare (fixnum buffer-pos buffer-end index integer-factor reserve)
-               (type (array octet *) buffer))
+               (boolean want-chars-p))
       (flet ((compute-minimum ()
                "Computes the minimum amount of octets we can savely
 read into the buffer without violating the stream's bound \(if there
@@ -243,6 +243,15 @@
              (fill-buffer (end)
                "Tries to fill the buffer from BUFFER-POS to END and
 returns NIL if the buffer doesn't contain any new data."
+               ;; put data from octet stack into buffer if there is any
+               (loop
+                (when (>= buffer-pos end)
+                  (return))
+                (let ((next-octet (pop octet-stack)))
+                  (cond (next-octet
+                         (setf (aref (the (array octet *) buffer) buffer-pos) (the octet next-octet))
+                         (incf buffer-pos))
+                        (t (return)))))
                (setq buffer-end (read-sequence buffer stream
                                                :start buffer-pos
                                                :end end))
@@ -254,15 +263,7 @@
                  (incf position buffer-end))))
         (let ((minimum (compute-minimum)))
           (declare (fixnum minimum))
-          ;; put data from octet stack into buffer if there is any
-          (loop
-           (when (>= buffer-pos minimum)
-             (return))
-           (let ((next-octet (pop octet-stack)))
-             (cond (next-octet
-                    (setf (aref buffer buffer-pos) (the octet next-octet))
-                    (incf buffer-pos))
-                   (t (return)))))
+          (setq buffer (make-octet-buffer minimum))
           ;; fill buffer for the first time or return immediately if
           ;; we don't succeed
           (unless (fill-buffer minimum)
@@ -277,7 +278,7 @@
                    (unless (fill-buffer (compute-minimum))
                      (return-from next-octet)))
                  (prog1
-                     (aref buffer buffer-pos)
+                     (aref (the (array octet *) buffer) buffer-pos)
                    (incf buffer-pos)))
                (unreader (char)
                  (unread-char% char flexi-input-stream)))
@@ -310,7 +311,7 @@
                                 (when (>= buffer-pos buffer-end)
                                   (return))
                                 (decf buffer-end)
-                                (push (aref buffer buffer-end) octet-stack))
+                                (push (aref (the (array octet *) buffer) buffer-end) octet-stack))
                                (leave))
                              (let ((next-thing ,(if octetp
                                                   '(next-octet)
Modified: branches/edi/mapping.lisp
==============================================================================
--- branches/edi/mapping.lisp	(original)
+++ branches/edi/mapping.lisp	Tue May 20 19:45:25 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/mapping.lisp,v 1.1 2008/05/19 09:09:15 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/mapping.lisp,v 1.2 2008/05/20 21:15:45 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -40,9 +40,16 @@
   #-:lispworks 'character)
 
 (deftype char-code-integer ()
-  "The type of integers which can be returned by the function CHAR-CODE."
+  "The subtype of integers which can be returned by the function CHAR-CODE."
   '(integer 0 #.(1- char-code-limit)))
 
+(deftype code-point ()
+  "The subtype of integers that's just big enough to hold all Unicode
+codepoints.
+
+See for example <http://unicode.org/glossary/#C>."
+  '(mod #x110000))
+
 (defmacro defconstant (name value &optional doc)
   "Make sure VALUE is evaluated only once \(to appease SBCL)."
   `(cl:defconstant ,name (if (boundp ',name) (symbol-value ',name) ,value)
Modified: branches/edi/output.lisp
==============================================================================
--- branches/edi/output.lisp	(original)
+++ branches/edi/output.lisp	Tue May 20 19:45:25 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/output.lisp,v 1.54 2008/05/20 06:15:44 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/output.lisp,v 1.56 2008/05/20 23:44:45 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -29,37 +29,37 @@
 
 (in-package :flexi-streams)
 
-(defgeneric write-byte* (byte sink)
+(defgeneric write-byte* (byte stream)
+  (declare #.*standard-optimize-settings*)
   (:documentation "Writes one byte \(octet) to the underlying stream
-of SINK \(if SINK is a flexi stream) or adds the byte to the end of
-SINK \(if SINK is an array with a fill pointer)."))
+STREAM."))
 
 #-:lispworks
-(defmethod write-byte* (byte (sink flexi-output-stream))  
+(defmethod write-byte* (byte (flexi-output-stream flexi-output-stream))  
   (declare #.*standard-optimize-settings*)
   (with-accessors ((stream flexi-stream-stream))
-      sink
+      flexi-output-stream
     (write-byte byte stream)))
 
 #+:lispworks
-(defmethod write-byte* (byte (sink flexi-output-stream))
+(defmethod write-byte* (byte (flexi-output-stream flexi-output-stream))
   (declare #.*standard-optimize-settings*)
   ;; we use WRITE-SEQUENCE because WRITE-BYTE doesn't work with all
   ;; bivalent streams in LispWorks (4.4.6)
   (with-accessors ((stream flexi-stream-stream))
-      sink
+      flexi-output-stream
     (write-sequence (make-array 1 :element-type 'octet
                                 :initial-element byte)
                     stream)
     byte))
 
 #+:lispworks
-(defmethod write-byte* (byte (sink flexi-binary-output-stream))
+(defmethod write-byte* (byte (flexi-output-stream flexi-binary-output-stream))
   "Optimized version \(only needed for LispWorks) in case the
 underlying stream is binary."
   (declare #.*standard-optimize-settings*)
   (with-accessors ((stream flexi-stream-stream))
-      sink
+      flexi-output-stream
     (write-byte byte stream)))
 
 (defmethod stream-write-char ((stream flexi-output-stream) char)
@@ -180,7 +180,7 @@
     (return-from stream-write-sequence
       (call-next-method)))
   (let ((buffer (make-array (+ +buffer-size+ 20)
-                            :element-type '(unsigned-byte 8)
+                            :element-type 'octet
                             :fill-pointer 0))
         (last-newline-pos (position #\Newline sequence
                                     :test #'char=
Modified: branches/edi/packages.lisp
==============================================================================
--- branches/edi/packages.lisp	(original)
+++ branches/edi/packages.lisp	Tue May 20 19:45:25 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/packages.lisp,v 1.33 2008/05/19 07:57:08 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/packages.lisp,v 1.34 2008/05/20 23:44:45 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -53,12 +53,13 @@
            :flexi-io-stream
            :flexi-stream
            :flexi-stream-bound
+           :flexi-stream-column
            :flexi-stream-external-format
            :flexi-stream-element-type
            :flexi-stream-element-type-error
            :flexi-stream-element-type-error-element-type
            :flexi-stream-error
-           :flexi-stream-column
+           :flexi-stream-out-of-sync-error
            :flexi-stream-position
            :flexi-stream-stream
            :get-output-stream-sequence
Modified: branches/edi/specials.lisp
==============================================================================
--- branches/edi/specials.lisp	(original)
+++ branches/edi/specials.lisp	Tue May 20 19:45:25 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/specials.lisp,v 1.31 2008/05/19 07:57:08 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/specials.lisp,v 1.32 2008/05/20 23:01:51 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -38,6 +38,17 @@
     (compilation-speed 0))
   "The standard optimize settings used by most declaration expressions.")
 
+(defvar *fixnum-optimize-settings*
+  '(optimize
+    speed
+    (safety 0)
+    (space 0)
+    (debug 1)
+    (compilation-speed 0)
+    #+:lispworks (hcl:fixnum-safety 0))
+  "Like *STANDARD-OPTIMIZE-SETTINGS*, but \(on LispWorks) with all
+arithmetic being fixnum arithmetic.")
+
 (defvar *current-unreader* nil
   "A unary function which might be called to `unread' a character
 \(i.e. the sequence of octets it represents).
@@ -162,7 +173,7 @@
 corresponding octets.")
 
 (defconstant +buffer-size+ 8192
-  "Size of buffers used for internal purposes.")
+  "Default size for buffers used for internal purposes.")
 
 (pushnew :flexi-streams *features*)
 
Modified: branches/edi/test/test.lisp
==============================================================================
--- branches/edi/test/test.lisp	(original)
+++ branches/edi/test/test.lisp	Tue May 20 19:45:25 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS-TEST; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/test/test.lisp,v 1.30 2008/05/20 09:37:30 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/test/test.lisp,v 1.31 2008/05/20 23:01:53 edi Exp $
 
 ;;; Copyright (c) 2006-2008, Dr. Edmund Weitz.  All rights reserved.
 
Modified: branches/edi/util.lisp
==============================================================================
--- branches/edi/util.lisp	(original)
+++ branches/edi/util.lisp	Tue May 20 19:45:25 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/util.lisp,v 1.19 2008/05/19 22:32:57 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/util.lisp,v 1.21 2008/05/20 23:44:45 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -176,12 +176,20 @@
        ,instance
      ,@body))
 
-(defun make-octet-buffer ()
+(defun make-octet-buffer (&optional (size +buffer-size+))
   "Creates and returns a fresh buffer \(a specialized array) of size
 +BUFFER-SIZE+ to hold octets."
-  (make-array +buffer-size+ :element-type 'octet))
+  (declare #.*standard-optimize-settings*)
+  (make-array size :element-type 'octet))
 
 (defun type-equal (type1 type2)
   "Whether TYPE1 and TYPE2 denote the same type."
+  (declare #.*standard-optimize-settings*)
   (and (subtypep type1 type2)
-       (subtypep type2 type1)))
\ No newline at end of file
+       (subtypep type2 type1)))
+
+(defun maybe-rewind (stream octets)
+  "Tries to `rewind' the \(binary) stream STREAM by OCTETS octets.
+Returns a true value if it succeeds."
+  (when-let (position (file-position stream))
+    (file-position stream (- position octets))))
\ No newline at end of file
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        Author: eweitz
Date: Tue May 20 08:56:10 2008
New Revision: 37
Modified:
   branches/edi/test/test.lisp
Log:
Remove debugging stuff
Modified: branches/edi/test/test.lisp
==============================================================================
--- branches/edi/test/test.lisp	(original)
+++ branches/edi/test/test.lisp	Tue May 20 08:56:10 2008
@@ -532,11 +532,9 @@
          (no-tests (* 8 (length compare-files-args-list))))
     #+:lispworks
     (setq no-tests (* 2 no-tests))
-    #+(or)
     (dolist (*copy-function* '(copy-stream copy-stream*))
       (dolist (args compare-files-args-list)
         (apply 'compare-files args)))
-    #+(or)
     (let ((string-test-args-list (loop for (file-name symbols) in *test-files*
                                        nconc (create-test-combinations file-name symbols t))))
       (incf no-tests (length string-test-args-list))
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        Author: eweitz
Date: Tue May 20 08:55:00 2008
New Revision: 36
Modified:
   branches/edi/decode.lisp
   branches/edi/input.lisp
   branches/edi/strings.lisp
   branches/edi/test/test.lisp
Log:
Checkpoint
Modified: branches/edi/decode.lisp
==============================================================================
--- branches/edi/decode.lisp	(original)
+++ branches/edi/decode.lisp	Tue May 20 08:55:00 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/decode.lisp,v 1.14 2008/05/20 07:51:09 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/decode.lisp,v 1.15 2008/05/20 09:37:43 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -239,6 +239,7 @@
 
 (defmethod octets-to-char-code ((format flexi-cr-mixin) reader)
   (declare #.*standard-optimize-settings*)
+  (declare (ignore reader))
   (let ((char-code (call-next-method)))
     (case char-code
       (#.(char-code #\Return) #.(char-code #\Newline))
@@ -247,6 +248,7 @@
 (defmethod octets-to-char-code ((format flexi-crlf-mixin) reader)
   (declare #.*standard-optimize-settings*)
   (declare (function *current-unreader*))
+  (declare (ignore reader))
   (let ((char-code (call-next-method)))
     (case char-code
       (#.(char-code #\Return)
Modified: branches/edi/input.lisp
==============================================================================
--- branches/edi/input.lisp	(original)
+++ branches/edi/input.lisp	Tue May 20 08:55:00 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/input.lisp,v 1.66 2008/05/20 00:37:27 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/input.lisp,v 1.67 2008/05/20 09:38:07 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -199,7 +199,9 @@
   "An optimized version which uses a buffer underneath.  The function
 can deliver characters as well as octets and it decides what to do
 based on the element type of the sequence \(which takes precedence)
-and the element type of the stream."
+and the element type of the stream.  What you'll really get might also
+depend on your Lisp.  Some of the implementations are more picky than
+others - see for example FLEXI-STREAMS-TEST:READ-SEQUENCE-TEST."
   (declare #.*standard-optimize-settings*)
   (declare (fixnum start end))
   (with-accessors ((position flexi-stream-position)
Modified: branches/edi/strings.lisp
==============================================================================
--- branches/edi/strings.lisp	(original)
+++ branches/edi/strings.lisp	Tue May 20 08:55:00 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/strings.lisp,v 1.20 2008/05/20 06:15:38 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/strings.lisp,v 1.21 2008/05/20 09:04:23 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -130,7 +130,7 @@
           (declare (inline next-char))
           (etypecase factor
             (integer
-             (let* ((string-length (/ length factor))
+             (let* ((string-length (ceiling length factor))
                     (string (make-array string-length
                                         :element-type 'char*)))
                (declare (fixnum string-length))
Modified: branches/edi/test/test.lisp
==============================================================================
--- branches/edi/test/test.lisp	(original)
+++ branches/edi/test/test.lisp	Tue May 20 08:55:00 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS-TEST; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/test/test.lisp,v 1.29 2008/05/20 00:37:30 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/test/test.lisp,v 1.30 2008/05/20 09:37:30 edi Exp $
 
 ;;; Copyright (c) 2006-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -339,11 +339,17 @@
            (octets (file-as-octet-vector full-path))
            (octet-length (length octets)))
       (when (external-format-equal external-format (make-external-format :utf8))
+        #-:openmcl
+        ;; FLEXI-STREAMS puts integers into the list, but OpenMCL
+        ;; thinks they are characters...
         (with-open-file (in full-path :element-type 'octet)
           (let* ((in (make-flexi-stream in :external-format external-format))
                  (list (make-list octet-length)))
             (setf (flexi-stream-element-type in) 'octet)
+            #-:clisp
             (read-sequence list in)
+            #+:clisp
+            (ext:read-byte-sequence list in)
             (check (sequence-equal list octets))))
         (with-open-file (in full-path :element-type 'octet)
           (let* ((in (make-flexi-stream in :external-format external-format))
@@ -370,7 +376,10 @@
           (check (sequence-equal (loop repeat 50
                                        collect (read-char in))
                                  (subseq file-string 0 50)))
+          #-:clisp
           (read-sequence list in)
+          #+:clisp
+          (ext:read-char-sequence list in)
           (check (sequence-equal list (subseq file-string 50 (- string-length 50))))
           (check (sequence-equal (loop repeat 50
                                        collect (read-char in))
@@ -381,7 +390,10 @@
           (check (sequence-equal (loop repeat 25
                                        collect (read-char in))
                                  (subseq file-string 0 25)))
+          #-:clisp
           (read-sequence array in)
+          #+:clisp
+          (ext:read-char-sequence array in)
           (check (sequence-equal array (subseq file-string 25 (- string-length 25))))
           (check (sequence-equal (loop repeat 25
                                        collect (read-char in))
@@ -500,11 +512,11 @@
     (flet ((test-one-file (file-name external-format)
              (with-open-file (in (merge-pathnames file-name *this-file*)
                                  :element-type 'flex:octet)
-               (setq in (make-flexi-stream in :external-format external-format))
-               (loop repeat 300
-                     for char = (read-char in)
-                     do (unread-char char in)
-                     (check (char= (read-char in) char))))))
+               (let ((in (make-flexi-stream in :external-format external-format)))
+                 (loop repeat 300
+                       for char = (read-char in)
+                       do (unread-char char in)
+                          (check (char= (read-char in) char)))))))
       (loop for (file-name symbols) in *test-files*
             do (loop for symbol in symbols
                      do (loop for (file-name . external-format) in (create-file-variants file-name symbol)
@@ -520,9 +532,11 @@
          (no-tests (* 8 (length compare-files-args-list))))
     #+:lispworks
     (setq no-tests (* 2 no-tests))
+    #+(or)
     (dolist (*copy-function* '(copy-stream copy-stream*))
       (dolist (args compare-files-args-list)
         (apply 'compare-files args)))
+    #+(or)
     (let ((string-test-args-list (loop for (file-name symbols) in *test-files*
                                        nconc (create-test-combinations file-name symbols t))))
       (incf no-tests (length string-test-args-list))
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    20 May '08
                    
                        Author: eweitz
Date: Tue May 20 04:03:28 2008
New Revision: 35
Modified:
   branches/edi/decode.lisp
   branches/edi/doc/index.html
   branches/edi/encode.lisp
   branches/edi/external-format.lisp
   branches/edi/input.lisp
   branches/edi/output.lisp
   branches/edi/strings.lisp
   branches/edi/test/test.lisp
Log:
Checkpoint
Modified: branches/edi/decode.lisp
==============================================================================
--- branches/edi/decode.lisp	(original)
+++ branches/edi/decode.lisp	Tue May 20 04:03:28 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/decode.lisp,v 1.12 2008/05/19 22:32:56 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/decode.lisp,v 1.14 2008/05/20 07:51:09 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -69,8 +69,7 @@
   (declare #.*standard-optimize-settings*)
   (declare (function reader))
   (when-let (octet (funcall reader))
-    (declare (type octet octet))
-    (if (> octet 127)
+    (if (> (the octet octet) 127)
       (recover-from-encoding-error format
                                    "No character which corresponds to octet #x~X." octet)
       octet)))
@@ -81,8 +80,8 @@
   (with-accessors ((decoding-table external-format-decoding-table))
       format
     (when-let (octet (funcall reader))
-      (declare (type octet octet))
-      (let ((char-code (aref (the (simple-array char-code-integer *) decoding-table) octet)))
+      (let ((char-code (aref (the (simple-array char-code-integer *) decoding-table)
+                             (the octet octet))))
         (if (or (null char-code)
                 (= (the char-code-integer char-code) 65533))
           (recover-from-encoding-error format
Modified: branches/edi/doc/index.html
==============================================================================
--- branches/edi/doc/index.html	(original)
+++ branches/edi/doc/index.html	Tue May 20 04:03:28 2008
@@ -196,7 +196,9 @@
 
 <p>
 For more examples see the source code
-of <a
+of 
+<a href="http://mr-co.de/projects/cl-rfc2047/">CL-RFC2047</a>,
+<a
 href="http://weitz.de/drakma/">Drakma</a>, <a
 href="http://weitz.de/chunga/">Chunga</a>,
 or <a href="http://weitz.de/cl-wbxml/">CL-WBXML</a>.
@@ -970,29 +972,25 @@
 <blockquote><br>
 
 Converts the Lisp string <code><i>string</i></code> from <code><i>start</i></code> to <code><i>end</i></code> to an array of
-<a href="#octet">octets</a> corresponding to the <a href="#external-formats">external format</a> <code><i>external-format</i></code>. The defaults for
+<a href="#octet">octets</a> corresponding to the external format designated by <a href="#external-formats">external format</a> <code><i>external-format</i></code>. The defaults for
 <code><i>start</i></code> and <code><i>end</i></code>
-are <code>0</code> and the length of the
-string.  The default for <code><i>external-format</i></code> is the
-value of
-evaluating <code>(<a
-href="#make-external-format">MAKE-EXTERNAL-FORMAT</a> :LATIN1)</code>
+are <code>0</code> and the length of the string.  The default
+for <code><i>external-format</i></code> is <code>:LATIN1</code>.
 
 </blockquote>
 
 <p><br>[Function]
 <br><a class=none name="octets-to-string"><b>octets-to-string</b> <i>sequence <tt>&key</tt> external-format start end</i> => <i>string</i></a>
 
-<blockquote><br> Converts the Lisp sequence <code><i>sequence</i></code>
-of <a href="#octet">octets</a> from <code><i>start</i></code>
-to <code><i>end</i></code> to string using
-the <a href="#external-formats">external
+<blockquote><br> Converts the Lisp
+sequence <code><i>sequence</i></code> of <a href="#octet">octets</a>
+from <code><i>start</i></code> to <code><i>end</i></code> to string
+using the external format designated
+by <a href="#external-formats">external
 format</a> <code><i>external-format</i></code>.  The defaults for
 <code><i>start</i></code> and <code><i>end</i></code>
 are <code>0</code> and the length of the sequence.  The default
-for <code><i>external-format</i></code> is the value of
-evaluating <code>(<a
-href="#make-external-format">MAKE-EXTERNAL-FORMAT</a> :LATIN1)</code>
+for <code><i>external-format</i></code> is <code>:LATIN1</code>.
 </blockquote>
 
 <br> <br><h3><a class=none name="position">File positions</a></h3>
@@ -1032,7 +1030,7 @@
 numerous patches and additions.
 
 <p>
-$Header: /usr/local/cvsrep/flexi-streams/doc/index.html,v 1.102 2008/05/19 07:57:10 edi Exp $
+$Header: /usr/local/cvsrep/flexi-streams/doc/index.html,v 1.104 2008/05/20 06:55:21 edi Exp $
 <p><a href="http://weitz.de/index.html">BACK TO MY HOMEPAGE</a>
 
 </body>
Modified: branches/edi/encode.lisp
==============================================================================
--- branches/edi/encode.lisp	(original)
+++ branches/edi/encode.lisp	Tue May 20 04:03:28 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/encode.lisp,v 1.10 2008/05/19 22:32:56 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/encode.lisp,v 1.11 2008/05/20 08:02:49 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -101,7 +101,7 @@
   (flet ((write-word (word)
            (funcall writer (ldb (byte 8 0) word))
            (funcall writer (ldb (byte 8 8) word))))
-    (declare (inline read-next-word))
+    (declare (inline write-word))
     (let ((char-code (char-code char)))
       (declare (type char-code-integer char-code))
       (cond ((< char-code #x10000)
@@ -116,7 +116,7 @@
   (flet ((write-word (word)
            (funcall writer (ldb (byte 8 8) word))
            (funcall writer (ldb (byte 8 0) word))))
-    (declare (inline read-next-word))
+    (declare (inline write-word))
     (let ((char-code (char-code char)))
       (declare (type char-code-integer char-code))
       (cond ((< char-code #x10000)
Modified: branches/edi/external-format.lisp
==============================================================================
--- branches/edi/external-format.lisp	(original)
+++ branches/edi/external-format.lisp	Tue May 20 04:03:28 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/external-format.lisp,v 1.19 2008/05/19 11:20:11 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/external-format.lisp,v 1.20 2008/05/20 08:02:50 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -219,7 +219,7 @@
   (declare #.*standard-optimize-settings*)
   (declare (ignore initargs))
   (with-accessors ((encoding-hash external-format-encoding-hash)
-                   (decoding-table flexi-stream-decoding-table)
+                   (decoding-table external-format-decoding-table)
                    (name external-format-name)
                    (id external-format-id))
       external-format
Modified: branches/edi/input.lisp
==============================================================================
--- branches/edi/input.lisp	(original)
+++ branches/edi/input.lisp	Tue May 20 04:03:28 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/input.lisp,v 1.65 2008/05/19 22:54:10 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/input.lisp,v 1.66 2008/05/20 00:37:27 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -196,6 +196,10 @@
        (stream-read-char stream)))
 
 (defmethod stream-read-sequence ((flexi-input-stream flexi-input-stream) sequence start end &key)
+  "An optimized version which uses a buffer underneath.  The function
+can deliver characters as well as octets and it decides what to do
+based on the element type of the sequence \(which takes precedence)
+and the element type of the stream."
   (declare #.*standard-optimize-settings*)
   (declare (fixnum start end))
   (with-accessors ((position flexi-stream-position)
@@ -207,21 +211,31 @@
                    (element-type flexi-stream-element-type)
                    (stream flexi-stream-stream))
       flexi-input-stream
-    (let ((buffer (make-octet-buffer))
-          (buffer-pos 0)
-          (buffer-end 0)
-          (index start))
-      (declare (fixnum buffer-pos buffer-end index)
+    (let* ((buffer (make-octet-buffer))
+           (buffer-pos 0)
+           (buffer-end 0)
+           (index start)
+           (want-chars-p (or (stringp sequence)
+                             (and (vectorp sequence)
+                                  (not (subtypep (array-element-type sequence) 'integer)))
+                             (type-equal element-type 'octet)))
+           (factor (if want-chars-p (encoding-factor external-format) 1))
+           (integer-factor (floor factor))
+           ;; it's an interesting question whether it makes sense
+           ;; performance-wise to make RESERVE significantly bigger
+           ;; (and thus put potentially a lot more octets into
+           ;; OCTET-STACK), especially for UTF-8
+           (reserve (if (floatp factor) (* 2 integer-factor) 0)))
+      (declare (fixnum buffer-pos buffer-end index integer-factor reserve)
                (type (array octet *) buffer))
       (flet ((compute-minimum ()
                "Computes the minimum amount of octets we can savely
 read into the buffer without violating the stream's bound \(if there
-is one) and without potentially reading more than we need."
-               ;; this has to be done conservatively, unfortunately -
-               ;; it is possible that we only fill the buffer in very
-               ;; small chunks once we're near END (but this is only
-               ;; relevant for multi-byte encodings, of course)
-               (let ((minimum (min (the fixnum (- end index)) +buffer-size+)))
+is one) and without potentially reading much more than we need."
+               (let ((minimum (min (the fixnum (+ (the fixnum (* integer-factor
+                                                                 (the fixnum (- end index))))
+                                                  reserve))
+                                   +buffer-size+)))
                  (cond (bound (min minimum (- bound position)))
                        (t minimum))))
              (fill-buffer (end)
@@ -286,7 +300,16 @@
                                            ,(sublis '((index . (1- index))) set-place)))
                                    (return-from stream-read-sequence index)))
                             (loop
-                             (when (>= index end) (leave))
+                             (when (>= index end)
+                               ;; check if there are octets in the
+                               ;; buffer we didn't use - see
+                               ;; COMPUTE-MINIMUM above
+                               (loop
+                                (when (>= buffer-pos buffer-end)
+                                  (return))
+                                (decf buffer-end)
+                                (push (aref buffer buffer-end) octet-stack))
+                               (leave))
                              (let ((next-thing ,(if octetp
                                                   '(next-octet)
                                                   '(octets-to-char-code external-format #'next-octet))))
Modified: branches/edi/output.lisp
==============================================================================
--- branches/edi/output.lisp	(original)
+++ branches/edi/output.lisp	Tue May 20 04:03:28 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/output.lisp,v 1.52 2008/05/19 22:32:56 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/output.lisp,v 1.54 2008/05/20 06:15:44 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -129,6 +129,19 @@
   ;; needed for AllegroCL - grrr...
   (stream-write-char stream #\Newline))
 
+;; TODO: file-position -> octet-stack (and others?)
+
+;; other way around: function "resync" trying to use File-position?
+
+;; "resync" independent function to empty octet-stack?
+;; (decrement-file-position) => success
+;; (resync ... &optional how-much (length octet-stack)) => success
+
+;; in stream-read-sequence: if file stream, read more into buffer,
+;; then resync with file-position?
+
+;; TODO: interaction between read and write
+
 (defmethod stream-write-sequence ((flexi-output-stream flexi-output-stream) sequence start end &key)
   "Writes all elements of the sequence SEQUENCE from START to END
 to the underlying stream.  The elements can be either octets or
Modified: branches/edi/strings.lisp
==============================================================================
--- branches/edi/strings.lisp	(original)
+++ branches/edi/strings.lisp	Tue May 20 04:03:28 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/strings.lisp,v 1.19 2008/05/19 22:32:56 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/strings.lisp,v 1.20 2008/05/20 06:15:38 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -30,10 +30,11 @@
 (in-package :flexi-streams)
 
 (defun string-to-octets (string &key
-                                (external-format (make-external-format :latin1))
+                                (external-format :latin1)
                                 (start 0) (end (length string)))
   "Converts the Lisp string STRING from START to END to an array of
-octets corresponding to the external format EXTERNAL-FORMAT."
+octets corresponding to the external format designated by
+EXTERNAL-FORMAT."
   (declare #.*standard-optimize-settings*)
   (declare (fixnum start end) (string string))
   (setq external-format (maybe-convert-external-format external-format))
@@ -87,10 +88,10 @@
            octets))))))
 
 (defun octets-to-string (sequence &key
-                                  (external-format (make-external-format :latin1))
+                                  (external-format :latin1)
                                   (start 0) (end (length sequence)))
   "Converts the Lisp sequence SEQUENCE of octets from START to END to
-string using the external format EXTERNAL-FORMAT."
+string using the external format designated by EXTERNAL-FORMAT."
   (declare #.*standard-optimize-settings*)
   (declare (fixnum start end))
   (setq external-format (maybe-convert-external-format external-format))
Modified: branches/edi/test/test.lisp
==============================================================================
--- branches/edi/test/test.lisp	(original)
+++ branches/edi/test/test.lisp	Tue May 20 04:03:28 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS-TEST; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/test/test.lisp,v 1.28 2008/05/19 23:54:55 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/test/test.lisp,v 1.29 2008/05/20 00:37:30 edi Exp $
 
 ;;; Copyright (c) 2006-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -367,19 +367,25 @@
       (with-open-file (in full-path :element-type 'octet)
         (let* ((in (make-flexi-stream in :external-format external-format))
                (list (make-list (- string-length 100))))
-          (check (sequence-equal (loop repeat 100
+          (check (sequence-equal (loop repeat 50
                                        collect (read-char in))
-                                 (subseq file-string 0 100)))
+                                 (subseq file-string 0 50)))
           (read-sequence list in)
-          (check (sequence-equal list (subseq file-string 100)))))
+          (check (sequence-equal list (subseq file-string 50 (- string-length 50))))
+          (check (sequence-equal (loop repeat 50
+                                       collect (read-char in))
+                                 (subseq file-string (- string-length 50))))))
       (with-open-file (in full-path :element-type 'octet)
         (let* ((in (make-flexi-stream in :external-format external-format))
                (array (make-array (- string-length 50))))
-          (check (sequence-equal (loop repeat 50
+          (check (sequence-equal (loop repeat 25
                                        collect (read-char in))
-                                 (subseq file-string 0 50)))
+                                 (subseq file-string 0 25)))
           (read-sequence array in)
-          (check (sequence-equal array (subseq file-string 50))))))))
+          (check (sequence-equal array (subseq file-string 25 (- string-length 25))))
+          (check (sequence-equal (loop repeat 25
+                                       collect (read-char in))
+                                 (subseq file-string (- string-length 25)))))))))
 
 (defmacro using-values ((&rest values) &body body)
   "Executes BODY and feeds an element from VALUES to the USE-VALUE
@@ -514,11 +520,9 @@
          (no-tests (* 8 (length compare-files-args-list))))
     #+:lispworks
     (setq no-tests (* 2 no-tests))
-    #+(or)
     (dolist (*copy-function* '(copy-stream copy-stream*))
       (dolist (args compare-files-args-list)
         (apply 'compare-files args)))
-    #+(or)
     (let ((string-test-args-list (loop for (file-name symbols) in *test-files*
                                        nconc (create-test-combinations file-name symbols t))))
       (incf no-tests (length string-test-args-list))
@@ -530,10 +534,8 @@
       (dolist (args read-sequence-test-args-list)
         (apply 'read-sequence-test args)))
     (incf no-tests)
-    #+(or)
     (error-handling-test)
     (incf no-tests)
-    #+(or)
     (unread-char-test)
     (format *error-output* "~%~%~:[~A of ~A tests failed..~;~*All ~A tests passed~].~%"
             (= no-tests *test-success-counter*) (- no-tests *test-success-counter*) no-tests)))
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        Author: eweitz
Date: Mon May 19 19:55:12 2008
New Revision: 34
Modified:
   branches/edi/test/test.lisp
Log:
More tests
Modified: branches/edi/test/test.lisp
==============================================================================
--- branches/edi/test/test.lisp	(original)
+++ branches/edi/test/test.lisp	Mon May 19 19:55:12 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS-TEST; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/test/test.lisp,v 1.27 2008/05/19 19:47:17 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/test/test.lisp,v 1.28 2008/05/19 23:54:55 edi Exp $
 
 ;;; Copyright (c) 2006-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -323,6 +323,64 @@
       (check (string= (old-octets-to-string octets-list :external-format external-format) string))
       (check (equalp (old-string-to-octets string :external-format external-format) octets-vector)))))
 
+(defun sequence-equal (seq1 seq2)
+  "Whether the two sequences have the same elements."
+  (and (= (length seq1) (length seq2))
+       (loop for i below (length seq1)
+             always (eql (elt seq1 i) (elt seq2 i)))))
+
+(defun read-sequence-test (pathspec external-format)
+  "Several tests to confirm that READ-SEQUENCE behaves as expected."
+  (with-test ((format nil "READ-SEQUENCE tests with format ~S."
+                      (flex::normalize-external-format external-format)))
+    (let* ((full-path (merge-pathnames pathspec *this-file*))
+           (file-string (file-as-string full-path external-format))
+           (string-length (length file-string))
+           (octets (file-as-octet-vector full-path))
+           (octet-length (length octets)))
+      (when (external-format-equal external-format (make-external-format :utf8))
+        (with-open-file (in full-path :element-type 'octet)
+          (let* ((in (make-flexi-stream in :external-format external-format))
+                 (list (make-list octet-length)))
+            (setf (flexi-stream-element-type in) 'octet)
+            (read-sequence list in)
+            (check (sequence-equal list octets))))
+        (with-open-file (in full-path :element-type 'octet)
+          (let* ((in (make-flexi-stream in :external-format external-format))
+                 (third (floor octet-length 3))
+                 (half (floor octet-length 2))
+                 (vector (make-array half :element-type 'octet)))
+            (check (sequence-equal (loop repeat third
+                                         collect (read-byte in))
+                                   (subseq octets 0 third)))
+            (read-sequence vector in)
+            (check (sequence-equal vector (subseq octets third (+ third half)))))))
+      (with-open-file (in full-path :element-type 'octet)
+        (let* ((in (make-flexi-stream in :external-format external-format))
+               (string (make-string (- string-length 10) :element-type 'flex::char*)))
+          (setf (flexi-stream-element-type in) 'octet)
+          (check (sequence-equal (loop repeat 10
+                                       collect (read-char in))
+                                 (subseq file-string 0 10)))
+          (read-sequence string in)
+          (check (sequence-equal string (subseq file-string 10)))))
+      (with-open-file (in full-path :element-type 'octet)
+        (let* ((in (make-flexi-stream in :external-format external-format))
+               (list (make-list (- string-length 100))))
+          (check (sequence-equal (loop repeat 100
+                                       collect (read-char in))
+                                 (subseq file-string 0 100)))
+          (read-sequence list in)
+          (check (sequence-equal list (subseq file-string 100)))))
+      (with-open-file (in full-path :element-type 'octet)
+        (let* ((in (make-flexi-stream in :external-format external-format))
+               (array (make-array (- string-length 50))))
+          (check (sequence-equal (loop repeat 50
+                                       collect (read-char in))
+                                 (subseq file-string 0 50)))
+          (read-sequence array in)
+          (check (sequence-equal array (subseq file-string 50))))))))
+
 (defmacro using-values ((&rest values) &body body)
   "Executes BODY and feeds an element from VALUES to the USE-VALUE
 restart each time a EXTERNAL-FORMAT-ENCODING-ERROR is signalled.
@@ -456,17 +514,26 @@
          (no-tests (* 8 (length compare-files-args-list))))
     #+:lispworks
     (setq no-tests (* 2 no-tests))
+    #+(or)
     (dolist (*copy-function* '(copy-stream copy-stream*))
       (dolist (args compare-files-args-list)
         (apply 'compare-files args)))
+    #+(or)
     (let ((string-test-args-list (loop for (file-name symbols) in *test-files*
                                        nconc (create-test-combinations file-name symbols t))))
       (incf no-tests (length string-test-args-list))
       (dolist (args string-test-args-list)
         (apply 'string-test args)))
+    (let ((read-sequence-test-args-list (loop for (file-name symbols) in *test-files*
+                                              nconc (create-test-combinations file-name symbols t))))
+      (incf no-tests (length read-sequence-test-args-list))
+      (dolist (args read-sequence-test-args-list)
+        (apply 'read-sequence-test args)))
     (incf no-tests)
+    #+(or)
     (error-handling-test)
     (incf no-tests)
+    #+(or)
     (unread-char-test)
     (format *error-output* "~%~%~:[~A of ~A tests failed..~;~*All ~A tests passed~].~%"
             (= no-tests *test-success-counter*) (- no-tests *test-success-counter*) no-tests)))
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        Author: eweitz
Date: Mon May 19 18:59:07 2008
New Revision: 33
Modified:
   branches/edi/decode.lisp
   branches/edi/encode.lisp
   branches/edi/external-format.lisp
   branches/edi/flexi-streams.asd
   branches/edi/input.lisp
   branches/edi/mapping.lisp
   branches/edi/output.lisp
   branches/edi/stream.lisp
   branches/edi/strings.lisp
   branches/edi/util.lisp
Log:
Better read-sequence implementation
Modified: branches/edi/decode.lisp
==============================================================================
--- branches/edi/decode.lisp	(original)
+++ branches/edi/decode.lisp	Mon May 19 18:59:07 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/decode.lisp,v 1.9 2008/05/19 07:57:07 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/decode.lisp,v 1.12 2008/05/19 22:32:56 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -52,24 +52,23 @@
 (defgeneric octets-to-char-code (format reader)
   (declare #.*standard-optimize-settings*)
   (:documentation "Converts a sequence of octets to a character code
-\(which is returned) using the external format FORMAT.  The sequence
-is obtained by calling the function \(which must be a functional
-object) READER with no arguments which should return one octet per
-call.
+\(which is returned, or NIL in case of EOF) using the external format
+FORMAT.  The sequence is obtained by calling the function \(which must
+be a functional object) READER with no arguments which should return
+one octet per call.  In the case of EOF, READER should return NIL.
 
-The special variables *CURRENT-STREAM* and *CURRENT-UNREADER* must be
-bound correctly whenever this function is called."))
+The special variable *CURRENT-UNREADER* must be bound correctly
+whenever this function is called."))
 
 (defmethod octets-to-char-code ((format flexi-latin-1-format) reader)
   (declare #.*standard-optimize-settings*)
   (declare (function reader))
-  (or (funcall reader) :eof))
+  (funcall reader))
 
 (defmethod octets-to-char-code ((format flexi-ascii-format) reader)
   (declare #.*standard-optimize-settings*)
   (declare (function reader))
-  (let ((octet (or (funcall reader)
-                   (return-from octets-to-char-code :eof))))
+  (when-let (octet (funcall reader))
     (declare (type octet octet))
     (if (> octet 127)
       (recover-from-encoding-error format
@@ -81,15 +80,14 @@
   (declare (function reader))
   (with-accessors ((decoding-table external-format-decoding-table))
       format
-    (let* ((octet (or (funcall reader)
-                      (return-from octets-to-char-code :eof)))
-           (char-code (aref (the (simple-array char-code-integer *) decoding-table) octet)))
+    (when-let (octet (funcall reader))
       (declare (type octet octet))
-      (if (or (null char-code)
-              (= (the char-code-integer char-code) 65533))
-        (recover-from-encoding-error format
-                                     "No character which corresponds to octet #x~X." octet)
-        char-code))))
+      (let ((char-code (aref (the (simple-array char-code-integer *) decoding-table) octet)))
+        (if (or (null char-code)
+                (= (the char-code-integer char-code) 65533))
+          (recover-from-encoding-error format
+                                       "No character which corresponds to octet #x~X." octet)
+          char-code)))))
 
 (defmethod octets-to-char-code ((format flexi-utf-8-format) reader)
   (declare #.*standard-optimize-settings*)
@@ -103,7 +101,7 @@
                                  (return-from octets-to-char-code
                                    (recover-from-encoding-error format
                                                                 "End of data while in UTF-8 sequence.")))
-                                (t (return-from octets-to-char-code :eof))))
+                                (t (return-from octets-to-char-code nil))))
                     (setq first-octet-seen t))))
       (let ((octet (read-next-byte)))
         (declare (type octet octet))
@@ -150,11 +148,12 @@
                                  (return-from octets-to-char-code
                                    (recover-from-encoding-error format
                                                                 "End of data while in UTF-16 sequence.")))
-                                (t (return-from octets-to-char-code :eof))))
+                                (t (return-from octets-to-char-code nil))))
                     (setq first-octet-seen t))))
       (flet ((read-next-word ()
                (+ (the octet (read-next-byte))
                   (ash (the octet (read-next-byte)) 8))))
+        (declare (inline read-next-word))
         (let ((word (read-next-word)))
           (declare (type (unsigned-byte 16) word))
           (cond ((<= #xd800 word #xdfff)
@@ -182,11 +181,12 @@
                                  (return-from octets-to-char-code
                                    (recover-from-encoding-error format
                                                                 "End of data while in UTF-16 sequence.")))
-                                (t (return-from octets-to-char-code :eof))))
+                                (t (return-from octets-to-char-code nil))))
                     (setq first-octet-seen t))))
       (flet ((read-next-word ()
                (+ (ash (the octet (read-next-byte)) 8)
                   (the octet (read-next-byte)))))
+        (declare (inline read-next-word))
         (let ((word (read-next-word)))
           (declare (type (unsigned-byte 16) word))
           (cond ((<= #xd800 word #xdfff)
@@ -214,7 +214,7 @@
                                  (return-from octets-to-char-code
                                    (recover-from-encoding-error format
                                                                 "End of data while in UTF-32 sequence.")))
-                                (t (return-from octets-to-char-code :eof))))
+                                (t (return-from octets-to-char-code nil))))
                     (setq first-octet-seen t))))
       (loop for count of-type fixnum from 0 to 24 by 8
             for octet of-type octet = (read-next-byte)
@@ -232,7 +232,7 @@
                                  (return-from octets-to-char-code
                                    (recover-from-encoding-error format
                                                                 "End of data while in UTF-32 sequence.")))
-                                (t (return-from octets-to-char-code :eof))))
+                                (t (return-from octets-to-char-code nil))))
                     (setq first-octet-seen t))))
       (loop for count of-type fixnum from 24 downto 0 by 8
             for octet of-type octet = (read-next-byte)
@@ -243,7 +243,6 @@
   (let ((char-code (call-next-method)))
     (case char-code
       (#.(char-code #\Return) #.(char-code #\Newline))
-      (:eof :eof)
       (otherwise char-code))))
 
 (defmethod octets-to-char-code ((format flexi-crlf-mixin) reader)
@@ -255,11 +254,12 @@
        (let ((next-char-code (call-next-method)))
          (case next-char-code
            (#.(char-code #\Linefeed) #.(char-code #\Newline))
-           (:eof char-code)
+           ;; we saw a CR but no LF afterwards, but then the data
+           ;; ended, so we just return #\Return
+           ((nil) #.(char-code #\Return))
            ;; if the character we peeked at wasn't a
            ;; linefeed character we unread its constituents
            (otherwise (funcall *current-unreader* (code-char next-char-code))
                       char-code))))
-      (:eof :eof)
-      (t char-code))))
+      (otherwise char-code))))
 
Modified: branches/edi/encode.lisp
==============================================================================
--- branches/edi/encode.lisp	(original)
+++ branches/edi/encode.lisp	Mon May 19 18:59:07 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/encode.lisp,v 1.8 2008/05/19 07:57:07 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/encode.lisp,v 1.10 2008/05/19 22:32:56 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -35,10 +35,7 @@
 using the external format FORMAT.  The conversion is performed by
 calling the unary function \(which must be a functional object) WRITER
 repeatedly each octet.  The return value of this function is
-unspecified.
-
-The special variable *CURRENT-STREAM* must be bound correctly whenever
-this function is called."))
+unspecified."))
 
 (defmethod char-to-octets ((format flexi-latin-1-format) char writer)
   (declare #.*standard-optimize-settings*)
@@ -104,6 +101,7 @@
   (flet ((write-word (word)
            (funcall writer (ldb (byte 8 0) word))
            (funcall writer (ldb (byte 8 8) word))))
+    (declare (inline read-next-word))
     (let ((char-code (char-code char)))
       (declare (type char-code-integer char-code))
       (cond ((< char-code #x10000)
@@ -118,6 +116,7 @@
   (flet ((write-word (word)
            (funcall writer (ldb (byte 8 8) word))
            (funcall writer (ldb (byte 8 0) word))))
+    (declare (inline read-next-word))
     (let ((char-code (char-code char)))
       (declare (type char-code-integer char-code))
       (cond ((< char-code #x10000)
Modified: branches/edi/external-format.lisp
==============================================================================
--- branches/edi/external-format.lisp	(original)
+++ branches/edi/external-format.lisp	Mon May 19 18:59:07 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/external-format.lisp,v 1.18 2008/05/18 15:54:34 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/external-format.lisp,v 1.19 2008/05/19 11:20:11 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -390,8 +390,8 @@
   (:documentation "Given an external format FORMAT, returns a factor
 which denotes the octets to characters ratio to expect when
 encoding/decoding.  If the returned value is an integer, the factor is
-assumed to be exact.  If it is a float, the factor is supposed to be
-based on heuristics and usually not exact.
+assumed to be exact.  If it is a \(double) float, the factor is
+supposed to be based on heuristics and usually not exact.
 
 This factor is used in string.lisp.")
   (declare #.*standard-optimize-settings*))
@@ -407,7 +407,7 @@
   ;; UTF-8 characters can be anything from one to six octets, but we
   ;; assume that the "overhead" is only about 5 percent - this
   ;; estimate is obviously very much dependant on the content
-  1.05)
+  1.05d0)
 
 (defmethod encoding-factor ((format flexi-utf-16-format))
   (declare #.*standard-optimize-settings*)
@@ -415,7 +415,7 @@
   ;; code points above #x10000 map to four octets - we assume that we
   ;; usually don't see these characters but of course have to return a
   ;; float
-  2.0)
+  2.0d0)
 
 (defmethod encoding-factor ((format flexi-utf-32-format))
   (declare #.*standard-optimize-settings*)
@@ -427,4 +427,4 @@
   ;; if the sequence #\Return #\Linefeed is the line-end marker, this
   ;; obviously makes encodings potentially longer and definitely makes
   ;; the estimate unexact
-  (* 1.02 (call-next-method)))
\ No newline at end of file
+  (* 1.02d0 (call-next-method)))
Modified: branches/edi/flexi-streams.asd
==============================================================================
--- branches/edi/flexi-streams.asd	(original)
+++ branches/edi/flexi-streams.asd	Mon May 19 18:59:07 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/flexi-streams.asd,v 1.62 2008/05/18 20:34:52 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/flexi-streams.asd,v 1.63 2008/05/18 23:13:59 edi Exp $
 
 ;;; Copyright (c) 2005-2007, Dr. Edmund Weitz.  All rights reserved.
 
@@ -39,8 +39,8 @@
   :serial t
   :components ((:file "packages")
                (:file "mapping")
-	       (:file "ascii")
-	       (:file "koi8-r")
+               (:file "ascii")
+               (:file "koi8-r")
                (:file "iso-8859")
                (:file "code-pages")
                (:file "specials")
Modified: branches/edi/input.lisp
==============================================================================
--- branches/edi/input.lisp	(original)
+++ branches/edi/input.lisp	Mon May 19 18:59:07 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/input.lisp,v 1.60 2008/05/19 07:57:07 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/input.lisp,v 1.65 2008/05/19 22:54:10 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -34,7 +34,7 @@
   "Reads one byte \(octet) from the underlying stream of
 FLEXI-OUTPUT-STREAM \(or from the internal stack if it's not
 empty)."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   ;; we're using S instead of STREAM here because of an
   ;; issue with SBCL:
   ;; <http://article.gmane.org/gmane.lisp.steel-bank.general/1386>
@@ -58,7 +58,7 @@
   "Reads one byte \(octet) from the underlying stream of
 FLEXI-OUTPUT-STREAM \(or from the internal stack if it's not
 empty)."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((position flexi-stream-position)
                    (bound flexi-stream-bound)
                    (octet-stack flexi-stream-octet-stack)
@@ -85,7 +85,7 @@
 FLEXI-OUTPUT-STREAM \(or from the internal stack if it's not empty).
 Optimized version \(only needed for LispWorks) in case the underlying
 stream is binary."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((position flexi-stream-position)
                    (bound flexi-stream-bound)
                    (octet-stack flexi-stream-octet-stack)
@@ -104,7 +104,7 @@
 (defmethod stream-clear-input ((flexi-input-stream flexi-input-stream))
   "Calls the corresponding method for the underlying input stream
 and also clears the value of the OCTET-STACK slot."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   ;; note that we don't reset the POSITION slot
   (with-accessors ((octet-stack flexi-stream-octet-stack)
                    (stream flexi-stream-stream))
@@ -116,12 +116,14 @@
   "Calls the corresponding method for the underlying input stream
 but first checks if \(old) input is available in the OCTET-STACK
 slot."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((position flexi-stream-position)
                    (bound flexi-stream-bound)
                    (octet-stack flexi-stream-octet-stack)
                    (stream flexi-stream-stream))
       flexi-input-stream
+    (declare (integer position)
+             (type (or null integer) bound))
     (when (and bound
                (>= position bound))
       (return-from stream-listen nil))
@@ -129,7 +131,7 @@
 
 (defmethod stream-read-byte ((stream flexi-input-stream))
   "Reads one byte \(octet) from the underlying stream."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   ;; set LAST-CHAR-CODE slot to NIL because we can't UNREAD-CHAR after
   ;; this operation
   (with-accessors ((last-char-code flexi-stream-last-char-code)
@@ -144,6 +146,7 @@
   "Used internally to put a character CHAR which was already read back
 on the stream.  Uses the OCTET-STACK slot and decrements the POSITION
 slot accordingly."
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((position flexi-stream-position)
                    (octet-stack flexi-stream-octet-stack)
                    (external-format flexi-stream-external-format))
@@ -151,16 +154,16 @@
     (let ((counter 0) octets-reversed)
       (declare (integer position)
                (fixnum counter))
-      (char-to-octets external-format
-                      char
-                      (lambda (octet)
-                        (incf counter)
-                        (push octet octets-reversed)))
-      (decf position counter)
-      (setq octet-stack (nreconc octets-reversed octet-stack)))))
+      (flet ((writer (octet)
+               (incf counter)
+               (push octet octets-reversed)))
+        (declare (dynamic-extent (function writer)))
+        (char-to-octets external-format char #'writer)
+        (decf position counter)
+        (setq octet-stack (nreconc octets-reversed octet-stack))))))
 
 (defmethod stream-read-char ((stream flexi-input-stream))
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   ;; note that we do nothing for the :LF EOL style because we assume
   ;; that #\Newline is the same as #\Linefeed in all Lisps which will
   ;; use this library
@@ -171,67 +174,148 @@
     ;; set LAST-OCTET slot to NIL because we can't UNREAD-BYTE after
     ;; this operation
     (setq last-octet nil)
-    (let* ((*current-unreader* (lambda (char)
-                                 (unread-char% char stream)))
-           (char-code (octets-to-char-code external-format
-                                           (lambda ()
-                                             (read-byte* stream)))))
-      ;; remember this character and its char code for UNREAD-CHAR
-      (setq last-char-code char-code)
-      (or (code-char char-code) char-code))))
+    (flet ((reader ()
+             (read-byte* stream))
+           (unreader (char)
+             (unread-char% char stream)))
+      (declare (dynamic-extent (function reader) (function unreader)))
+      (let* ((*current-unreader* #'unreader)
+             (char-code (or (octets-to-char-code external-format #'reader)
+                            (return-from stream-read-char :eof))))
+        ;; remember this character and its char code for UNREAD-CHAR
+        (setq last-char-code char-code)
+        (or (code-char char-code) char-code)))))
 
 (defmethod stream-read-char-no-hang ((stream flexi-input-stream))
   "Reads one character if the underlying stream has at least one
 octet available."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   ;; note that this may block for non-8-bit encodings - I think
   ;; there's no easy way to handle this correctly
   (and (stream-listen stream)
        (stream-read-char stream)))
 
 (defmethod stream-read-sequence ((flexi-input-stream flexi-input-stream) sequence start end &key)
-  "Reads enough input from STREAM to fill SEQUENCE from START to END.
-If SEQUENCE is an array which can store octets we use READ-SEQUENCE to
-fill it in one fell swoop, otherwise we iterate using
-STREAM-READ-CHAR."
-  (declare (optimize speed)
-           (type (integer 0 *) start end))
-  (with-accessors ((last-char-code flexi-stream-last-char-code)
+  (declare #.*standard-optimize-settings*)
+  (declare (fixnum start end))
+  (with-accessors ((position flexi-stream-position)
+                   (bound flexi-stream-bound)
+                   (octet-stack flexi-stream-octet-stack)
+                   (external-format flexi-stream-external-format)
                    (last-octet flexi-stream-last-octet)
-                   (stream flexi-stream-stream)
-                   (position flexi-stream-position)
-                   (octet-stack flexi-stream-octet-stack))
+                   (last-char-code flexi-stream-last-char-code)
+                   (element-type flexi-stream-element-type)
+                   (stream flexi-stream-stream))
       flexi-input-stream
-    (declare (integer position))
-    (cond ((and (arrayp sequence)
-                (subtypep 'octet (array-element-type sequence)))
-           (setf last-char-code nil)
-           (let ((cursor start))
-             (loop with stack = octet-stack
-                   for continuep = (< cursor end)
-                   for octet = (and continuep (pop stack))
-                   while octet
-                   do (setf (aref sequence cursor) (the octet octet))
-                   (incf cursor))
-             (let ((index
-                    (read-sequence sequence stream :start cursor :end end)))
-               (incf position (- index start))
-               (when (> index start)
-                 (setq last-octet (aref sequence (1- index))))
-               index)))
-          (t
-           (loop for index from start below end
-                 for element = (stream-read-char flexi-input-stream)
-                 until (eq element :eof)
-                 do (setf (elt sequence index) element)
-                 finally (return index))))))
+    (let ((buffer (make-octet-buffer))
+          (buffer-pos 0)
+          (buffer-end 0)
+          (index start))
+      (declare (fixnum buffer-pos buffer-end index)
+               (type (array octet *) buffer))
+      (flet ((compute-minimum ()
+               "Computes the minimum amount of octets we can savely
+read into the buffer without violating the stream's bound \(if there
+is one) and without potentially reading more than we need."
+               ;; this has to be done conservatively, unfortunately -
+               ;; it is possible that we only fill the buffer in very
+               ;; small chunks once we're near END (but this is only
+               ;; relevant for multi-byte encodings, of course)
+               (let ((minimum (min (the fixnum (- end index)) +buffer-size+)))
+                 (cond (bound (min minimum (- bound position)))
+                       (t minimum))))
+             (fill-buffer (end)
+               "Tries to fill the buffer from BUFFER-POS to END and
+returns NIL if the buffer doesn't contain any new data."
+               (setq buffer-end (read-sequence buffer stream
+                                               :start buffer-pos
+                                               :end end))
+               ;; BUFFER-POS is only greater than zero if the buffer
+               ;; already contains unread data from the octet stack
+               ;; (see below), so we test for ZEROP here and do /not/
+               ;; compare with BUFFER-POS
+               (unless (zerop buffer-end)
+                 (incf position buffer-end))))
+        (let ((minimum (compute-minimum)))
+          (declare (fixnum minimum))
+          ;; put data from octet stack into buffer if there is any
+          (loop
+           (when (>= buffer-pos minimum)
+             (return))
+           (let ((next-octet (pop octet-stack)))
+             (cond (next-octet
+                    (setf (aref buffer buffer-pos) (the octet next-octet))
+                    (incf buffer-pos))
+                   (t (return)))))
+          ;; fill buffer for the first time or return immediately if
+          ;; we don't succeed
+          (unless (fill-buffer minimum)
+            (return-from stream-read-sequence start)))
+        (setq buffer-pos 0)
+        (flet ((next-octet ()
+                 "Returns the next octet from the buffer and fills it
+if it is exhausted.  Returns NIL if there's no more data on the
+stream."
+                 (when (>= buffer-pos buffer-end)
+                   (setq buffer-pos 0)
+                   (unless (fill-buffer (compute-minimum))
+                     (return-from next-octet)))
+                 (prog1
+                     (aref buffer buffer-pos)
+                   (incf buffer-pos)))
+               (unreader (char)
+                 (unread-char% char flexi-input-stream)))
+          (declare (dynamic-extent (function next-octet) (function unreader)))
+          (let ((*current-unreader* #'unreader))
+            (macrolet ((iterate (octetp set-place)
+                         "A very unhygienic macro to implement the
+actual iteration through the sequence including housekeeping for the
+flexi stream.  If OCTETP is true, we put octets into the stream,
+otherwise characters.  SET-PLACE is the place \(using the index INDEX)
+used to access the sequence."
+                         `(flet ((leave ()
+                                   "This is the function used to abort
+the LOOP iteration below."
+                                   (when (> index start)
+                                     ;; if something was read at all,
+                                     ;; update LAST-OCTET and
+                                     ;; LAST-CHAR-CODE accordingly
+                                     (setq ,(if octetp 'last-char-code 'last-octet)
+                                           nil
+                                           ,(if octetp 'last-octet 'last-char-code)
+                                           ,(sublis '((index . (1- index))) set-place)))
+                                   (return-from stream-read-sequence index)))
+                            (loop
+                             (when (>= index end) (leave))
+                             (let ((next-thing ,(if octetp
+                                                  '(next-octet)
+                                                  '(octets-to-char-code external-format #'next-octet))))
+                               (unless next-thing (leave))
+                               (setf ,set-place ,(if octetp 'next-thing '(code-char next-thing)))
+                               (incf index))))))
+              (etypecase sequence
+                (string (iterate nil (char sequence index)))
+                (array
+                 (let ((array-element-type (array-element-type sequence)))
+                   (cond ((type-equal array-element-type 'octet)
+                          (iterate t (aref (the (array octet *) sequence) index)))
+                         ((or (subtypep array-element-type 'integer)
+                              (type-equal element-type 'octet))
+                          (iterate t (aref sequence index)))
+                         (t
+                          (iterate nil (aref sequence index))))))
+                (list
+                 (cond ((type-equal element-type 'octet)                        
+                        (iterate t (nth index sequence)))
+                       (t
+                        (iterate nil (nth index sequence)))))))))))))
 
 (defmethod stream-unread-char ((stream flexi-input-stream) char)
   "Implements UNREAD-CHAR for streams of type FLEXI-INPUT-STREAM.
 Makes sure CHAR will only be unread if it was the last character
 read and if it was read with the same encoding that's currently
 being used by the stream."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((last-char-code flexi-stream-last-char-code))
       stream
     (unless last-char-code
@@ -249,7 +333,7 @@
   "Similar to UNREAD-CHAR in that it `unreads' the last octet from
 STREAM.  Note that you can only call UNREAD-BYTE after a corresponding
 READ-BYTE."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((last-octet flexi-stream-last-octet)
                    (octet-stack flexi-stream-octet-stack)
                    (position flexi-stream-position))
@@ -274,7 +358,7 @@
 not 0 is returned, if PEEK-TYPE is an octet, the next octet which
 equals PEEK-TYPE is returned.  EOF-ERROR-P and EOF-VALUE are
 interpreted as usual."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (loop for octet = (read-byte flexi-input-stream eof-error-p eof-value)
         until (cond ((null peek-type))
                     ((eql octet eof-value))
Modified: branches/edi/mapping.lisp
==============================================================================
--- branches/edi/mapping.lisp	(original)
+++ branches/edi/mapping.lisp	Mon May 19 18:59:07 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/util.lisp,v 1.15 2008/05/18 15:54:34 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/mapping.lisp,v 1.1 2008/05/19 09:09:15 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
Modified: branches/edi/output.lisp
==============================================================================
--- branches/edi/output.lisp	(original)
+++ branches/edi/output.lisp	Mon May 19 18:59:07 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/output.lisp,v 1.50 2008/05/19 07:57:07 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/output.lisp,v 1.52 2008/05/19 22:32:56 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -36,14 +36,14 @@
 
 #-:lispworks
 (defmethod write-byte* (byte (sink flexi-output-stream))  
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((stream flexi-stream-stream))
       sink
     (write-byte byte stream)))
 
 #+:lispworks
 (defmethod write-byte* (byte (sink flexi-output-stream))
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   ;; we use WRITE-SEQUENCE because WRITE-BYTE doesn't work with all
   ;; bivalent streams in LispWorks (4.4.6)
   (with-accessors ((stream flexi-stream-stream))
@@ -57,22 +57,22 @@
 (defmethod write-byte* (byte (sink flexi-binary-output-stream))
   "Optimized version \(only needed for LispWorks) in case the
 underlying stream is binary."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((stream flexi-stream-stream))
       sink
     (write-byte byte stream)))
 
 (defmethod stream-write-char ((stream flexi-output-stream) char)
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((external-format flexi-stream-external-format))
       stream
-    (char-to-octets external-format
-                    char
-                    (lambda (octet)
-                      (write-byte* octet stream)))))
+    (flet ((writer (octet)
+             (write-byte* octet stream)))
+      (declare (dynamic-extent (function writer)))
+      (char-to-octets external-format char #'writer))))
 
 (defmethod stream-write-char :after ((stream flexi-output-stream) char)
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   ;; update the column unless we're in the middle of the line and
   ;; the current value is NIL
   (with-accessors ((column flexi-stream-column))
@@ -83,7 +83,7 @@
 (defmethod stream-clear-output ((flexi-output-stream flexi-output-stream))
   "Simply calls the corresponding method for the underlying
 output stream."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((stream flexi-stream-stream))
       flexi-output-stream
     (clear-output stream)))
@@ -91,7 +91,7 @@
 (defmethod stream-finish-output ((flexi-output-stream flexi-output-stream))
   "Simply calls the corresponding method for the underlying
 output stream."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((stream flexi-stream-stream))
       flexi-output-stream
     (finish-output stream)))
@@ -99,7 +99,7 @@
 (defmethod stream-force-output ((flexi-output-stream flexi-output-stream))
   "Simply calls the corresponding method for the underlying
 output stream."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((stream flexi-stream-stream))
       flexi-output-stream
     (force-output stream)))
@@ -107,14 +107,14 @@
 (defmethod stream-line-column ((flexi-output-stream flexi-output-stream))
   "Returns the column stored in the COLUMN slot of the
 FLEXI-OUTPUT-STREAM object STREAM."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((column flexi-stream-column))
       flexi-output-stream
     column))
 
 (defmethod stream-write-byte ((flexi-output-stream flexi-output-stream) byte)
   "Writes a byte \(octet) to the underlying stream."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   (with-accessors ((column flexi-stream-column))
       flexi-output-stream
     ;; set column to NIL because we don't know how to handle binary
@@ -125,7 +125,7 @@
 #+:allegro
 (defmethod stream-terpri ((stream flexi-output-stream))
   "Writes a #\Newline character to the underlying stream."
-  (declare (optimize speed))
+  (declare #.*standard-optimize-settings*)
   ;; needed for AllegroCL - grrr...
   (stream-write-char stream #\Newline))
 
@@ -135,8 +135,8 @@
 characters.  Characters are output according to the current
 encoding \(external format) of the FLEXI-OUTPUT-STREAM object
 STREAM."
-  (declare (optimize speed)
-           (type (integer 0 *) start end))
+  (declare #.*standard-optimize-settings*)
+  (declare (fixnum start end))
   (with-accessors ((stream flexi-stream-stream)
                    (column flexi-stream-column))
       flexi-output-stream
@@ -158,8 +158,8 @@
   "Optimized method for the cases where SEQUENCE is a string.  Fills
 an internal buffer and uses repeated calls to WRITE-SEQUENCE to write
 to the underlying stream."
-  (declare (optimize speed)
-           (type (integer 0 *) start end))
+  (declare #.*standard-optimize-settings*)
+  (declare (fixnum start end))
   ;; don't use this optimized method for bivalent character streams on
   ;; LispWorks, as it currently gets confused by the fill pointer
   #+:lispworks
@@ -194,4 +194,5 @@
 (defmethod stream-write-string ((stream flexi-output-stream) string
                                 &optional (start 0) (end (length string)))
   "Simply hands over to the optimized method for STREAM-WRITE-SEQUENCE."
+  (declare #.*standard-optimize-settings*)
   (stream-write-sequence stream string start (or end (length string))))
Modified: branches/edi/stream.lisp
==============================================================================
--- branches/edi/stream.lisp	(original)
+++ branches/edi/stream.lisp	Mon May 19 18:59:07 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/stream.lisp,v 1.60 2008/05/18 23:14:00 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/stream.lisp,v 1.61 2008/05/19 22:32:56 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -74,7 +74,7 @@
   "Checks whether the new value makes sense before it is set."
   (declare #.*standard-optimize-settings*)
   (unless (or (subtypep new-value 'character)
-              (subtypep new-value 'octet))
+              (type-equal new-value 'octet))
     (error 'flexi-stream-element-type-error
            :element-type new-value
            :stream flexi-stream)))
Modified: branches/edi/strings.lisp
==============================================================================
--- branches/edi/strings.lisp	(original)
+++ branches/edi/strings.lisp	Mon May 19 18:59:07 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/strings.lisp,v 1.14 2008/05/19 07:57:08 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/strings.lisp,v 1.19 2008/05/19 22:32:56 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -39,32 +39,52 @@
   (setq external-format (maybe-convert-external-format external-format))
   (let ((factor (encoding-factor external-format))
         (length (- end start)))
+    (declare (fixnum length))
     (etypecase factor
-      (float
-       (let ((octets (make-array (round (* factor length))
-                                 :element-type 'octet
-                                 :fill-pointer 0
-                                 :adjustable t)))
-         (flet ((writer (octet)
-                  ;; TODO: do this manually
-                  (vector-push-extend octet octets)))
-           (loop for i of-type fixnum from start below end
-                 do (char-to-octets external-format
-                                    (char string i)
-                                    #'writer)))
-         octets))
       (integer
        (let ((octets (make-array (* factor length) :element-type 'octet))
              (j 0))
          (declare (fixnum j))
          (flet ((writer (octet)
+                  (declare (octet octet))
                   (setf (aref (the (array octet *) octets) j) octet)
                   (incf j)))
+           (declare (dynamic-extent (function writer)))
            (loop for i of-type fixnum from start below end do
                  (char-to-octets external-format
                                  (char string i)
                                  #'writer)))
-         octets)))))
+         octets))
+      (double-float
+       ;; this is a bit clunky but hopefully a bit more efficient than
+       ;; using VECTOR-PUSH-EXTEND
+       (let* ((octets-length (ceiling (* factor length)))
+              (octets (make-array octets-length
+                                  :element-type 'octet
+                                  :fill-pointer t
+                                  :adjustable t))
+              (i start)
+              (j 0))
+         (declare (fixnum i j octets-length)
+                  (double-float factor))
+         (flet ((writer (octet)
+                  (declare (octet octet))
+                  (when (>= j octets-length)
+                    (setq factor (* factor 2.0d0))
+                    (incf octets-length (the fixnum (ceiling (* factor (- end i)))))
+                    (adjust-array octets octets-length :fill-pointer t))
+                  (setf (aref (the (array octet *) octets) j) octet)
+                  (incf j)))
+           (declare (dynamic-extent (function writer)))
+           (loop
+            (when (>= i end)
+              (return))
+            (char-to-octets external-format
+                            (char string i)
+                            #'writer)
+            (incf i))
+           (setf (fill-pointer octets) j)
+           octets))))))
 
 (defun octets-to-string (sequence &key
                                   (external-format (make-external-format :latin1))
@@ -80,51 +100,61 @@
          (reader (etypecase sequence
                    ((array octet *)
                     (lambda ()
-                      (when (>= i end)
-                        ;; TODO... -> NIL?
-                        (error "End of data."))
-                      (prog1
-                          (aref (the (array octet *) sequence) i)
-                        (incf i))))
+                      (and (< i end)
+                           (prog1
+                               (aref (the (array octet *) sequence) i)
+                             (incf i)))))
                    ((array * *)
                     (lambda ()
-                      (when (>= i end)
-                        ;; TODO...
-                        (error "End of data."))
-                      (prog1
-                          (aref sequence i)
-                        (incf i))))
+                      (and (< i end)
+                           (prog1
+                               (aref sequence i)
+                             (incf i)))))
                    (list
                     (lambda ()
-                      (when (>= i end)
-                        ;; TODO...
-                        (error "End of data."))
-                      (prog1
-                          (nth i sequence)
-                        (incf i))))))
-         (*current-unreader* (flet ((pseudo-writer (octet)
-                                      (declare (ignore octet))
-                                      (decf i)))
-                               (lambda (char)
-                                 (char-to-octets external-format char #'pseudo-writer)))))
-    (declare (fixnum i))
-    (flet ((next-char ()
-             (code-char (octets-to-char-code external-format reader))))
-      (etypecase factor
-        (float
-         (let ((string (make-array (round (/ length factor))
-                                   :element-type 'char*
-                                   :fill-pointer 0
-                                   :adjustable t)))
-           (loop while (< i end)
-                 ;; TODO: do this manually
-                 do (vector-push-extend (next-char) string)
-                 finally (return string))))
-        (integer
-         (let* ((string-length (/ length factor))
-                (string (make-array string-length
-                                    :element-type 'char*)))
-           (declare (fixnum string-length))
-           (loop for j of-type fixnum from 0 below string-length
-                 do (setf (schar string j) (next-char))
-                 finally (return string))))))))
+                      (and (< i end)
+                           (prog1
+                               (nth i sequence)
+                             (incf i))))))))
+    (declare (fixnum i length) (dynamic-extent reader))
+    (labels ((pseudo-writer (octet)
+               (declare (ignore octet))
+               (decf i))
+             (unreader (char)
+               (char-to-octets external-format char #'pseudo-writer)))
+      (declare (dynamic-extent (function pseudo-writer) (function unreader)))
+      (let ((*current-unreader* #'unreader))
+        (flet ((next-char ()
+                 (code-char (octets-to-char-code external-format reader))))
+          (declare (inline next-char))
+          (etypecase factor
+            (integer
+             (let* ((string-length (/ length factor))
+                    (string (make-array string-length
+                                        :element-type 'char*)))
+               (declare (fixnum string-length))
+               (loop for j of-type fixnum from 0 below string-length
+                     do (setf (schar string j) (next-char))
+                     finally (return string))))
+            (double-float
+             ;; this is a bit clunky but hopefully a bit more efficient than
+             ;; using VECTOR-PUSH-EXTEND
+             (let* ((string-length (ceiling length (the double-float factor)))
+                    (string (make-array string-length
+                                        :element-type 'char*
+                                        :fill-pointer t
+                                        :adjustable t))
+                    (j 0))
+               (declare (fixnum j string-length)
+                        (double-float factor))
+               (loop
+                (when (>= i end)
+                  (return))
+                (when (>= j string-length)
+                  (setq factor (/ factor 2.0d0))
+                  (incf string-length (the fixnum (ceiling (- end i) factor)))
+                  (adjust-array string string-length :fill-pointer t))
+                (setf (char string j) (next-char))
+                (incf j))
+               (setf (fill-pointer string) j)
+               string))))))))
Modified: branches/edi/util.lisp
==============================================================================
--- branches/edi/util.lisp	(original)
+++ branches/edi/util.lisp	Mon May 19 18:59:07 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/util.lisp,v 1.17 2008/05/19 07:57:08 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/util.lisp,v 1.19 2008/05/19 22:32:57 edi Exp $
 
 ;;; Copyright (c) 2005-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -31,7 +31,14 @@
 
 #+:lispworks
 (eval-when (:compile-toplevel :load-toplevel :execute)
-  (import 'lw:with-unique-names))
+  (import '(lw:with-unique-names lw:when-let)))
+
+#-:lispworks
+(defmacro when-let ((var form) &body body)
+  "Evaluates FORM and binds VAR to the result, then executes BODY
+if VAR has a true value."
+  `(let ((,var ,form))
+     (when ,var ,@body)))
 
 #-:lispworks
 (defmacro with-unique-names ((&rest bindings) &body body)
@@ -167,4 +174,14 @@
   ;; slots
   `(with-slots ,(mapcar #'car slot-entries)
        ,instance
-     ,@body))
\ No newline at end of file
+     ,@body))
+
+(defun make-octet-buffer ()
+  "Creates and returns a fresh buffer \(a specialized array) of size
++BUFFER-SIZE+ to hold octets."
+  (make-array +buffer-size+ :element-type 'octet))
+
+(defun type-equal (type1 type2)
+  "Whether TYPE1 and TYPE2 denote the same type."
+  (and (subtypep type1 type2)
+       (subtypep type2 type1)))
\ No newline at end of file
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        Author: eweitz
Date: Mon May 19 15:47:40 2008
New Revision: 32
Modified:
   branches/edi/test/test.lisp
Log:
More tests
Modified: branches/edi/test/test.lisp
==============================================================================
--- branches/edi/test/test.lisp	(original)
+++ branches/edi/test/test.lisp	Mon May 19 15:47:40 2008
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: FLEXI-STREAMS-TEST; Base: 10 -*-
-;;; $Header: /usr/local/cvsrep/flexi-streams/test/test.lisp,v 1.25 2008/05/19 07:57:12 edi Exp $
+;;; $Header: /usr/local/cvsrep/flexi-streams/test/test.lisp,v 1.27 2008/05/19 19:47:17 edi Exp $
 
 ;;; Copyright (c) 2006-2008, Dr. Edmund Weitz.  All rights reserved.
 
@@ -29,6 +29,13 @@
 
 (in-package :flexi-streams-test)
 
+(defconstant +buffer-size+ 8192
+  "Size of buffers for COPY-STREAM* below.")
+
+(defvar *copy-function* nil
+  "Which function to use when copying from one stream to the other -
+see for example COPY-FILE below.")
+
 (defvar *this-file* (load-time-value
                      (or #.*compile-file-pathname* *load-pathname*))
   "The pathname of the file \(`test.lisp') where this variable was
@@ -125,6 +132,17 @@
           while line
           do (write-line line out))))
 
+(defun copy-stream* (stream-in external-format-in stream-out external-format-out)
+  "Like COPY-STREAM, but uses READ-SEQUENCE and WRITE-SEQUENCE instead
+of READ-LINE and WRITE-LINE."
+  (let ((in (make-flexi-stream stream-in :external-format external-format-in))
+        (out (make-flexi-stream stream-out :external-format external-format-out))
+        (buffer (make-array +buffer-size+ :element-type 'flex::char*)))
+    (loop
+     (let ((position (read-sequence buffer in)))
+       (when (zerop position) (return))
+       (write-sequence buffer out :end position)))))
+
 (defun copy-file (path-in external-format-in path-out external-format-out direction-out direction-in)
   "Copies the contents of the file denoted by the pathname
 PATH-IN to the file denoted by the pathname PATH-OUT using flexi
@@ -143,7 +161,7 @@
                          :direction direction-out
                          :if-does-not-exist :create
                          :if-exists :supersede)
-      (copy-stream in external-format-in out external-format-out))))
+      (funcall *copy-function* in external-format-in out external-format-out))))
 
 #+:lispworks
 (defun copy-file-lw (path-in external-format-in path-out external-format-out direction-out direction-in)
@@ -162,7 +180,7 @@
                          :direction :output
                          :if-does-not-exist :create
                          :if-exists :supersede)
-      (copy-stream in external-format-in out external-format-out))))
+      (funcall *copy-function* in external-format-in out external-format-out))))
 
 (defun compare-files (path-in external-format-in path-out external-format-out)
   "Copies the contents of the file (in the `test') denoted by the
@@ -179,7 +197,8 @@
         (full-path-orig (merge-pathnames path-out *this-file*)))
     (dolist (direction-out '(:output :io))
       (dolist (direction-in '(:input :io))
-        (format *error-output* "Test ~S ~S [~A]~% --> ~S [~A].~%" path-in
+        (format *error-output* "Test \(using ~A) ~S ~S [~A]~% --> ~S [~A].~%"
+                *copy-function* path-in
                 (flex::normalize-external-format external-format-in) direction-in
                 (flex::normalize-external-format external-format-out) direction-out)
         (copy-file full-path-in external-format-in
@@ -190,7 +209,8 @@
               (t (format *error-output* " Test failed!!!~%")))
         (terpri *error-output*)
         #+:lispworks
-        (format *error-output* "LW-Test ~S ~S [~A]~%    --> ~S [~A].~%" path-in
+        (format *error-output* "LW-Test \(using ~A) ~S ~S [~A]~%    --> ~S [~A].~%"
+                *copy-function* path-in
                 (flex::normalize-external-format external-format-in) direction-in
                 (flex::normalize-external-format external-format-out) direction-out)
         #+:lispworks
@@ -331,6 +351,10 @@
     (setq in (make-flexi-stream in :external-format external-format))
     (read-line in)))
 
+(defun read-flexi-line* (sequence external-format)
+  "Like READ-FLEXI-LINE but uses OCTETS-TO-STRING internally."
+  (octets-to-string sequence :external-format external-format))
+
 (defun error-handling-test ()
   "Tests several possible errors and how they are handled."
   (with-test ("Handling of errors.")
@@ -340,45 +364,71 @@
     (let ((*substitution-char* #\?))
       ;; :ASCII doesn't have characters with char codes > 127
       (check (string= "a??" (read-flexi-line `(,(char-code #\a) 128 200) :ascii)))
+      (check (string= "a??" (read-flexi-line* `#(,(char-code #\a) 128 200) :ascii)))
       ;; :WINDOWS-1253 doesn't have a characters with codes 170 and 210
       (check (string= "a??" (read-flexi-line `(,(char-code #\a) 170 210) :windows-1253)))
+      (check (string= "a??" (read-flexi-line* `#(,(char-code #\a) 170 210) :windows-1253)))
       ;; not a valid UTF-8 sequence
-      (check (string= "??" (read-flexi-line `(#xe4 #xf6 #xfc) :utf8)))
+      (check (string= "??" (read-flexi-line '(#xe4 #xf6 #xfc) :utf8)))
+      (check (string= "??" (read-flexi-line* #(#xe4 #xf6 #xfc) :utf8)))
       ;; UTF-8 can't start neither with #b11111110 nor with #b11111111
-      (check (string= "??" (read-flexi-line `(#b11111110 #b11111111) :utf8))))
+      (check (string= "??" (read-flexi-line '(#b11111110 #b11111111) :utf8)))
+      (check (string= "??" (read-flexi-line* #(#b11111110 #b11111111) :utf8))))
     (let ((*substitution-char* nil))
       ;; :ASCII doesn't have characters with char codes > 127
       (check (string= "abc" (using-values (#\b #\c)
                               (read-flexi-line `(,(char-code #\a) 128 200) :ascii))))
+      (check (string= "abc" (using-values (#\b #\c)
+                              (read-flexi-line* `#(,(char-code #\a) 128 200) :ascii))))
       ;; :WINDOWS-1253 encoding doesn't have a characters with codes 170 and 210
       (check (string= "axy" (using-values (#\x #\y)
                               (read-flexi-line `(,(char-code #\a) 170 210) :windows-1253))))
+      (check (string= "axy" (using-values (#\x #\y)
+                              (read-flexi-line* `#(,(char-code #\a) 170 210) :windows-1253))))
       ;; not a valid UTF-8 sequence
-      (check (string= "QW" (using-values (#\Q #\W) (read-flexi-line `(#xe4 #xf6 #xfc) :utf8))))
+      (check (string= "QW" (using-values (#\Q #\W) (read-flexi-line '(#xe4 #xf6 #xfc) :utf8))))
+      (check (string= "QW" (using-values (#\Q #\W) (read-flexi-line* #(#xe4 #xf6 #xfc) :utf8))))
       ;; UTF-8 can't start neither with #b11111110 nor with #b11111111
-      (check (string= "QW" (using-values (#\Q #\W) (read-flexi-line `(#b11111110 #b11111111) :utf8))))
+      (check (string= "QW" (using-values (#\Q #\W) (read-flexi-line '(#b11111110 #b11111111) :utf8))))
+      (check (string= "QW" (using-values (#\Q #\W) (read-flexi-line* #(#b11111110 #b11111111) :utf8))))
       ;; only one byte
-      (check (string= "E" (using-values (#\E) (read-flexi-line `(#x01) :utf-16le))))
+      (check (string= "E" (using-values (#\E) (read-flexi-line '(#x01) :utf-16le))))
+      (check (string= "E" (using-values (#\E) (read-flexi-line* #(#x01) :utf-16le))))
       ;; two bytes, but value of resulting word suggests that another word follows
-      (check (string= "R" (using-values (#\R) (read-flexi-line `(#x01 #xd8) :utf-16le))))
+      (check (string= "R" (using-values (#\R) (read-flexi-line '(#x01 #xd8) :utf-16le))))
+      (check (string= "R" (using-values (#\R) (read-flexi-line* #(#x01 #xd8) :utf-16le))))
       ;; the second word must fit into the [#xdc00; #xdfff] interval, but it is #xdbff
-      (check (string= "T" (using-values (#\T) (read-flexi-line `(#x01 #xd8 #xff #xdb) :utf-16le))))
+      (check (string= "T" (using-values (#\T) (read-flexi-line '(#x01 #xd8 #xff #xdb) :utf-16le))))
+      (check (string= "T" (using-values (#\T) (read-flexi-line* #(#x01 #xd8 #xff #xdb) :utf-16le))))
       ;; the same as for little endian above, but using inverse order of bytes in words
-      (check (string= "E" (using-values (#\E) (read-flexi-line `(#x01) :utf-16be))))
-      (check (string= "R" (using-values (#\R) (read-flexi-line `(#xd8 #x01) :utf-16be))))
-      (check (string= "T" (using-values (#\T) (read-flexi-line `(#xd8 #x01 #xdb #xff) :utf-16be))))
+      (check (string= "E" (using-values (#\E) (read-flexi-line '(#x01) :utf-16be))))
+      (check (string= "R" (using-values (#\R) (read-flexi-line '(#xd8 #x01) :utf-16be))))
+      (check (string= "T" (using-values (#\T) (read-flexi-line '(#xd8 #x01 #xdb #xff) :utf-16be))))
+      (check (string= "E" (using-values (#\E) (read-flexi-line* #(#x01) :utf-16be))))
+      (check (string= "R" (using-values (#\R) (read-flexi-line* #(#xd8 #x01) :utf-16be))))
+      (check (string= "T" (using-values (#\T) (read-flexi-line* #(#xd8 #x01 #xdb #xff) :utf-16be))))
       ;; the only case when error is signalled for UTF-32 is at end of file
       ;; in the middle of 4-byte sequence, both for big and little endian
-      (check (string= "Y" (using-values (#\Y) (read-flexi-line `(#x01) :utf-32le))))
-      (check (string= "Y" (using-values (#\Y) (read-flexi-line `(#x01 #x01) :utf-32le))))
-      (check (string= "Y" (using-values (#\Y) (read-flexi-line `(#x01 #x01 #x01) :utf-32le))))
+      (check (string= "Y" (using-values (#\Y) (read-flexi-line '(#x01) :utf-32le))))
+      (check (string= "Y" (using-values (#\Y) (read-flexi-line '(#x01 #x01) :utf-32le))))
+      (check (string= "Y" (using-values (#\Y) (read-flexi-line '(#x01 #x01 #x01) :utf-32le))))
       (check (string= "aY" (using-values (#\Y)
                              (read-flexi-line `(,(char-code #\a) #x00 #x00 #x00 #x01) :utf-32le))))
-      (check (string= "Y" (using-values (#\Y) (read-flexi-line `(#x01) :utf-32be))))
-      (check (string= "Y" (using-values (#\Y) (read-flexi-line `(#x01 #x01) :utf-32be))))
-      (check (string= "Y" (using-values (#\Y) (read-flexi-line `(#x01 #x01 #x01) :utf-32be))))
+      (check (string= "Y" (using-values (#\Y) (read-flexi-line '(#x01) :utf-32be))))
+      (check (string= "Y" (using-values (#\Y) (read-flexi-line '(#x01 #x01) :utf-32be))))
+      (check (string= "Y" (using-values (#\Y) (read-flexi-line '(#x01 #x01 #x01) :utf-32be))))
+      (check (string= "aY" (using-values (#\Y)
+                             (read-flexi-line `(#x00 #x00 #x00 ,(char-code #\a) #x01) :utf-32be))))
+      (check (string= "Y" (using-values (#\Y) (read-flexi-line* #(#x01) :utf-32le))))
+      (check (string= "Y" (using-values (#\Y) (read-flexi-line* #(#x01 #x01) :utf-32le))))
+      (check (string= "Y" (using-values (#\Y) (read-flexi-line* #(#x01 #x01 #x01) :utf-32le))))
+      (check (string= "aY" (using-values (#\Y)
+                             (read-flexi-line* `#(,(char-code #\a) #x00 #x00 #x00 #x01) :utf-32le))))
+      (check (string= "Y" (using-values (#\Y) (read-flexi-line* #(#x01) :utf-32be))))
+      (check (string= "Y" (using-values (#\Y) (read-flexi-line* #(#x01 #x01) :utf-32be))))
+      (check (string= "Y" (using-values (#\Y) (read-flexi-line* #(#x01 #x01 #x01) :utf-32be))))
       (check (string= "aY" (using-values (#\Y)
-                             (read-flexi-line `(#x00 #x00 #x00 ,(char-code #\a) #x01) :utf-32be)))))))
+                             (read-flexi-line* `#(#x00 #x00 #x00 ,(char-code #\a) #x01) :utf-32be)))))))
 
 (defun unread-char-test ()
   "Tests whether UNREAD-CHAR behaves as expected."
@@ -398,16 +448,17 @@
 
 (defun run-tests ()
   "Applies COMPARE-FILES to all test scenarios created with
-CREATE-TEST-COMBINATIONS, runs test for handling of encoding errors,
-and shows simple statistics at the end."
+CREATE-TEST-COMBINATIONS, runs other tests like handling of encoding
+errors, shows simple statistics at the end."
   (let* ((*test-success-counter* 0)
          (compare-files-args-list (loop for (file-name symbols) in *test-files*
                                         nconc (create-test-combinations file-name symbols)))
-         (no-tests (* 4 (length compare-files-args-list))))
+         (no-tests (* 8 (length compare-files-args-list))))
     #+:lispworks
     (setq no-tests (* 2 no-tests))
-    (dolist (args compare-files-args-list)
-      (apply 'compare-files args))
+    (dolist (*copy-function* '(copy-stream copy-stream*))
+      (dolist (args compare-files-args-list)
+        (apply 'compare-files args)))
     (let ((string-test-args-list (loop for (file-name symbols) in *test-files*
                                        nconc (create-test-combinations file-name symbols t))))
       (incf no-tests (length string-test-args-list))
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0