add port->string, file->string, etc.

svn: r12388
This commit is contained in:
Matthew Flatt 2008-11-11 17:55:14 +00:00
parent 209b252f2c
commit a6d953b6f5
9 changed files with 363 additions and 16 deletions

View File

@ -44,20 +44,21 @@
(let ([c (read-bytes-avail! s src)])
(cond
[(number? c)
(for-each
(lambda (dest)
(let loop ([start 0])
(unless (= start c)
(let ([c2 (write-bytes-avail s dest start c)])
(loop (+ start c2))))))
dests)
(let loop ([dests dests])
(unless (null? dests)
(let loop ([start 0])
(unless (= start c)
(let ([c2 (write-bytes-avail s (car dests) start c)])
(loop (+ start c2)))))
(loop (cdr dests))))
(loop)]
[(procedure? c)
(let ([v (let-values ([(l col p) (port-next-location src)])
(c (object-name src) l col p))])
(for-each
(lambda (dest) (write-special v dest))
dests))
(let loop ([dests dests])
(unless (null? dests)
(write-special v (car dests))
(loop (cdr dests)))))
(loop)]
[else
;; Must be EOF

View File

@ -10,7 +10,18 @@
fold-files
find-files
pathlist-closure)
pathlist-closure
file->string
file->bytes
file->value
file->lines
file->bytes-lines
display-to-file
write-to-file
display-list-to-file)
(require "private/portlines.ss")
;; utility: sorted dirlist so functions are deterministic
(define (sorted-dirlist [dir (current-directory)])
@ -331,3 +342,95 @@
(loop2 base (if (or (member base r) (member base paths))
new (cons base new)))
(loop (cdr paths) (append (reverse new) r))))))))
(define (check-path who f)
(unless (path-string? f)
(raise-type-error who "path string" f)))
(define (check-file-mode who file-mode)
(unless (memq file-mode '(binary text))
(raise-type-error who "'binary or 'text" file-mode)))
(define (file->x who f file-mode read-x x-append)
(check-path who f)
(check-file-mode who file-mode)
(let ([sz (file-size f)])
(call-with-input-file*
f
#:mode file-mode
(lambda (in)
;; There's a good chance that `file-size' gets all the data:
(let ([s (read-x sz in)])
;; ... but double-check:
(let ([more (let loop ()
(let ([l (read-x 4096 in)])
(if (eof-object? l)
null
(cons l (loop)))))])
(if (null? more)
s
(apply x-append (cons s more)))))))))
(define (file->string f #:mode [mode 'binary])
(file->x 'file->string f mode read-string string-append))
(define (file->bytes f #:mode [mode 'binary])
(file->x 'file->bytes f mode read-bytes bytes-append))
(define (file->value f #:mode [file-mode 'binary])
(check-path 'file->value f)
(check-file-mode 'file->value file-mode)
(let ([sz (file-size f)])
(call-with-input-file*
f
#:mode file-mode
read)))
(define (file->x-lines who f line-mode file-mode read-line)
(check-path who f)
(check-mode who line-mode)
(check-file-mode who file-mode)
(call-with-input-file*
f
#:mode file-mode
(lambda (p) (port->x-lines who p line-mode read-line))))
(define (file->lines f #:line-mode [line-mode 'any] #:mode [file-mode 'binary])
(file->x-lines 'file->lines f line-mode file-mode read-line))
(define (file->bytes-lines f #:line-mode [line-mode 'any] #:mode [file-mode 'binary])
(file->x-lines 'file->bytes-lines f line-mode file-mode read-bytes-line))
(define (->file who f mode exists write)
(unless (path-string? f)
(raise-type-error who "path string" f))
(unless (memq mode '(binary text))
(raise-type-error who "'binary or 'text" mode))
(unless (memq exists '(error append update replace truncate truncate/replace))
(raise-type-error who "'error, 'append, 'update, 'replace, 'truncate, or 'truncate/replace" exists))
(call-with-output-file*
f
#:mode mode
#:exists exists
write))
(define (display-to-file s f
#:mode [mode 'binary]
#:exists [exists 'error])
(->file 'display-to-file f mode exists (lambda (p) (display s p))))
(define (write-to-file s f
#:mode [mode 'binary]
#:exists [exists 'error])
(->file 'write-to-file f mode exists (lambda (p) (write s p))))
(define (display-list-to-file l f
#:mode [mode 'binary]
#:exists [exists 'error]
#:separator [newline #"\n"])
(unless (list? l)
(raise-type-error 'display-list-to-file "list" l))
(->file 'display-list-to-file f mode exists
(lambda (p)
(do-lines->port l p newline))))

View File

@ -1,5 +1,37 @@
(module port scheme/base
(require mzlib/port)
(require mzlib/port
"private/portlines.ss")
(provide (except-out (all-from-out mzlib/port)
strip-shell-command-start)))
strip-shell-command-start)
port->string
port->bytes
port->lines
port->bytes-lines
display-list)
(define (port->string-port who p)
(unless (input-port? p)
(raise-type-error who "input-port" p))
(let ([s (open-output-string)])
(copy-port p s)
s))
(define (port->string [p (current-input-port)])
(get-output-string (port->string-port 'port->string p)))
(define (port->bytes [p (current-input-port)])
(get-output-bytes (port->string-port 'port->bytes p) #t))
(define (port->lines [p (current-input-port)] #:line-mode [mode 'any])
(port->x-lines 'port->lines p mode read-line))
(define (port->bytes-lines [p (current-input-port)] #:line-mode [mode 'any])
(port->x-lines 'port->bytes-lines p mode read-bytes-line))
(define (display-list l [p (current-output-port)] #:separator [newline #"\n"])
(unless (list? l)
(raise-type-error 'display-list "list" l))
(unless (output-port? p)
(raise-type-error 'display-list "output-port" p))
(do-lines->port l p newline)))

View File

@ -0,0 +1,24 @@
#lang scheme/base
(provide port->x-lines
check-mode
do-lines->port)
(define (check-mode who mode)
(unless (memq mode '(linefeed return return-linefeed any any-one))
(raise-type-error who "'linefeed, 'return, 'return-linefeed, 'any, or 'any-one" mode)))
(define (port->x-lines who p mode read-line)
(unless (input-port? p)
(raise-type-error who "input-port" p))
(check-mode who mode)
(let loop ([l null])
(let ([line (read-line p mode)])
(if (eof-object? line)
(reverse l)
(loop (cons line l))))))
(define (do-lines->port l p newline)
(for ([i (in-list l)])
(display i p)
(display newline p)))

View File

@ -536,6 +536,82 @@ module path.}
@note-lib[scheme/file]
@defproc[(file->string [path path-string?]
[#:mode mode-flag (or/c 'binary 'text) 'binary])
string?]{
Reads all characters from @scheme[path] and returns them as a string.
The @scheme[mode-flag] argument is the same as for
@scheme[open-input-file].}
@defproc[(file->bytes [path path-string?]
[#:mode mode-flag (or/c 'binary 'text) 'binary])
bytes?]{
Reads all characters from @scheme[path] and returns them as a
@tech{byte string}. The @scheme[mode-flag] argument is the same as
for @scheme[open-input-file].}
@defproc[(file->lines [path path-string?]
[#:mode mode-flag (or/c 'binary 'text) 'binary]
[#:line-mode line-mode (or/c 'linefeed 'return 'return-linefeed 'any 'any-one) 'any])
bytes?]{
Read all characters from @scheme[path], breaking them into lines. The
@scheme[line-mode] argument is the same as the second argument to
@scheme[read-line], but the default is @scheme['any] instead of
@scheme['linefeed]. The @scheme[mode-flag] argument is the same as for
@scheme[open-input-file].}
@defproc[(file->value [path path-string?]
[#:mode mode-flag (or/c 'binary 'text) 'binary])
bytes?]{
Reads a single S-expression from @scheme[path] using @scheme[read].
The @scheme[mode-flag] argument is the same as for
@scheme[open-input-file].}
@defproc[(file->bytes-lines [path path-string?]
[#:mode mode-flag (or/c 'binary 'text) 'binary]
[#:line-mode line-mode (or/c 'linefeed 'return 'return-linefeed 'any 'any-one) 'any])
bytes?]{
Like @scheme[file->lines], but reading bytes and collecting them into
lines like @scheme[read-bytes-line].}
@defproc[(display-to-file [v any/c]
[path path-string?]
[#:mode mode-flag (or/c 'binary 'text) 'binary]
[#:exists exists-flag (or/c 'error 'append 'update
'replace 'truncate 'truncate/replace) 'error])
void?]{
Uses @scheme[display] to print each @scheme[v] to @scheme[path]. The @scheme[mode-flag] and
@scheme[exists-flag] arguments are the same as for
@scheme[open-output-file].}
@defproc[(write-to-file [v any/c]
[path path-string?]
[#:mode mode-flag (or/c 'binary 'text) 'binary]
[#:exists exists-flag (or/c 'error 'append 'update
'replace 'truncate 'truncate/replace) 'error])
void?]{
Like @scheme[display-to-file], but using @scheme[write] instead of @scheme[display].}
@defproc[(display-list-to-file [lst list?]
[path path-string?]
[#:separator separator any/c #"\n"]
[#:mode mode-flag (or/c 'binary 'text) 'binary]
[#:exists exists-flag (or/c 'error 'append 'update
'replace 'truncate 'truncate/replace) 'error])
void?]{
Displays each element of @scheme[lst] to @scheme[path], adding
@scheme[separator] after each element. The @scheme[mode-flag] and
@scheme[exists-flag] arguments are the same as for
@scheme[open-output-file].}
@defproc[(copy-directory/files [src path-string?][dest path-string?])
void?]{

View File

@ -2,12 +2,48 @@
@(require "mz.ss"
(for-label scheme/port))
@title{More Port Constructors and Events}
@title[#:tag "port-lib"]{More Port Constructors, Procedures, and Events}
@note-lib-only[scheme/port]
@; ----------------------------------------------------------------------
@section{Port String and List Conversions}
@defproc[(port->string [in input-port? (current-input-port)]) string?]{
Reads all characters from @scheme[in] and returns them as a string.}
@defproc[(port->bytes [in input-port? (current-input-port)]) bytes?]{
Reads all bytes from @scheme[in] and returns them as a @tech{byte string}.}
@defproc[(port->lines [in input-port? (current-input-port)]
[#:line-mode line-mode (or/c 'linefeed 'return 'return-linefeed 'any 'any-one) 'any])
(listof string?)]{
Read all characters from @scheme[in], breaking them into lines. The
@scheme[line-mode] argument is the same as the second argument to
@scheme[read-line], but the default is @scheme['any] instead of
@scheme['linefeed].}
@defproc[(port->bytes-lines [in input-port? (current-input-port)]
[#:line-mode line-mode (or/c 'linefeed 'return 'return-linefeed 'any 'any-one) 'any])
(listof bytes?)]{
Like @scheme[port->lines], but reading bytes and collecting them into
lines like @scheme[read-bytes-line].}
@defproc[(display-list [lst list?]
[out output-port? (current-output-port)]
[#:separator separator any/c #"\n"])
void?]{
Use @scheme[display] to each each element of @scheme[lst] to @scheme[out], adding
@scheme[separator] after each element.}
@; ----------------------------------------------------------------------
@section{Creating Ports}
@defproc[(input-port-append [close-at-eof? any/c][in input-port?] ...) input-port?]{

View File

@ -3,10 +3,56 @@
(Section 'file)
(require mzlib/file
(require scheme/file
mzlib/process
mzlib/list)
(define tmp-name "tmp0-filelib")
(when (file-exists? tmp-name) (delete-file tmp-name))
(display-list-to-file '("a" "b" "c") tmp-name #:separator #"\r\n" #:mode 'binary)
(test "a\r\nb\r\nc\r\n" file->string tmp-name #:mode 'binary)
(test #"a\r\nb\r\nc\r\n" file->bytes tmp-name)
(test '("a" "b" "c") file->lines tmp-name)
(test '(#"a" #"b" #"c") file->bytes-lines tmp-name)
(test '("a" "b" "c") file->lines tmp-name #:line-mode 'any #:mode 'binary)
(test '(#"a" #"b" #"c") file->bytes-lines tmp-name #:line-mode 'any #:mode 'text)
(err/rt-test (display-to-file #"a\nb" tmp-name) exn:fail:filesystem:exists?)
(display-to-file #"a\nb" tmp-name #:exists 'truncate)
(test #"a\nb" file->bytes tmp-name)
(display-to-file "\u03BB" tmp-name #:exists 'truncate)
(test #"\316\273" file->bytes tmp-name)
(write-to-file "\u03BB" tmp-name #:exists 'truncate)
(test #"\"\316\273\"" file->bytes tmp-name)
(test "\u03BB" file->value tmp-name)
(define tmp-name "tmp0-filelib")
(define-syntax-rule (err/rt-chk-test (op arg ...))
(err/rt-test (op arg ...) (check-msg 'op)))
(define (check-msg op)
(lambda (exn)
(regexp-match (format "^~a: " op) (exn-message exn))))
(err/rt-chk-test (file->string 'x))
(err/rt-chk-test (file->bytes 'x))
(err/rt-chk-test (file->string "x" #:mode 'other))
(err/rt-chk-test (file->bytes "x" #:mode 'other))
(err/rt-chk-test (file->value "x" #:mode 'other))
(err/rt-chk-test (display-list-to-file 10 "x"))
(err/rt-chk-test (display-list-to-file '(10) "x" #:mode 'other))
(err/rt-chk-test (display-list-to-file '(10) "x" #:exists 'other))
(err/rt-chk-test (file->lines "x" #:line-mode 'junk))
(err/rt-chk-test (file->lines "x" #:mode 'other))
(err/rt-chk-test (file->bytes-lines "x" #:line-mode 'junk))
(err/rt-chk-test (file->bytes-lines "x" #:mode 'other))
(err/rt-chk-test (display-to-file "y" "x" #:exists 'other))
(err/rt-chk-test (display-to-file "y" "x" #:mode 'other))
(err/rt-chk-test (write-to-file #"y" "x" #:exists 'other))
(err/rt-chk-test (write-to-file #"y" "x" #:mode 'other))
(err/rt-chk-test (display-list-to-file 'y "x"))
(err/rt-chk-test (display-list-to-file '(y) "x" #:exists 'other))
(err/rt-chk-test (display-list-to-file '(y) "x" #:mode 'other))
;; ----------------------------------------
(parameterize ([current-directory (current-load-relative-directory)])
(let ([rel (find-files values)]
[abs (find-files values (current-directory))])

View File

@ -5,7 +5,31 @@
(define SLEEP-TIME 0.1)
(require mzlib/port)
(require scheme/port)
;; ----------------------------------------
(let* ([p (lambda () (open-input-string "hello\r\nthere"))])
(test "hello\r\nthere" port->string (p))
(test #"hello\r\nthere" port->bytes (p))
(test '("hello" "there") port->lines (p))
(test '(#"hello" #"there") port->bytes-lines (p))
(test '("hello\r" "there") port->lines (p) #:line-mode 'linefeed)
(test '(#"hello\r" #"there") port->bytes-lines (p) #:line-mode 'linefeed)
(test '("hello" "" "there") port->lines (p) #:line-mode 'any-one)
(test '(#"hello" #"" #"there") port->bytes-lines (p) #:line-mode 'any-one))
(let* ([x (make-string 50000 #\x)]
[p (lambda () (open-input-string x))])
(test (string-length x) 'long-string (string-length (port->string (p))))
(test (string-length x) 'long-string (bytes-length (port->bytes (p)))))
(let ([p (open-output-bytes)])
(display-list '(1 2 3) p)
(test "1\n2\n3\n" get-output-string p))
(let ([p (open-output-bytes)])
(display-list '(1 2 3) p #:separator #"!!")
(test "1!!2!!3!!" get-output-string p))
;; ----------------------------------------

View File

@ -1,5 +1,10 @@
Version 4.1.2.4
Added call-with-immediate-continuation-mark
In scheme/port: added port->string, port->bytes, port->lines
port->bytes-lines, and display-list
In scheme/file: added file->string, file->bytes, file->lines,
file->bytes-lines, write-to-file, display-to-file,
and display-list-to-file
Version 4.1.2.3
Added variable-reference? and empty #%variable-reference form