~ chicken-core (chicken-5) f4936490e67502fb81eacd37caaf3c92d107f6a2
commit f4936490e67502fb81eacd37caaf3c92d107f6a2 Author: felix <felix@call-with-current-continuation.org> AuthorDate: Tue Aug 10 04:39:18 2010 -0400 Commit: felix <felix@call-with-current-continuation.org> CommitDate: Tue Aug 10 04:39:18 2010 -0400 added copy-port (suggested by Moritz Heidkamp) diff --git a/manual/Unit ports b/manual/Unit ports index 6a50e398..e26122eb 100644 --- a/manual/Unit ports +++ b/manual/Unit ports @@ -120,6 +120,18 @@ Apply {{FN}} to successive results of calling the zero argument procedure {{THUN passing the {{ACC}} value as the second argument. The {{FN}} result becomes the new {{ACC}} value. When {{THUNK}} returns {{#!eof}}, the last {{FN}} result is returned. +==== copy-port + +<procedure>(copy-port FROM TO [READ [WRITE]])</procedure> + +Reads all remaining data from port {{FROM}} using the reader procedure +{{READ}} and writes it to port {{TO}} using the writer procedure +{{WRITE}}. {{READ}} defaults to {{read-char}} and {{WRITE} to +{{write-char}}. Note that this procedure does not check {{FROM}} and +{{TO}} for being ports, so the reader and writer procedures may +perform arbitrary operations as long as they can be invoked +as {{(READ FROM)}} and {{(WRITE X TO)}}, respectively. + === Funky ports diff --git a/ports.scm b/ports.scm index 6847a8b7..9070fcab 100644 --- a/ports.scm +++ b/ports.scm @@ -33,7 +33,9 @@ (declare - (unit ports)) + (unit ports) + (hide read-and-write write-buf read-buf read-and-write-buf)) + (include "common-declarations.scm") @@ -59,12 +61,67 @@ (loop (cons (fn x) xs)))))))) (define (port-fold fn acc thunk) - (let loop ([acc acc]) - (let ([x (thunk)]) + (let loop ((acc acc)) + (let ((x (thunk))) (if (eof-object? x) acc (loop (fn x acc))) ) ) ) +(define-constant +buf-size+ 1024) + +(define (read-buf port writer) + (let ((buf (make-string +buf-size+))) + (let loop () + (let ((n (read-string! +buf-size+ buf port))) + (unless (eq? n 0) + (writer buf n) + (loop)))))) + +(define (write-buf buf n port writer) + (do ((i 0 (fx+ i 1))) + ((fx>= i n)) + (writer (integer->char (##sys#byte buf n)) port))) + +(define (read-and-write reader writer) + (let loop () + (let ((x (reader))) + (unless (eof-object? x) + (writer x) + (loop))))) + +(define (read-and-write-buf src dest reader) + (let ((buf (make-string +buf-size+))) + (let loop ((n 0)) + (when (fx>= n +buf-size+) + (write-string buf +buf-size+ dest) + (set! n 0)) + (let ((c (reader src))) + (cond ((eof-object? c) + (when (fx>= n 0) + (write-string buf n dest))) + (else + (##sys#setbyte buf n (char->integer c)) + (loop (fx+ n 1)))))))) + +(define copy-port + (let ((read-char read-char) + (write-char write-char)) + (lambda (src dest #!optional (read read-char) (write write-char)) + ;; does not check port args intentionally + (cond ((eq? read read-char) + (read-buf + src + (if (eq? write write-char) + (lambda (buf n) (write-string buf n dest)) + (lambda (buf n) (write-buf buf n dest write))))) + ((eq? write write-char) + (read-and-write-buf src dest read)) + (else + (read-and-write + (lambda () (read src)) + (lambda (x) (write x dest)))))))) + + ;;;; funky-ports (define (make-broadcast-port . ports) diff --git a/setup-api.scm b/setup-api.scm index bffd48d7..94a609e4 100644 --- a/setup-api.scm +++ b/setup-api.scm @@ -45,7 +45,7 @@ setup-verbose-mode setup-install-mode deployment-mode installation-prefix destination-prefix - chicken-prefix ;XXX remove at some stage from exports + chicken-prefix find-library find-header program-path remove-file* patch abort-setup diff --git a/tests/port-tests.scm b/tests/port-tests.scm index 4b99cf73..bc0ae7c1 100644 --- a/tests/port-tests.scm +++ b/tests/port-tests.scm @@ -1,4 +1,4 @@ -(require-extension srfi-1) +(require-extension srfi-1 ports) (define *text* #<<EOF this is a test @@ -33,3 +33,45 @@ EOF "<foof> #;33> (let ((in (open-input-string \"\"))) (close-input-port in)" (read-line p))) (assert (= 20 (length (read-lines (open-input-string *text*))))) + + +;;; port operations + +(assert + (string=? + *text* + (with-output-to-string + (lambda () + (copy-port (open-input-string *text*) (current-output-port)))))) + +(assert + (equal? + '(3 2 1) + (let ((out '())) + (copy-port + (open-input-string "1 2 3") + #f + read + (lambda (x port) (set! out (cons x out)))) + out))) + +(print "slow...") +(time + (with-input-from-file "compiler.scm" + (lambda () + (with-output-to-file "compiler.scm.2" + (lambda () + (copy-port + (current-input-port) (current-output-port) + (lambda (port) (read-char port)) + (lambda (x port) (write-char x port)))))))) + +(print "fast...") +(time + (with-input-from-file "compiler.scm" + (lambda () + (with-output-to-file "compiler.scm.2" + (lambda () + (copy-port (current-input-port) (current-output-port))))))) + +(delete-file "compiler.scm.2")Trap