From c8280070ab890a463cec633049ed05a7836c47c2 Mon Sep 17 00:00:00 2001 From: Chris Hanson Date: Tue, 24 Jan 2017 19:15:03 -0800 Subject: [PATCH] Major refactor of textual I/O ports. New design uses a binary port to do actual I/O, so is mostly about coding. --- src/runtime/binary-port.scm | 125 ++- src/runtime/fileio.scm | 111 +-- src/runtime/genio.scm | 1610 +++++++++++++---------------------- src/runtime/process.scm | 6 +- src/runtime/runtime.pkg | 42 +- src/runtime/socket.scm | 4 +- src/runtime/stringio.scm | 26 +- src/runtime/ttyio.scm | 13 +- 8 files changed, 761 insertions(+), 1176 deletions(-) diff --git a/src/runtime/binary-port.scm b/src/runtime/binary-port.scm index ad6ce1127..b0945903e 100644 --- a/src/runtime/binary-port.scm +++ b/src/runtime/binary-port.scm @@ -29,8 +29,18 @@ USA. (declare (usual-integrations)) -(define (make-binary-port input-buffer output-buffer) - (%make-binary-port input-buffer output-buffer (make-alist-metadata-table))) +(define (make-binary-port source sink #!optional caller) + (if (not (or source sink)) + (error "Must provide either a source or a sink")) + (let ((port + (%make-binary-port (and source (make-input-buffer source caller)) + (and sink (make-output-buffer sink caller)) + (make-alist-metadata-table)))) + (if source + (set-source/sink-port! source port)) + (if sink + (set-source/sink-port! sink port)) + port)) (define-record-type (%make-binary-port input-buffer output-buffer metadata) @@ -39,28 +49,6 @@ USA. (output-buffer port-output-buffer) (metadata binary-port-metadata)) -(define (make-binary-input-port source caller) - (let ((port - (make-binary-port (make-input-buffer source caller) - #f))) - (set-source/sink-port! source port) - port)) - -(define (make-binary-output-port sink caller) - (let ((port - (make-binary-port #f - (make-output-buffer sink caller)))) - (set-source/sink-port! sink port) - port)) - -(define (make-binary-i/o-port source sink caller) - (let ((port - (make-binary-port (make-input-buffer source caller) - (make-output-buffer sink caller)))) - (set-source/sink-port! source port) - (set-source/sink-port! sink port) - port)) - (define (binary-input-port? object) (and (binary-port? object) (port-input-buffer object) @@ -115,7 +103,7 @@ USA. (if (not (fix:<= start end)) (error:bad-range-argument start 'open-input-bytevector)) start)))) - (make-binary-input-port + (make-binary-port (make-non-channel-input-source (lambda () (fix:<= start end)) @@ -127,6 +115,7 @@ USA. (set! start start*)) n) 0))) + #f 'open-input-bytevector))) ;;;; Bytevector output ports @@ -141,7 +130,8 @@ USA. initial-size))) (bytevector (make-bytevector size)) (index 0)) - (make-binary-output-port + (make-binary-port + #f (make-non-channel-output-sink (lambda (bv bs be) (let ((index* (fix:+ index (fix:- be bs)))) @@ -185,7 +175,7 @@ USA. (define (call-with-output-bytevector procedure) (let ((port (open-output-bytevector))) - (port port) + (procedure port) (get-output-bytevector port))) ;;;; Closing operations @@ -225,14 +215,67 @@ USA. (buffer-marked-closed? ib))))) (channel-close oc))))) +;;;; Positioning + +(define (positionable-binary-port? object) + (and (binary-port? object) + (binary-port-positionable? object))) + +(define (binary-port-positionable? port) + (let ((ib (port-input-buffer port)) + (ob (port-output-buffer port))) + (let ((ic (and ib (buffer-channel ib))) + (oc (and ob (buffer-channel ob)))) + (and (or ic oc) + (if (and ic oc) + (and (eq? ic oc) + (channel-type=file? ic)) + (channel-type=file? (or ic oc))))))) + +(add-boot-init! + (lambda () + (register-predicate! positionable-binary-port? 'positionable-binary-port + '<= binary-port?))) + +(define (binary-port-length port) + (guarantee positionable-binary-port? port 'port-length) + (channel-file-length (or (let ((ib (port-input-buffer port))) + (and ib + (buffer-channel ib))) + (buffer-channel (port-output-buffer port))))) + +(define (binary-port-position port) + (guarantee positionable-binary-port? port 'port-position) + (let ((ib (port-input-buffer port))) + (if ib + (- (channel-file-position (buffer-channel ib)) + (fix:- (buffer-end ib) (buffer-start ib))) + (channel-file-position (buffer-channel (port-output-buffer port)))))) + +(define (set-binary-port-position! port position) + (guarantee positionable-binary-port? port 'set-port-position!) + (let ((ib (port-input-buffer port)) + (ob (port-output-buffer port))) + (if ib (clear-input-buffer ib)) + (if ob (flush-output-buffer ob)) + (channel-file-set-position (or (and ib (buffer-channel ib)) + (and ob (buffer-channel ob))) + position))) + ;;;; Input operations (define (binary-input-port-open? port) (buffer-open? (port-input-buffer port))) +(define (binary-input-port-source port) + (buffer-source/sink (port-input-buffer port))) + (define (binary-input-port-channel port) (buffer-channel (port-input-buffer port))) +(define (binary-input-port-at-eof? port #!optional caller) + (eq? 'eof (input-buffer-state (port-input-buffer port) caller))) + (define (check-input-port port caller) (let* ((port (if (default-object? port) (current-input-port) port)) (ib (port-input-buffer port))) @@ -271,7 +314,7 @@ USA. ((eof) (eof-object)) (else #f))))) -(define (binary-input-port:buffer-contents port) +(define (binary-input-port-buffer-contents port) (let ((ib (check-input-port port 'input-port-buffer-contents))) (if (eq? 'filled (input-buffer-state ib 'input-port-buffer-contents)) (bytevector-copy (buffer-bytes ib) @@ -279,7 +322,7 @@ USA. (buffer-end ib)) (make-bytevector 0)))) -(define (binary-input-port:set-buffer-contents! port contents) +(define (set-binary-input-port-buffer-contents! port contents) (let ((ib (check-input-port port 'set-input-port-buffer-contents!))) (if (eq? 'unfilled (input-buffer-state ib 'set-input-port-buffer-contents!)) (let ((bv (buffer-bytes ib))) @@ -381,6 +424,10 @@ USA. (close-buffer ib) (mark-buffer-closed! ib)))) +(define (clear-input-buffer ib) + (set-buffer-start! ib 0) + (set-buffer-end! ib 0)) + (define (input-buffer-state ib caller) (if (buffer-marked-closed? ib) (error:bad-range-argument (buffer-port ib) caller)) @@ -410,15 +457,12 @@ USA. (define (binary-output-port-open? port) (buffer-open? (port-output-buffer port))) +(define (binary-output-port-sink port) + (buffer-source/sink (port-output-buffer port))) + (define (binary-output-port-channel port) (buffer-channel (port-output-buffer port))) -(define (flush-binary-output-port port) - (let ((ob (port-output-buffer port))) - (if (not (buffer-open? ob)) - (error:bad-range-argument port 'flush-output-port)) - (flush-output-buffer ob))) - (define (check-output-port port caller) (let* ((port (if (default-object? port) (current-output-port) port)) (ob (port-output-buffer port))) @@ -428,6 +472,13 @@ USA. (error:bad-range-argument port caller)) ob)) +(define (flush-binary-output-port port) + (flush-output-buffer (check-output-port port 'flush-output-port))) + +(define (binary-output-port-buffered-byte-count port) + (let ((ob (check-output-port port 'output-port-buffered-byte-count))) + (fix:- (buffer-end ob) (buffer-start ob)))) + (define (write-u8 byte #!optional port) (guarantee byte? byte 'write-u8) (let ((ob (check-output-port port 'write-u8))) @@ -649,7 +700,7 @@ USA. (define (make-channel-ss flavor channel . custom) (make-source/sink flavor - (lambda () channel) + channel (lambda () (channel-port channel)) (lambda (port) (set-channel-port! channel port)) (lambda () (channel-open? channel)) @@ -660,7 +711,7 @@ USA. (let ((port #f) (open? #t)) (make-source/sink flavor - (lambda () #f) + #f (lambda () port) (lambda (port*) (set! port port*) unspecific) (lambda () open?) diff --git a/src/runtime/fileio.scm b/src/runtime/fileio.scm index 236ce1203..31dc1ee69 100644 --- a/src/runtime/fileio.scm +++ b/src/runtime/fileio.scm @@ -50,55 +50,23 @@ USA. unspecific) (define (operation/pathname port) - (port-property 'pathname)) + (port-property port 'pathname)) (define (set-port-pathname! port pathname) (set-port-property! port 'pathname pathname)) (define (operation/length port) - (channel-file-length - (or (input-port-channel port) - (output-port-channel port)))) + (binary-port-length (generic-i/o-port->binary-port port))) (define (operation/write-self port output-port) (write-string " for file: " output-port) (write (->namestring (operation/pathname port)) output-port)) (define (operation/position port) - (guarantee-positionable-port port 'OPERATION/POSITION) - (if (output-port? port) - (flush-output port)) - (if (input-port? port) - (let ((input-buffer (port-input-buffer port))) - (- (channel-file-position (input-port-channel port)) - (input-buffer-free-bytes input-buffer))) - (channel-file-position (output-port-channel port)))) + (binary-port-position (generic-i/o-port->binary-port port))) (define (operation/set-position! port position) - (guarantee-positionable-port port 'OPERATION/SET-POSITION!) - (guarantee-exact-nonnegative-integer position 'OPERATION/SET-POSITION!) - (if (output-port? port) - (flush-output port)) - (if (input-port? port) - (clear-input-buffer (port-input-buffer port))) - (channel-file-set-position (if (input-port? port) - (input-port-channel port) - (output-port-channel port)) - position)) - -(define (guarantee-positionable-port port caller) - (guarantee textual-port? port caller) - (if (and (i/o-port? port) - (not (eq? (input-port-channel port) (output-port-channel port)))) - (error:bad-range-argument port caller)) - (if (and (input-port? port) - (not (input-buffer-using-binary-normalizer? - (port-input-buffer port)))) - (error:bad-range-argument port caller)) - (if (and (output-port? port) - (not (output-buffer-using-binary-denormalizer? - (port-output-buffer port)))) - (error:bad-range-argument port caller))) + (set-binary-port-position! (generic-i/o-port->binary-port port) position)) (define (input-file-opener caller make-port) (lambda (filename) @@ -129,26 +97,30 @@ USA. (channel (file-open-io-channel (->namestring pathname)))) (make-port channel channel pathname caller)))) -(define (make-textual-port input-channel output-channel pathname caller) +(define (make-textual-file-port input-channel output-channel pathname caller) caller - (let ((port (%make-textual-port input-channel output-channel pathname))) + (let ((port (%make-textual-file-port input-channel output-channel pathname))) (port/set-line-ending port (file-line-ending pathname)) port)) -(define (make-legacy-binary-port input-channel output-channel pathname caller) +(define (make-legacy-binary-file-port input-channel output-channel pathname + caller) caller - (let ((port (%make-textual-port input-channel output-channel pathname))) + (let ((port (%make-textual-file-port input-channel output-channel pathname))) (port/set-coding port 'BINARY) (port/set-line-ending port 'BINARY) port)) -(define (%make-textual-port input-channel output-channel pathname) +(define (%make-textual-file-port input-channel output-channel pathname) (let ((port - (make-generic-i/o-port input-channel - output-channel - (cond ((not input-channel) output-file-type) - ((not output-channel) input-file-type) - (else i/o-file-type))))) + (make-generic-i/o-port + (and input-channel + (make-channel-input-source input-channel)) + (and output-channel + (make-channel-output-sink output-channel)) + (cond ((not input-channel) output-file-type) + ((not output-channel) input-file-type) + (else i/o-file-type))))) ;; If both channels are set they are the same. (cond (input-channel (set-channel-port! input-channel port)) (output-channel (set-channel-port! output-channel port))) @@ -156,59 +128,56 @@ USA. port)) (define open-input-file - (input-file-opener 'open-input-file make-textual-port)) + (input-file-opener 'open-input-file make-textual-file-port)) (define open-output-file - (output-file-opener 'open-output-file make-textual-port)) + (output-file-opener 'open-output-file make-textual-file-port)) (define open-exclusive-output-file - (exclusive-output-file-opener 'open-exclusive-output-file make-textual-port)) + (exclusive-output-file-opener 'open-exclusive-output-file + make-textual-file-port)) (define open-i/o-file - (i/o-file-opener 'open-i/o-file make-textual-port)) + (i/o-file-opener 'open-i/o-file make-textual-file-port)) (define open-legacy-binary-input-file - (input-file-opener 'open-legacy-binary-input-file make-legacy-binary-port)) + (input-file-opener 'open-legacy-binary-input-file + make-legacy-binary-file-port)) (define open-legacy-binary-output-file - (output-file-opener 'open-legacy-binary-output-file make-legacy-binary-port)) + (output-file-opener 'open-legacy-binary-output-file + make-legacy-binary-file-port)) (define open-exclusive-legacy-binary-output-file (exclusive-output-file-opener 'open-exclusive-legacy-binary-output-file - make-legacy-binary-port)) + make-legacy-binary-file-port)) (define open-legacy-binary-i/o-file - (i/o-file-opener 'open-legacy-binary-i/o-file make-legacy-binary-port)) + (i/o-file-opener 'open-legacy-binary-i/o-file make-legacy-binary-file-port)) -(define (make-binary-port input-channel output-channel pathname caller) - (let ((port (%make-binary-port input-channel output-channel caller))) +(define (make-binary-file-port input-channel output-channel pathname caller) + (let ((port (%make-binary-file-port input-channel output-channel caller))) (set-port-pathname! port pathname) port)) -(define (%make-binary-port input-channel output-channel caller) - (cond ((not input-channel) - (make-binary-output-port (make-channel-output-sink output-channel) - caller)) - ((not output-channel) - (make-binary-input-port (make-channel-input-source input-channel) - caller)) - (else - (make-binary-i/o-port (make-channel-input-source input-channel) - (make-channel-output-sink output-channel) - caller)))) +(define (%make-binary-file-port input-channel output-channel caller) + (make-binary-port + (and input-channel (make-channel-input-source input-channel)) + (and output-channel (make-channel-output-sink output-channel)) + caller)) (define open-binary-input-file - (input-file-opener 'open-binary-input-file make-binary-port)) + (input-file-opener 'open-binary-input-file make-binary-file-port)) (define open-binary-output-file - (output-file-opener 'open-binary-output-file make-binary-port)) + (output-file-opener 'open-binary-output-file make-binary-file-port)) (define open-exclusive-binary-output-file (exclusive-output-file-opener 'open-exclusive-binary-output-file - make-binary-port)) + make-binary-file-port)) (define open-binary-i/o-file - (i/o-file-opener 'open-binary-i/o-file make-binary-port)) + (i/o-file-opener 'open-binary-i/o-file make-binary-file-port)) (define ((make-call-with-file open) input-specifier receiver) (let ((port (open input-specifier))) diff --git a/src/runtime/genio.scm b/src/runtime/genio.scm index 60213f456..80d70a4e8 100644 --- a/src/runtime/genio.scm +++ b/src/runtime/genio.scm @@ -27,8 +27,7 @@ USA. ;;;; Generic I/O Ports ;;; package: (runtime generic-i/o-port) -(declare (usual-integrations) - (integrate-external "port")) +(declare (usual-integrations)) (define (make-generic-i/o-port source sink #!optional type . extra-state) (if (not (or source sink)) @@ -42,20 +41,20 @@ USA. extra-state)))) (let ((ib (port-input-buffer port))) (if ib - ((source/set-port (input-buffer-source ib)) port))) + (set-input-buffer-port! ib port))) (let ((ob (port-output-buffer port))) (if ob - ((sink/set-port (output-buffer-sink ob)) port))) + (set-output-buffer-port! ob port))) port)) (define (source-type source) (cond ((not source) #f) - ((or (channel? source) ((source/get-channel source))) 'CHANNEL) + ((input-source-channel source) 'CHANNEL) (else #t))) (define (sink-type sink) (cond ((not sink) #f) - ((or (channel? sink) ((sink/get-channel sink))) 'CHANNEL) + ((output-sink-channel sink) 'CHANNEL) (else #t))) (define (generic-i/o-port-type source sink) @@ -75,104 +74,54 @@ USA. ((#F) generic-type10) ((CHANNEL) generic-type12) (else generic-type11))))) - -(define-structure (gstate (constructor %make-gstate)) - (input-buffer #f read-only #t) - (output-buffer #f read-only #t) - coding - line-ending - (extra #f read-only #t)) +(define (generic-i/o-port->binary-port port) + (or (let ((ib (port-input-buffer port))) + (and ib + (input-buffer-binary-port ib))) + (output-buffer-binary-port (port-output-buffer port)))) + (define (make-gstate source sink coder-name normalizer-name . extra) - (%make-gstate (and source - (make-input-buffer (->source source 'MAKE-GSTATE) - coder-name - normalizer-name)) - (and sink - (make-output-buffer (->sink sink 'MAKE-GSTATE) - coder-name - normalizer-name)) - coder-name - normalizer-name - (list->vector extra))) - -(define-integrable (port-input-buffer port) + (let ((binary-port (make-binary-port source sink))) + (%make-gstate (and source + (make-input-buffer binary-port + coder-name + normalizer-name)) + (and sink + (make-output-buffer binary-port + coder-name + normalizer-name)) + coder-name + normalizer-name + (list->vector extra)))) + +(define-record-type + (%make-gstate input-buffer output-buffer coder-name normalizer-name extra) + gstate? + (input-buffer gstate-input-buffer) + (output-buffer gstate-output-buffer) + (coder-name gstate-coder-name + set-gstate-coder-name!) + (normalizer-name gstate-normalizer-name + set-gstate-normalizer-name!) + (extra gstate-extra)) + +(define (port-input-buffer port) (gstate-input-buffer (textual-port-state port))) -(define-integrable (port-output-buffer port) +(define (port-output-buffer port) (gstate-output-buffer (textual-port-state port))) (define (generic-i/o-port-accessor index) - (guarantee-index-fixnum index 'GENERIC-I/O-PORT-ACCESSOR) + (guarantee index-fixnum? index 'generic-i/o-port-accessor) (lambda (port) - (let ((extra (gstate-extra (textual-port-state port)))) - (if (not (fix:< index (vector-length extra))) - (error "Accessor index out of range:" index)) - (vector-ref extra index)))) + (vector-ref (gstate-extra (textual-port-state port)) index))) (define (generic-i/o-port-modifier index) - (guarantee-index-fixnum index 'GENERIC-I/O-PORT-MODIFIER) + (guarantee index-fixnum? index 'generic-i/o-port-modifier) (lambda (port object) - (let ((extra (gstate-extra (textual-port-state port)))) - (if (not (fix:< index (vector-length extra))) - (error "Accessor index out of range:" index)) - (vector-set! extra index object)))) + (vector-set! (gstate-extra (textual-port-state port)) index object))) -(define (initialize-package!) - (let ((ops:in1 - `((CHAR-READY? ,generic-io/char-ready?) - (CLOSE-INPUT ,generic-io/close-input) - (EOF? ,generic-io/eof?) - (INPUT-LINE ,generic-io/input-line) - (INPUT-OPEN? ,generic-io/input-open?) - (PEEK-CHAR ,generic-io/peek-char) - (READ-CHAR ,generic-io/read-char) - (READ-SUBSTRING ,generic-io/read-substring) - (UNREAD-CHAR ,generic-io/unread-char))) - (ops:in2 - `((INPUT-CHANNEL ,generic-io/input-channel))) - (ops:out1 - `((BUFFERED-OUTPUT-BYTES ,generic-io/buffered-output-bytes) - (BYTES-WRITTEN ,generic-io/bytes-written) - (CLOSE-OUTPUT ,generic-io/close-output) - (FLUSH-OUTPUT ,generic-io/flush-output) - (OUTPUT-COLUMN ,generic-io/output-column) - (OUTPUT-OPEN? ,generic-io/output-open?) - (WRITE-CHAR ,generic-io/write-char) - (WRITE-SUBSTRING ,generic-io/write-substring))) - (ops:out2 - `((OUTPUT-CHANNEL ,generic-io/output-channel) - (SYNCHRONIZE-OUTPUT ,generic-io/synchronize-output))) - (other-operations - `((CLOSE ,generic-io/close) - (CODING ,generic-io/coding) - (KNOWN-CODING? ,generic-io/known-coding?) - (KNOWN-CODINGS ,generic-io/known-codings) - (KNOWN-LINE-ENDING? ,generic-io/known-line-ending?) - (KNOWN-LINE-ENDINGS ,generic-io/known-line-endings) - (LINE-ENDING ,generic-io/line-ending) - (OPEN? ,generic-io/open?) - (SET-CODING ,generic-io/set-coding) - (SET-LINE-ENDING ,generic-io/set-line-ending) - (SUPPORTS-CODING? ,generic-io/supports-coding?) - (WRITE-SELF ,generic-io/write-self)))) - (let ((make-type - (lambda ops - (make-textual-port-type (append (apply append ops) - other-operations) - #f)))) - (set! generic-type00 (make-type)) - (set! generic-type10 (make-type ops:in1)) - (set! generic-type20 (make-type ops:in1 ops:in2)) - (set! generic-type01 (make-type ops:out1)) - (set! generic-type02 (make-type ops:out1 ops:out2)) - (set! generic-type11 (make-type ops:in1 ops:out1)) - (set! generic-type21 (make-type ops:in1 ops:in2 ops:out1)) - (set! generic-type12 (make-type ops:in1 ops:out1 ops:out2)) - (set! generic-type22 (make-type ops:in1 ops:in2 ops:out1 ops:out2)))) - (initialize-name-maps!) - (initialize-conditions!)) - (define generic-type00) (define generic-type10) (define generic-type20) @@ -182,47 +131,109 @@ USA. (define generic-type21) (define generic-type12) (define generic-type22) +(add-boot-init! + (lambda () + (let ((ops:in1 + `((CHAR-READY? ,generic-io/char-ready?) + (CLOSE-INPUT ,generic-io/close-input) + (EOF? ,generic-io/eof?) + (INPUT-LINE ,generic-io/input-line) + (INPUT-OPEN? ,generic-io/input-open?) + (PEEK-CHAR ,generic-io/peek-char) + (READ-CHAR ,generic-io/read-char) + (READ-SUBSTRING ,generic-io/read-substring) + (UNREAD-CHAR ,generic-io/unread-char))) + (ops:in2 + `((INPUT-CHANNEL ,generic-io/input-channel))) + (ops:out1 + `((BUFFERED-OUTPUT-BYTES ,generic-io/buffered-output-bytes) + (BYTES-WRITTEN ,generic-io/bytes-written) + (CLOSE-OUTPUT ,generic-io/close-output) + (FLUSH-OUTPUT ,generic-io/flush-output) + (OUTPUT-COLUMN ,generic-io/output-column) + (OUTPUT-OPEN? ,generic-io/output-open?) + (WRITE-CHAR ,generic-io/write-char) + (WRITE-SUBSTRING ,generic-io/write-substring))) + (ops:out2 + `((OUTPUT-CHANNEL ,generic-io/output-channel) + (SYNCHRONIZE-OUTPUT ,generic-io/synchronize-output))) + (other-operations + `((CLOSE ,generic-io/close) + (CODING ,generic-io/coding) + (KNOWN-CODING? ,generic-io/known-coding?) + (KNOWN-CODINGS ,generic-io/known-codings) + (KNOWN-LINE-ENDING? ,generic-io/known-line-ending?) + (KNOWN-LINE-ENDINGS ,generic-io/known-line-endings) + (LINE-ENDING ,generic-io/line-ending) + (OPEN? ,generic-io/open?) + (SET-CODING ,generic-io/set-coding) + (SET-LINE-ENDING ,generic-io/set-line-ending) + (SUPPORTS-CODING? ,generic-io/supports-coding?) + (WRITE-SELF ,generic-io/write-self)))) + (let ((make-type + (lambda ops + (make-textual-port-type (append (apply append ops) + other-operations) + #f)))) + (set! generic-type00 (make-type)) + (set! generic-type10 (make-type ops:in1)) + (set! generic-type20 (make-type ops:in1 ops:in2)) + (set! generic-type01 (make-type ops:out1)) + (set! generic-type02 (make-type ops:out1 ops:out2)) + (set! generic-type11 (make-type ops:in1 ops:out1)) + (set! generic-type21 (make-type ops:in1 ops:in2 ops:out1)) + (set! generic-type12 (make-type ops:in1 ops:out1 ops:out2)) + (set! generic-type22 (make-type ops:in1 ops:in2 ops:out1 ops:out2)))))) ;;;; Input operations (define (generic-io/char-ready? port) - (buffer-has-input? (port-input-buffer port))) + (let ((ib (port-input-buffer port))) + (or (input-buffer-peeked ib) + (u8-ready? (input-buffer-binary-port ib))))) (define (generic-io/peek-char port) - (let* ((ib (port-input-buffer port)) - (line (input-buffer-line ib)) - (char (generic-io/read-char port))) - (if (char? char) - ;; Undo effect of read-char. - (begin - (set-input-buffer-line! ib line) - (set-input-buffer-start! ib (input-buffer-prev ib)))) - char)) + (let ((ib (port-input-buffer port))) + (or (input-buffer-peeked ib) + (let ((char ((input-buffer-normalizer ib) ib))) + (if (char? char) + (set-input-buffer-peeked! ib char)) + char)))) (define (generic-io/read-char port) (let ((ib (port-input-buffer port))) - (reset-prev-char ib) - (let loop () - (or (read-next-char ib) - (let ((r (fill-input-buffer ib))) - (case r - ((OK) (loop)) - ((WOULD-BLOCK) #f) - ((EOF) (eof-object)) - (else (error "Unknown result:" r)))))))) + (let ((char (input-buffer-peeked ib))) + (if char + (begin + (set-input-buffer-peeked! ib #f) + char) + (let ((char ((input-buffer-normalizer ib) ib))) + (if (eq? char #\newline) + (let ((line (input-buffer-line ib))) + (if line + (set-input-buffer-line! ib (fix:+ line 1))))) + char))))) (define (generic-io/unread-char port char) (let ((ib (port-input-buffer port))) - (let ((bp (input-buffer-prev ib))) - (if (not (fix:< bp (input-buffer-start ib))) - (error "No char to unread:" port)) - ;; If unreading a newline, decrement the line count. - (if (char=? char #\newline) - (set-input-buffer-line! ib (fix:- (input-buffer-line ib) 1))) - (set-input-buffer-start! ib bp)))) + (guarantee char? char 'unread-char) + (if (input-buffer-peeked ib) + (error "Can't unread another char:" char (input-buffer-port ib))) + (set-input-buffer-peeked! ib char) + ;; If unreading a newline, decrement the line count. + (if (char=? char #\newline) + (set-input-buffer-line! ib (fix:- (input-buffer-line ib) 1))))) (define (generic-io/read-substring port string start end) - (read-substring (port-input-buffer port) string start end)) + (let loop ((index start)) + (if (fix:< index end) + (let ((char (generic-io/read-char port))) + (cond ((not char) #f) + ((eof-object? char) (fix:- index start)) + (else + (xstring-set! string index char) + (loop (fix:+ index 1))))) + (fix:- end start)))) (define (generic-io/input-line port) (input-buffer-line (port-input-buffer port))) @@ -239,20 +250,21 @@ USA. ;;;; Output operations (define (generic-io/write-char port char) - (let ((ob (port-output-buffer port))) - (let loop () - (if (write-next-char ob char) - 1 - (let ((n (drain-output-buffer ob))) - (if (and n (fix:> n 0)) - (loop) - n)))))) + (guarantee char? char) + (write-next-char (port-output-buffer port) char)) (define (generic-io/write-substring port string start end) - (write-substring (port-output-buffer port) string start end)) + (let ((ob (port-output-buffer port))) + (let loop ((index start)) + (if (fix:< index end) + (let ((n (write-next-char ob (xstring-ref string index)))) + (cond ((and n (fix:> n 0)) (loop (fix:+ index 1))) + ((fix:< start index) (fix:- index start)) + (else n))) + (fix:- end start))))) (define (generic-io/flush-output port) - (force-drain-output-buffer (port-output-buffer port))) + (flush-output-buffer (port-output-buffer port))) (define (generic-io/output-column port) (output-buffer-column (port-output-buffer port))) @@ -269,7 +281,8 @@ USA. (channel-synchronize channel)))) (define (generic-io/buffered-output-bytes port) - (output-buffer-start (port-output-buffer port))) + (binary-output-port-buffered-byte-count + (output-buffer-binary-port (port-output-buffer port)))) (define (generic-io/bytes-written port) (output-buffer-total (port-output-buffer port))) @@ -277,52 +290,23 @@ USA. ;;;; Non-specific operations (define (generic-io/close port) - (maybe-close-input port) - (maybe-close-output port) - (maybe-close-channels port)) - -(define (generic-io/close-output port) - (maybe-close-output port) - (maybe-close-channels port)) - -(define (generic-io/close-input port) - (maybe-close-input port) - (maybe-close-channels port)) - -(define (maybe-close-input port) - (let ((ib (port-input-buffer port))) - (if ib - (close-input-buffer ib)))) - -(define (maybe-close-output port) - (let ((ob (port-output-buffer port))) - (if ob - (close-output-buffer ob)))) - -(define (maybe-close-channels port) (let ((ib (port-input-buffer port)) (ob (port-output-buffer port))) - (let ((ic (and ib (input-buffer-channel ib))) - (oc (and ob (output-buffer-channel ob)))) - (if (and ic (eq? ic oc)) - (if (and (not (%input-buffer-open? ib)) - (not (%output-buffer-open? ob))) - (channel-close ic)) - (begin - (if (and ic (not (%input-buffer-open? ib))) - (channel-close ic)) - (if (and oc (not (%output-buffer-open? ob))) - (channel-close oc))))))) + (cond ((and ib + ob + (eq? (input-buffer-binary-port ib) + (output-buffer-binary-port ob))) + (close-binary-port (input-buffer-binary-port ib))) + (ib (close-binary-input-port (input-buffer-binary-port ib))) + (ob (close-binary-output-port (output-buffer-binary-port ob)))))) -(define (generic-io/output-open? port) - (let ((ob (port-output-buffer port))) - (and ob - (output-buffer-open? ob)))) +(define (generic-io/close-input port) + (close-binary-input-port + (input-buffer-binary-port (port-input-buffer port)))) -(define (generic-io/input-open? port) - (let ((ib (port-input-buffer port))) - (and ib - (input-buffer-open? ib)))) +(define (generic-io/close-output port) + (close-binary-output-port + (output-buffer-binary-port (port-output-buffer port)))) (define (generic-io/open? port) (and (let ((ib (port-input-buffer port))) @@ -334,6 +318,16 @@ USA. (output-buffer-open? ob) #t)))) +(define (generic-io/input-open? port) + (let ((ib (port-input-buffer port))) + (and ib + (input-buffer-open? ib)))) + +(define (generic-io/output-open? port) + (let ((ob (port-output-buffer port))) + (and ob + (output-buffer-open? ob)))) + (define (generic-io/write-self port output-port) (cond ((i/o-port? port) (write-string " for channels: " output-port) @@ -352,17 +346,16 @@ USA. #t) (define (generic-io/coding port) - (gstate-coding (textual-port-state port))) + (gstate-coder-name (textual-port-state port))) (define (generic-io/set-coding port name) - (let ((state (textual-port-state port))) - (let ((ib (gstate-input-buffer state))) - (if ib - (set-input-buffer-coding! ib name))) - (let ((ob (gstate-output-buffer state))) - (if ob - (set-output-buffer-coding! ob name))) - (set-gstate-coding! state name))) + (let ((ib (port-input-buffer port))) + (if ib + (set-input-buffer-coding! ib name))) + (let ((ob (port-output-buffer port))) + (if ob + (set-output-buffer-coding! ob name))) + (set-gstate-coder-name! (textual-port-state port) name)) (define (generic-io/known-coding? port coding) (and (if (input-port? port) (known-input-port-coding? coding) #t) @@ -370,28 +363,28 @@ USA. (define (generic-io/known-codings port) (cond ((i/o-port? port) - (eq-intersection (known-input-port-codings) - (known-output-port-codings))) + (lset-intersection eq? + (known-input-port-codings) + (known-output-port-codings))) ((input-port? port) (known-input-port-codings)) ((output-port? port) (known-output-port-codings)) (else '()))) (define (generic-io/line-ending port) - (gstate-line-ending (textual-port-state port))) + (gstate-normalizer-name (textual-port-state port))) (define (generic-io/set-line-ending port name) - (let ((state (textual-port-state port))) - (let ((ib (gstate-input-buffer state))) - (if ib - (set-input-buffer-line-ending! - ib - (line-ending (input-buffer-channel ib) name #f)))) - (let ((ob (gstate-output-buffer state))) - (if ob - (set-output-buffer-line-ending! - ob - (line-ending (output-buffer-channel ob) name #t)))) - (set-gstate-line-ending! state name))) + (let ((ib (port-input-buffer port))) + (if ib + (set-input-buffer-line-ending! + ib + (line-ending (input-buffer-channel ib) name #f)))) + (let ((ob (port-output-buffer port))) + (if ob + (set-output-buffer-line-ending! + ob + (line-ending (output-buffer-channel ob) name #t)))) + (set-gstate-normalizer-name! (textual-port-state port) name)) (define (generic-io/known-line-ending? port line-ending) (and (if (input-port? port) (known-input-line-ending? line-ending) #t) @@ -399,8 +392,9 @@ USA. (define (generic-io/known-line-endings port) (cond ((i/o-port? port) - (eq-intersection (known-input-line-endings) - (known-output-line-endings))) + (lset-intersection eq? + (known-input-line-endings) + (known-output-line-endings))) ((input-port? port) (known-input-line-endings)) ((output-port? port) (known-output-line-endings)) (else '()))) @@ -410,16 +404,11 @@ USA. (if (and for-output? (known-input-line-ending? name) (not (known-output-line-ending? name))) - (if (and channel (eq? (channel-type channel) 'TCP-STREAM-SOCKET)) + (if (and channel + (eq? (channel-type channel) 'TCP-STREAM-SOCKET)) 'CRLF (default-line-ending)) name)) - -(define (eq-intersection a b) - (let loop ((a a)) - (cond ((not (pair? a)) '()) - ((memq (car a) b) (cons (car a) (loop (cdr a)))) - (else (loop (cdr a)))))) ;;;; Name maps @@ -463,7 +452,6 @@ USA. (define-name-map decoder) (define-name-map encoder) -(define-name-map sizer) (define-name-map normalizer) (define-name-map denormalizer) @@ -499,63 +487,59 @@ USA. (append (hash-table/key-list denormalizer-aliases) (hash-table/key-list denormalizers))) -(define (initialize-name-maps!) - (let ((convert-reverse - (lambda (alist) - (let ((table (make-strong-eq-hash-table))) - (for-each (lambda (n.d) - (hash-table/put! table (cdr n.d) (car n.d))) - alist) - table))) - (convert-forward - (lambda (alist) - (let ((table (make-strong-eq-hash-table))) - (for-each (lambda (n.d) - (hash-table/put! table (car n.d) (cdr n.d))) - alist) - table)))) - (let-syntax - ((initialize-name-map - (sc-macro-transformer - (lambda (form environment) - environment - (if (syntax-match? '(SYMBOL) (cdr form)) - (let ((sing (cadr form))) - (let ((plur (symbol sing 'S)) - (aliases (symbol sing '-ALIASES)) - (proc (symbol 'DEFINE- sing))) - (let ((aproc (symbol proc '-ALIAS))) - `(BEGIN - (SET! ,(symbol plur '-REVERSE) - (CONVERT-REVERSE ,plur)) - (SET! ,plur (CONVERT-FORWARD ,plur)) - (SET! ,proc ,(symbol proc '/POST-BOOT)) - (SET! ,aliases (CONVERT-FORWARD ,aliases)) - (SET! ,aproc ,(symbol aproc '/POST-BOOT)))))) - (ill-formed-syntax form)))))) - (initialize-name-map decoder) - (initialize-name-map encoder) - (initialize-name-map sizer) - (initialize-name-map normalizer) - (initialize-name-map denormalizer))) - (set! binary-decoder (name->decoder 'BINARY)) - (set! binary-encoder (name->encoder 'BINARY)) - (set! binary-sizer (name->sizer 'BINARY)) - (set! binary-normalizer (name->normalizer 'BINARY)) - (set! binary-denormalizer (name->denormalizer 'BINARY)) - unspecific) - (define binary-decoder) (define binary-encoder) -(define binary-sizer) (define binary-normalizer) (define binary-denormalizer) +(add-boot-init! + (lambda () + (let ((convert-reverse + (lambda (alist) + (let ((table (make-strong-eq-hash-table))) + (for-each (lambda (n.d) + (hash-table/put! table (cdr n.d) (car n.d))) + alist) + table))) + (convert-forward + (lambda (alist) + (let ((table (make-strong-eq-hash-table))) + (for-each (lambda (n.d) + (hash-table/put! table (car n.d) (cdr n.d))) + alist) + table)))) + (let-syntax + ((initialize-name-map + (sc-macro-transformer + (lambda (form environment) + environment + (if (syntax-match? '(SYMBOL) (cdr form)) + (let ((sing (cadr form))) + (let ((plur (symbol sing 'S)) + (aliases (symbol sing '-ALIASES)) + (proc (symbol 'DEFINE- sing))) + (let ((aproc (symbol proc '-ALIAS))) + `(BEGIN + (SET! ,(symbol plur '-REVERSE) + (CONVERT-REVERSE ,plur)) + (SET! ,plur (CONVERT-FORWARD ,plur)) + (SET! ,proc ,(symbol proc '/POST-BOOT)) + (SET! ,aliases (CONVERT-FORWARD ,aliases)) + (SET! ,aproc ,(symbol aproc '/POST-BOOT)))))) + (ill-formed-syntax form)))))) + (initialize-name-map decoder) + (initialize-name-map encoder) + (initialize-name-map normalizer) + (initialize-name-map denormalizer))) + (set! binary-decoder (name->decoder 'BINARY)) + (set! binary-encoder (name->encoder 'BINARY)) + (set! binary-normalizer (name->normalizer 'BINARY)) + (set! binary-denormalizer (name->denormalizer 'BINARY)) + unspecific)) (define (define-coding-aliases name aliases) (for-each (lambda (alias) (define-decoder-alias alias name) - (define-encoder-alias alias name) - (define-sizer-alias alias name)) + (define-encoder-alias alias name)) aliases)) (define (primary-input-port-codings) @@ -563,483 +547,233 @@ USA. (define (primary-output-port-codings) (cons 'US-ASCII (hash-table/key-list encoders))) - -;;;; Byte sources - -(define-structure (source (constructor make-gsource) (conc-name source/)) - (get-channel #f read-only #t) - (get-port #f read-only #t) - (set-port #f read-only #t) - (open? #f read-only #t) - (close #f read-only #t) - (has-bytes? #f read-only #t) - (read #f read-only #t)) - -(define-guarantee source "byte source") - -(define (->source object #!optional caller) - (if (channel? object) - (make-channel-source object) - (begin - (guarantee-source object caller) - object))) - -(define (make-channel-source channel) - (make-gsource (lambda () channel) - (lambda () (channel-port channel)) - (lambda (port) (set-channel-port! channel port)) - (lambda () (channel-open? channel)) - (lambda () ;; channel-close provided by maybe-close-channels - unspecific) - (lambda () (channel-has-input? channel)) - (lambda (string start end) - (channel-read channel string start end)))) - -(define (make-non-channel-port-source has-bytes? read-bytes) - (let ((port #f) - (open? #t)) - (make-gsource (lambda () #f) - (lambda () port) - (lambda (port*) (set! port port*) unspecific) - (lambda () open?) - (lambda () (set! open? #f) unspecific) - has-bytes? - read-bytes))) - -;;;; Byte Sinks - -(define-structure (sink (constructor make-gsink) (conc-name sink/)) - (get-channel #f read-only #t) - (get-port #f read-only #t) - (set-port #f read-only #t) - (open? #f read-only #t) - (close #f read-only #t) - (write #f read-only #t)) - -(define-guarantee sink "byte sink") - -(define (->sink object #!optional caller) - (if (channel? object) - (make-channel-sink object) - (begin - (guarantee-sink object caller) - object))) - -(define (make-channel-sink channel) - (make-gsink (lambda () channel) - (lambda () (channel-port channel)) - (lambda (port) (set-channel-port! channel port)) - (lambda () (channel-open? channel)) - (lambda () ;; channel-close provided by maybe-close-channels - unspecific) - (lambda (string start end) - (channel-write channel string start end)))) - -(define (make-non-channel-port-sink write-bytes) - (let ((port #f) - (open? #t)) - (make-gsink (lambda () #f) - (lambda () port) - (lambda (port*) (set! port port*) unspecific) - (lambda () open?) - (lambda () (set! open? #f) unspecific) - write-bytes))) + +(define max-char-bytes 4) ;;;; Input buffer -(define-integrable page-size #x1000) -(define-integrable max-char-bytes 4) - -(define-integrable byte-buffer-length - (fix:+ page-size - (fix:- (fix:* max-char-bytes 4) 1))) - -(define-structure (input-buffer (constructor %make-input-buffer)) - (source #f read-only #t) - (bytes #f read-only #t) - prev - start - end - decode - normalize - line - compute-encoded-character-size) - -(define (make-input-buffer source coder-name normalizer-name) - (%make-input-buffer source - (make-string byte-buffer-length) - byte-buffer-length - byte-buffer-length - byte-buffer-length +(define (make-input-buffer binary-port coder-name normalizer-name) + (%make-input-buffer binary-port (name->decoder coder-name) (name->normalizer - (line-ending ((source/get-channel source)) + (line-ending (binary-input-port-channel binary-port) normalizer-name #f)) - 0 - (name->sizer coder-name))) + (make-bytevector max-char-bytes) + #f + '() + 0)) + +(define-record-type + (%make-input-buffer binary-port decoder normalizer + bytes peeked decoded-chars line) + input-buffer? + (binary-port input-buffer-binary-port) + (decoder input-buffer-decoder + set-input-buffer-decoder!) + (normalizer input-buffer-normalizer + set-input-buffer-normalizer!) + (bytes input-buffer-bytes) + (peeked input-buffer-peeked + set-input-buffer-peeked!) + (decoded-chars input-buffer-decoded-chars + set-input-buffer-decoded-chars!) + (line input-buffer-line + set-input-buffer-line!)) (define (input-buffer-open? ib) - (and (%input-buffer-open? ib) - ((source/open? (input-buffer-source ib))))) - -(define (%input-buffer-open? ib) - (fix:>= (input-buffer-end ib) 0)) - -(define (clear-input-buffer ib) - (set-input-buffer-prev! ib byte-buffer-length) - (set-input-buffer-start! ib byte-buffer-length) - (set-input-buffer-end! ib byte-buffer-length)) - -(define (close-input-buffer ib) - ((source/close (input-buffer-source ib))) - (set-input-buffer-line! ib -1) - (set-input-buffer-prev! ib -1) - (set-input-buffer-start! ib -1) - (set-input-buffer-end! ib -1)) - + (binary-input-port-open? (input-buffer-binary-port ib))) + (define (input-buffer-channel ib) - ((source/get-channel (input-buffer-source ib)))) + (input-source-channel (%input-buffer-source ib))) (define (input-buffer-port ib) - ((source/get-port (input-buffer-source ib)))) - -(define (input-buffer-at-eof? ib) - (or (fix:<= (input-buffer-end ib) 0) - (and (fix:= (input-buffer-prev ib) 0) - (fix:= (input-buffer-start ib) (input-buffer-end ib))))) - -(define (input-buffer-encoded-character-size ib char) - ((input-buffer-compute-encoded-character-size ib) ib char)) - -(define (read-next-char ib) - (let ((char ((input-buffer-normalize ib) ib))) - (if (and (char? char) - (char=? char #\newline)) - (let ((line (input-buffer-line ib))) - (if line - (set-input-buffer-line! ib (fix:+ line 1))))) - char)) + (input-source-port (%input-buffer-source ib))) -(define (decode-char ib) - (and (fix:< (input-buffer-start ib) (input-buffer-end ib)) - (let ((cp ((input-buffer-decode ib) ib))) - (and cp - (integer->char cp))))) +(define (set-input-buffer-port! ib port) + (set-input-source-port! (%input-buffer-source ib) port)) -(define (reset-prev-char ib) - (set-input-buffer-prev! ib (input-buffer-start ib))) +(define (%input-buffer-source ib) + (binary-input-port-source (input-buffer-binary-port ib))) +(define (input-buffer-at-eof? ib) + (binary-input-port-at-eof? (input-buffer-binary-port ib))) + (define (set-input-buffer-coding! ib coding) - (reset-prev-char ib) - (set-input-buffer-decode! ib (name->decoder coding))) + (set-input-buffer-decoder! ib (name->decoder coding))) (define (set-input-buffer-line-ending! ib name) - (reset-prev-char ib) - (set-input-buffer-normalize! ib (name->normalizer name))) - -(define (input-buffer-using-binary-normalizer? ib) - (eq? (input-buffer-normalize ib) binary-normalizer)) - -(define (input-buffer-contents ib) - (substring (input-buffer-bytes ib) - (input-buffer-start ib) - (input-buffer-end ib))) - -(define (set-input-buffer-contents! ib contents) - (guarantee-string contents 'SET-INPUT-BUFFER-CONTENTS!) - (let ((bv (input-buffer-bytes ib))) - (let ((n (fix:min (string-length contents) (string-length bv)))) - (substring-move! contents 0 n bv 0) - (set-input-buffer-prev! ib 0) - (set-input-buffer-start! ib 0) - (set-input-buffer-end! ib n)))) - -(define (input-buffer-free-bytes ib) - (fix:- (input-buffer-end ib) - (input-buffer-start ib))) - -(define (fill-input-buffer ib) - (if (input-buffer-at-eof? ib) - 'EOF - (let ((n (read-bytes ib))) - (cond ((not n) 'WOULD-BLOCK) - ((fix:> n 0) 'OK) - (else 'EOF))))) - -(define (buffer-has-input? ib) - (or (next-char-ready? ib) - (input-buffer-at-eof? ib) - (and ((source/has-bytes? (input-buffer-source ib))) - (begin - (read-bytes ib) - (next-char-ready? ib))))) - -(define (next-char-ready? ib) - (let ((bl (input-buffer-line ib)) - (bs (input-buffer-start ib))) - (and (read-next-char ib) - (begin - (set-input-buffer-line! ib bl) - (set-input-buffer-start! ib bs) - #t)))) - -(define (read-bytes ib) - ;; assumption: (not (input-buffer-at-eof? ib)) - (reset-prev-char ib) - (let ((bv (input-buffer-bytes ib))) - (let ((do-read - (lambda (be) - (let ((be* (fix:+ be page-size))) - (if (not (fix:<= be* (vector-8b-length bv))) - (error "Input buffer overflow:" ib)) - ((source/read (input-buffer-source ib)) bv be be*))))) - (let ((bs (input-buffer-start ib)) - (be (input-buffer-end ib))) - (if (fix:< bs be) - (begin - (if (fix:> bs 0) - (do ((i bs (fix:+ i 1)) - (j 0 (fix:+ j 1))) - ((not (fix:< i be)) - (set-input-buffer-prev! ib 0) - (set-input-buffer-start! ib 0) - (set-input-buffer-end! ib j)) - (string-set! bv j (string-ref bv i)))) - (let ((be (input-buffer-end ib))) - (let ((n (do-read be))) - (if n - (set-input-buffer-end! ib (fix:+ be n))) - n))) - (let ((n (do-read 0))) - (if n - (begin - (set-input-buffer-prev! ib 0) - (set-input-buffer-start! ib 0) - (set-input-buffer-end! ib n))) - n)))))) - -(define (read-substring ib string start end) - (reset-prev-char ib) - (cond ((string? string) - (if (input-buffer-in-8-bit-mode? ib) - (let ((bv (input-buffer-bytes ib)) - (bs (input-buffer-start ib)) - (be (input-buffer-end ib))) - (if (fix:< bs be) - (let ((n (fix:min (fix:- be bs) (fix:- end start)))) - (let ((be (fix:+ bs n))) - (%substring-move! bv bs be string start) - (set-input-buffer-prev! ib be) - (set-input-buffer-start! ib be) - n)) - ((source/read (input-buffer-source ib)) string start end))) - (read-to-8-bit ib string start end))) - ((wide-string? string) - (let ((v (wide-string-contents string))) - (let loop ((i start)) - (cond ((not (fix:< i end)) - (fix:- i start)) - ((read-next-char ib) - => (lambda (char) - (vector-set! v i char) - (loop (fix:+ i 1)))) - ((fix:> i start) - (fix:- i start)) - (else - (let ((r (fill-input-buffer ib))) - (case r - ((OK) (loop i)) - ((WOULD-BLOCK) #f) - ((EOF) 0) - (else (error "Unknown result:" r))))))))) - (else - (error:not-string string 'INPUT-PORT/READ-SUBSTRING!)))) - -(define (input-buffer-in-8-bit-mode? ib) - (and (eq? (input-buffer-decode ib) binary-decoder) - (eq? (input-buffer-normalize ib) binary-normalizer))) - -(define (read-to-8-bit ib string start end) - (let ((n - (let loop ((i start)) - (if (fix:< i end) - (let ((char (read-next-char ib))) - (if char - (if (fix:< (char->integer char) #x100) - (begin - (string-set! string i char) - (loop (fix:+ i 1))) - (error "Character too large for 8-bit string:" char)) - (fix:- i start))) - (fix:- i start))))) - (if (fix:> n 0) - n - (let ((r (fill-input-buffer ib))) - (case r - ((OK) (read-to-8-bit ib string start end)) - ((WOULD-BLOCK) #f) - ((EOF) 0) - (else (error "Unknown result:" r))))))) + (set-input-buffer-normalizer! ib (name->normalizer name))) + +(define (generic-input-port-buffer-contents port) + (binary-input-port-buffer-contents + (input-buffer-binary-port (port-input-buffer port)))) + +(define (set-generic-input-port-buffer-contents! port contents) + (set-binary-input-port-buffer-contents! + (input-buffer-binary-port (port-input-buffer port)) + contents)) + +;; Next two for use only in normalizers. + +(define (decode-char ib) + (let ((chars (input-buffer-decoded-chars ib))) + (if (pair? chars) + (let ((char (car chars))) + (set-input-buffer-decoded-chars! ib (cdr chars)) + char) + (let ((u8 (peek-byte ib))) + (if (fix:fixnum? u8) + ((input-buffer-decoder ib) ib) + u8))))) + +(define (unread-decoded-char ib char) + (set-input-buffer-decoded-chars! + ib + (cons char (input-buffer-decoded-chars ib)))) + +;;; Next three for use only in decoders. + +(define (peek-byte ib) + (peek-u8 (input-buffer-binary-port ib))) + +(define (read-byte ib) + (read-u8 (input-buffer-binary-port ib))) + +(define (read-bytes! ib start end) + (let loop ((index start)) + (if (fix:< index end) + (let ((n + (read-bytevector! (input-buffer-bytes ib) + (input-buffer-binary-port ib) + index + end))) + (if (not (and (fix:fixnum? n) (fix:> n 0))) + (error:char-decoding ib)) + (loop (fix:+ index n)))))) ;;;; Output buffer -(define-structure (output-buffer (constructor %make-output-buffer)) - (sink #f read-only #t) - (bytes #f read-only #t) - start - total - encode - denormalize - column) - -(define (make-output-buffer sink coder-name normalizer-name) - (%make-output-buffer sink - (make-string byte-buffer-length) - 0 - 0 +(define (make-output-buffer binary-port coder-name normalizer-name) + (%make-output-buffer binary-port (name->encoder coder-name) (name->denormalizer - (line-ending ((sink/get-channel sink)) + (line-ending (binary-output-port-channel binary-port) normalizer-name #t)) + (make-bytevector max-char-bytes) + 0 + 0 0)) -(define (output-buffer-open? ob) - (and (%output-buffer-open? ob) - ((sink/open? (output-buffer-sink ob))))) - -(define (%output-buffer-open? ob) - (fix:>= (output-buffer-start ob) 0)) +(define-record-type + (%make-output-buffer binary-port encoder denormalizer + bytes line column total) + output-buffer? + (binary-port output-buffer-binary-port) + (encoder output-buffer-encoder + set-output-buffer-encoder!) + (denormalizer output-buffer-denormalizer + set-output-buffer-denormalizer!) + (bytes output-buffer-bytes) + (line output-buffer-line + set-output-buffer-line!) + (column output-buffer-column + set-output-buffer-column!) + (total output-buffer-total + set-output-buffer-total!)) -(define (close-output-buffer ob) - (if (output-buffer-open? ob) - (begin - (force-drain-output-buffer ob) - ((sink/close (output-buffer-sink ob))) - (set-output-buffer-start! ob -1)))) +(define (output-buffer-open? ob) + (binary-output-port-open? (output-buffer-binary-port ob))) (define (output-buffer-channel ob) - ((sink/get-channel (output-buffer-sink ob)))) + (output-sink-channel (%output-buffer-sink ob))) (define (output-buffer-port ob) - ((sink/get-port (output-buffer-sink ob)))) + (output-sink-port (%output-buffer-sink ob))) -(define-integrable (output-buffer-end ob) - (string-length (output-buffer-bytes ob))) +(define (set-output-buffer-port! ob port) + (set-output-sink-port! (%output-buffer-sink ob) port)) -(define (flush-output-buffer buffer) - (set-output-buffer-start! buffer 0)) +(define (%output-buffer-sink ob) + (binary-output-port-sink (output-buffer-binary-port ob))) -(define (force-drain-output-buffer ob) +(define (flush-output-buffer ob) (let ((channel (output-buffer-channel ob)) - (drain-buffer + (do-flush (lambda () - (let loop () - (drain-output-buffer ob) - (if (fix:> (output-buffer-start ob) 0) - (loop)))))) + (flush-binary-output-port (output-buffer-binary-port ob))))) (if channel - (with-channel-blocking channel #t drain-buffer) - (drain-buffer)))) + (with-channel-blocking channel #t do-flush) + (do-flush)))) -(define (drain-output-buffer ob) - (let ((bs (output-buffer-start ob))) - (if (fix:> bs 0) - (let ((bv (output-buffer-bytes ob))) - (let ((n - ((sink/write (output-buffer-sink ob)) - bv - 0 - (fix:min bs page-size)))) - (if (and n (fix:> n 0)) - (do ((bi n (fix:+ bi 1)) - (bj 0 (fix:+ bj 1))) - ((not (fix:< bi bs)) - (set-output-buffer-start! ob bj)) - (vector-8b-set! bv bj (vector-8b-ref bv bi)))) - n)) - 0))) +(define (set-output-buffer-coding! ob coding) + (set-output-buffer-encoder! ob (name->encoder coding))) -(define (write-next-char ob char) - (and (fix:< (output-buffer-start ob) page-size) - (begin - ((output-buffer-denormalize ob) ob char) - (if (char=? char #\newline) - (set-output-buffer-column! ob 0) - (let ((column (output-buffer-column ob))) - (if column - (set-output-buffer-column! - ob - (cond ((char=? char #\tab) - (fix:+ column (fix:- 8 (fix:remainder column 8)))) - ((and (fix:<= #x20 (char->integer char)) - (fix:<= (char->integer char) #x7E)) - (fix:+ column 1)) - (else #f)))))) - #t))) - -(define (output-buffer-in-8-bit-mode? ob) - (and (eq? (output-buffer-encode ob) binary-encoder) - (eq? (output-buffer-denormalize ob) binary-denormalizer))) +(define (set-output-buffer-line-ending! ob name) + (set-output-buffer-denormalizer! ob (name->denormalizer name))) (define (output-buffer-using-binary-denormalizer? ob) - (eq? (output-buffer-denormalize ob) binary-denormalizer)) + (eq? (output-buffer-denormalizer ob) binary-denormalizer)) +;; Returns >0 if the character was written in its entirety. +;; Returns 0 if the character wasn't written at all. +;; Returns #f if the write would block. +;; Throws an error if there was a short write. +(define (write-next-char ob char) + (let ((n ((output-buffer-denormalizer ob) ob char))) + (if (and n (fix:> n 0)) + (if (char=? char #\newline) + (begin + (set-output-buffer-column! ob 0) + (set-output-buffer-line! ob (fix:+ (output-buffer-line ob) 1))) + (let ((column (output-buffer-column ob))) + (if column + (set-output-buffer-column! + ob + (cond ((char=? char #\tab) + (fix:+ column (fix:- 8 (fix:remainder column 8)))) + ((and (fix:<= #x20 (char->integer char)) + (fix:<= (char->integer char) #x7E)) + (fix:+ column 1)) + (else #f))))))) + n)) + +;; For use only in denormalizers. +;; Returns 1 if the character was written in its entirety. +;; Returns 0 if the character wasn't written at all. +;; Returns #f if the write would block. +;; Throws an error if there was a short write. (define (encode-char ob char) - (let ((n-bytes ((output-buffer-encode ob) ob (char->integer char)))) - (set-output-buffer-start! ob (fix:+ (output-buffer-start ob) n-bytes)) - (set-output-buffer-total! ob (fix:+ (output-buffer-total ob) n-bytes)))) - -(define (set-output-buffer-coding! ob coding) - (set-output-buffer-encode! ob (name->encoder coding))) - -(define (set-output-buffer-line-ending! ob name) - (set-output-buffer-denormalize! ob (name->denormalizer name))) - -(define (write-substring ob string start end) - (cond ((string? string) - (let loop ((i start)) - (if (fix:< i end) - (if (write-next-char ob (string-ref string i)) - (loop (fix:+ i 1)) - (let ((n (drain-output-buffer ob))) - (cond ((not n) (and (fix:> i start) (fix:- i start))) - ((fix:> n 0) (loop i)) - (else (fix:- i start))))) - (fix:- end start)))) - ((wide-string? string) - (let ((v (wide-string-contents string))) - (let loop ((i start)) - (if (fix:< i end) - (if (write-next-char ob (vector-ref v i)) - (loop (fix:+ i 1)) - (let ((n (drain-output-buffer ob))) - (cond ((not n) (and (fix:> i start) (fix:- i start))) - ((fix:> n 0) (loop i)) - (else (fix:- i start))))) - (fix:- end start))))) - (else - (error:not-string string 'OUTPUT-PORT/WRITE-SUBSTRING)))) + (let ((n ((output-buffer-encoder ob) ob char))) + (let ((m + (write-bytevector (output-buffer-bytes ob) + (output-buffer-binary-port ob) + 0 + n))) + (if (and m (fix:> m 0)) + (begin + (if (fix:< m n) + (error:char-encoding ob char)) + (set-output-buffer-total! ob (fix:+ (output-buffer-total ob) n)) + 1) + m)))) ;;;; 8-bit codecs (define-decoder 'ISO-8859-1 (lambda (ib) - (let ((cp (vector-8b-ref (input-buffer-bytes ib) (input-buffer-start ib)))) - (set-input-buffer-start! ib (fix:+ (input-buffer-start ib) 1)) - cp))) + (let ((sv (read-byte ib))) + (if (fix:fixnum? sv) + (integer->char sv) + sv)))) (define-encoder 'ISO-8859-1 - (lambda (ob cp) - (if (not (fix:< cp #x100)) - (error:char-encoding ob cp)) - (vector-8b-set! (output-buffer-bytes ob) (output-buffer-start ob) cp) - 1)) - -(define-sizer 'ISO-8859-1 - (lambda (ib cp) - ib cp + (lambda (ob char) + (let ((cp (char->integer char))) + (if (not (fix:< cp #x100)) + (error:char-encoding ob cp)) + (bytevector-u8-set! (output-buffer-bytes ob) 0 cp)) 1)) (define-coding-aliases 'ISO-8859-1 @@ -1061,69 +795,61 @@ USA. (let ((name (cadr form)) (start (caddr form)) (code-points (cdddr form))) - `(BEGIN - (DEFINE-DECODER ',name - (LET ((TABLE - #(,@(let loop ((i 0)) - (if (fix:< i start) - (cons i (loop (fix:+ i 1))) - code-points))))) - (LAMBDA (IB) - (DECODE-8-BIT IB TABLE)))) - (DEFINE-ENCODER ',name - (RECEIVE (LHS RHS) (REVERSE-ISO-8859-MAP ,start ',code-points) - (LAMBDA (OB CP) - (ENCODE-8-BIT OB CP ,start LHS RHS)))) - (DEFINE-SIZER-ALIAS ',name 'ISO-8859-1))) + (let ((alist + (sort (filter-map (lambda (cp byte) + (and cp + (cons cp byte))) + code-points + (iota (length code-points) start)) + (lambda (a b) + (fix:< (car a) (car b)))))) + (let ((lhs (list->vector (map car alist))) + (rhs (map cdr alist))) + `(BEGIN + (DEFINE-DECODER ',name + (LET ((TABLE + #(,@(map (lambda (cp) + (and cp + (integer->char cp))) + (let loop ((i 0)) + (if (fix:< i start) + (cons i (loop (fix:+ i 1))) + code-points)))))) + (LAMBDA (IB) + (DECODE-8-BIT IB TABLE)))) + (DEFINE-ENCODER ',name + (LET ((LHS ',lhs) + (RHS (APPLY BYTEVECTOR ',rhs))) + (LAMBDA (OB CHAR) + (ENCODE-8-BIT OB CHAR ,start LHS RHS)))))))) (ill-formed-syntax form))))) (define (decode-8-bit ib table) - (let ((cp - (vector-ref table - (vector-8b-ref (input-buffer-bytes ib) - (input-buffer-start ib))))) - (if cp - (begin - (set-input-buffer-start! ib (fix:+ (input-buffer-start ib) 1)) - cp) - (error:char-decoding ib)))) - -(define (encode-8-bit ob cp start map-lhs map-rhs) - (vector-8b-set! (input-buffer-bytes ob) - (input-buffer-start ob) - (if (fix:< cp start) - cp - (let loop ((low 0) (high (vector-length map-lhs))) - (if (not (fix:< low high)) - (error:char-encoding ob cp)) - (let ((i (fix:quotient (fix:+ low high) 2))) - (cond ((fix:< cp (vector-ref map-lhs i)) - (loop low i)) - ((fix:> cp (vector-ref map-lhs i)) - (loop (fix:+ i 1) high)) - (else - (vector-8b-ref map-rhs i))))))) + (let ((u8 (read-byte ib))) + (if (fix:fixnum? u8) + (let ((char (vector-ref table u8))) + (if (not char) + (error:char-decoding ib)) + char) + u8))) + +(define (encode-8-bit ob char start map-lhs map-rhs) + (bytevector-u8-set! (output-buffer-bytes ob) + 0 + (let ((cp (char->integer char))) + (if (fix:< cp start) + cp + (let loop ((low 0) (high (vector-length map-lhs))) + (if (not (fix:< low high)) + (error:char-encoding ob cp)) + (let ((i (fix:quotient (fix:+ low high) 2))) + (cond ((fix:< cp (vector-ref map-lhs i)) + (loop low i)) + ((fix:> cp (vector-ref map-lhs i)) + (loop (fix:+ i 1) high)) + (else + (bytevector-u8-ref map-rhs i)))))))) 1) - -(define (reverse-iso-8859-map start code-points) - (let ((n (length code-points))) - (let ((lhs (make-vector n)) - (rhs (make-vector-8b n))) - (do ((alist (sort (let loop ((code-points code-points) (i start)) - (if (pair? code-points) - (if (car code-points) - (cons (cons (car code-points) i) - (loop (cdr code-points) (fix:+ i 1))) - (loop (cdr code-points) (fix:+ i 1))) - '())) - (lambda (a b) - (fix:< (car a) (car b)))) - (cdr alist)) - (i 0 (fix:+ i 1))) - ((not (pair? alist))) - (vector-set! lhs i (caar alist)) - (vector-8b-set! rhs i (cdar alist))) - (values lhs rhs)))) (define-8-bit-codecs iso-8859-2 #xA1 #x0104 #x02D8 #x0141 #x00A4 #x013D #x015A #x00A7 #x00A8 @@ -1586,187 +1312,46 @@ USA. (define-decoder 'UTF-8 (lambda (ib) + (let ((n (initial-byte->utf8-char-length (peek-byte ib)))) + (read-bytes! ib 0 n) + (decode-utf8-char (input-buffer-bytes ib) 0)))) - (define-integrable (done cp bs) - (set-input-buffer-start! ib bs) - cp) - - (let ((bv (input-buffer-bytes ib)) - (bs (input-buffer-start ib))) - (let ((b0 (get-byte bv bs 0))) - (cond ((fix:< b0 #x80) - (done b0 (fix:+ bs 1))) - ((fix:< b0 #xE0) - (and (fix:<= (fix:+ bs 2) (input-buffer-end ib)) - (let ((b1 (get-byte bv bs 1))) - (if (and (fix:> b0 #xC1) - (trailing-byte? b1)) - (done (fix:or (extract b0 #x1F 6) - (extract b1 #x3F 0)) - (fix:+ bs 2)) - (error:char-decoding ib))))) - ((fix:< b0 #xF0) - (and (fix:<= (fix:+ bs 3) (input-buffer-end ib)) - (let ((b1 (get-byte bv bs 1)) - (b2 (get-byte bv bs 2))) - (if (and (or (fix:> b0 #xE0) (fix:> b1 #x9F)) - (trailing-byte? b1) - (trailing-byte? b2)) - (let ((cp - (fix:or (fix:or (extract b0 #x0F 12) - (extract b1 #x3F 6)) - (extract b2 #x3F 0)))) - (if (illegal-low? cp) - (error:char-decoding ib) - (done cp (fix:+ bs 3)))) - (error:char-decoding ib))))) - ((fix:< b0 #xF8) - (and (fix:<= (fix:+ bs 4) (input-buffer-end ib)) - (let ((b1 (get-byte bv bs 1)) - (b2 (get-byte bv bs 2)) - (b3 (get-byte bv bs 3))) - (if (and (or (fix:> b0 #xF0) (fix:> b1 #x8F)) - (trailing-byte? b1) - (trailing-byte? b2) - (trailing-byte? b3)) - (let ((cp - (fix:or (fix:or (extract b0 #x07 18) - (extract b1 #x3F 12)) - (fix:or (extract b2 #x3F 6) - (extract b3 #x3F 0))))) - (if (fix:< cp #x110000) - (done cp (fix:+ bs 4)) - (error:char-decoding ib))) - (error:char-decoding ib))))) - (else - (error:char-decoding ib))))))) - (define-encoder 'UTF-8 - (lambda (ob cp) - (let ((bv (output-buffer-bytes ob)) - (bs (output-buffer-start ob))) - - (define-integrable (initial-byte n-bits offset) - (fix:or (fix:and (fix:lsh #xFF (fix:+ n-bits 1)) #xFF) - (fix:lsh cp (fix:- 0 offset)))) - - (define-integrable (trailing-byte offset) - (fix:or #x80 (fix:and (fix:lsh cp (fix:- 0 offset)) #x3F))) - - (cond ((fix:< cp #x00000080) - (put-byte bv bs 0 cp) - 1) - ((fix:< cp #x00000800) - (put-byte bv bs 0 (initial-byte 5 6)) - (put-byte bv bs 1 (trailing-byte 0)) - 2) - ((fix:< cp #x00010000) - (put-byte bv bs 0 (initial-byte 4 12)) - (put-byte bv bs 1 (trailing-byte 6)) - (put-byte bv bs 2 (trailing-byte 0)) - 3) - ((fix:< cp #x00110000) - (put-byte bv bs 0 (initial-byte 3 18)) - (put-byte bv bs 1 (trailing-byte 12)) - (put-byte bv bs 2 (trailing-byte 6)) - (put-byte bv bs 3 (trailing-byte 0)) - 4) - (else - (error:char-encoding ob cp)))))) - -(define-sizer 'UTF-8 - (lambda (ib cp) - (cond ((fix:< cp #x00000080) 1) - ((fix:< cp #x00000800) 2) - ((fix:< cp #x00010000) 3) - ((fix:< cp #x00110000) 4) - (else (error:char-encoding ib cp))))) - -(define-integrable (get-byte bv base offset) - (vector-8b-ref bv (fix:+ base offset))) - -(define-integrable (put-byte bv base offset byte) - (vector-8b-set! bv (fix:+ base offset) byte)) - -(define-integrable (extract b m n) - (fix:lsh (fix:and b m) n)) - -(define-integrable (trailing-byte? b) - (fix:= (fix:and #xC0 b) #x80)) - -(define-integrable (illegal-low? n) - (or (fix:= (fix:and #xF800 n) #xD800) - (fix:= (fix:and #xFFFE n) #xFFFE))) - + (lambda (ob char) + (encode-utf8-char! (output-buffer-bytes ob) 0 char))) + (let ((alias (lambda () (if (host-big-endian?) 'UTF-16BE 'UTF-16LE)))) (define-decoder-alias 'UTF-16 alias) (define-encoder-alias 'UTF-16 alias)) -(define-decoder 'UTF-16BE (lambda (ib) (decode-utf-16 ib be-bytes->digit16))) -(define-decoder 'UTF-16LE (lambda (ib) (decode-utf-16 ib le-bytes->digit16))) - -(define-integrable (decode-utf-16 ib combine) - - (define-integrable (done cp bs) - (set-input-buffer-start! ib bs) - cp) - - (let ((bv (input-buffer-bytes ib)) - (bs (input-buffer-start ib))) - (and (fix:<= (fix:+ bs 2) (input-buffer-end ib)) - (let ((d0 - (combine (get-byte bv bs 0) - (get-byte bv bs 1)))) - (if (utf16-high-surrogate? d0) - (and (fix:<= (fix:+ bs 4) (input-buffer-end ib)) - (let ((d1 - (combine (get-byte bv bs 2) - (get-byte bv bs 3)))) - (if (utf16-low-surrogate? d1) - (done (combine-utf16-surrogates d0 d1) (fix:+ bs 4)) - (error:char-decoding ib)))) - (if (illegal-low? d0) - (error:char-decoding ib) - (done d0 (fix:+ bs 2)))))))) +(define-decoder 'utf-16be + (lambda (ib) + (read-bytes! ib 0 2) + (let ((n + (initial-u16->utf16-char-length + (bytevector-u16be-ref (input-buffer-bytes ib) 0)))) + (if (fix:> n 2) + (read-bytes! ib 2 n)) + (decode-utf16be-char (input-buffer-bytes ib) 0)))) + +(define-decoder 'utf-16le + (lambda (ib) + (read-bytes! ib 0 2) + (let ((n + (initial-u16->utf16-char-length + (bytevector-u16le-ref (input-buffer-bytes ib) 0)))) + (if (fix:> n 2) + (read-bytes! ib 2 n)) + (decode-utf16le-char (input-buffer-bytes ib) 0)))) (define-encoder 'UTF-16BE - (lambda (ob cp) - (encode-utf-16 ob cp high-byte low-byte))) + (lambda (ob char) + (encode-utf16be-char! (output-buffer-bytes ob) 0 char))) (define-encoder 'UTF-16LE - (lambda (ob cp) - (encode-utf-16 ob cp low-byte high-byte))) - -(define-integrable (encode-utf-16 ob cp first-byte second-byte) - (let ((bv (output-buffer-bytes ob)) - (bs (output-buffer-start ob))) - (cond ((fix:< cp #x10000) - (put-byte bv bs 0 (first-byte cp)) - (put-byte bv bs 1 (second-byte cp)) - 2) - ((fix:< cp #x110000) - (receive (h l) (split-into-utf16-surrogates cp) - (put-byte bv bs 0 (first-byte h)) - (put-byte bv bs 1 (second-byte h)) - (put-byte bv bs 2 (first-byte l)) - (put-byte bv bs 3 (second-byte l))) - 4) - (else - (error:char-encoding ob cp))))) - -(define-sizer 'UTF-16 - (lambda (ib cp) - (cond ((fix:< cp #x00010000) 2) - ((fix:< cp #x00110000) 4) - (else (error:char-encoding ib cp))))) -(define-sizer-alias 'UTF-16BE 'UTF-16) -(define-sizer-alias 'UTF-16LE 'UTF-16) - -(define-integrable (be-bytes->digit16 b0 b1) (fix:or (fix:lsh b0 8) b1)) -(define-integrable (le-bytes->digit16 b0 b1) (fix:or b0 (fix:lsh b1 8))) -(define-integrable (high-byte d) (fix:lsh d -8)) -(define-integrable (low-byte d) (fix:and d #xFF)) - + (lambda (ob char) + (encode-utf16le-char! (output-buffer-bytes ob) 0 char))) + (let ((alias (lambda () (if (host-big-endian?) @@ -1775,68 +1360,23 @@ USA. (define-decoder-alias 'UTF-32 alias) (define-encoder-alias 'UTF-32 alias)) -(define-decoder 'UTF-32BE +(define-decoder 'utf-32be (lambda (ib) - (let ((bv (input-buffer-bytes ib)) - (bs (input-buffer-start ib))) - (and (fix:<= (fix:+ bs 4) (input-buffer-end ib)) - (let ((cp - (+ (* (get-byte bv bs 0) #x1000000) - (* (get-byte bv bs 1) #x10000) - (* (get-byte bv bs 2) #x100) - (get-byte bv bs 3)))) - (if (unicode-scalar-value? cp) - (begin - (set-input-buffer-start! ib (fix:+ bs 4)) - cp) - (error:char-decoding ib))))))) - -(define-decoder 'UTF-32LE + (read-bytes! ib 0 4) + (decode-utf32be-char (input-buffer-bytes ib) 0))) + +(define-decoder 'utf-32le (lambda (ib) - (let ((bv (input-buffer-bytes ib)) - (bs (input-buffer-start ib))) - (and (fix:<= (fix:+ bs 4) (input-buffer-end ib)) - (let ((cp - (+ (* (get-byte bv bs 3) #x1000000) - (* (get-byte bv bs 2) #x10000) - (* (get-byte bv bs 1) #x100) - (get-byte bv bs 0)))) - (if (unicode-scalar-value? cp) - (begin - (set-input-buffer-start! ib (fix:+ bs 4)) - cp) - (error:char-decoding ib))))))) + (read-bytes! ib 0 4) + (decode-utf32le-char (input-buffer-bytes ib) 0))) (define-encoder 'UTF-32BE - (lambda (ob cp) - (if (fix:< cp #x110000) - (let ((bv (output-buffer-bytes ob)) - (bs (output-buffer-start ob))) - (put-byte bv bs 0 #x00) - (put-byte bv bs 1 (fix:and (fix:lsh cp -16) #xFF)) - (put-byte bv bs 2 (fix:and (fix:lsh cp -8) #xFF)) - (put-byte bv bs 3 (fix:and cp #xFF)) - 4) - (error:char-encoding ob cp)))) + (lambda (ob char) + (encode-utf32be-char! (output-buffer-bytes ob) 0 char))) (define-encoder 'UTF-32LE - (lambda (ob cp) - (if (fix:< cp #x110000) - (let ((bv (output-buffer-bytes ob)) - (bs (output-buffer-start ob))) - (put-byte bv bs 0 (fix:and cp #xFF)) - (put-byte bv bs 1 (fix:and (fix:lsh cp -8) #xFF)) - (put-byte bv bs 2 (fix:and (fix:lsh cp -16) #xFF)) - (put-byte bv bs 3 #x00) - 4) - (error:char-encoding ob cp)))) - -(define-sizer 'UTF-32 - (lambda (ib cp) - (cond ((fix:< cp #x110000) 4) - (else (error:char-encoding ib cp))))) -(define-sizer-alias 'UTF-32BE 'UTF-32) -(define-sizer-alias 'UTF-32LE 'UTF-32) + (lambda (ob char) + (encode-utf32le-char! (output-buffer-bytes ob) 0 char))) ;;;; Normalizers @@ -1861,67 +1401,69 @@ USA. (define-normalizer 'CRLF (lambda (ib) - (let* ((bs0 (input-buffer-start ib)) - (c0 (decode-char ib))) - (if (eq? c0 #\U+000D) - (let* ((bs1 (input-buffer-start ib)) - (c1 (decode-char ib))) - (case c1 - ((#\U+000A) - #\newline) - ((#f) - (set-input-buffer-start! ib bs0) - #f) - (else - (set-input-buffer-start! ib bs1) - c0))) - c0)))) + (let ((c0 (decode-char ib))) + (case c0 + ((#\U+000D) + (let ((c1 (decode-char ib))) + (case c1 + ((#\U+000A) + #\newline) + ((#f) + (unread-decoded-char ib c1) + (unread-decoded-char ib c0) + #f) + (else + (unread-decoded-char ib c1) + c0)))) + (else c0))))) (define-denormalizer 'CRLF (lambda (ob char) (if (char=? char #\newline) - (begin - (encode-char ob #\U+000D) - (encode-char ob #\U+000A)) + (let ((n1 (encode-char ob #\U+000D))) + (if (eq? n1 1) + (let ((n2 (encode-char ob #\U+000A))) + (if (not (eq? n2 1)) + (error:char-encoding ob char)) + 2) + n1)) (encode-char ob char)))) (define-normalizer 'XML-1.0 (lambda (ib) - (let* ((bs0 (input-buffer-start ib)) - (c0 (decode-char ib))) + (let ((c0 (decode-char ib))) (case c0 ((#\U+000D) - (let* ((bs1 (input-buffer-start ib)) - (c1 (decode-char ib))) + (let ((c1 (decode-char ib))) (case c1 ((#\U+000A) - #\U+000A) + #\newline) ((#f) - (set-input-buffer-start! ib bs0) + (unread-decoded-char ib c1) + (unread-decoded-char ib c0) #f) (else - (set-input-buffer-start! ib bs1) - #\U+000A)))) + (unread-decoded-char ib c1) + #\newline)))) (else c0))))) (define-normalizer 'XML-1.1 (lambda (ib) - (let* ((bs0 (input-buffer-start ib)) - (c0 (decode-char ib))) + (let ((c0 (decode-char ib))) (case c0 ((#\U+000D) - (let* ((bs1 (input-buffer-start ib)) - (c1 (decode-char ib))) + (let ((c1 (decode-char ib))) (case c1 ((#\U+000A #\U+0085) - #\U+000A) + #\newline) ((#f) - (set-input-buffer-start! ib bs0) + (unread-decoded-char ib c1) + (unread-decoded-char ib c0) #f) (else - (set-input-buffer-start! ib bs1) - #\U+000A)))) - ((#\U+0085 #\U+2028) #\U+000A) + (unread-decoded-char ib c1) + #\newline)))) + ((#\U+0085 #\U+2028) #\newline) (else c0))))) (define-normalizer-alias 'TEXT 'XML-1.0) @@ -1934,34 +1476,40 @@ USA. ;;;; Conditions +(define (error:char-decoding ib) + (%error:char-decoding (input-buffer-port ib))) + +(define (error:char-encoding ob cp) + (%error:char-encoding (output-buffer-port ob) (integer->char cp))) + (define condition-type:char-decoding-error) (define condition-type:char-encoding-error) -(define error:char-decoding) -(define error:char-encoding) - -(define (initialize-conditions!) - (set! condition-type:char-decoding-error - (make-condition-type 'CHAR-DECODING-ERROR condition-type:port-error '() - (lambda (condition port) - (write-string "The input port " port) - (write (access-condition condition 'PORT) port) - (write-string " was unable to decode a character." port) - (newline port)))) - (set! error:char-decoding - (condition-signaller condition-type:char-decoding-error - '(PORT) - standard-error-handler)) - (set! condition-type:char-encoding-error - (make-condition-type 'CHAR-ENCODING-ERROR condition-type:port-error - '(CHAR) - (lambda (condition port) - (write-string "The output port " port) - (write (access-condition condition 'PORT) port) - (write-string " was unable to encode the character " port) - (write (access-condition condition 'CHAR) port) - (newline port)))) - (set! error:char-encoding - (condition-signaller condition-type:char-encoding-error - '(PORT CHAR) - standard-error-handler)) - unspecific) \ No newline at end of file +(define %error:char-decoding) +(define %error:char-encoding) +(add-boot-init! + (lambda () + (set! condition-type:char-decoding-error + (make-condition-type 'CHAR-DECODING-ERROR condition-type:port-error '() + (lambda (condition port) + (write-string "The input port " port) + (write (access-condition condition 'PORT) port) + (write-string " was unable to decode a character." port) + (newline port)))) + (set! %error:char-decoding + (condition-signaller condition-type:char-decoding-error + '(PORT) + standard-error-handler)) + (set! condition-type:char-encoding-error + (make-condition-type 'CHAR-ENCODING-ERROR condition-type:port-error + '(CHAR) + (lambda (condition port) + (write-string "The output port " port) + (write (access-condition condition 'PORT) port) + (write-string " was unable to encode the character " port) + (write (access-condition condition 'CHAR) port) + (newline port)))) + (set! %error:char-encoding + (condition-signaller condition-type:char-encoding-error + '(PORT CHAR) + standard-error-handler)) + unspecific)) \ No newline at end of file diff --git a/src/runtime/process.scm b/src/runtime/process.scm index be5571747..b12b16456 100644 --- a/src/runtime/process.scm +++ b/src/runtime/process.scm @@ -87,7 +87,11 @@ USA. (let ((input-channel (subprocess-input-channel process)) (output-channel (subprocess-output-channel process))) (and (or input-channel output-channel) - (make-generic-i/o-port input-channel output-channel))))) + (make-generic-i/o-port + (and input-channel + (make-channel-input-source input-channel)) + (and output-channel + (make-channel-output-sink output-channel))))))) (set-subprocess-%i/o-port! process port) port))))) diff --git a/src/runtime/runtime.pkg b/src/runtime/runtime.pkg index 4812643d5..1add920e4 100644 --- a/src/runtime/runtime.pkg +++ b/src/runtime/runtime.pkg @@ -2303,23 +2303,14 @@ USA. known-output-port-coding? known-output-port-codings make-generic-i/o-port - make-non-channel-port-sink - make-non-channel-port-source primary-input-port-codings primary-output-port-codings) (export (runtime console-i/o-port) - input-buffer-contents + generic-input-port-buffer-contents make-gstate - port-input-buffer - set-input-buffer-contents!) + set-generic-input-port-buffer-contents!) (export (runtime file-i/o-port) - clear-input-buffer - input-buffer-encoded-character-size - input-buffer-free-bytes - input-buffer-using-binary-normalizer? - output-buffer-using-binary-denormalizer? - port-input-buffer - port-output-buffer) + generic-i/o-port->binary-port) (initialization (initialize-package!))) (define-package (runtime gensym) @@ -2534,9 +2525,7 @@ USA. input-source-open? input-source-port input-source? - make-binary-i/o-port - make-binary-input-port - make-binary-output-port + make-binary-port make-channel-input-source make-channel-output-sink make-non-channel-input-source @@ -2549,8 +2538,6 @@ USA. (export (runtime port) binary-input-port-channel binary-input-port-open? - binary-input-port:buffer-contents - binary-input-port:set-buffer-contents! binary-output-port-channel binary-output-port-open? binary-port-metadata @@ -2558,15 +2545,32 @@ USA. close-binary-output-port close-binary-port) (export (runtime generic-i/o-port) - close-input-source - close-output-sink + binary-input-port-at-eof? + binary-input-port-channel + binary-input-port-open? + binary-input-port-source + binary-input-port-buffer-contents + binary-output-port-buffered-byte-count + binary-output-port-channel + binary-output-port-open? + binary-output-port-sink + close-binary-input-port + close-binary-output-port + close-binary-port + flush-binary-output-port input-source-has-bytes? input-source-open? input-source-read-bytes! output-sink-open? output-sink-write-bytes + set-binary-input-port-buffer-contents! set-input-source-port! set-output-sink-port!) + (export (runtime file-i/o-port) + binary-port-length + binary-port-position + binary-port-positionable? + set-binary-port-position!) (export (runtime output-port) flush-binary-output-port)) diff --git a/src/runtime/socket.scm b/src/runtime/socket.scm index ff6d226c6..8e23dffe8 100644 --- a/src/runtime/socket.scm +++ b/src/runtime/socket.scm @@ -145,7 +145,9 @@ USA. ((ucode-primitive new-open-unix-stream-socket 2) filename p)))))) (define (make-socket-port channel) - (make-generic-i/o-port channel channel socket-port-type)) + (make-generic-i/o-port (make-channel-input-source channel) + (make-channel-output-sink channel) + socket-port-type)) (define socket-port-type) (define (initialize-package!) diff --git a/src/runtime/stringio.scm b/src/runtime/stringio.scm index d73602dd3..6c1be3c1d 100644 --- a/src/runtime/stringio.scm +++ b/src/runtime/stringio.scm @@ -244,20 +244,24 @@ USA. (make-generic-i/o-port (make-octets-source octets start end) #f octets-input-type))) - (port/set-coding port 'ISO-8859-1) - (port/set-line-ending port 'NEWLINE) + (port/set-coding port 'BINARY) + (port/set-line-ending port 'BINARY) port))) (define (make-octets-source string start end) (let ((index start)) - (make-non-channel-port-source + (make-non-channel-input-source (lambda () (< index end)) - (lambda (string* start* end*) + (lambda (bv start* end*) (let ((n (min (- end index) (- end* start*)))) (let ((limit (+ index n))) - (xsubstring-move! string index limit string* start*) - (set! index limit)) + (do ((i index (+ i 1)) + (j start* (+ j 1))) + ((not (< i limit)) + (set! index i)) + (bytevector-u8-set! bv j + (char->ascii (xstring-ref string i))))) n))))) (define (make-octets-input-type) @@ -473,8 +477,8 @@ USA. port)) (define (make-byte-sink os) - (make-non-channel-port-sink - (lambda (octets start end) + (make-non-channel-output-sink + (lambda (bv start end) (let ((index (ostate-index os))) (let ((n (fix:+ index (fix:- end start)))) (let ((buffer (ostate-buffer os))) @@ -489,7 +493,11 @@ USA. (loop (fix:+ m m))))))) (substring-move! buffer 0 index new 0) new)))) - (substring-move! octets start end (ostate-buffer os) index) + (let ((buffer (ostate-buffer os))) + (do ((i start (fix:+ i 1)) + (j index (fix:+ j 1))) + ((not (fix:< i end))) + (vector-8b-set! buffer j (bytevector-u8-ref bv j)))) (set-ostate-index! os n) (fix:- end start)))))) diff --git a/src/runtime/ttyio.scm b/src/runtime/ttyio.scm index 36de538b6..0a47a04b8 100644 --- a/src/runtime/ttyio.scm +++ b/src/runtime/ttyio.scm @@ -65,23 +65,22 @@ USA. (define (save-console-input) ((ucode-primitive reload-save-string 1) - (input-buffer-contents (port-input-buffer console-input-port)))) + (generic-input-port-buffer-contents console-input-port))) (define (reset-console) (let ((input-channel (tty-input-channel)) (output-channel (tty-output-channel))) (set-textual-port-state! the-console-port (make-cstate input-channel output-channel)) - (let ((s ((ucode-primitive reload-retrieve-string 0)))) - (if s - (set-input-buffer-contents! (port-input-buffer the-console-port) - s))) + (let ((contents ((ucode-primitive reload-retrieve-string 0)))) + (if contents + (set-generic-input-port-buffer-contents! the-console-port contents))) (set-channel-port! input-channel the-console-port) (set-channel-port! output-channel the-console-port))) (define (make-cstate input-channel output-channel) - (make-gstate input-channel - output-channel + (make-gstate (make-channel-input-source input-channel) + (make-channel-output-sink output-channel) 'TEXT 'TEXT (channel-type=file? input-channel))) -- 2.25.1