1;;; io.ms
2;;; Copyright 1984-2017 Cisco Systems, Inc.
3;;;
4;;; Licensed under the Apache License, Version 2.0 (the "License");
5;;; you may not use this file except in compliance with the License.
6;;; You may obtain a copy of the License at
7;;;
8;;; http://www.apache.org/licenses/LICENSE-2.0
9;;;
10;;; Unless required by applicable law or agreed to in writing, software
11;;; distributed under the License is distributed on an "AS IS" BASIS,
12;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13;;; See the License for the specific language governing permissions and
14;;; limitations under the License.
15
16(define (native-string->bytevector s)
17  (string->bytevector s (native-transcoder)))
18
19; convert uses of custom-port-warning? to warning? if custom-port warnings
20; are enabled in io.ss
21(define (custom-port-warning? x) #t)
22
23(define prettytest.ss (format "~a/prettytest.ss" *mats-dir*))
24
25(mat port-operations
26  (error? (close-port cons))
27  ; the following several clauses test various open-file-output-port options
28  (let ([p (open-file-output-port "testfile.ss" (file-options no-fail))])
29    (and (port? p) (output-port? p) (begin (close-port p) #t)))
30  (error? ; file already exists
31    (open-file-output-port "testfile.ss"))
32  (error? ; file already exists
33    (open-file-output-port "testfile.ss" (file-options compressed)))
34  (let ([p (open-file-output-port "testfile.ss" (file-options replace))])
35    (and (port? p) (output-port? p) (begin (close-port p) #t)))
36  (let ([p (open-file-output-port "testfile.ss" (file-options no-fail))])
37    (and (port? p) (output-port? p) (begin (close-port p) #t)))
38  (let ([p (open-file-output-port "testfile.ss" (file-options no-fail))])
39    (put-bytevector p (native-string->bytevector "\"hello"))
40    (close-port p)
41    (let ([p (open-file-output-port "testfile.ss" (file-options no-fail no-truncate append))])
42      (put-bytevector p (native-string->bytevector " there\""))
43      (close-port p)
44      (let ([p (open-file-input-port "testfile.ss")])
45        (and (equal? (get-bytevector-all p) (native-string->bytevector "\"hello there\""))
46             (eof-object? (get-u8 p))
47             (begin (close-port p)
48                    #t)))))
49  (let ([p (let loop () (if (file-exists? "testfile.ss")
50                            (begin (delete-file "testfile.ss" #f) (loop))
51                            (open-file-output-port "testfile.ss")))])
52    (for-each (lambda (x)
53                (put-bytevector p (native-string->bytevector x))
54                (put-bytevector p (native-string->bytevector " ")))
55              '("a" "b" "c" "d" "e"))
56    (put-bytevector p (native-string->bytevector "\n"))
57    (close-port p)
58    #t)
59  (equal? (let ([p (open-file-input-port "testfile.ss")])
60            (let f ([x (get-u8 p)])
61              (if (eof-object? x)
62                  (begin (close-port p) '())
63                  (cons (integer->char x) (f (get-u8 p))))))
64          (if (eq? (native-eol-style) 'crlf)
65              '(#\a #\space #\b #\space #\c #\space
66                #\d #\space #\e #\space #\return #\newline)
67              '(#\a #\space #\b #\space #\c #\space
68                #\d #\space #\e #\space #\newline)))
69  (error? (call-with-port 3 values))
70  (error? (call-with-port (current-input-port) 'a))
71  (equal? (call-with-values
72              (lambda ()
73                (call-with-port
74                 (open-file-output-port "testfile.ss" (file-options replace))
75                 (lambda (p)
76                   (for-each (lambda (c) (put-u8 p (char->integer c)))
77                             (string->list "a b c d e"))
78                   (values 1 2 3))))
79            list)
80          '(1 2 3))
81  (equal? (call-with-port
82           (open-file-input-port "testfile.ss")
83           (lambda (p)
84             (list->string
85              (let f ()
86                (let ([c (get-u8 p)])
87                  (if (eof-object? c)
88                      '()
89                      (begin (unget-u8 p c)
90                             (let ([c (get-u8 p)])
91                               (cons (integer->char c) (f))))))))))
92          "a b c d e")
93  (equal? (call-with-port
94           (open-file-input-port "testfile.ss")
95           (lambda (p)
96             (list->string
97              (let f ()
98                (let ([c (get-u8 p)])
99                  (unget-u8 p c)
100                  (if (eof-object? c)
101                      (begin
102                        (unless (and (eof-object? (lookahead-u8 p))
103                                     (port-eof? p)
104                                     (eof-object? (get-u8 p)))
105                          (errorf #f "unget of eof apparently failed"))
106                        '())
107                      (let ([c (get-u8 p)])
108                        (cons (integer->char c) (f)))))))))
109          "a b c d e")
110  (andmap (lambda (p)
111            (equal? (call-with-port
112                     p
113                     (lambda (p)
114                       (list->string
115                        (let f ()
116                          (let ([c (lookahead-u8 p)])
117                            (if (eof-object? c)
118                                '()
119                                (let ([c (get-u8 p)])
120                                  (cons (integer->char c) (f)))))))))
121                    "a b c d e"))
122          (list (open-file-input-port "testfile.ss")
123                (open-bytevector-input-port '#vu8(97 32 98 32 99 32 100 32 101))
124                (open-bytevector-input-port (bytevector->immutable-bytevector '#vu8(97 32 98 32 99 32 100 32 101)))))
125  ; test various errors related to input ports
126  (begin (set! ip (open-file-input-port "testfile.ss"))
127         (and (port? ip) (input-port? ip)))
128  (error? ; unget can only follow get
129    (unget-u8 ip 40))
130  (eqv? (get-u8 ip) (char->integer #\a))
131  (begin (unget-u8 ip (char->integer #\a)) (eqv? (get-u8 ip) (char->integer #\a)))
132  (error? (put-u8 ip (char->integer #\a)))
133  (error? (put-bytevector ip #vu8()))
134  (error? (flush-output-port ip))
135  (begin (close-port ip) #t)
136  (begin (close-port ip) #t)
137  (error? (port-eof? ip))
138  (error? (input-port-ready? ip))
139  (error? (get-u8? ip))
140  (error? (lookahead-u8? ip))
141  (error? (unget-u8? ip))
142  (error? (get-bytevector-n ip 1))
143  (error? (get-bytevector-n! ip (make-bytevector 10) 0 10))
144  (error? (get-bytevector-some ip))
145  (error? (get-bytevector-all ip))
146  ; test various errors related to output ports
147  (begin (set! op (open-file-output-port "testfile.ss" (file-options replace)))
148         (and (port? op) (output-port? op)))
149  (error? (input-port-ready? op))
150  (error? (lookahead-u8 op))
151  (error? (get-u8 op))
152  (error? (unget-u8 op 40))
153  (error? (get-bytevector-n op 1))
154  (error? (get-bytevector-n! op (make-bytevector 10) 0 10))
155  (error? (get-bytevector-some op))
156  (error? (get-bytevector-all op))
157  (begin (close-port op) #t)
158  (begin (close-port op) #t)
159  (error? (put-u8 op (char->integer #\a)))
160  (error? (put-bytevector op #vu8(1)))
161  (error? (flush-output-port op))
162
163  (let ([s (native-string->bytevector "hi there, mom!")])
164    (let ([ip (open-bytevector-input-port s)])
165      (let-values ([(op op-ex) (open-bytevector-output-port)])
166        (do ([c (get-u8 ip) (get-u8 ip)])
167            ((eof-object? c)
168             (equal? (op-ex) s))
169             (unget-u8 ip c)
170             (put-u8 op (get-u8 ip))))))
171
172  (error? (eof-object #!eof))
173  (eq? (call-with-port (open-bytevector-input-port #vu8()) get-u8) #!eof)
174  (eq? (call-with-port (open-bytevector-input-port #vu8()) get-u8) (eof-object))
175  (eq? (eof-object) #!eof)
176  (let ([s (native-string->bytevector "hi there, mom!")])
177    (equal?
178      (call-with-port (open-bytevector-input-port s)
179        (lambda (i)
180          (call-with-bytevector-output-port
181            (lambda (o)
182              (do ([c (get-u8 i) (get-u8 i)])
183                  ((eof-object? c))
184                (unget-u8 i c)
185                (put-u8 o (get-u8 i)))))))
186      s))
187
188  ; the following makes sure that call-with-port closes the at least on
189  ; systems which restrict the number of open ports to less than 2048
190  (let ([filename "testfile.ss"])
191    (let loop ((i 2048))
192      (or (zero? i)
193          (begin
194            (call-with-port
195             (open-file-output-port filename (file-options replace))
196             (lambda (p) (put-u8 p (quotient i 256)) (put-u8 p (modulo i 256))))
197            (and (eq? (call-with-port
198                       (open-file-input-port filename)
199                       (lambda (p)
200                         (let* ([hi (get-u8 p)]
201                                [lo (get-u8 p)])
202                           (+ (* 256 hi) lo))))
203                      i)
204                 (loop (- i 1)))))))
205  (begin
206    (close-input-port #%$console-input-port)
207    (not (port-closed? #%$console-input-port)))
208  (begin
209    (close-output-port #%$console-output-port)
210    (not (port-closed? #%$console-output-port)))
211 )
212
213(mat port-operations1
214  (error? ; incorrect number of arguments
215    (open-file-input-port))
216  (error? ; furball is not a string
217    (open-file-input-port 'furball))
218  (error? ; not a file-options object
219    (open-file-input-port "testfile.ss" '()))
220  (error? ; not a valid buffer mode
221    (open-file-input-port "testfile.ss" (file-options) 17))
222  (error? ; not a transcoder
223    (open-file-input-port "testfile.ss" (file-options) (buffer-mode block) 'wow))
224  (error? ; incorrect number of arguments
225    (open-file-input-port "testfile.ss" (file-options) (buffer-mode block) #f 'now?))
226  (error? ; cannot open
227    (open-file-input-port "/probably/not/a/good/path"))
228  (error? ; cannot open
229    (open-file-input-port "/probably/not/a/good/path" (file-options compressed)))
230  (error? ; invalid options
231    (open-file-input-port "testfile.ss" (file-options uncompressed)))
232  (error? ; invalid options
233    (open-file-input-port "testfile.ss" (file-options truncate)))
234  (error? ; incorrect number of arguments
235    (open-file-output-port))
236  (error? ; furball is not a string
237    (open-file-output-port 'furball))
238  (error? ; not a file-options object
239    (open-file-output-port "testfile.ss" '(no-create)))
240  (error? ; not a valid buffer mode
241    (open-file-output-port "testfile.ss" (file-options) 17))
242  (error? ; not a transcoder
243    (open-file-output-port "testfile.ss" (file-options) (buffer-mode block) 'wow))
244  (error? ; incorrect number of arguments
245    (open-file-output-port "testfile.ss" (file-options) (buffer-mode block) #f 'now?))
246  (error? ; cannot open
247    (open-file-output-port "/probably/not/a/good/path"))
248  (error? ; invalid options
249    (open-file-output-port "testfile.ss" (file-options uncompressed)))
250  (error? ; invalid options
251    (open-file-output-port "testfile.ss" (file-options truncate)))
252  (error? ; incorrect number of arguments
253    (open-file-input/output-port))
254  (error? ; furball is not a string
255    (open-file-input/output-port 'furball))
256  (error? ; not a file-options object
257    (open-file-input/output-port "testfile.ss" '(no-create)))
258  (error? ; not a valid buffer mode
259    (open-file-input/output-port "testfile.ss" (file-options) 17))
260  (error? ; not a transcoder
261    (open-file-input/output-port "testfile.ss" (file-options) (buffer-mode block) 'wow))
262  (error? ; incorrect number of arguments
263    (open-file-input/output-port "testfile.ss" (file-options) (buffer-mode block) #f 'now?))
264  (error? ; cannot open
265    (open-file-input/output-port "/probably/not/a/good/path"))
266  (error? ; invalid options
267    (open-file-input/output-port "testfile.ss" (file-options uncompressed)))
268  (error? ; invalid options
269    (open-file-input/output-port "testfile.ss" (file-options truncate)))
270  (begin (delete-file "testfile.ss") #t)
271  (error? ; no such file
272    (open-file-input-port "testfile.ss"))
273  (error? ; no such file
274    (open-file-output-port "testfile.ss" (file-options no-create)))
275  (error? ; no such file
276    (open-file-input/output-port "testfile.ss" (file-options no-create)))
277  (begin (mkdir "testfile.ss") #t)
278  (guard (c [(and (i/o-filename-error? c)
279                  (equal? (i/o-error-filename c) "testfile.ss"))])
280    (open-file-output-port "testfile.ss" (file-options no-create)))
281  (guard (c [(and (i/o-filename-error? c)
282                  (equal? (i/o-error-filename c) "testfile.ss"))])
283    (open-file-input/output-port "testfile.ss" (file-options no-create)))
284  (begin (delete-directory "testfile.ss") #t)
285  (begin
286    (define $ppp (open-file-input/output-port "testfile.ss" (file-options replace)))
287    (and (input-port? $ppp) (output-port? $ppp) (port? $ppp)))
288  (error? (set-port-length! $ppp -3))
289  (error? (set-port-length! $ppp 'all-the-way))
290  (eof-object?
291   (begin
292     (set-port-length! $ppp 0)
293     (set-port-position! $ppp 0)
294     (put-bytevector $ppp (native-string->bytevector "hello"))
295     (flush-output-port $ppp)
296     (get-u8 $ppp)))
297  (equal? (begin (set-port-position! $ppp 0) (get-bytevector-all $ppp))
298          (native-string->bytevector "hello"))
299  (eqv? (begin
300          (put-bytevector $ppp (native-string->bytevector "goodbye\n"))
301          (truncate-port $ppp 9)
302          (port-position $ppp))
303        9)
304  (eof-object? (get-u8 $ppp))
305  (eqv? (begin (set-port-position! $ppp 0) (port-position $ppp)) 0)
306  (equal? (get-bytevector-all $ppp) (native-string->bytevector "hellogood"))
307  (eqv? (begin
308          (put-bytevector $ppp (native-string->bytevector "byebye\n"))
309          (truncate-port $ppp 0)
310          (port-position $ppp))
311        0)
312  (eof-object? (get-u8 $ppp))
313  (eof-object?
314   (begin
315     (close-port $ppp)
316     (let ([ip (open-file-input-port "testfile.ss")])
317       (let ([c (get-u8 ip)])
318         (close-port $ppp)
319         (close-port ip)
320         c))))
321  (error?
322   (let ([ip (open-file-input-port "testfile.ss")])
323     (dynamic-wind
324         void
325         (lambda () (truncate-port ip))
326         (lambda () (close-port ip)))))
327  (error? (truncate-port 'animal-crackers))
328  (error? (truncate-port))
329  (error? (truncate-port $ppp))
330  (let-values ([(op get) (open-bytevector-output-port)])
331    (and (= (port-position op) 0)
332         (= (port-length op) 0)
333         (do ([i 4000 (fx- i 1)])
334             ((fx= i 0) #t)
335           (put-bytevector op (string->utf8 "hello")))
336         (= (port-length op) 20000)
337         (= (port-position op) 20000)
338         (begin (set-port-position! op 5000) #t)
339         (= (port-position op) 5000)
340         (= (port-length op) 20000)
341         (begin (truncate-port op) #t)
342         (= (port-position op) 0)
343         (= (port-length op) 0)
344         (begin (truncate-port op 17) #t)
345         (= (port-position op) 17)
346         (= (port-length op) 17)
347         (begin (put-bytevector op (string->utf8 "okay")) #t)
348         (= (port-position op) 21)
349         (= (port-length op) 21)
350         (let ([bv (get)])
351           (and (= (char->integer #\o) (bytevector-u8-ref bv 17))
352                (= (char->integer #\k) (bytevector-u8-ref bv 18))
353                (= (char->integer #\a) (bytevector-u8-ref bv 19))
354                (= (char->integer #\y) (bytevector-u8-ref bv 20))))
355         (= (port-position op) 0)
356         (= (port-length op) 0)
357         (begin (put-u8 op (char->integer #\a))
358                (put-u8 op (char->integer #\newline))
359                #t)
360         (= (port-position op) 2)
361         (equal? (get) (string->utf8 "a\n"))))
362  (let ([ip (open-bytevector-input-port (native-string->bytevector "beam me up, scotty!"))]
363        [bv (make-bytevector 10)])
364    (and (= (port-position ip) 0)
365         (= (port-length ip) 19)
366         (not (eof-object? (lookahead-u8 ip)))
367         (equal? (get-bytevector-n ip 4) (native-string->bytevector "beam"))
368         (= (port-position ip) 4)
369         (not (eof-object? (lookahead-u8 ip)))
370         (equal? (get-bytevector-n! ip bv 0 10) 10)
371         (equal? bv (native-string->bytevector " me up, sc"))
372         (= (port-position ip) 14)
373         (equal? (get-bytevector-n! ip bv 0 10) 5)
374         (equal? bv (native-string->bytevector "otty!p, sc"))
375         (= (port-position ip) 19)
376         (eof-object? (lookahead-u8 ip))
377         (eof-object? (get-u8 ip))
378         (eof-object? (get-bytevector-n! ip bv 0 10))
379         (= (get-bytevector-n! ip bv 0 0) 0) ;; TODO: check w/ Kent about this
380         (begin
381           (set-port-position! ip 10)
382           (= (port-position ip) 10))
383         (equal? (get-bytevector-n! ip bv 0 10) 9)
384         (equal? bv (native-string->bytevector ", scotty!c"))))
385)
386
387(mat port-operations2
388  (equal?
389    (let* ([op (open-file-output-port "testfile.ss" (file-options replace) (buffer-mode none))]
390           [ip (open-file-input-port "testfile.ss")])
391      (put-u8 op 97)
392      (let* ([b1 (get-u8 ip)] [b2 (get-u8 ip)])
393        (put-u8 op 98)
394        (let* ([b3 (get-u8 ip)] [b4 (get-u8 ip)])
395          (put-u8 op 99)
396          (let ([b5 (get-u8 ip)])
397            (close-port op)
398              (let ([b6 (get-u8 ip)])
399                (close-port ip)
400                (list b1 b2 b3 b4 b5 b6))))))
401    '(97 #!eof 98 #!eof 99 #!eof))
402  (equal?
403    (let* ([op (open-file-output-port "testfile.ss" (file-options replace) (buffer-mode none))]
404           [ip (open-file-input-port "testfile.ss")])
405      (let ([eof1? (port-eof? ip)])
406        (put-u8 op 97)
407       ; the port-eof? call above buffers the eof, so b1 should be #!eof
408        (let* ([b1 (get-u8 ip)] [b2 (get-u8 ip)])
409          (put-u8 op 98)
410          (let* ([eof2? (port-eof? ip)] [b3 (get-u8 ip)])
411            (let ([b4 (get-u8 ip)])
412              (put-u8 op 99)
413              (let* ([b5 (get-u8 ip)])
414                (close-port op)
415                (let* ([b6 (get-u8 ip)] [eof3? (port-eof? ip)])
416                  (close-port ip)
417                  (list eof1? b1 b2 eof2? b3 b4 b5 b6 eof3?))))))))
418    '(#t #!eof 97 #f 98 #!eof 99 #!eof #t))
419  (equal?
420   ; following assumes block buffering really doesn't cause any writes until
421   ; at least after a few bytes have been written
422    (let* ([op (open-file-output-port "testfile.ss" (file-options replace) (buffer-mode block))]
423           [ip (open-file-input-port "testfile.ss")])
424      (put-u8 op 97)
425      (let ([b1 (get-u8 ip)])
426        (put-u8 op 98)
427        (let ([b2 (get-u8 ip)])
428          (close-port op)
429          (let* ([b3 (get-u8 ip)] [b4 (get-u8 ip)] [b5 (get-u8 ip)])
430            (close-port ip)
431            (list b1 b2 b3 b4 b5)))))
432    '(#!eof #!eof 97 98 #!eof))
433 ; test switching between input and output modes
434 ; should be adapted for textual ports
435  (equal?
436    (begin
437      (call-with-port
438        (open-file-output-port "testfile.ss" (file-options replace))
439        (lambda (p) (put-bytevector p #vu8(1 2 3 4 5))))
440      (let ([iop (open-file-input/output-port "testfile.ss"
441                   (file-options no-fail no-truncate))])
442        (let ([b1 (get-u8 iop)])
443          (put-u8 iop 17)
444          (let ([b2 (get-u8 iop)])
445            (close-port iop)
446            (list b1 b2
447              (call-with-port
448                (open-file-input-port "testfile.ss")
449                get-bytevector-all))))))
450    '(1 3 #vu8(1 17 3 4 5)))
451 ; test switching between input and output modes
452 ; old implementation is broken---uncomment for new implementation
453 ; and move to set of mats testing convenience i/o
454  #;(equal?
455    (begin
456      (with-output-to-file "testfile.ss"
457        (lambda () (display "hi there"))
458        'replace)
459      (let ([iop (open-input-output-file "testfile.ss")])
460        (let ([c1 (read-char iop)])
461          (write-char #\! iop)
462          (let ([c2 (read-char iop)])
463            (close-port iop)
464            (list c1 c2
465              (with-input-from-file "testfile.ss"
466                (lambda ()
467                  (list->string
468                    (let f ()
469                      (let ([c (read-char)])
470                        (if (eof-object? c)
471                            '()
472                            (cons c (f)))))))))))))
473    '(#\h #\space "h! there"))
474  (equal?
475    (let-values ([(p g) (open-string-output-port)])
476      (fresh-line p)
477      (fresh-line p)
478      (display "hello" p)
479      (fresh-line p)
480      (fresh-line p)
481      (newline p)
482      (fresh-line p)
483      (display "goodbye" p)
484      (newline p)
485      (fresh-line p)
486      (g))
487    "hello\n\ngoodbye\n")
488 ; check for bug fix in transcoded-port-put-some
489  (let f ([n 1000])
490    (or (fx= n 0)
491        (begin
492          (let ([op (open-file-output-port "testfile.ss" (file-options replace)
493                      (buffer-mode line) (native-transcoder))])
494            (do ([i 1000 (- i 1)])
495                ((fx= i 0))
496              (display #!eof op))
497            (close-port op))
498          (and (equal? (call-with-port
499                         (open-file-input-port "testfile.ss" (file-options)
500                           (buffer-mode block) (native-transcoder))
501                         get-string-all)
502                       (apply string-append (make-list 1000 "#!eof")))
503               (f (- n 1))))))
504)
505
506(mat port-operations3
507  (error? (file-port? "not a port"))
508  (error? (port-file-descriptor 'oops))
509  (error? (port-file-descriptor (open-input-string "hello")))
510  (or (threaded?) (file-port? (console-input-port)))
511  (or (threaded?) (file-port? (console-output-port)))
512  (not (file-port? (open-input-string "hello")))
513  (or (threaded?) (= (port-file-descriptor (console-input-port)) 0))
514  (or (threaded?) (= (port-file-descriptor (console-output-port)) 1))
515  (> (let ([ip (open-input-file prettytest.ss)])
516       (let ([n (and (file-port? ip) (port-file-descriptor ip))])
517         (close-port ip)
518         n))
519     1)
520  (> (let ([ip (open-input-file prettytest.ss 'compressed)])
521       (let ([n (and (file-port? ip) (port-file-descriptor ip))])
522         (close-port ip)
523         n))
524     1)
525  (> (let ([op (open-output-file "testfile.ss" '(replace))])
526       (let ([n (and (file-port? op) (port-file-descriptor op))])
527         (close-port op)
528         n))
529     1)
530  (> (let ([op (open-output-file "testfile.ss" '(replace compressed))])
531       (let ([n (and (file-port? op) (port-file-descriptor op))])
532         (close-port op)
533         n))
534     1)
535 )
536
537(if (case (machine-type)
538     [(pb) #t]
539     [else (embedded?)])
540    (mat iconv-codec
541      (error? (errorf 'iconv-codec "-73 is not a string"))
542      (error? (errorf 'transcoded-port "unsupported encoding almost certainly bogus"))
543      (error? (errorf 'close-port "iconv CP1252 codec cannot encode #\\x3BB"))
544      (error? (errorf 'close-port "iconv CP1252 codec cannot encode #\\newline with eol-style ls"))
545      (error? (errorf 'close-port "latin-1 codec cannot encode #\\newline with eol-style ls")))
546    (mat iconv-codec
547      (error? ; invalid codec
548        (iconv-codec -73))
549      (error? ; unsupported encoding
550        (let ()
551          (define codec (iconv-codec "almost certainly bogus"))
552          (define transcoder
553            (make-transcoder codec
554              (eol-style none)
555              (error-handling-mode ignore)))
556          (define-values (bp get) (open-bytevector-output-port))
557          (define op (transcoded-port bp transcoder))
558          (newline op)
559          (close-port op)))
560      (let ()
561        (define codec (iconv-codec "UTF-8"))
562        (define transcoder
563          (make-transcoder codec
564            (eol-style none)
565            (error-handling-mode ignore)))
566        (define op
567          (open-file-output-port "testfile.ss"
568            (file-options replace)
569            (buffer-mode line)
570            transcoder))
571        (define p1)
572        (define p2)
573        (define p3)
574        (define p4)
575        (newline op)
576        (display "hello l\x0;ambda:\n\x3bb;!\n" op)
577        (close-port op)
578        (and
579          (equal?
580            (call-with-port (open-file-input-port "testfile.ss" (file-options)
581                              (buffer-mode block)
582                              (make-transcoder (utf-8-codec) (eol-style none)
583                                (error-handling-mode raise)))
584              (lambda (ip)
585                (set! p1 (port-position ip))
586                (let ([s (get-string-all ip)])
587                  (set! p2 (port-position ip))
588                  s)))
589            "\nhello l\x0;ambda:\n\x3bb;!\n")
590          (equal?
591            (call-with-port (open-file-input-port "testfile.ss" (file-options)
592                              (buffer-mode block)
593                              transcoder)
594              (lambda (ip)
595                (set! p3 (port-position ip))
596                (let ([s (get-string-all ip)])
597                  (set! p4 (port-position ip))
598                  s)))
599            "\nhello l\x0;ambda:\n\x3bb;!\n")
600          (eq? p1 0)
601          (eq? p2 20)
602          (eq? p3 0)
603          (eq? p4 20)))
604      (let () ; same but eol-style lf
605        (define codec (iconv-codec "UTF-8"))
606        (define transcoder
607          (make-transcoder codec
608            (eol-style lf)
609            (error-handling-mode ignore)))
610        (define op
611          (open-file-output-port "testfile.ss"
612            (file-options replace)
613            (buffer-mode line)
614            transcoder))
615        (define p1)
616        (define p2)
617        (define p3)
618        (define p4)
619        (newline op)
620        (display "hello l\x0;ambda:\n\x3bb;!\n" op)
621        (close-port op)
622        (and
623          (equal?
624            (call-with-port (open-file-input-port "testfile.ss" (file-options)
625                              (buffer-mode block)
626                              (make-transcoder (utf-8-codec) (eol-style lf)
627                                (error-handling-mode raise)))
628              (lambda (ip)
629                (set! p1 (port-position ip))
630                (let ([s (get-string-all ip)])
631                  (set! p2 (port-position ip))
632                  s)))
633            "\nhello l\x0;ambda:\n\x3bb;!\n")
634          (equal?
635            (call-with-port (open-file-input-port "testfile.ss" (file-options)
636                              (buffer-mode block)
637                              transcoder)
638              (lambda (ip)
639                (set! p3 (port-position ip))
640                (let ([s (get-string-all ip)])
641                  (set! p4 (port-position ip))
642                  s)))
643            "\nhello l\x0;ambda:\n\x3bb;!\n")
644          (eq? p1 0)
645          (eq? p2 20)
646          (eq? p3 0)
647          (eq? p4 20)))
648      (let () ; same but eol-style crlf
649        (define codec (iconv-codec "UTF-8"))
650        (define transcoder
651          (make-transcoder codec
652            (eol-style crlf)
653            (error-handling-mode ignore)))
654        (define op
655          (open-file-output-port "testfile.ss"
656            (file-options replace)
657            (buffer-mode line)
658            transcoder))
659        (define p1)
660        (define p2)
661        (define p3)
662        (define p4)
663        (newline op)
664        (display "hello l\x0;ambda:\n\x3bb;!\n" op)
665        (close-port op)
666        (and
667          (equal?
668            (call-with-port (open-file-input-port "testfile.ss" (file-options)
669                              (buffer-mode block)
670                              (make-transcoder (utf-8-codec) (eol-style crlf)
671                                (error-handling-mode raise)))
672              (lambda (ip)
673                (set! p1 (port-position ip))
674                (let ([s (get-string-all ip)])
675                  (set! p2 (port-position ip))
676                  s)))
677            "\nhello l\x0;ambda:\n\x3bb;!\n")
678          (equal?
679            (call-with-port (open-file-input-port "testfile.ss" (file-options)
680                              (buffer-mode block)
681                              transcoder)
682              (lambda (ip)
683                (set! p3 (port-position ip))
684                (let ([s (get-string-all ip)])
685                  (set! p4 (port-position ip))
686                  s)))
687            "\nhello l\x0;ambda:\n\x3bb;!\n")
688          (eq? p1 0)
689          (eq? p2 23)
690          (eq? p3 0)
691          (eq? p4 23)))
692      (let ()
693        (define codec (iconv-codec "GB18030"))
694        (define transcoder
695          (make-transcoder codec
696            (eol-style none)
697            (error-handling-mode raise)))
698        (define op
699          (open-file-output-port "testfile.ss"
700            (file-options replace)
701            (buffer-mode line)
702            transcoder))
703        (newline op)
704        (display "hello l\x0;ambda:\n\x3bb;!\n" op)
705        (close-port op)
706        (and
707          (equal?
708            (call-with-port (open-file-input-port "testfile.ss")
709              get-bytevector-all)
710            #vu8(#x0a #x68 #x65 #x6c #x6c #x6f #x20 #x6c #x00 #x61 #x6d #x62 #x64 #x61 #x3a #x0a #xa6 #xcb #x21 #x0a))
711          (equal?
712            (call-with-port (open-file-input-port "testfile.ss" (file-options)
713                              (buffer-mode block)
714                              transcoder)
715              get-string-all)
716            "\nhello l\x0;ambda:\n\x3bb;!\n")))
717      (let ()
718        (define codec (iconv-codec "CP1252"))
719        (define transcoder
720          (make-transcoder codec
721            (eol-style none)
722            (error-handling-mode replace)))
723        (define op
724          (open-file-output-port "testfile.ss"
725            (file-options replace)
726            (buffer-mode line)
727            transcoder))
728        (newline op)
729        (display "hello l\x0;ambda:\n\x3bb;!\n" op)
730        (close-port op)
731        (and
732          (equal?
733            (call-with-port (open-file-input-port "testfile.ss")
734              get-bytevector-all)
735            #vu8(#x0a #x68 #x65 #x6c #x6c #x6f #x20 #x6c #x00 #x61 #x6d #x62 #x64 #x61 #x3a #x0a #x3f #x21 #x0a))
736          (equal?
737            (call-with-port (open-file-input-port "testfile.ss" (file-options)
738                              (buffer-mode block)
739                              transcoder)
740              get-string-all)
741            "\nhello l\x0;ambda:\n?!\n")))
742      (let () ; same but eol-style lf
743        (define codec (iconv-codec "CP1252"))
744        (define transcoder
745          (make-transcoder codec
746            (eol-style lf)
747            (error-handling-mode replace)))
748        (define op
749          (open-file-output-port "testfile.ss"
750            (file-options replace)
751            (buffer-mode line)
752            transcoder))
753        (newline op)
754        (display "hello l\x0;ambda:\n\x3bb;!\n" op)
755        (close-port op)
756        (and
757          (equal?
758            (call-with-port (open-file-input-port "testfile.ss")
759              get-bytevector-all)
760            #vu8(#x0a #x68 #x65 #x6c #x6c #x6f #x20 #x6c #x00 #x61 #x6d #x62 #x64 #x61 #x3a #x0a #x3f #x21 #x0a))
761          (equal?
762            (call-with-port (open-file-input-port "testfile.ss" (file-options)
763                              (buffer-mode block)
764                              transcoder)
765              get-string-all)
766            "\nhello l\x0;ambda:\n?!\n")))
767      (let () ; same but eol-style crlf
768        (define codec (iconv-codec "CP1252"))
769        (define transcoder
770          (make-transcoder codec
771            (eol-style crlf)
772            (error-handling-mode replace)))
773        (define op
774          (open-file-output-port "testfile.ss"
775            (file-options replace)
776            (buffer-mode line)
777            transcoder))
778        (newline op)
779        (display "hello l\x0;ambda:\n\x3bb;!\n" op)
780        (close-port op)
781        (and
782          (equal?
783            (call-with-port (open-file-input-port "testfile.ss")
784              get-bytevector-all)
785            #vu8(#x0d #x0a #x68 #x65 #x6c #x6c #x6f #x20 #x6c #x00 #x61 #x6d #x62 #x64 #x61 #x3a #x0d #x0a #x3f #x21 #x0d #x0a))
786          (equal?
787            (call-with-port (open-file-input-port "testfile.ss" (file-options)
788                              (buffer-mode block)
789                              transcoder)
790              get-string-all)
791            "\nhello l\x0;ambda:\n?!\n")))
792      (let ()
793        (define codec (iconv-codec "CP1252"))
794        (define transcoder
795          (make-transcoder codec
796            (eol-style none)
797            (error-handling-mode ignore)))
798        (define op
799          (open-file-output-port "testfile.ss"
800            (file-options replace)
801            (buffer-mode line)
802            transcoder))
803        (newline op)
804        (display "hello l\x0;ambda:\n\x3bb;!\n" op)
805        (close-port op)
806        (and
807          (equal?
808            (call-with-port (open-file-input-port "testfile.ss")
809              get-bytevector-all)
810            #vu8(#x0a #x68 #x65 #x6c #x6c #x6f #x20 #x6c #x00 #x61 #x6d #x62 #x64 #x61 #x3a #x0a #x21 #x0a))
811          (equal?
812            (call-with-port (open-file-input-port "testfile.ss" (file-options)
813                              (buffer-mode block)
814                              transcoder)
815              get-string-all)
816            "\nhello l\x0;ambda:\n!\n")))
817      (error? ; encoding error
818        (let-values ([(bp get) (open-bytevector-output-port)])
819          (define codec (iconv-codec "CP1252"))
820          (define transcoder
821            (make-transcoder codec
822              (eol-style none)
823              (error-handling-mode raise)))
824          (define op (transcoded-port bp transcoder))
825          (newline op)
826          (display "hello l\x0;ambda: \x3bb;!\n" op)
827          (close-port op)))
828      (error? ; encoding error
829        (let-values ([(bp get) (open-bytevector-output-port)])
830          (define codec (iconv-codec "CP1252"))
831          (define transcoder
832            (make-transcoder codec
833              (eol-style ls)
834              (error-handling-mode raise)))
835          (define op (transcoded-port bp transcoder))
836          (newline op)
837          (close-port op)))
838      ; some (older?) versions of iconv don't handle unassigned code-page 1252
839      ; characters properly.  c'est la vie.
840      #;(let ()
841          (define bp (open-bytevector-input-port #vu8(#x80 #x81 #x82 #x8c #x8d #x8e #x8f #x90 #x91 #x9c #x9d #x9e)))
842          (define codec (iconv-codec "CP1252"))
843          (define transcoder
844            (make-transcoder codec
845              (eol-style none)
846              (error-handling-mode replace)))
847          (define ip (transcoded-port bp transcoder))
848          (equal?
849            (get-string-all ip)
850            "\x20ac;\xfffd;\x201a;\x0152;\xfffd;\x017d;\xfffd;\xfffd;\x2018;\x0153;\xfffd;\x017e;"))
851      #;(let ()
852          (define bp (open-bytevector-input-port #vu8(#x80 #x81 #x82 #x8c #x8d #x8e #x8f #x90 #x91 #x9c #x9d #x9e)))
853          (define codec (iconv-codec "CP1252"))
854          (define transcoder
855            (make-transcoder codec
856              (eol-style none)
857              (error-handling-mode ignore)))
858          (define ip (transcoded-port bp transcoder))
859          (equal?
860            (get-string-all ip)
861            "\x20ac;\x201a;\x0152;\x017d;\x2018;\x0153;\x017e;"))
862      #;(error? ; decoding error
863          (let ()
864            (define bp (open-bytevector-input-port #vu8(#x80 #x81 #x82 #x8c #x8d #x8e #x8f #x90 #x91 #x9c #x9d #x9e)))
865            (define codec (iconv-codec "CP1252"))
866            (define transcoder
867              (make-transcoder codec
868                (eol-style none)
869                (error-handling-mode raise)))
870            (define ip (transcoded-port bp transcoder))
871            (equal?
872              (get-string-all ip)
873              "\x20ac;\xfffd;\x201a;\x0152;\xfffd;\x017d;\xfffd;\xfffd;\x2018;\x0153;\xfffd;\x017e;")))
874      (let () ; SBCS CP1252
875        (define cp1252
876          '((#x00 #x0000) (#x01 #x0001) (#x02 #x0002) (#x03 #x0003)
877                          (#x04 #x0004) (#x05 #x0005) (#x06 #x0006) (#x07 #x0007)
878                          (#x08 #x0008) (#x09 #x0009) (#x0A #x000A) (#x0B #x000B)
879                          (#x0C #x000C) (#x0D #x000D) (#x0E #x000E) (#x0F #x000F)
880                          (#x10 #x0010) (#x11 #x0011) (#x12 #x0012) (#x13 #x0013)
881                          (#x14 #x0014) (#x15 #x0015) (#x16 #x0016) (#x17 #x0017)
882                          (#x18 #x0018) (#x19 #x0019) (#x1A #x001A) (#x1B #x001B)
883                          (#x1C #x001C) (#x1D #x001D) (#x1E #x001E) (#x1F #x001F)
884                          (#x20 #x0020) (#x21 #x0021) (#x22 #x0022) (#x23 #x0023)
885                          (#x24 #x0024) (#x25 #x0025) (#x26 #x0026) (#x27 #x0027)
886                          (#x28 #x0028) (#x29 #x0029) (#x2A #x002A) (#x2B #x002B)
887                          (#x2C #x002C) (#x2D #x002D) (#x2E #x002E) (#x2F #x002F)
888                          (#x30 #x0030) (#x31 #x0031) (#x32 #x0032) (#x33 #x0033)
889                          (#x34 #x0034) (#x35 #x0035) (#x36 #x0036) (#x37 #x0037)
890                          (#x38 #x0038) (#x39 #x0039) (#x3A #x003A) (#x3B #x003B)
891                          (#x3C #x003C) (#x3D #x003D) (#x3E #x003E) (#x3F #x003F)
892                          (#x40 #x0040) (#x41 #x0041) (#x42 #x0042) (#x43 #x0043)
893                          (#x44 #x0044) (#x45 #x0045) (#x46 #x0046) (#x47 #x0047)
894                          (#x48 #x0048) (#x49 #x0049) (#x4A #x004A) (#x4B #x004B)
895                          (#x4C #x004C) (#x4D #x004D) (#x4E #x004E) (#x4F #x004F)
896                          (#x50 #x0050) (#x51 #x0051) (#x52 #x0052) (#x53 #x0053)
897                          (#x54 #x0054) (#x55 #x0055) (#x56 #x0056) (#x57 #x0057)
898                          (#x58 #x0058) (#x59 #x0059) (#x5A #x005A) (#x5B #x005B)
899                          (#x5C #x005C) (#x5D #x005D) (#x5E #x005E) (#x5F #x005F)
900                          (#x60 #x0060) (#x61 #x0061) (#x62 #x0062) (#x63 #x0063)
901                          (#x64 #x0064) (#x65 #x0065) (#x66 #x0066) (#x67 #x0067)
902                          (#x68 #x0068) (#x69 #x0069) (#x6A #x006A) (#x6B #x006B)
903                          (#x6C #x006C) (#x6D #x006D) (#x6E #x006E) (#x6F #x006F)
904                          (#x70 #x0070) (#x71 #x0071) (#x72 #x0072) (#x73 #x0073)
905                          (#x74 #x0074) (#x75 #x0075) (#x76 #x0076) (#x77 #x0077)
906                          (#x78 #x0078) (#x79 #x0079) (#x7A #x007A) (#x7B #x007B)
907                          (#x7C #x007C) (#x7D #x007D) (#x7E #x007E) (#x7F #x007F)
908                          (#x80 #x20AC) (#x82 #x201A) (#x83 #x0192) (#x84 #x201E)
909                          (#x85 #x2026) (#x86 #x2020) (#x87 #x2021) (#x88 #x02C6)
910                          (#x89 #x2030) (#x8A #x0160) (#x8B #x2039) (#x8C #x0152)
911                          (#x8E #x017D) (#x91 #x2018) (#x92 #x2019) (#x93 #x201C)
912                          (#x94 #x201D) (#x95 #x2022) (#x96 #x2013) (#x97 #x2014)
913                          (#x98 #x02DC) (#x99 #x2122) (#x9A #x0161) (#x9B #x203A)
914                          (#x9C #x0153) (#x9E #x017E) (#x9F #x0178) (#xA0 #x00A0)
915                          (#xA1 #x00A1) (#xA2 #x00A2) (#xA3 #x00A3) (#xA4 #x00A4)
916                          (#xA5 #x00A5) (#xA6 #x00A6) (#xA7 #x00A7) (#xA8 #x00A8)
917                          (#xA9 #x00A9) (#xAA #x00AA) (#xAB #x00AB) (#xAC #x00AC)
918                          (#xAD #x00AD) (#xAE #x00AE) (#xAF #x00AF) (#xB0 #x00B0)
919                          (#xB1 #x00B1) (#xB2 #x00B2) (#xB3 #x00B3) (#xB4 #x00B4)
920                          (#xB5 #x00B5) (#xB6 #x00B6) (#xB7 #x00B7) (#xB8 #x00B8)
921                          (#xB9 #x00B9) (#xBA #x00BA) (#xBB #x00BB) (#xBC #x00BC)
922                          (#xBD #x00BD) (#xBE #x00BE) (#xBF #x00BF) (#xC0 #x00C0)
923                          (#xC1 #x00C1) (#xC2 #x00C2) (#xC3 #x00C3) (#xC4 #x00C4)
924                          (#xC5 #x00C5) (#xC6 #x00C6) (#xC7 #x00C7) (#xC8 #x00C8)
925                          (#xC9 #x00C9) (#xCA #x00CA) (#xCB #x00CB) (#xCC #x00CC)
926                          (#xCD #x00CD) (#xCE #x00CE) (#xCF #x00CF) (#xD0 #x00D0)
927                          (#xD1 #x00D1) (#xD2 #x00D2) (#xD3 #x00D3) (#xD4 #x00D4)
928                          (#xD5 #x00D5) (#xD6 #x00D6) (#xD7 #x00D7) (#xD8 #x00D8)
929                          (#xD9 #x00D9) (#xDA #x00DA) (#xDB #x00DB) (#xDC #x00DC)
930                          (#xDD #x00DD) (#xDE #x00DE) (#xDF #x00DF) (#xE0 #x00E0)
931                          (#xE1 #x00E1) (#xE2 #x00E2) (#xE3 #x00E3) (#xE4 #x00E4)
932                          (#xE5 #x00E5) (#xE6 #x00E6) (#xE7 #x00E7) (#xE8 #x00E8)
933                          (#xE9 #x00E9) (#xEA #x00EA) (#xEB #x00EB) (#xEC #x00EC)
934                          (#xED #x00ED) (#xEE #x00EE) (#xEF #x00EF) (#xF0 #x00F0)
935                          (#xF1 #x00F1) (#xF2 #x00F2) (#xF3 #x00F3) (#xF4 #x00F4)
936                          (#xF5 #x00F5) (#xF6 #x00F6) (#xF7 #x00F7) (#xF8 #x00F8)
937                          (#xF9 #x00F9) (#xFA #x00FA) (#xFB #x00FB) (#xFC #x00FC)
938                          (#xFD #x00FD) (#xFE #x00FE) (#xFF #x00FF)))
939        (define transcoder
940          (make-transcoder (iconv-codec "CP1252")
941            (eol-style none)
942            (error-handling-mode raise)))
943        (define ls
944          (append cp1252
945            (let ([v (list->vector cp1252)])
946              (let f ([n 100000])
947                (if (fx= n 0)
948                    '()
949                    (cons
950                      (vector-ref v (random (vector-length v)))
951                      (f (fx- n 1))))))))
952        (define s (apply string (map integer->char (map cadr ls))))
953        (define op
954          (open-file-output-port "testfile.ss"
955            (file-options replace) (buffer-mode block)
956            transcoder))
957        #;(put-string op s)
958        (let loop ([i 0] [n (string-length s)])
959          (unless (fx= n 0)
960            (let ([k (fx+ (random n) 1)])
961              (put-string op s i k)
962              (loop (fx+ i k) (fx- n k)))))
963        (close-port op)
964        (and
965          (equal?
966            (call-with-port (open-file-input-port "testfile.ss")
967              get-bytevector-all)
968            (apply bytevector (map car ls)))
969          (equal?
970            (call-with-port (open-file-input-port "testfile.ss"
971                              (file-options) (buffer-mode block)
972                              transcoder)
973              #;get-string-all
974              (lambda (ip)
975                (let ([t (make-string (string-length s))])
976                  (let loop ([i 0] [n (string-length s)])
977                    (unless (fx= n 0)
978                      (let ([k (fx+ (random n) 1)])
979                        (get-string-n! ip t i k)
980                        (loop (fx+ i k) (fx- n k)))))
981                  t)))
982            s)))
983      (let () ; MBCS UTF-8
984        (define transcoder
985          (make-transcoder (iconv-codec "UTF-8")
986            (eol-style none)
987            (error-handling-mode raise)))
988        (define ls1
989          (let f ([i 0])
990            (if (fx= i #x11000)
991                '()
992                (if (fx= i #xD800)
993                    (f #xE000)
994                    (cons i (f (fx+ i 1)))))))
995        (define ls2
996          (let f ([n 1000000])
997            (if (fx= n 0)
998                '()
999                (cons
1000                  (let ([n (random (- #x110000 (- #xE000 #xD800)))])
1001                    (if (<= #xD800 n #xDFFF)
1002                        (+ n (- #xE000 #xD800))
1003                        n))
1004                  (f (fx- n 1))))))
1005        (define s (apply string (map integer->char (append ls1 ls2))))
1006        #;(define s (apply string (map integer->char ls1)))
1007        #;(define s "hello\x1447A;")
1008        (define op
1009          (open-file-output-port "testfile.ss"
1010            (file-options replace) (buffer-mode block)
1011            transcoder))
1012        #;(put-string op s)
1013        (let loop ([i 0] [n (string-length s)])
1014          (unless (fx= n 0)
1015            (let ([k (fx+ (random n) 1)])
1016              (put-string op s i k)
1017              (loop (fx+ i k) (fx- n k)))))
1018        (close-port op)
1019        (and
1020          (equal?
1021            (call-with-port (open-file-input-port "testfile.ss"
1022                              (file-options) (buffer-mode block)
1023                              (make-transcoder (utf-8-codec) (eol-style none)
1024                                (error-handling-mode raise)))
1025              get-string-all)
1026            s)
1027          (equal?
1028            (call-with-port (open-file-input-port "testfile.ss"
1029                              (file-options) (buffer-mode block)
1030                              transcoder)
1031              #;get-string-all
1032              (lambda (ip)
1033                (let ([t (make-string (string-length s))])
1034                  (let loop ([i 0] [n (string-length s)])
1035                    (unless (fx= n 0)
1036                      (let ([k (fx+ (random n) 1)])
1037                        (get-string-n! ip t i k)
1038                        (loop (fx+ i k) (fx- n k)))))
1039                  t)))
1040            s)))
1041      (error? ; encoding error
1042        (let ()
1043          (define transcoder
1044            (make-transcoder (latin-1-codec)
1045              (eol-style ls)
1046              (error-handling-mode raise)))
1047          (define-values (bp get) (open-bytevector-output-port))
1048          (define op (transcoded-port bp transcoder))
1049          (newline op)
1050          (close-port op)))
1051      ; NB: keep this last among the iconv-codec mats
1052      ; close any files left open by failing iconv tests.  this is particulary
1053      ; important on windows when the iconv dll isn't available and where keeping
1054      ; file open can prevent it from being reopened.
1055      (begin (collect (collect-maximum-generation)) #t)
1056      ))
1057
1058(mat port-operations4
1059  (begin
1060    (define po4-tx (make-transcoder (latin-1-codec) (eol-style none) (error-handling-mode raise)))
1061    #t)
1062  (transcoder? po4-tx)
1063  (not (transcoder? (latin-1-codec)))
1064  (eq? (call-with-port
1065         (open-file-output-port "testfile.ss" (file-options replace)
1066           (buffer-mode block) po4-tx)
1067         (lambda (op) (put-string op "hi there")))
1068       (void))
1069 ; binary input port
1070  (begin
1071    (define po4-p (open-file-input-port "testfile.ss"))
1072    #t)
1073  (and (input-port? po4-p) (binary-port? po4-p) (file-port? po4-p))
1074  (error? (put-string po4-p "hello"))
1075  (error? (put-bytevector po4-p #vu8(100)))
1076  (error? (get-string-all po4-p))
1077  (error? (get-char po4-p))
1078  (error? (lookahead-char po4-p))
1079  (fixnum? (port-file-descriptor po4-p))
1080  (port-has-port-position? po4-p)
1081  (eqv? (port-position po4-p) 0)
1082  (port-has-set-port-position!? po4-p)
1083  (eq? (set-port-position! po4-p 3) (void))
1084  (eqv? (port-position po4-p) 3)
1085  (equal? (get-bytevector-n po4-p 5) (string->bytevector "there" po4-tx))
1086  (eof-object? (get-bytevector-n po4-p 1))
1087  (port-has-port-length? po4-p)
1088  (eqv? (port-length po4-p) 8)
1089  (not (port-has-set-port-length!? po4-p))
1090  (error? (set-port-length! po4-p 7))
1091  (eq? (close-port po4-p) (void))
1092 ; textual input port
1093  (begin
1094    (define po4-p
1095      (open-file-input-port "testfile.ss" (file-options)
1096        (buffer-mode block) po4-tx))
1097    #t)
1098  (and (input-port? po4-p) (textual-port? po4-p) (file-port? po4-p))
1099  (error? (put-string po4-p "hello"))
1100  (error? (put-bytevector po4-p #vu8(100)))
1101  (error? (get-bytevector-all po4-p))
1102  (error? (get-u8 po4-p))
1103  (error? (lookahead-u8 po4-p))
1104  (fixnum? (port-file-descriptor po4-p))
1105  (port-has-port-position? po4-p)
1106  (eqv? (port-position po4-p) 0)
1107  (port-has-set-port-position!? po4-p)
1108  (eqv? (set-port-position! po4-p 3) (void))
1109  (eqv? (port-position po4-p) 3)
1110  (equal? (get-string-n po4-p 5) "there")
1111  (eof-object? (get-string-n po4-p 1))
1112  (port-has-port-length? po4-p)
1113  (eqv? (port-length po4-p) 8)
1114  (not (port-has-set-port-length!? po4-p))
1115  (error? (set-port-length! po4-p 7))
1116  (eq? (close-port po4-p) (void))
1117 ; binary output port
1118  (begin
1119    (define po4-p
1120      (open-file-output-port "testfile.ss" (file-options replace)))
1121    #t)
1122  (and (output-port? po4-p) (binary-port? po4-p) (file-port? po4-p))
1123  (error? (get-string-all po4-p))
1124  (error? (get-char po4-p))
1125  (error? (lookahead-char po4-p))
1126  (error? (get-bytevector-all po4-p))
1127  (error? (get-u8 po4-p))
1128  (error? (lookahead-u8 po4-p))
1129  (error? (put-string po4-p "hello"))
1130  (fixnum? (port-file-descriptor po4-p))
1131  (port-has-port-position? po4-p)
1132  (eqv? (port-position po4-p) 0)
1133  (port-has-set-port-position!? po4-p)
1134  (eq? (set-port-position! po4-p 3) (void))
1135  (eqv? (port-position po4-p) 3)
1136  (eq? (put-bytevector po4-p (string->bytevector "123456" po4-tx)) (void))
1137  (port-has-port-length? po4-p)
1138  (eqv? (port-length po4-p) 9)
1139  (port-has-set-port-length!? po4-p)
1140  (eq? (set-port-length! po4-p 7) (void))
1141  (eq? (set-port-position! po4-p 0) (void))
1142  (eq? (put-bytevector po4-p (string->bytevector "abcd" po4-tx)) (void))
1143  (eq? (close-port po4-p) (void))
1144  (equal?
1145    (call-with-port
1146      (open-file-input-port "testfile.ss" (file-options)
1147        (buffer-mode block) po4-tx)
1148      get-string-all)
1149    "abcd234")
1150 ; textual output port
1151  (begin
1152    (define po4-p
1153      (open-file-output-port "testfile.ss" (file-options replace)
1154        (buffer-mode block) po4-tx))
1155    #t)
1156  (and (output-port? po4-p) (textual-port? po4-p) (file-port? po4-p))
1157  (error? (get-string-all po4-p))
1158  (error? (get-char po4-p))
1159  (error? (lookahead-char po4-p))
1160  (error? (get-bytevector-all po4-p))
1161  (error? (get-u8 po4-p))
1162  (error? (lookahead-u8 po4-p))
1163  (error? (put-bytevector po4-p #vu8()))
1164  (fixnum? (port-file-descriptor po4-p))
1165  (port-has-port-position? po4-p)
1166  (eqv? (port-position po4-p) 0)
1167  (port-has-set-port-position!? po4-p)
1168  (eq? (set-port-position! po4-p 3) (void))
1169  (eqv? (port-position po4-p) 3)
1170  (eq? (put-string po4-p "abcdef") (void))
1171  (port-has-port-length? po4-p)
1172  (eqv? (port-length po4-p) 9)
1173  (port-has-set-port-length!? po4-p)
1174  (eq? (set-port-length! po4-p 7) (void))
1175  (eq? (set-port-position! po4-p 0) (void))
1176  (eq? (put-string po4-p "1234") (void))
1177  (eq? (close-port po4-p) (void))
1178  (equal?
1179    (call-with-port
1180      (open-file-input-port "testfile.ss" (file-options)
1181        (buffer-mode block) po4-tx)
1182      get-string-all)
1183    "1234bcd")
1184 ; binary input/output port
1185  (begin
1186    (define po4-p
1187      (open-file-input/output-port "testfile.ss" (file-options replace)))
1188    #t)
1189  (and (output-port? po4-p) (binary-port? po4-p) (file-port? po4-p))
1190  (and (input-port? po4-p) (binary-port? po4-p) (file-port? po4-p))
1191  (fixnum? (port-file-descriptor po4-p))
1192  (port-has-port-position? po4-p)
1193  (eqv? (port-position po4-p) 0)
1194  (port-has-set-port-position!? po4-p)
1195  (eq? (set-port-position! po4-p 3) (void))
1196  (eqv? (port-position po4-p) 3)
1197  (eq? (put-bytevector po4-p (string->bytevector "foobar" po4-tx)) (void))
1198  (port-has-port-length? po4-p)
1199  (eqv? (port-length po4-p) 9)
1200  (port-has-set-port-length!? po4-p)
1201  (eq? (set-port-length! po4-p 7) (void))
1202  (eq? (set-port-position! po4-p 0) (void))
1203  (eq? (put-bytevector po4-p (string->bytevector "4321" po4-tx)) (void))
1204  (equal? (get-bytevector-all po4-p) (string->bytevector "oob" po4-tx))
1205  (eq? (set-port-position! po4-p 0) (void))
1206  (equal? (get-bytevector-all po4-p) (string->bytevector "4321oob" po4-tx))
1207  (eq? (close-port po4-p) (void))
1208  (equal?
1209    (call-with-port
1210      (open-file-input-port "testfile.ss" (file-options)
1211        (buffer-mode block) po4-tx)
1212      get-string-all)
1213    "4321oob")
1214 ; textual input/output port
1215  (begin
1216    (define po4-p
1217      (open-file-input/output-port "testfile.ss" (file-options replace)
1218        (buffer-mode block) po4-tx))
1219    #t)
1220  (and (output-port? po4-p) (textual-port? po4-p) (file-port? po4-p))
1221  (and (input-port? po4-p) (textual-port? po4-p) (file-port? po4-p))
1222  (fixnum? (port-file-descriptor po4-p))
1223  (port-has-port-position? po4-p)
1224  (eqv? (port-position po4-p) 0)
1225  (port-has-set-port-position!? po4-p)
1226  (eq? (set-port-position! po4-p 3) (void))
1227  (eqv? (port-position po4-p) 3)
1228  (eq? (put-string po4-p "abcdef") (void))
1229  (port-has-port-length? po4-p)
1230  (eqv? (port-length po4-p) 9)
1231  (port-has-set-port-length!? po4-p)
1232  (eq? (set-port-length! po4-p 7) (void))
1233  (eq? (set-port-position! po4-p 0) (void))
1234  (eq? (put-string po4-p "1234") (void))
1235  (equal? (get-string-all po4-p) "bcd")
1236  (eq? (set-port-position! po4-p 0) (void))
1237  (equal? (get-string-all po4-p) "1234bcd")
1238  (eq? (close-port po4-p) (void))
1239  (equal?
1240    (call-with-port
1241      (open-file-input-port "testfile.ss" (file-options)
1242        (buffer-mode block) po4-tx)
1243      get-string-all)
1244    "1234bcd")
1245)
1246
1247(mat get-line
1248  (error? ; not a port
1249    (get-line "current-input-port"))
1250  (error? ; not a port
1251    (get-line 3))
1252  (error? ; not a textual input port
1253    (get-line (open-bytevector-input-port #vu8(1 2 3 4 5))))
1254  (begin
1255    (with-output-to-file "testfile.ss"
1256      (lambda ()
1257        (display "hello from line 1!\n")
1258        (display (make-string 1017 #\a))
1259        (display " hello from line 2!\n")
1260        (display "goodbye from (incomplete) line 3!"))
1261      'replace)
1262    (define $tip (open-input-file "testfile.ss"))
1263    #t)
1264  (equal? (get-line $tip) "hello from line 1!")
1265  (equal? (get-line $tip) (format "~a hello from line 2!" (make-string 1017 #\a)))
1266  (equal? (get-line $tip) "goodbye from (incomplete) line 3!")
1267  (eof-object? (get-line $tip))
1268  (eqv? (close-port $tip) (void))
1269  (begin
1270    (with-output-to-file "testfile.ss"
1271      (lambda ()
1272        (display "hello from line 1!\n")
1273        (display "\n")
1274        (display "goodbye from (complete) line 3!\n"))
1275      'replace)
1276    (define $tip (open-input-file "testfile.ss"))
1277    #t)
1278  (equal? (get-line $tip) "hello from line 1!")
1279  (equal? (get-line $tip) "")
1280  (equal? (get-line $tip) "goodbye from (complete) line 3!")
1281  (eof-object? (get-line $tip))
1282  (eqv? (close-port $tip) (void))
1283)
1284
1285(mat low-level-port-operations
1286  (<= (textual-port-input-index (console-input-port))
1287      (textual-port-input-size (console-input-port))
1288      (string-length (textual-port-input-buffer (console-input-port))))
1289  (<= (textual-port-input-count (console-input-port))
1290      (string-length (textual-port-input-buffer (console-input-port))))
1291  (<= (textual-port-output-index (console-output-port))
1292      (textual-port-output-size (console-output-port))
1293      (string-length (textual-port-output-buffer (console-output-port))))
1294  (<= (textual-port-output-count (console-output-port))
1295      (string-length (textual-port-output-buffer (console-output-port))))
1296  (begin
1297    (define $tip (open-string-input-port "hello"))
1298    (define $top (let-values ([(op get) (open-string-output-port)]) (set-textual-port-output-buffer! op "hello") op))
1299    (define $bip (open-bytevector-input-port #vu8(1 2 3 4 5)))
1300    (define $bop (let-values ([(op get) (open-bytevector-output-port)]) (set-binary-port-output-buffer! op #vu8(1 2 3 4 5)) op))
1301    #t)
1302  ; textual input
1303  (andmap (lambda (str)
1304            (equal?
1305             (let ([ip (open-string-input-port str)])
1306               (let ([buffer0 (textual-port-input-buffer ip)]
1307                     [index0 (textual-port-input-index ip)]
1308                     [size0 (textual-port-input-size ip)]
1309                     [count0 (textual-port-input-count ip)])
1310                 (read-char ip)
1311                 (list
1312                  (list buffer0 index0 size0 count0)
1313                  (list
1314                   (textual-port-input-buffer ip)
1315                   (textual-port-input-index ip)
1316                   (textual-port-input-size ip)
1317                   (textual-port-input-count ip)))))
1318             '(("hello" 0 5 5) ("hello" 1 5 4))))
1319          (list "hello"
1320                (string->immutable-string "hello")))
1321  (equal?
1322    (let ([ip (open-string-input-port "hello")])
1323      (let ([buffer0 (textual-port-input-buffer ip)]
1324            [index0 (textual-port-input-index ip)]
1325            [size0 (textual-port-input-size ip)]
1326            [count0 (textual-port-input-count ip)])
1327        (read-char ip)
1328        (set-textual-port-input-buffer! ip "goodbye")
1329        (read-char ip)
1330        (list
1331          (list buffer0 index0 size0 count0)
1332          (list
1333            (textual-port-input-buffer ip)
1334            (textual-port-input-index ip)
1335            (textual-port-input-size ip)
1336            (textual-port-input-count ip)))))
1337    '(("hello" 0 5 5) ("goodbye" 1 7 6)))
1338  (equal?
1339    (let ([ip (open-string-input-port "hello")])
1340      (let ([buffer0 (textual-port-input-buffer ip)]
1341            [index0 (textual-port-input-index ip)]
1342            [size0 (textual-port-input-size ip)]
1343            [count0 (textual-port-input-count ip)])
1344        (read-char ip)
1345        (set-textual-port-input-size! ip 4)
1346        (read-char ip)
1347        (list
1348          (list buffer0 index0 size0 count0)
1349          (list
1350            (textual-port-input-buffer ip)
1351            (textual-port-input-index ip)
1352            (textual-port-input-size ip)
1353            (textual-port-input-count ip)))))
1354    '(("hello" 0 5 5) ("hello" 1 4 3)))
1355  (equal?
1356    (let ([ip (open-string-input-port "hello")])
1357      (let ([buffer0 (textual-port-input-buffer ip)]
1358            [index0 (textual-port-input-index ip)]
1359            [size0 (textual-port-input-size ip)]
1360            [count0 (textual-port-input-count ip)])
1361        (read-char ip)
1362        (set-textual-port-input-index! ip 4)
1363        (read-char ip)
1364        (list
1365          (list buffer0 index0 size0 count0)
1366          (list
1367            (textual-port-input-buffer ip)
1368            (textual-port-input-index ip)
1369            (textual-port-input-size ip)
1370            (textual-port-input-count ip)))))
1371    '(("hello" 0 5 5) ("hello" 5 5 0)))
1372  (error? ; not a textual input port
1373    (textual-port-input-buffer $top))
1374  (error? ; not a textual input port
1375    (textual-port-input-buffer $bip))
1376  (error? ; not a textual input port
1377    (textual-port-input-buffer $bop))
1378  (error? ; not a textual input port
1379    (textual-port-input-buffer 75))
1380  (error? ; not a textual input port
1381    (textual-port-input-index $top))
1382  (error? ; not a textual input port
1383    (textual-port-input-index $bip))
1384  (error? ; not a textual input port
1385    (textual-port-input-index $bop))
1386  (error? ; not a textual input port
1387    (textual-port-input-index 75))
1388  (error? ; not a textual input port
1389    (textual-port-input-size $top))
1390  (error? ; not a textual input port
1391    (textual-port-input-size $bip))
1392  (error? ; not a textual input port
1393    (textual-port-input-size $bop))
1394  (error? ; not a textual input port
1395    (textual-port-input-size 75))
1396  (error? ; not a textual input port
1397    (textual-port-input-count $top))
1398  (error? ; not a textual input port
1399    (textual-port-input-count $bip))
1400  (error? ; not a textual input port
1401    (textual-port-input-count $bop))
1402  (error? ; not a textual input port
1403    (textual-port-input-count 75))
1404  (error? ; not a textual input port
1405    (set-textual-port-input-buffer! $top ""))
1406  (error? ; not a textual input port
1407    (set-textual-port-input-buffer! $bip ""))
1408  (error? ; not a textual input port
1409    (set-textual-port-input-buffer! $bop ""))
1410  (error? ; not a textual input port
1411    (set-textual-port-input-buffer! 75 ""))
1412  (error? ; not a textual input port
1413    (set-textual-port-input-index! $top 0))
1414  (error? ; not a textual input port
1415    (set-textual-port-input-index! $bip 0))
1416  (error? ; not a textual input port
1417    (set-textual-port-input-index! $bop 0))
1418  (error? ; not a textual input port
1419    (set-textual-port-input-index! 75 0))
1420  (error? ; not a textual input port
1421    (set-textual-port-input-size! $top 0))
1422  (error? ; not a textual input port
1423    (set-textual-port-input-size! $bip 0))
1424  (error? ; not a textual input port
1425    (set-textual-port-input-size! $bop 0))
1426  (error? ; not a textual input port
1427    (set-textual-port-input-size! 75 0))
1428  (error? ; not a string
1429    (set-textual-port-input-buffer! $tip #vu8(1 2 3)))
1430  (error? ; not a string
1431    (set-textual-port-input-buffer! $tip 0))
1432  (error? ; invalid index
1433    (set-textual-port-input-index! $tip "hello"))
1434  (error? ; invalid index
1435    (set-textual-port-input-index! $tip -1))
1436  (error? ; invalid index
1437    (set-textual-port-input-index! $tip 6))
1438  (error? ; invalid size
1439    (set-textual-port-input-size! $tip "hello"))
1440  (error? ; invalid size
1441    (set-textual-port-input-size! $tip -1))
1442  (error? ; invalid size
1443    (set-textual-port-input-size! $tip 6))
1444  ; textual output
1445  (equal?
1446    (let ([op (make-output-port (lambda args (error #f "oops")) (make-string 10 #\$))])
1447      (let ([buffer0 (string-copy (textual-port-output-buffer op))]
1448            [index0 (textual-port-output-index op)]
1449            [size0 (textual-port-output-size op)]
1450            [count0 (textual-port-output-count op)])
1451        (display "hey!" op)
1452        (list
1453          (list buffer0 index0 size0 count0)
1454          (list
1455            (textual-port-output-buffer op)
1456            (textual-port-output-index op)
1457            (textual-port-output-size op)
1458            (textual-port-output-count op)))))
1459    '(("$$$$$$$$$$" 0 10 10)
1460      ("hey!$$$$$$" 4 10 6)))
1461  (equal?
1462    (let-values ([(op get) (open-string-output-port)])
1463      (let ([buffer (make-string 8 #\$)])
1464        (set-textual-port-output-buffer! op buffer)
1465        (let ([buffer0 (string-copy (textual-port-output-buffer op))]
1466              [index0 (textual-port-output-index op)]
1467              [size0 (textual-port-output-size op)]
1468              [count0 (textual-port-output-count op)])
1469          (display "yo!" op)
1470          (list
1471            buffer
1472            (list buffer0 index0 size0 count0)
1473            (list
1474              (textual-port-output-buffer op)
1475              (textual-port-output-index op)
1476              (textual-port-output-size op)
1477              (textual-port-output-count op))))))
1478    '("yo!$$$$$"
1479      ("$$$$$$$$" 0 8 8)
1480      ("yo!$$$$$" 3 8 5)))
1481  (equal?
1482    (let-values ([(op get) (open-string-output-port)])
1483      (let ([buffer (make-string 8 #\$)])
1484        (set-textual-port-output-buffer! op buffer)
1485        (let ([buffer0 (string-copy (textual-port-output-buffer op))]
1486              [index0 (textual-port-output-index op)]
1487              [size0 (textual-port-output-size op)]
1488              [count0 (textual-port-output-count op)])
1489          (display "yo" op)
1490          (set-textual-port-output-buffer! op (string #\a #\b #\c))
1491          (display "!?" op)
1492          (list
1493            buffer
1494            (list buffer0 index0 size0 count0)
1495            (list
1496              (textual-port-output-buffer op)
1497              (textual-port-output-index op)
1498              (textual-port-output-size op)
1499              (textual-port-output-count op))))))
1500    '("yo$$$$$$"
1501      ("$$$$$$$$" 0 8 8)
1502      ("!?c" 2 3 1)))
1503  (equal?
1504    (let-values ([(op get) (open-string-output-port)])
1505      (let ([buffer (make-string 8 #\$)])
1506        (set-textual-port-output-buffer! op buffer)
1507        (let ([buffer0 (string-copy (textual-port-output-buffer op))]
1508              [index0 (textual-port-output-index op)]
1509              [size0 (textual-port-output-size op)]
1510              [count0 (textual-port-output-count op)])
1511          (display "yo" op)
1512          (set-textual-port-output-index! op 4)
1513          (display "!?" op)
1514          (list
1515            buffer
1516            (list buffer0 index0 size0 count0)
1517            (list
1518              (textual-port-output-buffer op)
1519              (textual-port-output-index op)
1520              (textual-port-output-size op)
1521              (textual-port-output-count op))))))
1522    '("yo$$!?$$"
1523      ("$$$$$$$$" 0 8 8)
1524      ("yo$$!?$$" 6 8 2)))
1525  (equal?
1526    (let-values ([(op get) (open-string-output-port)])
1527      (let ([buffer (make-string 8 #\$)])
1528        (set-textual-port-output-buffer! op buffer)
1529        (let ([buffer0 (string-copy (textual-port-output-buffer op))]
1530              [index0 (textual-port-output-index op)]
1531              [size0 (textual-port-output-size op)]
1532              [count0 (textual-port-output-count op)])
1533          (display "yo" op)
1534          (set-textual-port-output-size! op 4)
1535          (display "!?" op)
1536          (list
1537            buffer
1538            (list buffer0 index0 size0 count0)
1539            (list
1540              (textual-port-output-buffer op)
1541              (textual-port-output-index op)
1542              (textual-port-output-size op)
1543              (textual-port-output-count op))))))
1544    '("!?$$$$$$"
1545      ("$$$$$$$$" 0 8 8)
1546      ("!?$$$$$$" 2 4 2)))
1547  (error? ; not a textual output port
1548    (textual-port-output-buffer $tip))
1549  (error? ; not a textual output port
1550    (textual-port-output-buffer $bip))
1551  (error? ; not a textual output port
1552    (textual-port-output-buffer $bop))
1553  (error? ; not a textual output port
1554    (textual-port-output-buffer 75))
1555  (error? ; not a textual output port
1556    (textual-port-output-index $tip))
1557  (error? ; not a textual output port
1558    (textual-port-output-index $bip))
1559  (error? ; not a textual output port
1560    (textual-port-output-index $bop))
1561  (error? ; not a textual output port
1562    (textual-port-output-index 75))
1563  (error? ; not a textual output port
1564    (textual-port-output-size $tip))
1565  (error? ; not a textual output port
1566    (textual-port-output-size $bip))
1567  (error? ; not a textual output port
1568    (textual-port-output-size $bop))
1569  (error? ; not a textual output port
1570    (textual-port-output-size 75))
1571  (error? ; not a textual output port
1572    (textual-port-output-count $tip))
1573  (error? ; not a textual output port
1574    (textual-port-output-count $bip))
1575  (error? ; not a textual output port
1576    (textual-port-output-count $bop))
1577  (error? ; not a textual output port
1578    (textual-port-output-count 75))
1579  (error? ; not a textual output port
1580    (set-textual-port-output-buffer! $tip ""))
1581  (error? ; not a textual output port
1582    (set-textual-port-output-buffer! $bip ""))
1583  (error? ; not a textual output port
1584    (set-textual-port-output-buffer! $bop ""))
1585  (error? ; not a textual output port
1586    (set-textual-port-output-buffer! 75 ""))
1587  (error? ; not a textual output port
1588    (set-textual-port-output-index! $tip 0))
1589  (error? ; not a textual output port
1590    (set-textual-port-output-index! $bip 0))
1591  (error? ; not a textual output port
1592    (set-textual-port-output-index! $bop 0))
1593  (error? ; not a textual output port
1594    (set-textual-port-output-index! 75 0))
1595  (error? ; not a textual output port
1596    (set-textual-port-output-size! $tip 0))
1597  (error? ; not a textual output port
1598    (set-textual-port-output-size! $bip 0))
1599  (error? ; not a textual output port
1600    (set-textual-port-output-size! $bop 0))
1601  (error? ; not a textual output port
1602    (set-textual-port-output-size! 75 0))
1603  (error? ; not a string
1604    (set-textual-port-output-buffer! $top #vu8(1 2 3)))
1605  (error? ; not a string
1606    (set-textual-port-output-buffer! $top 0))
1607  (error? ; invalid index
1608    (set-textual-port-output-index! $top "hello"))
1609  (error? ; invalid index
1610    (set-textual-port-output-index! $top -1))
1611  (error? ; invalid index
1612    (set-textual-port-output-index! $top 6))
1613  (error? ; invalid size
1614    (set-textual-port-output-size! $top "hello"))
1615  (error? ; invalid size
1616    (set-textual-port-output-size! $top -1))
1617  (error? ; invalid size
1618    (set-textual-port-output-size! $top 6))
1619  ; binary input
1620  (equal?
1621    (let ([ip (open-bytevector-input-port (string->utf8 "hello"))])
1622      (let ([buffer0 (binary-port-input-buffer ip)]
1623            [index0 (binary-port-input-index ip)]
1624            [size0 (binary-port-input-size ip)]
1625            [count0 (binary-port-input-count ip)])
1626        (get-u8 ip)
1627        (list
1628          (list buffer0 index0 size0 count0)
1629          (list
1630            (binary-port-input-buffer ip)
1631            (binary-port-input-index ip)
1632            (binary-port-input-size ip)
1633            (binary-port-input-count ip)))))
1634    `((,(string->utf8 "hello") 0 5 5) (,(string->utf8 "hello") 1 5 4)))
1635  (equal?
1636    (let ([ip (open-bytevector-input-port (string->utf8 "hello"))])
1637      (let ([buffer0 (binary-port-input-buffer ip)]
1638            [index0 (binary-port-input-index ip)]
1639            [size0 (binary-port-input-size ip)]
1640            [count0 (binary-port-input-count ip)])
1641        (get-u8 ip)
1642        (set-binary-port-input-buffer! ip (string->utf8 "goodbye"))
1643        (get-u8 ip)
1644        (list
1645          (list buffer0 index0 size0 count0)
1646          (list
1647            (binary-port-input-buffer ip)
1648            (binary-port-input-index ip)
1649            (binary-port-input-size ip)
1650            (binary-port-input-count ip)))))
1651    `((,(string->utf8 "hello") 0 5 5) (,(string->utf8 "goodbye") 1 7 6)))
1652  (equal?
1653    (let ([ip (open-bytevector-input-port (string->utf8 "hello"))])
1654      (let ([buffer0 (binary-port-input-buffer ip)]
1655            [index0 (binary-port-input-index ip)]
1656            [size0 (binary-port-input-size ip)]
1657            [count0 (binary-port-input-count ip)])
1658        (get-u8 ip)
1659        (set-binary-port-input-size! ip 3)
1660        (get-u8 ip)
1661        (list
1662          (list buffer0 index0 size0 count0)
1663          (list
1664            (binary-port-input-buffer ip)
1665            (binary-port-input-index ip)
1666            (binary-port-input-size ip)
1667            (binary-port-input-count ip)))))
1668    `((,(string->utf8 "hello") 0 5 5) (,(string->utf8 "hello") 1 3 2)))
1669  (equal?
1670    (let ([ip (open-bytevector-input-port (string->utf8 "hello"))])
1671      (let ([buffer0 (binary-port-input-buffer ip)]
1672            [index0 (binary-port-input-index ip)]
1673            [size0 (binary-port-input-size ip)]
1674            [count0 (binary-port-input-count ip)])
1675        (get-u8 ip)
1676        (set-binary-port-input-index! ip 3)
1677        (get-u8 ip)
1678        (list
1679          (list buffer0 index0 size0 count0)
1680          (list
1681            (binary-port-input-buffer ip)
1682            (binary-port-input-index ip)
1683            (binary-port-input-size ip)
1684            (binary-port-input-count ip)))))
1685    `((,(string->utf8 "hello") 0 5 5) (,(string->utf8 "hello") 4 5 1)))
1686  (error? ; not a binary input port
1687    (binary-port-input-buffer $tip))
1688  (error? ; not a binary input port
1689    (binary-port-input-buffer $top))
1690  (error? ; not a binary input port
1691    (binary-port-input-buffer $bop))
1692  (error? ; not a binary input port
1693    (binary-port-input-buffer 75))
1694  (error? ; not a binary input port
1695    (binary-port-input-index $tip))
1696  (error? ; not a binary input port
1697    (binary-port-input-index $top))
1698  (error? ; not a binary input port
1699    (binary-port-input-index $bop))
1700  (error? ; not a binary input port
1701    (binary-port-input-index 75))
1702  (error? ; not a binary input port
1703    (binary-port-input-size $tip))
1704  (error? ; not a binary input port
1705    (binary-port-input-size $top))
1706  (error? ; not a binary input port
1707    (binary-port-input-size $bop))
1708  (error? ; not a binary input port
1709    (binary-port-input-size 75))
1710  (error? ; not a binary input port
1711    (binary-port-input-count $tip))
1712  (error? ; not a binary input port
1713    (binary-port-input-count $top))
1714  (error? ; not a binary input port
1715    (binary-port-input-count $bop))
1716  (error? ; not a binary input port
1717    (binary-port-input-count 75))
1718  (error? ; not a binary input port
1719    (set-binary-port-input-buffer! $tip ""))
1720  (error? ; not a binary input port
1721    (set-binary-port-input-buffer! $top ""))
1722  (error? ; not a binary input port
1723    (set-binary-port-input-buffer! $bop ""))
1724  (error? ; not a binary input port
1725    (set-binary-port-input-buffer! 75 ""))
1726  (error? ; not a binary input port
1727    (set-binary-port-input-index! $tip 0))
1728  (error? ; not a binary input port
1729    (set-binary-port-input-index! $top 0))
1730  (error? ; not a binary input port
1731    (set-binary-port-input-index! $bop 0))
1732  (error? ; not a binary input port
1733    (set-binary-port-input-index! 75 0))
1734  (error? ; not a binary input port
1735    (set-binary-port-input-size! $tip 0))
1736  (error? ; not a binary input port
1737    (set-binary-port-input-size! $top 0))
1738  (error? ; not a binary input port
1739    (set-binary-port-input-size! $bop 0))
1740  (error? ; not a binary input port
1741    (set-binary-port-input-size! 75 0))
1742  (error? ; not a bytevector
1743    (set-binary-port-input-buffer! $bip "hello"))
1744  (error? ; not a bytevector
1745    (set-binary-port-input-buffer! $bip 0))
1746  (error? ; invalid index
1747    (set-binary-port-input-index! $bip #vu8(1 2 3)))
1748  (error? ; invalid index
1749    (set-binary-port-input-index! $bip -1))
1750  (error? ; invalid index
1751    (set-binary-port-input-index! $bip 6))
1752  (error? ; invalid size
1753    (set-binary-port-input-size! $bip #vu8(1 2 3)))
1754  (error? ; invalid size
1755    (set-binary-port-input-size! $bip -1))
1756  (error? ; invalid size
1757    (set-binary-port-input-size! $bip 6))
1758  ; binary output
1759  (equal?
1760    (let-values ([(op get) (open-bytevector-output-port)])
1761      (let ([buffer (string->utf8 "hello")])
1762        (set-binary-port-output-buffer! op buffer)
1763        (let ([buffer0 (bytevector-copy (binary-port-output-buffer op))]
1764              [index0 (binary-port-output-index op)]
1765              [size0 (binary-port-output-size op)]
1766              [count0 (binary-port-output-count op)])
1767          (put-u8 op (char->integer #\j))
1768          (list
1769            buffer
1770            (list buffer0 index0 size0 count0)
1771            (list
1772              (binary-port-output-buffer op)
1773              (binary-port-output-index op)
1774              (binary-port-output-size op)
1775              (binary-port-output-count op))))))
1776    `(,(string->utf8 "jello")
1777      (,(string->utf8 "hello") 0 5 5)
1778      (,(string->utf8 "jello") 1 5 4)))
1779  (equal?
1780    (let-values ([(op get) (open-bytevector-output-port)])
1781      (let ([buffer (string->utf8 "hello")])
1782        (set-binary-port-output-buffer! op buffer)
1783        (let ([buffer0 (bytevector-copy (binary-port-output-buffer op))]
1784              [index0 (binary-port-output-index op)]
1785              [size0 (binary-port-output-size op)]
1786              [count0 (binary-port-output-count op)])
1787          (put-u8 op (char->integer #\j))
1788          (set-binary-port-output-buffer! op (bytevector 1 2 3 4 5 6))
1789          (put-u8 op 31)
1790          (list
1791            buffer
1792            (list buffer0 index0 size0 count0)
1793            (list
1794              (binary-port-output-buffer op)
1795              (binary-port-output-index op)
1796              (binary-port-output-size op)
1797              (binary-port-output-count op))))))
1798    `(,(string->utf8 "jello")
1799      (,(string->utf8 "hello") 0 5 5)
1800      (#vu8(31 2 3 4 5 6) 1 6 5)))
1801  (equal?
1802    (let-values ([(op get) (open-bytevector-output-port)])
1803      (let ([buffer (string->utf8 "hello")])
1804        (set-binary-port-output-buffer! op buffer)
1805        (let ([buffer0 (bytevector-copy (binary-port-output-buffer op))]
1806              [index0 (binary-port-output-index op)]
1807              [size0 (binary-port-output-size op)]
1808              [count0 (binary-port-output-count op)])
1809          (put-u8 op (char->integer #\j))
1810          (set-binary-port-output-index! op 4)
1811          (put-u8 op (char->integer #\y))
1812          (list
1813            buffer
1814            (list buffer0 index0 size0 count0)
1815            (list
1816              (binary-port-output-buffer op)
1817              (binary-port-output-index op)
1818              (binary-port-output-size op)
1819              (binary-port-output-count op))))))
1820    `(,(string->utf8 "jelly")
1821      (,(string->utf8 "hello") 0 5 5)
1822      (,(string->utf8 "jelly") 5 5 0)))
1823  (equal?
1824    (let-values ([(op get) (open-bytevector-output-port)])
1825      (let ([buffer (string->utf8 "hello")])
1826        (set-binary-port-output-buffer! op buffer)
1827        (let ([buffer0 (bytevector-copy (binary-port-output-buffer op))]
1828              [index0 (binary-port-output-index op)]
1829              [size0 (binary-port-output-size op)]
1830              [count0 (binary-port-output-count op)])
1831          (put-u8 op (char->integer #\j))
1832          (set-binary-port-output-size! op 4)
1833          (put-u8 op (char->integer #\b))
1834          (list
1835            buffer
1836            (list buffer0 index0 size0 count0)
1837            (list
1838              (binary-port-output-buffer op)
1839              (binary-port-output-index op)
1840              (binary-port-output-size op)
1841              (binary-port-output-count op))))))
1842    `(,(string->utf8 "bello")
1843      (,(string->utf8 "hello") 0 5 5)
1844      (,(string->utf8 "bello") 1 4 3)))
1845  (error? ; not a binary output port
1846    (binary-port-output-buffer $tip))
1847  (error? ; not a binary output port
1848    (binary-port-output-buffer $top))
1849  (error? ; not a binary output port
1850    (binary-port-output-buffer $bip))
1851  (error? ; not a binary output port
1852    (binary-port-output-buffer 75))
1853  (error? ; not a binary output port
1854    (binary-port-output-index $tip))
1855  (error? ; not a binary output port
1856    (binary-port-output-index $top))
1857  (error? ; not a binary output port
1858    (binary-port-output-index $bip))
1859  (error? ; not a binary output port
1860    (binary-port-output-index 75))
1861  (error? ; not a binary output port
1862    (binary-port-output-size $tip))
1863  (error? ; not a binary output port
1864    (binary-port-output-size $top))
1865  (error? ; not a binary output port
1866    (binary-port-output-size $bip))
1867  (error? ; not a binary output port
1868    (binary-port-output-size 75))
1869  (error? ; not a binary output port
1870    (binary-port-output-count $tip))
1871  (error? ; not a binary output port
1872    (binary-port-output-count $top))
1873  (error? ; not a binary output port
1874    (binary-port-output-count $bip))
1875  (error? ; not a binary output port
1876    (binary-port-output-count 75))
1877  (error? ; not a binary output port
1878    (set-binary-port-output-buffer! $tip ""))
1879  (error? ; not a binary output port
1880    (set-binary-port-output-buffer! $top ""))
1881  (error? ; not a binary output port
1882    (set-binary-port-output-buffer! $bip ""))
1883  (error? ; not a binary output port
1884    (set-binary-port-output-buffer! 75 ""))
1885  (error? ; not a binary output port
1886    (set-binary-port-output-index! $tip 0))
1887  (error? ; not a binary output port
1888    (set-binary-port-output-index! $top 0))
1889  (error? ; not a binary output port
1890    (set-binary-port-output-index! $bip 0))
1891  (error? ; not a binary output port
1892    (set-binary-port-output-index! 75 0))
1893  (error? ; not a binary output port
1894    (set-binary-port-output-size! $tip 0))
1895  (error? ; not a binary output port
1896    (set-binary-port-output-size! $top 0))
1897  (error? ; not a binary output port
1898    (set-binary-port-output-size! $bip 0))
1899  (error? ; not a binary output port
1900    (set-binary-port-output-size! 75 0))
1901  (error? ; not a string
1902    (set-binary-port-output-buffer! $bop "hello"))
1903  (error? ; not a string
1904    (set-binary-port-output-buffer! $bop 0))
1905  (error? ; invalid index
1906    (set-binary-port-output-index! $bop #vu8(1 2 3)))
1907  (error? ; invalid index
1908    (set-binary-port-output-index! $bop -1))
1909  (error? ; invalid index
1910    (set-binary-port-output-index! $bop 6))
1911  (error? ; invalid size
1912    (set-binary-port-output-size! $bop #vu8(1 2 3)))
1913  (error? ; invalid size
1914    (set-binary-port-output-size! $bop -1))
1915  (error? ; invalid size
1916    (set-binary-port-output-size! $bop 6))
1917  (begin
1918    (define $handler-standin (#%$port-handler (open-string-input-port "hi")))
1919    #t)
1920  (let ([name "foo"] [ib "hey!"])
1921    (let ([p (#%$make-textual-input-port name $handler-standin ib)])
1922      (and (port? p)
1923           (textual-port? p)
1924           (not (binary-port? p))
1925           (input-port? p)
1926           (not (output-port? p))
1927           (eq? (port-name p) name)
1928           (eq? (#%$port-handler p) $handler-standin)
1929           (eq? (#%$port-info p) #f)
1930           (eq? (textual-port-input-buffer p) ib)
1931           (eqv? (textual-port-input-size p) (string-length ib))
1932           (eqv? (textual-port-input-index p) 0)
1933           (eqv? (textual-port-input-count p) (string-length ib)))))
1934  (let ([name "foo"] [info "info"] [ib "hey!"])
1935    (let ([p (#%$make-textual-input-port name $handler-standin ib info)])
1936      (and (port? p)
1937           (textual-port? p)
1938           (not (binary-port? p))
1939           (input-port? p)
1940           (not (output-port? p))
1941           (eq? (port-name p) name)
1942           (eq? (#%$port-handler p) $handler-standin)
1943           (eq? (#%$port-info p) info)
1944           (eq? (textual-port-input-buffer p) ib)
1945           (eqv? (textual-port-input-size p) (string-length ib))
1946           (eqv? (textual-port-input-index p) 0)
1947           (eqv? (textual-port-input-count p) (string-length ib)))))
1948  (let ([name "foo"] [ob "hey!"])
1949    (let ([p (#%$make-textual-output-port name $handler-standin ob)])
1950      (and (port? p)
1951           (textual-port? p)
1952           (not (binary-port? p))
1953           (not (input-port? p))
1954           (output-port? p)
1955           (eq? (port-name p) name)
1956           (eq? (#%$port-handler p) $handler-standin)
1957           (eq? (#%$port-info p) #f)
1958           (eq? (textual-port-output-buffer p) ob)
1959           (eqv? (textual-port-output-size p) (string-length ob))
1960           (eqv? (textual-port-output-index p) 0)
1961           (eqv? (textual-port-output-count p) (string-length ob)))))
1962  (let ([name "foo"] [info "info"] [ob "hey!"])
1963    (let ([p (#%$make-textual-output-port name $handler-standin ob info)])
1964      (and (port? p)
1965           (textual-port? p)
1966           (not (binary-port? p))
1967           (not (input-port? p))
1968           (output-port? p)
1969           (eq? (port-name p) name)
1970           (eq? (#%$port-handler p) $handler-standin)
1971           (eq? (#%$port-info p) info)
1972           (eq? (textual-port-output-buffer p) ob)
1973           (eqv? (textual-port-output-size p) (string-length ob))
1974           (eqv? (textual-port-output-index p) 0)
1975           (eqv? (textual-port-output-count p) (string-length ob)))))
1976  (let ([name "foo"] [ib "hay!"] [ob "hey!"])
1977    (let ([p (#%$make-textual-input/output-port name $handler-standin ib ob)])
1978      (and (port? p)
1979           (textual-port? p)
1980           (not (binary-port? p))
1981           (input-port? p)
1982           (output-port? p)
1983           (eq? (port-name p) name)
1984           (eq? (#%$port-handler p) $handler-standin)
1985           (eq? (#%$port-info p) #f)
1986           (eq? (textual-port-input-buffer p) ib)
1987           (eqv? (textual-port-input-size p) (string-length ib))
1988           (eqv? (textual-port-input-index p) 0)
1989           (eqv? (textual-port-input-count p) (string-length ib))
1990           (eq? (textual-port-output-buffer p) ob)
1991           (eqv? (textual-port-output-size p) (string-length ob))
1992           (eqv? (textual-port-output-index p) 0)
1993           (eqv? (textual-port-output-count p) (string-length ob)))))
1994  (let ([name "foo"] [info "info"] [ib "hay!"] [ob "hey!"])
1995    (let ([p (#%$make-textual-input/output-port name $handler-standin ib ob info)])
1996      (and (port? p)
1997           (textual-port? p)
1998           (not (binary-port? p))
1999           (input-port? p)
2000           (output-port? p)
2001           (eq? (port-name p) name)
2002           (eq? (#%$port-handler p) $handler-standin)
2003           (eq? (#%$port-info p) info)
2004           (eq? (textual-port-input-buffer p) ib)
2005           (eqv? (textual-port-input-size p) (string-length ib))
2006           (eqv? (textual-port-input-index p) 0)
2007           (eqv? (textual-port-input-count p) (string-length ib))
2008           (eq? (textual-port-output-buffer p) ob)
2009           (eqv? (textual-port-output-size p) (string-length ob))
2010           (eqv? (textual-port-output-index p) 0)
2011           (eqv? (textual-port-output-count p) (string-length ob)))))
2012  (let ([name "foo"] [ib #vu8(1 2 3 4)])
2013    (let ([p (#%$make-binary-input-port name $handler-standin ib)])
2014      (and (port? p)
2015           (not (textual-port? p))
2016           (binary-port? p)
2017           (input-port? p)
2018           (not (output-port? p))
2019           (eq? (port-name p) name)
2020           (eq? (#%$port-handler p) $handler-standin)
2021           (eq? (#%$port-info p) #f)
2022           (eq? (binary-port-input-buffer p) ib)
2023           (eqv? (binary-port-input-size p) (bytevector-length ib))
2024           (eqv? (binary-port-input-index p) 0)
2025           (eqv? (binary-port-input-count p) (bytevector-length ib)))))
2026  (let ([name "foo"] [info "info"] [ib #vu8(1 2 3 4)])
2027    (let ([p (#%$make-binary-input-port name $handler-standin ib info)])
2028      (and (port? p)
2029           (not (textual-port? p))
2030           (binary-port? p)
2031           (input-port? p)
2032           (not (output-port? p))
2033           (eq? (port-name p) name)
2034           (eq? (#%$port-handler p) $handler-standin)
2035           (eq? (#%$port-info p) info)
2036           (eq? (binary-port-input-buffer p) ib)
2037           (eqv? (binary-port-input-size p) (bytevector-length ib))
2038           (eqv? (binary-port-input-index p) 0)
2039           (eqv? (binary-port-input-count p) (bytevector-length ib)))))
2040  (let ([name "foo"] [ob #vu8(1 2 3 4)])
2041    (let ([p (#%$make-binary-output-port name $handler-standin ob)])
2042      (and (port? p)
2043           (not (textual-port? p))
2044           (binary-port? p)
2045           (not (input-port? p))
2046           (output-port? p)
2047           (eq? (port-name p) name)
2048           (eq? (#%$port-handler p) $handler-standin)
2049           (eq? (#%$port-info p) #f)
2050           (eq? (binary-port-output-buffer p) ob)
2051           (eqv? (binary-port-output-size p) (bytevector-length ob))
2052           (eqv? (binary-port-output-index p) 0)
2053           (eqv? (binary-port-output-count p) (bytevector-length ob)))))
2054  (let ([name "foo"] [info "info"] [ob #vu8(1 2 3 4)])
2055    (let ([p (#%$make-binary-output-port name $handler-standin ob info)])
2056      (and (port? p)
2057           (not (textual-port? p))
2058           (binary-port? p)
2059           (not (input-port? p))
2060           (output-port? p)
2061           (eq? (port-name p) name)
2062           (eq? (#%$port-handler p) $handler-standin)
2063           (eq? (#%$port-info p) info)
2064           (eq? (binary-port-output-buffer p) ob)
2065           (eqv? (binary-port-output-size p) (bytevector-length ob))
2066           (eqv? (binary-port-output-index p) 0)
2067           (eqv? (binary-port-output-count p) (bytevector-length ob)))))
2068  (let ([name "foo"] [ib #vu8(4 3 2 1)] [ob #vu8(1 2 3 4)])
2069    (let ([p (#%$make-binary-input/output-port name $handler-standin ib ob)])
2070      (and (port? p)
2071           (not (textual-port? p))
2072           (binary-port? p)
2073           (input-port? p)
2074           (output-port? p)
2075           (eq? (port-name p) name)
2076           (eq? (#%$port-handler p) $handler-standin)
2077           (eq? (#%$port-info p) #f)
2078           (eq? (binary-port-input-buffer p) ib)
2079           (eqv? (binary-port-input-size p) (bytevector-length ib))
2080           (eqv? (binary-port-input-index p) 0)
2081           (eqv? (binary-port-input-count p) (bytevector-length ib))
2082           (eq? (binary-port-output-buffer p) ob)
2083           (eqv? (binary-port-output-size p) (bytevector-length ob))
2084           (eqv? (binary-port-output-index p) 0)
2085           (eqv? (binary-port-output-count p) (bytevector-length ob)))))
2086  (let ([name "foo"] [info "info"] [ib #vu8(4 3 2 1)] [ob #vu8(1 2 3 4)])
2087    (let ([p (#%$make-binary-input/output-port name $handler-standin ib ob info)])
2088      (and (port? p)
2089           (not (textual-port? p))
2090           (binary-port? p)
2091           (input-port? p)
2092           (output-port? p)
2093           (eq? (port-name p) name)
2094           (eq? (#%$port-handler p) $handler-standin)
2095           (eq? (#%$port-info p) info)
2096           (eq? (binary-port-input-buffer p) ib)
2097           (eqv? (binary-port-input-size p) (bytevector-length ib))
2098           (eqv? (binary-port-input-index p) 0)
2099           (eqv? (binary-port-input-count p) (bytevector-length ib))
2100           (eq? (binary-port-output-buffer p) ob)
2101           (eqv? (binary-port-output-size p) (bytevector-length ob))
2102           (eqv? (binary-port-output-index p) 0)
2103           (eqv? (binary-port-output-count p) (bytevector-length ob)))))
2104 )
2105
2106(mat file-buffer-size
2107  (let ([x (file-buffer-size)])
2108    (and (fixnum? x) (> x 0)))
2109  (error? (file-buffer-size 1024 15))
2110  (error? (file-buffer-size 'shoe))
2111  (error? (file-buffer-size 0))
2112  (error? (file-buffer-size -15))
2113  (error? (file-buffer-size (+ (most-positive-fixnum) 1)))
2114  (error? (file-buffer-size 1024.0))
2115  (parameterize ([file-buffer-size (* (file-buffer-size) 2)])
2116    (let ([ip (open-file-input-port prettytest.ss)])
2117      (let ([n (bytevector-length (binary-port-input-buffer ip))])
2118        (close-input-port ip)
2119        (eqv? n (file-buffer-size)))))
2120)
2121
2122(mat custom-port-buffer-size
2123  (let ([x (custom-port-buffer-size)])
2124    (and (fixnum? x) (> x 0)))
2125  (error? (custom-port-buffer-size 1024 15))
2126  (error? (custom-port-buffer-size 'shoe))
2127  (error? (custom-port-buffer-size 0))
2128  (error? (custom-port-buffer-size -15))
2129  (error? (custom-port-buffer-size (+ (most-positive-fixnum) 1)))
2130  (error? (custom-port-buffer-size 1024.0))
2131  (parameterize ([custom-port-buffer-size (* (custom-port-buffer-size) 2)])
2132    (let ([q #f])
2133      (let ([ip (make-custom-textual-input-port "foo"
2134                  (lambda (str s c) (set! q c) 0)
2135                  #f #f #f)])
2136        (read-char ip)
2137        (= q (custom-port-buffer-size)))))
2138)
2139
2140(mat compress-parameters
2141  (error? ; unsupported format
2142    (compress-format 'foo))
2143  (error? ; unsupported format
2144    (compress-format "gzip"))
2145  (eq? (compress-format) 'lz4)
2146  (eq? (parameterize ([compress-format 'gzip]) (compress-format)) 'gzip)
2147  (eq? (parameterize ([compress-format 'lz4]) (compress-format)) 'lz4)
2148  (error? ; unsupported level
2149    (compress-level 'foo))
2150  (error? ; unsupported level
2151    (compress-level 1))
2152  (eq? (compress-level) 'medium)
2153  (eq? (parameterize ([compress-level 'low]) (compress-level)) 'low)
2154  (eq? (parameterize ([compress-level 'medium]) (compress-level)) 'medium)
2155  (eq? (parameterize ([compress-level 'high]) (compress-level)) 'high)
2156  (eq? (parameterize ([compress-level 'maximum]) (compress-level)) 'maximum)
2157  (begin
2158    (define (fnlength ifn) (call-with-port (open-file-input-port ifn) port-length))
2159    (define (compress-file ifn ofn fmt lvl)
2160      (call-with-port (open-file-input-port ifn)
2161        (lambda (ip)
2162          (call-with-port (parameterize ([compress-format fmt] [compress-level lvl])
2163                            (open-file-output-port ofn (file-options compressed replace)))
2164            (lambda (op) (put-bytevector op (get-bytevector-all ip))))))
2165      (fnlength ofn))
2166    (define (compress-file-test fmt)
2167      (let ([orig (fnlength prettytest.ss)]
2168            [low (compress-file prettytest.ss "testfile.ss" fmt 'low)]
2169            [medium (compress-file prettytest.ss "testfile.ss" fmt 'medium)]
2170            [high (compress-file prettytest.ss "testfile.ss" fmt 'high)]
2171            [maximum (compress-file prettytest.ss "testfile.ss" fmt 'maximum)])
2172        (define-syntax test1
2173          (syntax-rules ()
2174            [(_ level)
2175             (unless (< level orig) (errorf #f "~s ~s did not compress" fmt 'level))]))
2176        (define-syntax test2
2177          (syntax-rules ()
2178            [(_ level1 level2)
2179             (unless (<= level2 level1) (errorf #f "~s ~s did worse than ~s" fmt 'level2 'level1))]))
2180        (test1 low)
2181        (test1 medium)
2182        (test1 high)
2183        (test1 maximum)
2184        (test2 low medium)
2185        (test2 medium high)
2186        (test2 high maximum)
2187        (unless (< maximum low) (errorf #f "~s maximum didn't do better than low" fmt))))
2188    (compress-file-test 'lz4)
2189    (compress-file-test 'gzip)
2190    #t)
2191)
2192
2193(mat compression
2194  (parameters [compress-format 'gzip 'lz4] [compress-level 'low 'medium 'high 'maximum])
2195  (and (memq (compress-format) '(gzip lz4)) #t)
2196  (and (memq (compress-level) '(low medium high maximum)) #t)
2197  (let ()
2198    (define cp
2199      (lambda (src dst)
2200        (define buf-size 4096)
2201        (let ([buf (make-bytevector buf-size)])
2202          (call-with-port dst
2203            (lambda (op)
2204              (call-with-port src
2205                (lambda (ip)
2206                  (let loop ()
2207                    (let ([n (get-bytevector-n! ip buf 0 buf-size)])
2208                      (unless (eof-object? n)
2209                        (put-bytevector op buf 0 n)
2210                        (loop)))))))))))
2211
2212    (define cmp
2213      (lambda (src1 src2)
2214        (define buf-size 4096)
2215        (let ([buf1 (make-bytevector buf-size)]
2216              [buf2 (make-bytevector buf-size)])
2217          (call-with-port src1
2218            (lambda (ip1)
2219              (call-with-port src2
2220                (lambda (ip2)
2221                  (let loop ()
2222                    (let ([n1 (get-bytevector-n! ip1 buf1 0 buf-size)]
2223                          [n2 (get-bytevector-n! ip2 buf2 0 buf-size)])
2224                      (if (eof-object? n1)
2225                          (eof-object? n2)
2226                          (and (= n1 n2)
2227                               (let test ([i 0])
2228                                 (or (= i n1)
2229                                     (and (= (bytevector-u8-ref buf1 i)
2230                                             (bytevector-u8-ref buf2 i))
2231                                          (test (+ 1 i)))))
2232                               (loop))))))))))))
2233    (and
2234     (cmp (open-file-input-port prettytest.ss)
2235          (open-file-input-port prettytest.ss))
2236     (cmp (open-file-input-port prettytest.ss (file-options compressed))
2237          (open-file-input-port prettytest.ss))
2238     (cmp (open-file-input-port prettytest.ss)
2239          (open-file-input-port prettytest.ss (file-options compressed)))
2240     (cmp (open-file-input-port prettytest.ss (file-options compressed))
2241          (open-file-input-port prettytest.ss (file-options compressed)))
2242     (begin
2243       (cp (open-file-input-port prettytest.ss)
2244           (open-file-output-port "testfile.ss" (file-options replace compressed)))
2245       #t)
2246     (cmp (open-file-input-port "testfile.ss" (file-options compressed))
2247          (open-file-input-port prettytest.ss))
2248     (not (cmp (open-file-input-port "testfile.ss")
2249               (open-file-input-port prettytest.ss)))
2250     (begin
2251       (cp (open-file-input-port prettytest.ss)
2252           (open-file-output-port "testfile.ss" (file-options no-fail no-truncate append compressed)))
2253       #t)
2254     (not (cmp (open-file-input-port "testfile.ss" (file-options compressed))
2255               (open-file-input-port prettytest.ss)))))
2256  ; test workaround for bogus gzclose error return for empty input files
2257  (and
2258   (eqv? (call-with-port
2259          (open-file-output-port "testfile.ss" (file-options replace))
2260          (lambda (x) (void)))
2261         (void))
2262   (eof-object? (call-with-port
2263                 (open-file-input-port "testfile.ss" (file-options compressed))
2264                 get-u8)))
2265  (begin
2266    (let ([op (open-file-output-port "testfile.ss" (file-options replace))])
2267      (put-bytevector op #vu8(#x23 #x88 #x09 #x72 #xf3 #x72))
2268      (port-file-compressed! op)
2269      (put-bytevector op #vu8(#x93 #x21 #x88 #xe7 #x67))
2270      (let ([op (transcoded-port op (native-transcoder))])
2271        (display "hello!\n" op)
2272        (close-port op)))
2273    #t)
2274  (equal?
2275    (let ([ip (open-file-input-port "testfile.ss")])
2276      (let ([bv1 (get-bytevector-n ip 6)])
2277        (port-file-compressed! ip)
2278        (let ([bv2 (get-bytevector-n ip 5)])
2279          (let ([ip (transcoded-port ip (native-transcoder))])
2280            (let ([s (get-string-all ip)])
2281              (close-port ip)
2282              (list bv1 bv2 s))))))
2283    '(#vu8(#x23 #x88 #x09 #x72 #xf3 #x72)
2284      #vu8(#x93 #x21 #x88 #xe7 #x67)
2285      "hello!\n"))
2286  (not
2287    (equal?
2288      (let ([ip (open-file-input-port "testfile.ss")])
2289        (let ([bv1 (get-bytevector-n ip 6)])
2290          (let ([bv2 (get-bytevector-n ip 5)])
2291            (close-port ip)
2292            (list bv1 bv2))))
2293      '(#vu8(#x23 #x88 #x09 #x72 #xf3 #x72)
2294        #vu8(#x93 #x21 #x88 #xe7 #x67))))
2295  (begin
2296    (let ([op (open-file-output-port "testfile.ss" (file-options replace) (buffer-mode block) (native-transcoder))])
2297      (put-string op "uncompressed string")
2298      (port-file-compressed! op)
2299      (put-string op "compressed string")
2300      (close-port op))
2301    #t)
2302  (equal?
2303    (let ([ip (open-file-input-port "testfile.ss" (file-options) (buffer-mode block) (native-transcoder))])
2304      (let ([s1 (get-string-n ip (string-length "uncompressed string"))])
2305        (port-file-compressed! ip)
2306        (let ([s2 (get-string-all ip)])
2307          (close-port ip)
2308          (list s1 s2))))
2309    '("uncompressed string" "compressed string"))
2310  (error? ; not a file port
2311    (call-with-string-output-port port-file-compressed!))
2312  (error? ; input/output ports aren't supported
2313    (let ([iop (open-file-input/output-port "testfile.ss" (file-options replace))])
2314      (guard (c [else (close-port iop) (raise c)])
2315        (port-file-compressed! iop))))
2316  (begin
2317    (let ([op (open-file-output-port "testfile.ss" (file-options compressed replace) (buffer-mode block) (native-transcoder))])
2318      (port-file-compressed! op)
2319      (put-string op "compressed string")
2320      (close-port op))
2321    #t)
2322  (equal?
2323    (let ([ip (open-file-input-port "testfile.ss" (file-options compressed) (buffer-mode block) (native-transcoder))])
2324      (port-file-compressed! ip)
2325      (let ([s (get-string-all ip)])
2326        (close-port ip)
2327        s))
2328    '"compressed string")
2329)
2330
2331(mat bytevector-input-port
2332  (error? ; incorrect number of arguments
2333    (open-bytevector-input-port))
2334  (error? ; not a bytevector
2335    (open-bytevector-input-port '#(1 2 3 4)))
2336  (error? ; none is not a transcoder
2337    (open-bytevector-input-port #vu8(1 2 3 4) 'none))
2338  (error? ; incorrect number of arguments
2339    (open-bytevector-input-port #vu8(1 2 3 4) #f 'none))
2340  (let ()
2341    (define x (open-bytevector-input-port #vu8(1 2 3 4)))
2342    (and (eq? (get-u8 x) 1)
2343         (eq? (get-u8 x) 2)
2344         (eq? (get-u8 x) 3)
2345         (eq? (get-u8 x) 4)
2346         (eq? (get-u8 x) (eof-object))))
2347  (let ()
2348    (define x (open-bytevector-input-port #vu8(1 2 3 4)))
2349    (and (port-has-port-position? x)
2350         (eq? (port-position x) 0)
2351         (eq? (get-u8 x) 1)
2352         (eq? (port-position x) 1)
2353         (eq? (get-u8 x) 2)
2354         (eq? (port-position x) 2)
2355         (eq? (get-u8 x) 3)
2356         (eq? (port-position x) 3)
2357         (eq? (get-u8 x) 4)
2358         (eq? (port-position x) 4)
2359         (eq? (get-u8 x) #!eof)
2360         (eq? (port-position x) 4)
2361         (eq? (get-u8 x) #!eof)
2362         (eq? (port-position x) 4)
2363         (eq? (get-u8 x) #!eof)
2364         (eq? (port-position x) 4)))
2365  (let ()
2366    (define x (open-bytevector-input-port #vu8(1 2 3 4)))
2367    (and (port-has-set-port-position!? x)
2368         (eq? (port-position x) 0)
2369         (eq? (get-u8 x) 1)
2370         (eq? (port-position x) 1)
2371         (eq? (get-u8 x) 2)
2372         (eq? (port-position x) 2)
2373         (begin (set-port-position! x 0) #t)
2374         (eq? (get-u8 x) 1)
2375         (begin (set-port-position! x 4) #t)
2376         (eq? (get-u8 x) #!eof)))
2377  (error? (set-port-position! (open-bytevector-input-port #vu8(1 2 3 4)) -1))
2378  (error? (set-port-position! (open-bytevector-input-port #vu8(1 2 3 4)) 5))
2379
2380  (let ()
2381    (define x (open-bytevector-input-port #vu8(1 2 3 4)))
2382    (and (eq? (lookahead-u8 x) 1)
2383         (eq? (lookahead-u8 x) 1)
2384         (eq? (lookahead-u8 x) 1)
2385         (eq? (get-u8 x) 1)
2386         (eq? (lookahead-u8 x) 2)
2387         (eq? (get-u8 x) 2)
2388         (eq? (lookahead-u8 x) 3)
2389         (eq? (get-u8 x) 3)
2390         (eq? (lookahead-u8 x) 4)
2391         (eq? (get-u8 x) 4)
2392         (eq? (lookahead-u8 x) #!eof)
2393         (eq? (get-u8 x) #!eof)
2394         (eq? (lookahead-u8 x) #!eof)
2395         (eq? (get-u8 x) #!eof)))
2396  (eq? (buffer-mode none) 'none)
2397  (eq? (buffer-mode line) 'line)
2398  (eq? (buffer-mode block) 'block)
2399  (error? (buffer-mode bar))
2400  (error? (buffer-mode 'none))
2401  (eq? (buffer-mode? 'none) #t)
2402  (eq? (buffer-mode? 'line) #t)
2403  (eq? (buffer-mode? 'block) #t)
2404  (eq? (buffer-mode? 'foo) #f)
2405)
2406
2407(mat bytevector-output-port
2408  (error? ; not a transcoder
2409    (open-bytevector-output-port 'oops))
2410  (error? ; incorrect number of arguments
2411    (open-bytevector-output-port #f 'none))
2412)
2413
2414(mat custom-binary-ports
2415  (begin
2416    (define $cp-ip
2417      (let ([pos 0])
2418        (make-custom-binary-input-port "foo"
2419          (lambda (bv s c)
2420            (let loop ([i s])
2421              (unless (eq? i (+ s c))
2422                (bytevector-u8-set! bv i (modulo (+ pos i) 256))
2423                (loop (+ 1 i))))
2424            (set! pos (+ pos c))
2425            c)
2426          (lambda () pos)
2427          (lambda (x) (set! pos x))
2428          #f)))
2429    #t)
2430  (eq? (port-position $cp-ip) 0)
2431  (error? ; cannot unget
2432    (unget-u8 $cp-ip 255))
2433  (begin (unget-u8 $cp-ip (eof-object)) #t)
2434  (port-eof? $cp-ip)
2435  (eof-object? (lookahead-u8 $cp-ip))
2436  (eof-object? (get-u8 $cp-ip))
2437  (equal?
2438    (get-bytevector-n $cp-ip 10)
2439    #vu8(0 1 2 3 4 5 6 7 8 9))
2440  (eqv? (port-position $cp-ip) 10)
2441  (eqv? (get-u8 $cp-ip) 10)
2442  (begin (set-port-position! $cp-ip 256000) #t)
2443  (eqv? (get-u8 $cp-ip) 0)
2444  (eqv? (port-position $cp-ip) 256001)
2445  (error? ; not a binary output port
2446    (put-u8 $cp-ip 255))
2447  (not (port-has-port-length? $cp-ip))
2448  (not (port-has-set-port-length!? $cp-ip))
2449  (not (port-has-port-nonblocking?? $cp-ip))
2450  (not (port-has-set-port-nonblocking!? $cp-ip))
2451  (error? ; not supported
2452    (port-length $cp-ip))
2453  (error? ; not supported
2454    (set-port-length! $cp-ip 50))
2455  (error? ; not supported
2456    (port-nonblocking? $cp-ip))
2457  (error? ; not supported
2458    (set-port-nonblocking! $cp-ip #t))
2459  (error? ; not supported
2460    (set-port-nonblocking! $cp-ip #f))
2461  (begin
2462    (define $cp-op
2463      (let ([pos 0])
2464        (make-custom-binary-output-port "foo"
2465          (lambda (bv s c)
2466            (set! pos (+ pos c))
2467            (printf "write ~s\n" c)
2468            c)
2469          (lambda () pos)
2470          (lambda (x) (set! pos x))
2471          (lambda () (printf "closed\n")))))
2472    #t)
2473  (eq? (port-position $cp-op) 0)
2474  (error? ; not a binary input port
2475    (unget-u8 $cp-op 255))
2476  (not (port-has-port-length? $cp-op))
2477  (not (port-has-set-port-length!? $cp-op))
2478  (not (port-has-port-nonblocking?? $cp-op))
2479  (not (port-has-set-port-nonblocking!? $cp-op))
2480  (error? ; not supported
2481    (port-length $cp-op))
2482  (error? ; not supported
2483    (set-port-length! $cp-op 50))
2484  (error? ; not supported
2485    (port-nonblocking? $cp-op))
2486  (error? ; not supported
2487    (set-port-nonblocking! $cp-op #t))
2488  (error? ; not supported
2489    (set-port-nonblocking! $cp-op #f))
2490  (begin (put-u8 $cp-op 255) #t)
2491  (eqv? (port-position $cp-op) 1)
2492  (begin (set-port-position! $cp-op 17) #t)
2493  (equal?
2494    (with-output-to-string
2495      (lambda ()
2496        (put-bytevector $cp-op #vu8(17 18 19 20))
2497        (put-bytevector $cp-op #vu8(20 21 22 23 24 25) 1)
2498        (put-bytevector $cp-op #vu8(24 25 26 27 28 29) 1 4)))
2499    "")
2500  (equal? ; in our current implementation...
2501    (with-output-to-string
2502      (lambda ()
2503        (printf "pos = ~s\n" (port-position $cp-op))))
2504    "pos = 30\n")
2505  (equal? ; ... actual flush won't happen until here
2506    (with-output-to-string
2507      (lambda ()
2508        (r6rs:flush-output-port $cp-op)))
2509    "write 13\n")
2510  (equal?
2511    (with-output-to-string
2512      (lambda ()
2513        (printf "pos = ~s\n" (port-position $cp-op))))
2514    "pos = 30\n")
2515  (equal?
2516    (with-output-to-string
2517      (lambda ()
2518        (put-bytevector $cp-op #vu8(17 18 19 20))
2519        (put-bytevector $cp-op #vu8(20 21 22 23 24 25) 1)
2520        (put-bytevector $cp-op #vu8(24 25 26 27 28 29) 1 4)))
2521    "")
2522  (equal?
2523    (with-output-to-string
2524      (lambda ()
2525        (close-port $cp-op)))
2526    "write 13\nclosed\n")
2527  (error? ; closed
2528    (put-u8 $cp-op 0))
2529  (error? ; closed
2530    (put-bytevector $cp-op #vu8(3)))
2531  (error? ; closed
2532    (r6rs:flush-output-port $cp-op))
2533  (begin
2534    (define $cp-iop
2535      (let ([pos 0])
2536        (make-custom-binary-input/output-port "foo"
2537          (lambda (bv s c)
2538            (let loop ([i s])
2539              (unless (eq? i (+ s c))
2540                (bytevector-u8-set! bv i (modulo (+ pos i) 256))
2541                (loop (+ 1 i))))
2542            (set! pos (+ pos c))
2543            c)
2544          (lambda (bv s c)
2545            (set! pos (+ pos c))
2546            (printf "write ~s\n" c)
2547            c)
2548          (lambda () pos)
2549          (lambda (x) (set! pos x))
2550          (lambda () (printf "closed\n")))))
2551    #t)
2552  (eq? (port-position $cp-iop) 0)
2553  (error? ; cannot unget
2554    (unget-u8 $cp-iop 255))
2555  (begin (unget-u8 $cp-iop (eof-object)) #t)
2556  (port-eof? $cp-iop)
2557  (eof-object? (lookahead-u8 $cp-iop))
2558  (eof-object? (get-u8 $cp-iop))
2559  (equal?
2560    (get-bytevector-n $cp-iop 10)
2561    #vu8(0 1 2 3 4 5 6 7 8 9))
2562  (eqv? (port-position $cp-iop) 10)
2563  (eqv? (lookahead-u8 $cp-iop) 10)
2564  (eqv? (get-u8 $cp-iop) 10)
2565  (begin (set-port-position! $cp-iop 256000) #t)
2566  (eqv? (get-u8 $cp-iop) 0)
2567  (eqv? (port-position $cp-iop) 256001)
2568  (not (port-has-port-length? $cp-iop))
2569  (not (port-has-set-port-length!? $cp-iop))
2570  (not (port-has-port-nonblocking?? $cp-iop))
2571  (not (port-has-set-port-nonblocking!? $cp-iop))
2572  (error? ; not supported
2573    (port-length $cp-iop))
2574  (error? ; not supported
2575    (set-port-length! $cp-iop 50))
2576  (error? ; not supported
2577    (port-nonblocking? $cp-iop))
2578  (error? ; not supported
2579    (set-port-nonblocking! $cp-iop #t))
2580  (error? ; not supported
2581    (set-port-nonblocking! $cp-iop #f))
2582  (begin (put-u8 $cp-iop 255) #t)
2583  (eqv? (port-position $cp-iop) 256002)
2584  (begin (set-port-position! $cp-iop 17) #t)
2585  (equal?
2586    (with-output-to-string
2587      (lambda ()
2588        (put-bytevector $cp-iop #vu8(17 18 19 20))
2589        (put-bytevector $cp-iop #vu8(20 21 22 23 24 25) 1)
2590        (put-bytevector $cp-iop #vu8(24 25 26 27 28 29) 1 4)))
2591    "")
2592  (equal? ; in our current implementation...
2593    (with-output-to-string
2594      (lambda ()
2595        (printf "pos = ~s\n" (port-position $cp-iop))))
2596    "pos = 30\n")
2597  (equal? ; ... actual flush won't happen until here
2598    (with-output-to-string
2599      (lambda ()
2600        (r6rs:flush-output-port $cp-iop)))
2601    "write 13\n")
2602  (equal?
2603    (with-output-to-string
2604      (lambda ()
2605        (printf "pos = ~s\n" (port-position $cp-iop))))
2606    "pos = 30\n")
2607  (equal?
2608    (with-output-to-string
2609      (lambda ()
2610        (put-bytevector $cp-iop #vu8(17 18 19 20))
2611        (put-bytevector $cp-iop #vu8(20 21 22 23 24 25) 1)
2612        (put-bytevector $cp-iop #vu8(24 25 26 27 28 29) 1 4)))
2613    "")
2614  (equal?
2615    (with-output-to-string
2616      (lambda ()
2617        (close-port $cp-iop)))
2618    "write 13\nclosed\n")
2619  (error? ; closed
2620    (put-u8 $cp-iop 0))
2621  (error? ; closed
2622    (put-bytevector $cp-iop #vu8(3)))
2623  (error? ; closed
2624    (r6rs:flush-output-port $cp-iop))
2625
2626  (begin
2627    (define $cp-iop
2628      (let ([pos 0])
2629        (make-custom-binary-input/output-port "foo"
2630          (lambda (bv s c)
2631            (let loop ([i s])
2632              (unless (eq? i (+ s c))
2633                (bytevector-u8-set! bv i (modulo (+ pos i) 256))
2634                (loop (+ 1 i))))
2635            (set! pos (+ pos c))
2636            c)
2637          (lambda (bv s c)
2638            (set! pos (+ pos c))
2639            (printf "write ~s\n" c)
2640            c)
2641          #f
2642          (lambda (x) (set! pos x))
2643          (lambda () (printf "closed\n")))))
2644    #t)
2645  (not (port-has-port-position? $cp-iop))
2646  (error? ; operation not supported
2647    (port-position $cp-iop))
2648  (begin
2649    (guard (c [(warning? c) (errorf #f "unexpected warning ~s" c)])
2650      (put-u8 $cp-iop 255))
2651    #t)
2652  (eqv? (get-u8 $cp-iop) 1)
2653  (custom-port-warning? ; can't determine position for write
2654    (put-u8 $cp-iop 255))
2655  (begin (set-port-position! $cp-iop 50) #t)
2656  (begin
2657    (guard (c [(warning? c) (errorf #f "unexpected warning ~s" c)])
2658      (put-u8 $cp-iop 255))
2659    #t)
2660  (eqv? (get-u8 $cp-iop) 51)
2661  (custom-port-warning? ; can't determine position for write
2662    (put-bytevector $cp-iop #vu8(17)))
2663
2664  (begin
2665    (define $cp-iop
2666      (let ([pos 0])
2667        (make-custom-binary-input/output-port "foo"
2668          (lambda (bv s c)
2669            (let loop ([i s])
2670              (unless (eq? i (+ s c))
2671                (bytevector-u8-set! bv i (modulo (+ pos i) 256))
2672                (loop (+ 1 i))))
2673            (set! pos (+ pos c))
2674            c)
2675          (lambda (bv s c)
2676            (set! pos (+ pos c))
2677            (printf "write ~s\n" c)
2678            c)
2679          (lambda () pos)
2680          #f
2681          (lambda () (printf "closed\n")))))
2682    #t)
2683  (not (port-has-set-port-position!? $cp-iop))
2684  (error? ; operation not supported
2685    (set-port-position! $cp-iop 3))
2686  (begin
2687    (guard (c [(warning? c) (errorf #f "unexpected warning ~s" c)])
2688      (put-u8 $cp-iop 255))
2689    #t)
2690  (eqv? (get-u8 $cp-iop) 1)
2691  (custom-port-warning? ; can't set position for write
2692   ; convoluted because we want warning to return normally so that operation
2693   ; is completed
2694    (let ([hit? #f])
2695      (with-exception-handler
2696        (lambda (c) (if (warning? c) (set! hit? c) (raise c)))
2697        (lambda () (put-u8 $cp-iop 255)))
2698      (when hit? (raise hit?))))
2699  (begin
2700    (guard (c [(warning? c) (errorf #f "unexpected warning ~s" c)])
2701      (put-u8 $cp-iop 255))
2702    #t)
2703  (begin (get-u8 $cp-iop) #t) ; position undefined, so value undefined
2704  (custom-port-warning? ; can't set position for write
2705    (put-bytevector $cp-iop #vu8(17)))
2706
2707  (begin
2708    (define $cp-iop
2709      (let ([pos 0])
2710        (make-custom-binary-input/output-port "foo"
2711          (lambda (bv s c)
2712            (let loop ([i s])
2713              (unless (eq? i (+ s c))
2714                (bytevector-u8-set! bv i (modulo (+ pos i) 256))
2715                (loop (+ 1 i))))
2716            (set! pos (+ pos c))
2717            c)
2718          (lambda (bv s c)
2719            (set! pos (+ pos c))
2720            (printf "write ~s\n" c)
2721            c)
2722          #f
2723          #f
2724          (lambda () (printf "closed\n")))))
2725    #t)
2726  (not (port-has-port-position? $cp-iop))
2727  (error? ; operation not supported
2728    (port-position $cp-iop))
2729  (not (port-has-set-port-position!? $cp-iop))
2730  (error? ; operation not supported
2731    (set-port-position! $cp-iop 3))
2732  (begin
2733    (guard (c [(warning? c) (errorf #f "unexpected warning ~s" c)])
2734      (put-u8 $cp-iop 255))
2735    #t)
2736  (eqv? (get-u8 $cp-iop) 1)
2737  (custom-port-warning? ; can't determine position for write
2738   ; convoluted because we want warning to return normally so that operation
2739   ; is completed
2740    (let ([hit? #f])
2741      (with-exception-handler
2742        (lambda (c) (if (warning? c) (set! hit? c) (raise c)))
2743        (lambda () (put-u8 $cp-iop 255)))
2744      (when hit? (raise hit?))))
2745  (begin
2746    (guard (c [(warning? c) (errorf #f "unexpected warning ~s" c)])
2747      (put-u8 $cp-iop 255))
2748    #t)
2749  (begin (get-u8 $cp-iop) #t) ; position undefined, so value undefined
2750  (custom-port-warning? ; can't determine position for write
2751    (put-bytevector $cp-iop #vu8(17)))
2752)
2753
2754(mat custom-textual-ports
2755  (begin
2756    (define $cp-ip
2757      (let ([pos 0] [chars "0123456789abcdefghijklmnopqrstuvwxyz"])
2758        (make-custom-textual-input-port "foo"
2759          (lambda (str s c)
2760            (let loop ([i s])
2761              (unless (eq? i (+ s c))
2762                (string-set! str i (string-ref chars (modulo (+ pos i) 36)))
2763                (loop (+ 1 i))))
2764            (set! pos (+ pos c))
2765            c)
2766          (lambda () pos)
2767          (lambda (x) (set! pos x))
2768          #f)))
2769    #t)
2770  (eq? (port-position $cp-ip) 0)
2771  (error? ; cannot unget
2772    (unget-char $cp-ip #\q))
2773  (begin (unget-char $cp-ip (eof-object)) #t)
2774  (port-eof? $cp-ip)
2775  (eof-object? (lookahead-char $cp-ip))
2776  (eof-object? (get-char $cp-ip))
2777  (equal?
2778    (get-string-n $cp-ip 10)
2779    "0123456789")
2780  (eqv? (port-position $cp-ip) 10)
2781  (eqv? (get-char $cp-ip) #\a)
2782  (begin (set-port-position! $cp-ip 36000) #t)
2783  (eqv? (get-char $cp-ip) #\0)
2784  (custom-port-warning? (port-position $cp-ip))
2785  (error? ; not a textual output port
2786    (put-char $cp-ip #\a))
2787  (not (port-has-port-length? $cp-ip))
2788  (not (port-has-set-port-length!? $cp-ip))
2789  (not (port-has-port-nonblocking?? $cp-ip))
2790  (not (port-has-set-port-nonblocking!? $cp-ip))
2791  (error? ; not supported
2792    (port-length $cp-ip))
2793  (error? ; not supported
2794    (set-port-length! $cp-ip 50))
2795  (error? ; not supported
2796    (port-nonblocking? $cp-ip))
2797  (error? ; not supported
2798    (set-port-nonblocking! $cp-ip #t))
2799  (error? ; not supported
2800    (set-port-nonblocking! $cp-ip #f))
2801
2802  (begin
2803    (define $cp-op
2804      (let ([pos 0])
2805        (make-custom-textual-output-port "foo"
2806          (lambda (str s c)
2807            (set! pos (+ pos c))
2808            (printf "write ~s\n" c)
2809            c)
2810          (lambda () pos)
2811          (lambda (x) (set! pos x))
2812          (lambda () (printf "closed\n")))))
2813    #t)
2814  (eq? (port-position $cp-op) 0)
2815  (error? ; not a textual output port
2816    (unget-char $cp-op 255))
2817  (not (port-has-port-length? $cp-op))
2818  (not (port-has-set-port-length!? $cp-op))
2819  (not (port-has-port-nonblocking?? $cp-op))
2820  (not (port-has-set-port-nonblocking!? $cp-op))
2821  (error? ; not supported
2822    (port-length $cp-op))
2823  (error? ; not supported
2824    (set-port-length! $cp-op 50))
2825  (error? ; not supported
2826    (port-nonblocking? $cp-op))
2827  (error? ; not supported
2828    (set-port-nonblocking! $cp-op #t))
2829  (error? ; not supported
2830    (set-port-nonblocking! $cp-op #f))
2831  (begin (put-char $cp-op #\$) #t)
2832  (eqv? (port-position $cp-op) 1)
2833  (begin (set-port-position! $cp-op 17) #t)
2834  (equal?
2835    (with-output-to-string
2836      (lambda ()
2837        (put-string $cp-op "abcd")
2838        (put-string $cp-op "defghi" 1)
2839        (put-string $cp-op "hijklm" 1 4)))
2840    "")
2841  (equal? ; in our current implementation...
2842    (with-output-to-string
2843      (lambda ()
2844        (printf "pos = ~s\n" (port-position $cp-op))))
2845    "write 13\npos = 30\n")
2846  (equal?
2847    (with-output-to-string
2848      (lambda ()
2849        (printf "pos = ~s\n" (port-position $cp-op))))
2850    "pos = 30\n")
2851  (equal?
2852    (with-output-to-string
2853      (lambda ()
2854        (put-string $cp-op "abcd")
2855        (put-string $cp-op "defghi" 1)
2856        (put-string $cp-op "hijklm" 1 4)))
2857    "")
2858  (equal?
2859    (with-output-to-string
2860      (lambda ()
2861        (close-port $cp-op)))
2862    "write 13\nclosed\n")
2863  (error? ; closed
2864    (put-char $cp-op #\$))
2865  (error? ; closed
2866    (put-string $cp-op "3"))
2867  (error? ; closed
2868    (r6rs:flush-output-port $cp-op))
2869
2870  (begin
2871    (define $cp-iop
2872      (let ([pos 0] [chars "0123456789abcdefghijklmnopqrstuvwxyz"])
2873        (make-custom-textual-input/output-port "foo"
2874          (lambda (str s c)
2875            (let loop ([i s])
2876              (unless (eq? i (+ s c))
2877                (string-set! str i (string-ref chars (modulo (+ pos i) 36)))
2878                (loop (+ 1 i))))
2879            (set! pos (+ pos c))
2880            c)
2881          (lambda (str s c)
2882            (set! pos (+ pos c))
2883            (printf "write ~s\n" c)
2884            c)
2885          (lambda () pos)
2886          (lambda (x) (set! pos x))
2887          (lambda () (printf "closed\n")))))
2888    #t)
2889  (eq? (port-position $cp-iop) 0)
2890  (error? ; cannot unget
2891    (unget-char $cp-iop #\$))
2892  (begin (unget-char $cp-iop (eof-object)) #t)
2893  (port-eof? $cp-iop)
2894  (eof-object? (lookahead-char $cp-iop))
2895  (eof-object? (get-char $cp-iop))
2896  (equal?
2897    (get-string-n $cp-iop 10)
2898    "0123456789")
2899  (eqv? (port-position $cp-iop) 10)
2900  (eqv? (get-char $cp-iop) #\a)
2901  (begin (set-port-position! $cp-iop 36000) #t)
2902  (eqv? (get-char $cp-iop) #\0)
2903  (custom-port-warning? (port-position $cp-iop))
2904  (not (port-has-port-length? $cp-iop))
2905  (not (port-has-set-port-length!? $cp-iop))
2906  (not (port-has-port-nonblocking?? $cp-iop))
2907  (not (port-has-set-port-nonblocking!? $cp-iop))
2908  (error? ; not supported
2909    (port-length $cp-iop))
2910  (error? ; not supported
2911    (set-port-length! $cp-iop 50))
2912  (error? ; not supported
2913    (port-nonblocking? $cp-iop))
2914  (error? ; not supported
2915    (set-port-nonblocking! $cp-iop #t))
2916  (error? ; not supported
2917    (set-port-nonblocking! $cp-iop #f))
2918  (custom-port-warning? (put-char $cp-iop #\$))
2919  (begin (set-port-position! $cp-iop 17) #t)
2920  (eqv? (port-position $cp-iop) 17)
2921  (equal?
2922    (with-output-to-string
2923      (lambda ()
2924        (put-string $cp-iop "abcd")
2925        (put-string $cp-iop "defghi" 1)
2926        (put-string $cp-iop "hijklm" 1 4)))
2927    "")
2928  (equal? ; in our current implementation...
2929    (with-output-to-string
2930      (lambda ()
2931        (printf "pos = ~s\n" (port-position $cp-iop))))
2932    "write 13\npos = 30\n")
2933  (equal?
2934    (with-output-to-string
2935      (lambda ()
2936        (printf "pos = ~s\n" (port-position $cp-iop))))
2937    "pos = 30\n")
2938  (equal?
2939    (with-output-to-string
2940      (lambda ()
2941        (put-string $cp-iop "abcd")
2942        (put-string $cp-iop "defghi" 1)
2943        (put-string $cp-iop "hijklm" 1 4)))
2944    "")
2945  (equal?
2946    (with-output-to-string
2947      (lambda ()
2948        (close-port $cp-iop)))
2949    "write 13\nclosed\n")
2950  (error? ; closed
2951    (put-char $cp-iop #\$))
2952  (error? ; closed
2953    (put-string $cp-iop "3"))
2954  (error? ; closed
2955    (r6rs:flush-output-port $cp-iop))
2956
2957  (begin
2958    (define $cp-iop
2959      (let ([pos 0] [chars "0123456789abcdefghijklmnopqrstuvwxyz"])
2960        (make-custom-textual-input/output-port "foo"
2961          (lambda (str s c)
2962            (let loop ([i s])
2963              (unless (eq? i (+ s c))
2964                (string-set! str i (string-ref chars (modulo (+ pos i) 36)))
2965                (loop (+ 1 i))))
2966            (set! pos (+ pos c))
2967            c)
2968          (lambda (str s c)
2969            (set! pos (+ pos c))
2970            (printf "write ~s\n" c)
2971            c)
2972          #f
2973          (lambda (x) (set! pos x))
2974          (lambda () (printf "closed\n")))))
2975    #t)
2976  (not (port-has-port-position? $cp-iop))
2977  (error? ; operation not supported
2978    (port-position $cp-iop))
2979  (begin
2980    (guard (c [(warning? c) (errorf #f "unexpected warning ~s" c)])
2981      (put-char $cp-iop #\$))
2982    #t)
2983  (eqv? (get-char $cp-iop) #\1)
2984  (custom-port-warning? ; can't determine position for write
2985    (put-char $cp-iop #\$))
2986  (begin (set-port-position! $cp-iop 50) #t)
2987  (begin
2988    (guard (c [(warning? c) (errorf #f "unexpected warning ~s" c)])
2989      (put-char $cp-iop #\$))
2990    #t)
2991  (eqv? (get-char $cp-iop) #\f)
2992  (custom-port-warning? ; can't determine position for write
2993    (put-string $cp-iop "a"))
2994
2995  (begin
2996    (define $cp-iop
2997      (let ([pos 0] [chars "0123456789abcdefghijklmnopqrstuvwxyz"])
2998        (make-custom-textual-input/output-port "foo"
2999          (lambda (str s c)
3000            (let loop ([i s])
3001              (unless (eq? i (+ s c))
3002                (string-set! str i (string-ref chars (modulo (+ pos i) 36)))
3003                (loop (+ 1 i))))
3004            (set! pos (+ pos c))
3005            c)
3006          (lambda (str s c)
3007            (set! pos (+ pos c))
3008            (printf "write ~s\n" c)
3009            c)
3010          (lambda () pos)
3011          #f
3012          (lambda () (printf "closed\n")))))
3013    #t)
3014  (not (port-has-set-port-position!? $cp-iop))
3015  (error? ; operation not supported
3016    (set-port-position! $cp-iop 3))
3017  (begin
3018    (guard (c [(warning? c) (errorf #f "unexpected warning ~s" c)])
3019      (put-char $cp-iop #\$))
3020    #t)
3021  (eqv? (get-char $cp-iop) #\1)
3022  (custom-port-warning? ; can't set position for write
3023   ; convoluted because we want warning to return normally so that operation
3024   ; is completed
3025    (let ([hit? #f])
3026      (with-exception-handler
3027        (lambda (c) (if (warning? c) (set! hit? c) (raise c)))
3028        (lambda () (put-char $cp-iop #\$)))
3029      (when hit? (raise hit?))))
3030  (begin
3031    (guard (c [(warning? c) (errorf #f "unexpected warning ~s" c)])
3032      (put-char $cp-iop #\$))
3033    #t)
3034  (begin (get-char $cp-iop) #t) ; position undefined, so value undefined
3035  (custom-port-warning? ; can't set position for write
3036    (put-string $cp-iop "a"))
3037
3038  (begin
3039    (define $cp-iop
3040      (let ([pos 0] [chars "0123456789abcdefghijklmnopqrstuvwxyz"])
3041        (make-custom-textual-input/output-port "foo"
3042          (lambda (str s c)
3043            (let loop ([i s])
3044              (unless (eq? i (+ s c))
3045                (string-set! str i (string-ref chars (modulo (+ pos i) 36)))
3046                (loop (+ 1 i))))
3047            (set! pos (+ pos c))
3048            c)
3049          (lambda (str s c)
3050            (set! pos (+ pos c))
3051            (printf "write ~s\n" c)
3052            c)
3053          #f
3054          #f
3055          (lambda () (printf "closed\n")))))
3056    #t)
3057  (not (port-has-port-position? $cp-iop))
3058  (error? ; operation not supported
3059    (port-position $cp-iop))
3060  (not (port-has-set-port-position!? $cp-iop))
3061  (error? ; operation not supported
3062    (set-port-position! $cp-iop 3))
3063  (begin
3064    (guard (c [(warning? c) (errorf #f "unexpected warning ~s" c)])
3065      (put-char $cp-iop #\$))
3066    #t)
3067  (eqv? (get-char $cp-iop) #\1)
3068  (custom-port-warning? ; can't determine position for write
3069   ; convoluted because we want warning to return normally so that operation
3070   ; is completed
3071    (let ([hit? #f])
3072      (with-exception-handler
3073        (lambda (c) (if (warning? c) (set! hit? c) (raise c)))
3074        (lambda () (put-char $cp-iop #\$)))
3075      (when hit? (raise hit?))))
3076  (begin
3077    (guard (c [(warning? c) (errorf #f "unexpected warning ~s" c)])
3078      (put-char $cp-iop #\$))
3079    #t)
3080  (begin (get-char $cp-iop) #t) ; position undefined, so value undefined
3081  (custom-port-warning? ; can't determine position for write
3082    (put-string $cp-iop "a"))
3083
3084  (equal?
3085    (let-values ([(sop get) (open-string-output-port)])
3086      (define op
3087        (make-custom-textual-output-port "foo"
3088          (lambda (str s c)
3089            (put-string sop str s c)
3090            c)
3091          #f #f #f))
3092      (fresh-line op)
3093      (fresh-line op)
3094      (put-string op "hello")
3095      (fresh-line op)
3096      (fresh-line op)
3097      (put-string op "hello")
3098      (flush-output-port op)
3099      (fresh-line op)
3100      (fresh-line op)
3101      (put-string op "hello\n")
3102      (flush-output-port op)
3103      (fresh-line op)
3104      (fresh-line op)
3105      (put-string op "hello\n")
3106      (fresh-line op)
3107      (close-port op)
3108      (get))
3109    "hello\nhello\nhello\nhello\n")
3110
3111  (equal?
3112    (let-values ([(sop get) (open-string-output-port)])
3113      (define op
3114        (make-custom-textual-input/output-port "foo"
3115          (lambda (str s c) (errorf #f "oops"))
3116          (lambda (str s c)
3117            (put-string sop str s c)
3118            c)
3119          #f #f #f))
3120      (fresh-line op)
3121      (fresh-line op)
3122      (put-string op "hello")
3123      (fresh-line op)
3124      (fresh-line op)
3125      (put-string op "hello")
3126      (flush-output-port op)
3127      (fresh-line op)
3128      (fresh-line op)
3129      (put-string op "hello\n")
3130      (flush-output-port op)
3131      (fresh-line op)
3132      (fresh-line op)
3133      (put-string op "hello\n")
3134      (fresh-line op)
3135      (close-port op)
3136      (get))
3137    "hello\nhello\nhello\nhello\n")
3138)
3139
3140(mat compression-textual
3141  (parameters [compress-format 'gzip 'lz4] [compress-level 'low 'medium 'high 'maximum])
3142  (let ()
3143    (define cp
3144      (lambda (src dst)
3145        (define buf-size 103)
3146        (let ([buf (make-string buf-size)])
3147          (call-with-port dst
3148            (lambda (op)
3149              (call-with-port src
3150                (lambda (ip)
3151                  (let loop ()
3152                    (do ([i 0 (fx+ i 1)])
3153                        ((fx= i buf-size))
3154                      (let ([c (get-char ip)])
3155                        (unless (eof-object? c) (put-char op c))))
3156                    (let ([n (get-string-n! ip buf 0 buf-size)])
3157                      (unless (eof-object? n)
3158                        (put-string op buf 0 n)
3159                        (loop)))))))))))
3160    (define cmp
3161      (lambda (src1 src2)
3162        (define buf-size 128)
3163        (let ([buf (make-string buf-size)])
3164          (call-with-port src1
3165            (lambda (ip1)
3166              (call-with-port src2
3167                (lambda (ip2)
3168                  (let loop ([pos 0])
3169                    (let ([n (get-string-n! ip1 buf 0 buf-size)])
3170                      (if (eof-object? n)
3171                          (unless (eof-object? (lookahead-char ip2)) (errorf #f "ip1 eof before ip2"))
3172                          (if (eof-object? (lookahead-char ip2))
3173                              (errorf #f "ip2 eof before ip1")
3174                              (let test ([i 0] [pos pos])
3175                                (if (= i n)
3176                                    (loop pos)
3177                                    (let ([c1 (string-ref buf i)] [c2 (get-char ip2)])
3178                                      (if (char=? c1 c2)
3179                                          (test (+ 1 i) (+ pos 1))
3180                                          (errorf #f "ip1 c = ~s =/= ip2 c = ~s at pos ~s" c1 c2 pos))))))))))))))))
3181    (define (in fn compressed? codec)
3182      (open-file-input-port fn
3183        (if compressed? (file-options compressed) (file-options))
3184        (buffer-mode block)
3185        (make-transcoder codec)))
3186    (define (out fn compressed? codec)
3187      (open-file-output-port fn
3188        (if compressed? (file-options compressed replace) (file-options replace))
3189        (buffer-mode block)
3190        (make-transcoder codec)))
3191    (time (cmp (in prettytest.ss #f (latin-1-codec)) (in prettytest.ss #f (latin-1-codec))))
3192    (time (cmp (in prettytest.ss #t (latin-1-codec)) (in prettytest.ss #f (latin-1-codec))))
3193    (time (cmp (in prettytest.ss #f (latin-1-codec)) (in prettytest.ss #t (latin-1-codec))))
3194    (time (cmp (in prettytest.ss #t (latin-1-codec)) (in prettytest.ss #t (latin-1-codec))))
3195    (time (cmp (in prettytest.ss #f (utf-8-codec)) (in prettytest.ss #f (utf-8-codec))))
3196    (time (cmp (in prettytest.ss #t (utf-8-codec)) (in prettytest.ss #f (utf-8-codec))))
3197    (time (cmp (in prettytest.ss #f (utf-8-codec)) (in prettytest.ss #t (utf-8-codec))))
3198    (time (cmp (in prettytest.ss #t (utf-8-codec)) (in prettytest.ss #t (utf-8-codec))))
3199    (cp (in prettytest.ss #f (latin-1-codec)) (out "testfile.ss" #t (latin-1-codec)))
3200    (cmp (in prettytest.ss #f (latin-1-codec)) (in "testfile.ss" #t (latin-1-codec)))
3201    (cmp (in prettytest.ss #t (latin-1-codec)) (in "testfile.ss" #t (latin-1-codec)))
3202    (cmp (in prettytest.ss #f (utf-8-codec)) (in "testfile.ss" #t (utf-8-codec)))
3203    (cmp (in prettytest.ss #t (utf-8-codec)) (in "testfile.ss" #t (utf-8-codec)))
3204    (cp (in prettytest.ss #f (utf-8-codec)) (out "testfile.ss" #t (utf-8-codec)))
3205    (cmp (in prettytest.ss #f (latin-1-codec)) (in "testfile.ss" #t (latin-1-codec)))
3206    (cmp (in prettytest.ss #t (latin-1-codec)) (in "testfile.ss" #t (latin-1-codec)))
3207    (cmp (in prettytest.ss #f (utf-8-codec)) (in "testfile.ss" #t (utf-8-codec)))
3208    (cmp (in prettytest.ss #t (utf-8-codec)) (in "testfile.ss" #t (utf-8-codec)))
3209    #t)
3210  ; test workaround for bogus gzclose error return for empty input files
3211  (and
3212    (eqv? (call-with-port
3213            (open-file-output-port "testfile.ss" (file-options replace) (buffer-mode block) (native-transcoder))
3214            (lambda (x) (void)))
3215          (void))
3216    (eof-object?
3217      (call-with-port
3218        (open-file-input-port "testfile.ss" (file-options compressed)
3219          (buffer-mode block) (native-transcoder))
3220        get-char)))
3221)
3222
3223(mat string-ports
3224  (let ()
3225    (define pretty-test-string
3226      (call-with-port
3227        (open-file-input-port prettytest.ss
3228          (file-options) (buffer-mode none) (native-transcoder))
3229        get-string-all))
3230    (define cp ; doesn't close the ports
3231      (lambda (ip op)
3232        (define buf-size 103)
3233        (let ([buf (make-string buf-size)])
3234          (let loop ()
3235            (do ([i 0 (fx+ i 1)])
3236                ((fx= i buf-size))
3237              (let ([c (get-char ip)])
3238                (unless (eof-object? c) (put-char op c))))
3239            (let ([n (get-string-n! ip buf 0 buf-size)])
3240              (unless (eof-object? n)
3241                (put-string op buf 0 n)
3242                (loop)))))))
3243    (define cmp
3244      (lambda (src1 src2)
3245        (define buf-size 64)
3246        (let ([buf (make-string buf-size)])
3247          (call-with-port src1
3248            (lambda (ip1)
3249              (call-with-port src2
3250                (lambda (ip2)
3251                  (let loop ([pos 0])
3252                    (let ([n (get-string-n! ip1 buf 0 buf-size)])
3253                      (if (eof-object? n)
3254                          (unless (eof-object? (lookahead-char ip2)) (errorf #f "ip1 eof before ip2"))
3255                          (if (eof-object? (lookahead-char ip2))
3256                              (errorf #f "ip2 eof before ip1")
3257                              (let test ([i 0] [pos pos])
3258                                (if (= i n)
3259                                    (loop pos)
3260                                    (let ([c1 (string-ref buf i)] [c2 (get-char ip2)])
3261                                      (if (char=? c1 c2)
3262                                          (test (+ 1 i) (+ pos 1))
3263                                          (errorf #f "ip1 c = ~s =/= ip2 c = ~s at pos ~s" c1 c2 pos))))))))))))))))
3264    (define (in fn compressed? codec)
3265      (open-file-input-port fn
3266        (if compressed? (file-options compressed) (file-options))
3267        (buffer-mode block)
3268        (make-transcoder codec)))
3269    (define (out fn compressed? codec)
3270      (open-file-output-port fn
3271        (if compressed? (file-options compressed replace) (file-options replace))
3272        (buffer-mode block)
3273        (make-transcoder codec)))
3274    (time (cmp (in prettytest.ss #f (latin-1-codec)) (open-string-input-port pretty-test-string)))
3275    (time (cmp (open-string-input-port pretty-test-string) (in prettytest.ss #f (latin-1-codec))))
3276    (let-values ([(op retrieve) (open-string-output-port)])
3277      (cp (open-string-input-port pretty-test-string) op)
3278      (cmp (in prettytest.ss #f (latin-1-codec)) (open-string-input-port (retrieve))))
3279    #t)
3280)
3281
3282(mat current-ports
3283  (input-port? (current-input-port))
3284  (textual-port? (current-input-port))
3285  (not (output-port? (open-input-string "hello")))
3286  (output-port? (current-output-port))
3287  (textual-port? (current-output-port))
3288  (output-port? (current-error-port))
3289  (textual-port? (current-error-port))
3290  (not (input-port? (open-output-string)))
3291  (eq? (r6rs:current-input-port) (current-input-port))
3292  (eq? (r6rs:current-output-port) (current-output-port))
3293  (eq? (r6rs:current-error-port) (current-error-port))
3294  (equal?
3295    (with-output-to-string
3296      (lambda ()
3297        (write (list
3298                 (eq? (r6rs:current-input-port) (current-input-port))
3299                 (eq? (r6rs:current-output-port) (current-output-port))
3300                 (eq? (r6rs:current-error-port) (current-error-port))))))
3301    "(#t #t #t)")
3302  (error? (current-input-port (standard-input-port)))
3303  (error? (current-output-port (standard-output-port)))
3304  (error? (current-error-port (standard-output-port)))
3305  (error? (current-input-port (open-output-string)))
3306  (error? (current-output-port (open-input-string "")))
3307  (error? (current-error-port (open-input-string "")))
3308  (error? (console-input-port (standard-input-port)))
3309  (error? (console-output-port (standard-output-port)))
3310  (error? (console-error-port (standard-output-port)))
3311  (error? (console-input-port (open-output-string)))
3312  (error? (console-output-port (open-input-string "")))
3313  (error? (console-error-port (open-input-string "")))
3314)
3315
3316(mat current-transcoder
3317  (transcoder? (current-transcoder))
3318  (eqv? (current-transcoder) (native-transcoder))
3319  (error? (current-transcoder (open-output-string)))
3320  (parameterize ([current-transcoder (native-transcoder)])
3321    (eqv? (current-transcoder) (native-transcoder)))
3322  (parameterize ([current-transcoder (make-transcoder (utf-16le-codec))])
3323    (with-output-to-file "testfile.ss" (lambda () (write '\x3bb;12345)) 'replace)
3324    (file-exists? "testfile.ss"))
3325  (parameterize ([current-transcoder (make-transcoder (utf-16le-codec))])
3326    (with-input-from-file "testfile.ss"
3327      (lambda ()
3328        (and (eqv? (read) '\x3bb;12345) (eof-object? (read))))))
3329  (equal?
3330    (call-with-port (open-file-input-port "testfile.ss") get-bytevector-all)
3331    #vu8(#xBB #x3 #x31 #x0 #x32 #x0 #x33 #x0 #x34 #x0 #x35 #x0))
3332)
3333
3334(mat get/put-datum
3335  (error? (get-datum))
3336  (error? (get-datum (current-input-port) (current-input-port)))
3337  (error? (get-datum (open-output-string)))
3338  (error? (get-datum (open-bytevector-input-port #vu8())))
3339  (call-with-port
3340    (open-string-input-port "hey #;there dude!")
3341    (lambda (p)
3342      (and (eq? (get-datum p) 'hey)
3343           (eqv? (get-char p) #\space)
3344           (eq? (get-datum p) 'dude!)
3345           (eof-object? (get-datum p)))))
3346  (error? (put-datum))
3347  (error? (put-datum (current-output-port)))
3348  (error? (put-datum (current-output-port) 'a 'a))
3349  (error? (put-datum (open-input-string "hello") 'a))
3350  (error? (put-datum (let-values ([(p g) (open-bytevector-output-port)]) p) 'a))
3351  (equal?
3352    (let-values ([(p g) (open-string-output-port)])
3353      (put-datum p '(this is))
3354      (put-datum p "cool")
3355      (put-datum p '(or (maybe . not)))
3356      (g))
3357    "(this is)\"cool\"(or (maybe . not))")
3358  (call-with-port
3359    (open-string-input-port "#3(a b c) #!r6rs #(d e) #!chezscheme #3(f g)")
3360    (lambda (p)
3361      (and
3362        (equal? (get-datum p) '#(a b c))
3363        (equal? (get-datum p) '#(d e))
3364        (equal? (get-datum p) '#(f g g))
3365        (equal? (get-datum p) #!eof))))
3366 ; make sure that nel and ls are treated properly
3367  (call-with-port
3368    (open-string-input-port "#!r6rs \x85; \x2028; #\\x85 #\\x2028 \"\\x85; \\x2028;\"")
3369    (lambda (p)
3370      (and
3371        (equal? (get-datum p) (integer->char #x85))
3372        (equal? (get-datum p) (integer->char #x2028))
3373        (equal? (get-datum p) (string (integer->char #x85) #\space (integer->char #x2028))))))
3374  (equal?
3375    (call-with-string-output-port
3376      (lambda (p)
3377        (put-char p #\x85)
3378        (put-char p #\space)
3379        (put-char p #\x2028)
3380        (put-char p #\space)
3381        (put-datum p #\x85)
3382        (put-char p #\space)
3383        (put-datum p #\x2028)
3384        (put-char p #\space)
3385        (put-datum p "\x85; \x2028;")))
3386    "\x85; \x2028; #\\x85 #\\x2028 \"\\x85; \\x2028;\"")
3387  (let ()
3388    (define (rw? x1)
3389      (let ([str (let-values ([(p e) (open-string-output-port)])
3390                   (write x1 p)
3391                   (e))])
3392        (let ([x2 (read (open-string-input-port str))])
3393          (equal? x1 x2))))
3394    (and
3395      (rw? "  \x85;  ")
3396      (rw? "  \x2028;  ")
3397      (rw? #\x85)
3398      (rw? #\x2028)))
3399)
3400
3401(mat utf-16-codec
3402  (error? (r6rs:utf-16-codec #f))
3403  (error? (utf-16-codec #f))
3404 ; test decoding
3405  (let ()
3406    (define utf-16->string
3407      (lambda (eol bv)
3408        (let ([ip (transcoded-port
3409                    (let ([n (bytevector-length bv)] [i 0])
3410                      (make-custom-binary-input-port "foo"
3411                        (lambda (buf start count)
3412                          (let ([count (min (+ (random (min count 3)) 1) (fx- n i))])
3413                            (bytevector-copy! bv i buf start count)
3414                            (set! i (+ i count))
3415                            count))
3416                        (lambda () i)
3417                        (lambda (p) (set! i p))
3418                        #f))
3419                    (make-transcoder (utf-16-codec) eol (error-handling-mode replace)))])
3420          (call-with-string-output-port
3421            (lambda (op)
3422              (define (deref s) (if (eof-object? s) s (string-ref s 0)))
3423              (let again ()
3424                (let ([c (if (= (random 5) 3) (deref (get-string-n ip 1)) (get-char ip))])
3425                  (if (eof-object? c)
3426                      (let ([pos (port-position ip)])
3427                        (unless (= pos (bytevector-length bv))
3428                          (errorf #f "wrong pos ~s at eof" pos)))
3429                      (begin (put-char op c) (again))))))))))
3430    (define (big bv)
3431      (let ([n (bytevector-length bv)])
3432        (let ([newbv (make-bytevector (+ n 2))])
3433          (bytevector-u8-set! newbv 0 #xfe)
3434          (bytevector-u8-set! newbv 1 #xff)
3435          (do ([i 0 (fx+ i 2)])
3436              ((fx>= i (fx- n 1))
3437               (unless (fx= i n)
3438                 (bytevector-u8-set! newbv (fx+ i 2) (bytevector-u8-ref bv i))))
3439            (bytevector-u8-set! newbv (fx+ i 2) (bytevector-u8-ref bv i))
3440            (bytevector-u8-set! newbv (fx+ i 3) (bytevector-u8-ref bv (fx+ i 1))))
3441          newbv)))
3442    (define (little bv)
3443      (let ([n (bytevector-length bv)])
3444        (let ([newbv (make-bytevector (+ n 2))])
3445          (bytevector-u8-set! newbv 0 #xff)
3446          (bytevector-u8-set! newbv 1 #xfe)
3447          (do ([i 0 (fx+ i 2)])
3448              ((fx>= i (fx- n 1))
3449               (unless (fx= i n)
3450                 (bytevector-u8-set! newbv (fx+ i 2) (bytevector-u8-ref bv i))))
3451            (bytevector-u8-set! newbv (fx+ i 2) (bytevector-u8-ref bv (fx+ i 1)))
3452            (bytevector-u8-set! newbv (fx+ i 3) (bytevector-u8-ref bv i)))
3453          newbv)))
3454    (define (test eol bv s)
3455      (do ([n 1000 (fx- n 1)])
3456          ((fx= n 0))
3457        (let ([seed (random-seed)])
3458          (unless (and (equal? (utf-16->string eol bv) s)
3459                       (equal? (utf-16->string eol (big bv)) s)
3460                       (equal? (utf-16->string eol (little bv)) s))
3461            (errorf #f "failed, seed = ~s, bv = ~s, s = ~s" seed bv s)))))
3462    (test 'lf #vu8(#x00 #x61 #x00 #x0a) "a\n")
3463    (test 'lf #vu8(#x00 #x61 #x00 #x0d #x00 #x0a #x00 #x0d #x00 #x85 #x00 #x0d #x00 #x0d #x00 #x0a #x00 #x0d #x20 #x28) "a\n\n\n\n\n\n")
3464    (test 'crlf #vu8(#x00 #x61 #x00 #x0d #x00 #x0a #x00 #x0d #x00 #x85 #x00 #x0d #x00 #x0d #x00 #x0a #x00 #x0d #x20 #x28) "a\n\n\n\n\n\n")
3465    (test 'none #vu8(#x00 #x61 #x00 #x0d #x00 #x0a #x00 #x0d #x00 #x85 #x00 #x0d #x00 #x0d #x00 #x0a #x00 #x0d #x20 #x28) "a\r\n\r\x85;\r\r\n\r\x2028;")
3466    (test 'lf #vu8(#x00 #x0a #xd8 #x00 #xdc #x00 #xdb #xff #xdf #xff #xdc #x00 #xd8 #x00 #x00 #x00 #x00) "\n\x10000;\x10ffff;\xfffd;\xfffd;\xfffd;")
3467    #t)
3468 ; test encoding
3469  (let ()
3470    (define string->utf-16
3471      (lambda (eol s)
3472        (let-values ([(op getbv)
3473                      (let-values ([(bvop getbv) (open-bytevector-output-port)])
3474                        (values
3475                          (transcoded-port
3476                            (let ([i 0])
3477                              (make-custom-binary-output-port "foo"
3478                                (lambda (buf start count)
3479                                  (let ([count (random (min (fx+ count 1) 4))])
3480                                    (put-bytevector bvop buf start count)
3481                                    (set! i (+ i count))
3482                                    count))
3483                                (lambda () i)
3484                                #f #f))
3485                            (make-transcoder (utf-16be-codec) eol (error-handling-mode replace)))
3486                          getbv))])
3487          (let ([sip (open-string-input-port s)])
3488            (define (deref s) (if (eof-object? s) s (string-ref s 0)))
3489            (let again ()
3490              (let ([c (get-char sip)])
3491                (if (eof-object? c)
3492                    (let ([pos (port-position op)])
3493                      (close-port op)
3494                      (let ([bv (getbv)])
3495                        (unless (= pos (bytevector-length bv))
3496                          (errorf #f "wrong pos ~s at eof" pos))
3497                        bv))
3498                    (begin
3499                      (if (= (random 5) 3)
3500                          (put-string op (string c))
3501                          (put-char op c))
3502                      (again)))))))))
3503    (define (test eol s bv)
3504      (do ([n 1000 (fx- n 1)])
3505          ((fx= n 0))
3506        (let ([seed (random-seed)])
3507          (unless (equal? (string->utf-16 eol s) bv)
3508            (errorf #f "failed, seed = ~s, s = ~s, bv = ~s" seed s bv)))))
3509    (test 'lf "a\n" #vu8(#x00 #x61 #x00 #x0a))
3510    (test 'crlf "a\n" #vu8(#x00 #x61 #x00 #x0d #x00 #x0a))
3511    (test 'crnel "a\n" #vu8(#x00 #x61 #x00 #x0d #x00 #x85))
3512    (test 'nel "a\n" #vu8(#x00 #x61 #x00 #x85))
3513    (test 'ls "a\n" #vu8(#x00 #x61 #x20 #x28))
3514    (test 'none "a\r\n\r\x85;\r\r\n\r\x2028;" #vu8(#x00 #x61 #x00 #x0d #x00 #x0a #x00 #x0d #x00 #x85 #x00 #x0d #x00 #x0d #x00 #x0a #x00 #x0d #x20 #x28))
3515    (test 'lf "a\x10000;\x10ffff;\n" #vu8(#x00 #x61 #xd8 #x00 #xdc #x00 #xdb #xff #xdf #xff #x00 #x0a))
3516    #t)
3517)
3518
3519(mat utf-16-BOMs
3520  (let ()
3521    (define utf-16-tx (make-transcoder (utf-16-codec) (eol-style none) (error-handling-mode raise)))
3522    (and
3523      (let ()
3524        (define iop
3525          (open-file-input/output-port "testfile.ss" (file-options replace)
3526            (buffer-mode block) utf-16-tx))
3527        (define n (port-position iop))            ; should be 0
3528        (put-string iop "hello\n")                ; should write BOM
3529        (set-port-position! iop n)                ; should actually position past BOM (position 2)
3530        (and
3531          (eqv? n 0)
3532          (eqv? (port-position iop) 2)
3533          (equal? (get-string-all iop) "hello\n")
3534          (eq? (close-port iop) (void))))
3535      (let ()
3536        (define iop
3537          (open-file-input/output-port "testfile.ss" (file-options no-fail no-truncate)
3538            (buffer-mode block) utf-16-tx))
3539        (define n (port-position iop))
3540        (and
3541          (eqv? n 0)
3542          (eqv? (get-char iop) #\h)
3543          (eqv? (port-position iop) 4)
3544          (equal? (get-string-all iop) "ello\n")
3545          (eqv? (port-position iop) 14)
3546          (eq? (set-port-position! iop n) (void))
3547          (eqv? (port-position iop) 2)
3548          (put-string iop "something longer than hello\n")
3549          (eq? (set-port-position! iop n) (void))
3550          (equal? (get-string-all iop) "something longer than hello\n")
3551          (eq? (close-port iop) (void))))))
3552  (let () ; same as preceding w/slightly different transcoder
3553    (define utf-16-tx (make-transcoder (utf-16-codec) (eol-style lf) (error-handling-mode replace)))
3554    (and
3555      (let ()
3556        (define iop
3557          (open-file-input/output-port "testfile.ss" (file-options replace)
3558            (buffer-mode block) utf-16-tx))
3559        (define n (port-position iop))            ; should be 0
3560        (put-string iop "hello\n")                ; should write BOM
3561        (set-port-position! iop n)                ; should actually position past BOM (position 2)
3562        (and
3563          (eqv? n 0)
3564          (eqv? (port-position iop) 2)
3565          (equal? (get-string-all iop) "hello\n")
3566          (eq? (close-port iop) (void))))
3567      (let ()
3568        (define iop
3569          (open-file-input/output-port "testfile.ss" (file-options no-fail no-truncate)
3570            (buffer-mode block) utf-16-tx))
3571        (define n (port-position iop))
3572        (and
3573          (eqv? n 0)
3574          (equal? (get-string-all iop) "hello\n")
3575          (eq? (set-port-position! iop n) (void))
3576          (eqv? (port-position iop) 2)
3577          (put-string iop "something longer than hello\n")
3578          (eq? (set-port-position! iop n) (void))
3579          (equal? (get-string-all iop) "something longer than hello\n")
3580          (eq? (close-port iop) (void))))))
3581  (let ()
3582    (define utf-16-tx (make-transcoder (utf-16-codec) (eol-style none) (error-handling-mode raise)))
3583    (define utf-16be-tx (make-transcoder (utf-16be-codec) (eol-style none) (error-handling-mode raise)))
3584    (and
3585      (let ()
3586        (define iop
3587          (open-file-input/output-port "testfile.ss" (file-options replace)
3588            (buffer-mode block) utf-16-tx))
3589        (define n (port-position iop))            ; should be 0
3590        (put-string iop "hello\n")                ; should write BOM
3591        (set-port-position! iop n)                ; should actually position past BOM (position 2)
3592        (and
3593          (eqv? n 0)
3594          (eqv? (port-position iop) 2)
3595          (equal? (get-string-all iop) "hello\n")
3596          (eq? (close-port iop) (void))))
3597      (let ()
3598        (define iop
3599          (open-file-input/output-port "testfile.ss" (file-options no-fail no-truncate)
3600            (buffer-mode block) utf-16-tx))
3601       ; lookahead-char should position port past the BOM
3602        (define c (lookahead-char iop))
3603        (define n (port-position iop))            ; should be 2
3604        (and
3605          (eqv? c #\h)
3606          (eqv? n 2)
3607          (equal? (get-string-all iop) "hello\n")
3608          (eq? (set-port-position! iop n) (void))
3609          (eq? (put-string iop "something longer than hello\n") (void))
3610          (eq? (set-port-position! iop n) (void))
3611          (equal? (get-string-all iop) "something longer than hello\n")
3612          (eq? (close-port iop) (void))))
3613      (let ()
3614        (define iop
3615          (open-file-input/output-port "testfile.ss" (file-options no-fail no-truncate)
3616            (buffer-mode block) utf-16be-tx))
3617        (define n (port-position iop))            ; should be 0
3618        (and
3619          (eqv? (get-char iop) #\xfeff)
3620          (equal? (get-string-all iop) "something longer than hello\n")
3621          (eq? (set-port-position! iop n) (void))
3622          (eqv? (get-char iop) #\xfeff)
3623          (equal? (get-string-all iop) "something longer than hello\n")
3624          (eq? (close-port iop) (void))))))
3625  (let ()
3626    (define utf-16le-tx (make-transcoder (utf-16le-codec) (eol-style none) (error-handling-mode raise)))
3627    (and
3628      (let ()
3629        (define iop
3630          (open-file-input/output-port "testfile.ss" (file-options replace)
3631            (buffer-mode block) utf-16le-tx))
3632        (define n (port-position iop))            ; should be 0
3633        (put-string iop "hello\n")                ; should not write BOM
3634        (set-port-position! iop n)                ; should set to 0
3635        (and
3636          (eqv? n 0)
3637          (eqv? (port-position iop) 0)
3638          (equal? (get-string-all iop) "hello\n")
3639          (eq? (close-port iop) (void))))
3640      (let ()
3641        (define iop
3642          (open-file-input/output-port "testfile.ss" (file-options no-fail no-truncate)
3643            (buffer-mode block) utf-16le-tx))
3644        (define n (port-position iop))            ; should be 0
3645        (and
3646          (eq? n 0)
3647          (equal? (get-string-all iop) "hello\n")
3648          (eq? (set-port-position! iop n) (void))
3649          (eqv? (port-position iop) 0)
3650          (eq? (put-string iop "something longer than hello\n") (void))
3651          (eq? (set-port-position! iop n) (void))
3652          (eqv? (port-position iop) 0)
3653          (equal? (get-string-all iop) "something longer than hello\n")
3654          (eq? (close-port iop) (void))))))
3655  (let ()
3656    (define utf-16be-tx (make-transcoder (utf-16be-codec) (eol-style none) (error-handling-mode raise)))
3657    (and
3658      (let ()
3659        (define iop
3660          (open-file-input/output-port "testfile.ss" (file-options replace)
3661            (buffer-mode block) utf-16be-tx))
3662        (define n (port-position iop))            ; should be 0
3663        (put-string iop "hello\n")                ; should not write BOM
3664        (set-port-position! iop n)                ; should set to 0
3665        (and
3666          (eqv? n 0)
3667          (eqv? (port-position iop) 0)
3668          (equal? (get-string-all iop) "hello\n")
3669          (eq? (close-port iop) (void))))
3670      (let ()
3671        (define iop
3672          (open-file-input/output-port "testfile.ss" (file-options no-fail no-truncate)
3673            (buffer-mode block) utf-16be-tx))
3674        (define n (port-position iop))            ; should be 0
3675        (and
3676          (eq? n 0)
3677          (equal? (get-string-all iop) "hello\n")
3678          (eq? (set-port-position! iop n) (void))
3679          (eqv? (port-position iop) 0)
3680          (eq? (put-string iop "something longer than hello\n") (void))
3681          (eq? (set-port-position! iop n) (void))
3682          (eqv? (port-position iop) 0)
3683          (equal? (get-string-all iop) "something longer than hello\n")
3684          (eq? (close-port iop) (void))))))
3685  (let ()
3686    (define utf-16be-tx (make-transcoder (utf-16be-codec) (eol-style none) (error-handling-mode raise)))
3687    (define utf-16-tx (make-transcoder (utf-16-codec) (eol-style none) (error-handling-mode raise)))
3688    (and
3689      (let ()
3690        (define iop
3691          (open-file-input/output-port "testfile.ss" (file-options replace)
3692            (buffer-mode block) utf-16be-tx))
3693        (define n (port-position iop))            ; should be 0
3694        (put-string iop "hello\n")                ; should not write BOM
3695        (set-port-position! iop n)                ; should set to 0
3696        (and
3697          (eqv? n 0)
3698          (eqv? (port-position iop) 0)
3699          (equal? (get-string-all iop) "hello\n")
3700          (eq? (close-port iop) (void))))
3701      (let ()
3702        (define iop
3703          (open-file-input/output-port "testfile.ss" (file-options no-fail no-truncate)
3704            (buffer-mode block) utf-16-tx))
3705        (define n (port-position iop))            ; should be 0
3706        (and
3707          (eq? n 0)
3708          (equal? (get-string-all iop) "hello\n")
3709          (eq? (set-port-position! iop n) (void))
3710          (eqv? (port-position iop) 0)
3711          (eq? (put-string iop "something longer than hello\n") (void))
3712          (eq? (set-port-position! iop n) (void))
3713          (eqv? (port-position iop) 0)
3714          (equal? (get-string-all iop) "something longer than hello\n")
3715          (eq? (close-port iop) (void))))))
3716  (let ()
3717    (define utf-16le-tx (make-transcoder (utf-16le-codec) (eol-style none) (error-handling-mode raise)))
3718    (define utf-16-tx (make-transcoder (utf-16-codec) (eol-style none) (error-handling-mode raise)))
3719    (and
3720      (let ()
3721        (define iop
3722          (open-file-input/output-port "testfile.ss" (file-options replace)
3723            (buffer-mode block) utf-16le-tx))
3724        (define n0 (port-position iop))             ; should be 0
3725        (put-char iop #\xfeff)                      ; insert explicit BOM
3726        (let ()
3727          (define n (port-position iop))            ; should be 0
3728          (put-string iop "hello\n")                ; should not write BOM
3729          (set-port-position! iop n)                ; should set to 0
3730          (and
3731            (eqv? n0 0)
3732            (eqv? n 2)
3733            (equal? (get-string-all iop) "hello\n")
3734            (eq? (close-port iop) (void)))))
3735      (let ()
3736        (define iop
3737          (open-file-input/output-port "testfile.ss" (file-options no-fail no-truncate)
3738            (buffer-mode block) utf-16-tx))
3739        (define n (port-position iop))
3740        (and (equal? (get-string-all iop) "hello\n")
3741             (begin
3742               (set-port-position! iop n)
3743               (put-string iop "hello again\n")
3744               (set-port-position! iop n))
3745             (and (equal? (get-string-all iop) "hello again\n")
3746                  (eq? (close-port iop) (void)))))
3747      (let ()
3748        (define iop
3749          (open-file-input/output-port "testfile.ss" (file-options no-fail no-truncate)
3750            (buffer-mode block) utf-16le-tx))
3751        (define n (port-position iop))            ; should be 0
3752        (and
3753          (eqv? (get-char iop) #\xfeff)           ; BOM should still be there
3754          (equal? (get-string-all iop) "hello again\n")
3755          (eq? (set-port-position! iop n) (void))
3756          (eqv? (port-position iop) 0)
3757          (eq? (put-string iop "hello yet again!\n") (void))
3758          (eq? (set-port-position! iop n) (void))
3759          (eqv? (port-position iop) 0)
3760          (equal? (get-string-all iop) "hello yet again!\n")   ; BOM is gone now
3761          (eq? (close-port iop) (void))))))
3762  (let ()
3763    (define utf-16le-tx (make-transcoder (utf-16le-codec) (eol-style none) (error-handling-mode raise)))
3764    (define faux-utf-16-tx (make-transcoder (utf-16-codec 'little) (eol-style none) (error-handling-mode raise)))
3765    (and
3766      (let ()
3767        (define iop
3768          (open-file-input/output-port "testfile.ss" (file-options replace)
3769            (buffer-mode block) utf-16le-tx))
3770        (define n (port-position iop))            ; should be 0
3771        (put-string iop "hello\n")
3772        (set-port-position! iop n)
3773        (and
3774          (eqv? n 0)
3775          (eqv? (port-position iop) 0)
3776          (equal? (get-string-all iop) "hello\n")
3777          (eq? (close-port iop) (void))))
3778      (let ()
3779        (define iop
3780          (open-file-input/output-port "testfile.ss" (file-options no-fail no-truncate)
3781            (buffer-mode block) faux-utf-16-tx))
3782        (define n (port-position iop))            ; should be 0
3783        (and
3784          (eqv? n 0)
3785          (equal? (get-string-all iop) "hello\n")
3786          (eq? (set-port-position! iop n) (void))
3787          (eqv? (port-position iop) 0)
3788          (eq? (put-string iop "hello again\n") (void))
3789          (eq? (set-port-position! iop n) (void))
3790          (eqv? (port-position iop) 0)
3791          (equal? (get-string-all iop) "hello again\n")
3792          (eq? (close-port iop) (void))))
3793      (let ()
3794        (define iop
3795          (open-file-input/output-port "testfile.ss" (file-options no-fail no-truncate)
3796            (buffer-mode block) utf-16le-tx))
3797        (define n (port-position iop))            ; should be 0
3798        (and
3799          (eqv? n 0)
3800          (equal? (get-string-all iop) "hello again\n")
3801          (eq? (set-port-position! iop n) (void))
3802          (eqv? (port-position iop) 0)
3803          (eq? (put-string iop "hello yet again!\n") (void))
3804          (eq? (set-port-position! iop n) (void))
3805          (eqv? (port-position iop) 0)
3806          (equal? (get-string-all iop) "hello yet again!\n")
3807          (eq? (close-port iop) (void))))))
3808  (let ()
3809    (define-syntax and
3810      (let ()
3811        (import scheme)
3812        (syntax-rules ()
3813          [(_ e ...)
3814           (and (let ([x e]) (pretty-print x) x) ...)])))
3815    (define utf-16-tx (make-transcoder (utf-16-codec) (eol-style none) (error-handling-mode raise)))
3816    (and
3817      (let ()
3818        (define op
3819          (open-file-output-port "testfile.ss" (file-options replace)
3820            (buffer-mode block) utf-16-tx))
3821        (define n (port-position op))                  ; should be 0
3822        (and
3823          (eqv? n 0)
3824          (eq? (put-string op "hello\n") (void))       ; should write BOM
3825          (eq? (set-port-position! op n) (void))       ; should actually position past BOM (position 2)
3826          (eqv? (port-position op) 2)
3827          (eq? (put-string op "not hello\n") (void))   ; should not write (another) BOM
3828          (eq? (close-port op) (void))))
3829      (let ()
3830        (define ip
3831          (open-file-input-port "testfile.ss" (file-options)
3832            (buffer-mode block) utf-16-tx))
3833        (define n (port-position ip))                  ; should be 0
3834        (define c (lookahead-char ip))                 ; should be #\n
3835        (and
3836          (eqv? n 0)
3837          (eqv? c #\n)
3838          (eqv? (port-position ip) 2)
3839          (equal? (get-string-all ip) "not hello\n")
3840          (eq? (set-port-position! ip 2) (void))
3841          (equal? (get-string-all ip) "not hello\n")
3842          (eq? (close-port ip) (void))))))
3843)
3844
3845(mat encode/decode-consistency
3846 ; verify that encoding/decoding is consistent (but not necessarily correct)
3847 ; crank up loop bounds to stress test
3848  (let ()
3849    (define (random-string n)
3850      (define (random-char) (integer->char (random 256)))
3851      (let ([s (make-string n)])
3852        (do ([i 0 (fx+ i 1)])
3853            ((fx= i n))
3854          (string-set! s i (random-char)))
3855        s))
3856    (define (check who s1 s2)
3857      (unless (string=? s1 s2)
3858        (errorf who "failed for ~a"
3859          (parameterize ([print-unicode #f]) (format "~s" s1)))))
3860    (time
3861      (let ([latin-1-tx (make-transcoder (latin-1-codec) (eol-style none) (error-handling-mode raise))])
3862        (do ([n 1000 (fx- n 1)])
3863            ((fx= n 0) #t)
3864          (let ([s (random-string (random 50))])
3865            (check 'latin-1-test4 s (bytevector->string (string->bytevector s latin-1-tx) latin-1-tx)))))))
3866  (let ()
3867    (define (random-string n)
3868      (define (random-char)
3869        (integer->char
3870          (let ([k (random (fx- #x110000 (fx- #xe000 #xd800)))])
3871            (if (fx>= k #xd800)
3872                (fx+ k (fx- #xe000 #xd800))
3873                k))))
3874      (let ([s (make-string n)])
3875        (unless (fx= n 0)
3876         ; don't let a BOM sneak in at first character
3877          (string-set! s 0
3878            (let f () (let ([c (random-char)]) (if (memv c '(#\xfeff #\xfffe)) (f) c))))
3879          (do ([i 1 (fx+ i 1)])
3880              ((fx= i n))
3881            (string-set! s i (random-char))))
3882        s))
3883    (define (check who s1 s2)
3884      (unless (string=? s1 s2)
3885        (errorf who "failed for ~a"
3886          (parameterize ([print-unicode #f]) (format "~s" s1)))))
3887    (time
3888      (let ()
3889        (define utf-8-tx (make-transcoder (utf-8-codec) (eol-style none) (error-handling-mode raise)))
3890        (define utf-16-tx (make-transcoder (utf-16-codec) (eol-style none) (error-handling-mode raise)))
3891        (define utf-16le-tx (make-transcoder (utf-16le-codec) (eol-style none) (error-handling-mode raise)))
3892        (define utf-16be-tx (make-transcoder (utf-16be-codec) (eol-style none) (error-handling-mode raise)))
3893        (do ([n 1000 (fx- n 1)])
3894            ((fx= n 0) #t)
3895          (let ([s (random-string (random 50))])
3896            (check 'utf-8-test1 s (utf8->string (string->utf8 s)))
3897            (check 'utf-8-test2 s (utf8->string (string->bytevector s utf-8-tx)))
3898            (check 'utf-8-test3 s (bytevector->string (string->utf8 s) utf-8-tx))
3899            (check 'utf-8-test4 s (bytevector->string (string->bytevector s utf-8-tx) utf-8-tx))
3900            (check 'utf-16-test1a s (utf16->string (string->utf16 s 'big) 'big))
3901            (check 'utf-16-test1b s (utf16->string (string->utf16 s 'big) 'big #t))
3902            (check 'utf-16-test2a s (utf16->string (string->bytevector s utf-16-tx) 'big))
3903            (check 'utf-16-test2b s (utf16->string (string->bytevector s utf-16be-tx) 'big #t))
3904            (check 'utf-16-test2c s (utf16->string (string->bytevector s utf-16le-tx) 'little #t))
3905            (check 'utf-16-test3a s (bytevector->string (string->utf16 s 'big) utf-16-tx))
3906            (check 'utf-16-test3b s (bytevector->string (string->utf16 s 'big) utf-16be-tx))
3907            (check 'utf-16-test3c s (bytevector->string (string->utf16 s 'little) utf-16le-tx))
3908            (check 'utf-16-test4a s (bytevector->string (string->bytevector s utf-16-tx) utf-16-tx))
3909            (check 'utf-16-test4b s (bytevector->string (string->bytevector s utf-16le-tx) utf-16le-tx))
3910            (check 'utf-16-test4c s (bytevector->string (string->bytevector s utf-16be-tx) utf-16be-tx))
3911            (check 'utf-16-test5a s (utf16->string (string->utf16 s 'little) 'little))
3912            (check 'utf-16-test5b s (utf16->string (string->utf16 s 'little) 'little #t))
3913            (let* ([bv (string->bytevector s utf-16be-tx)]
3914                   [bvn (bytevector-length bv)]
3915                   [bv^ (make-bytevector (fx+ bvn 2))])
3916             ; insert big-endian BOM
3917              (bytevector-u8-set! bv^ 0 #xfe)
3918              (bytevector-u8-set! bv^ 1 #xff)
3919              (bytevector-copy! bv 0 bv^ 2 bvn)
3920              (check 'utf-16-test6 s (utf16->string bv^ 'big))
3921              (check 'utf-16-test7 s (bytevector->string bv^ utf-16-tx)))
3922            (let* ([bv (string->utf16 s 'little)]
3923                   [bvn (bytevector-length bv)]
3924                   [bv^ (make-bytevector (fx+ bvn 2))])
3925             ; insert little-endian BOM
3926              (bytevector-u8-set! bv^ 0 #xff)
3927              (bytevector-u8-set! bv^ 1 #xfe)
3928              (bytevector-copy! bv 0 bv^ 2 bvn)
3929              (check 'utf-16-test8 s (utf16->string bv^ 'little))
3930              (check 'utf-16-test9 s (bytevector->string bv^ utf-16-tx)))
3931          (check 'utf-32-test1a s (utf32->string (string->utf32 s 'big) 'big))
3932          (check 'utf-32-test1a s (utf32->string (string->utf32 s 'big) 'big #t))
3933          (check 'utf-32-test2a s (utf32->string (string->utf32 s 'little) 'little))
3934          (check 'utf-32-test2b s (utf32->string (string->utf32 s 'little) 'little #f)))))))
3935)
3936
3937(mat string<->bytevector-conversions
3938 ; adapted with minor modifications from bv2string.sch, which is:
3939 ;
3940 ; Copyright 2007 William D Clinger.
3941 ;
3942 ; Permission to copy this software, in whole or in part, to use this
3943 ; software for any lawful purpose, and to redistribute this software
3944 ; is granted subject to the restriction that all copies made of this
3945 ; software must include this copyright notice in full.
3946 ;
3947 ; I also request that you send me a copy of any improvements that you
3948 ; make to this software so that they may be incorporated within it to
3949 ; the benefit of the Scheme community.
3950  (begin
3951    (library (bv2string) (export main)
3952      (import (rnrs base)
3953              (rnrs unicode)
3954              (rename (rnrs bytevectors)
3955                (utf8->string rnrs:utf8->string)
3956                (string->utf8 rnrs:string->utf8))
3957              (rnrs control)
3958              (rnrs io simple)
3959              (rnrs mutable-strings))
3960
3961      ; Crude test rig, just for benchmarking.
3962
3963      (define utf8->string)
3964      (define string->utf8)
3965
3966      (define (test name actual expected)
3967        (if (not (equal? actual expected))
3968            (error 'test name)))
3969
3970      ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3971      ;
3972      ; The R6RS doesn't specify exactly how many replacement
3973      ; characters get generated by an encoding or decoding error,
3974      ; so the results of some tests are compared by treating any
3975      ; sequence of consecutive replacement characters the same as
3976      ; a single replacement character.
3977      ;
3978      ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3979
3980      (define (string~? s1 s2)
3981        (define (replacement? c)
3982          (char=? c #\xfffd))
3983        (define (canonicalized s)
3984          (let loop ((rchars (reverse (string->list s)))
3985                     (cchars '()))
3986            (cond ((or (null? rchars) (null? (cdr rchars)))
3987                   (list->string cchars))
3988                  ((and (replacement? (car rchars))
3989                        (replacement? (cadr rchars)))
3990                   (loop (cdr rchars) cchars))
3991                  (else
3992                   (loop (cdr rchars) (cons (car rchars) cchars))))))
3993        (string=? (canonicalized s1) (canonicalized s2)))
3994
3995      ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3996      ;
3997      ; Basic sanity tests, followed by stress tests on random inputs.
3998      ;
3999      ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4000
4001      (define (string-bytevector-tests
4002               *random-stress-tests* *random-stress-test-max-size*)
4003
4004        (define (test-roundtrip bvec tostring tobvec)
4005          (let* ((s1 (tostring bvec))
4006                 (b2 (tobvec s1))
4007                 (s2 (tostring b2)))
4008            (test "round trip of string conversion" (string=? s1 s2) #t)))
4009
4010        ; This random number generator doesn't have to be good.
4011        ; It just has to be fast.
4012
4013        (define random
4014          (letrec ((random14
4015                    (lambda (n)
4016                      (set! x (mod (+ (* a x) c) (+ m 1)))
4017                      (mod (div x 8) n)))
4018                   (a 701)
4019                   (x 1)
4020                   (c 743483)
4021                   (m 524287)
4022                   (loop
4023                    (lambda (q r n)
4024                      (if (zero? q)
4025                          (mod r n)
4026                          (loop (div q 16384)
4027                                (+ (* 16384 r) (random14 16384))
4028                                n)))))
4029            (lambda (n)
4030              (if (< n 16384)
4031                  (random14 n)
4032                  (loop (div n 16384) (random14 16384) n)))))
4033
4034        ; Returns a random bytevector of length up to n.
4035
4036        (define (random-bytevector n)
4037          (let* ((n (random n))
4038                 (bv (make-bytevector n)))
4039            (do ((i 0 (+ i 1)))
4040                ((= i n) bv)
4041              (bytevector-u8-set! bv i (random 256)))))
4042
4043        ; Returns a random bytevector of even length up to n.
4044
4045        (define (random-bytevector2 n)
4046          (let* ((n (random n))
4047                 (n (if (odd? n) (+ n 1) n))
4048                 (bv (make-bytevector n)))
4049            (do ((i 0 (+ i 1)))
4050                ((= i n) bv)
4051              (bytevector-u8-set! bv i (random 256)))))
4052
4053        ; Returns a random bytevector of multiple-of-4 length up to n.
4054
4055        (define (random-bytevector4 n)
4056          (let* ((n (random n))
4057                 (n (* 4 (round (/ n 4))))
4058                 (bv (make-bytevector n)))
4059            (do ((i 0 (+ i 1)))
4060                ((= i n) bv)
4061              (bytevector-u8-set! bv i (random 256)))))
4062
4063        (test "utf-8, BMP"
4064              (bytevector=? (string->utf8 "k\x007f;\x0080;\x07ff;\x0800;\xffff;")
4065                            '#vu8(#x6b
4066                                  #x7f
4067                                  #b11000010 #b10000000
4068                                  #b11011111 #b10111111
4069                                  #b11100000 #b10100000 #b10000000
4070                                  #b11101111 #b10111111 #b10111111))
4071              #t)
4072
4073        (test "utf-8, supplemental"
4074              (bytevector=? (string->utf8 "\x010000;\x10ffff;")
4075                            '#vu8(#b11110000 #b10010000 #b10000000 #b10000000
4076                                  #b11110100 #b10001111 #b10111111 #b10111111))
4077              #t)
4078
4079        (test "utf-8, errors 1"
4080              (string~? (utf8->string '#vu8(#x61                             ; a
4081                                            #xc0 #x62                        ; ?b
4082                                            #xc1 #x63                        ; ?c
4083                                            #xc2 #x64                        ; ?d
4084                                            #x80 #x65                        ; ?e
4085                                            #xc0 #xc0 #x66                   ; ??f
4086                                            #xe0 #x67                        ; ?g
4087                                           ))
4088                        "a\xfffd;b\xfffd;c\xfffd;d\xfffd;e\xfffd;\xfffd;f\xfffd;g")
4089              #t)
4090
4091        (test "utf-8, errors 2"
4092              (string~? (utf8->string '#vu8(#xe0 #x80 #x80 #x68              ; ???h
4093                                            #xe0 #xc0 #x80 #x69              ; ???i
4094                                            #xf0 #x6a                        ; ?j
4095                                           ))
4096                        "\xfffd;\xfffd;\xfffd;h\xfffd;\xfffd;\xfffd;i\xfffd;j")
4097              #t)
4098
4099        (test "utf-8, errors 3"
4100              (string~? (utf8->string '#vu8(#x61                             ; a
4101                                            #xf0 #x80 #x80 #x80 #x62         ; ????b
4102                                            #xf0 #x90 #x80 #x80 #x63         ; .c
4103                                           ))
4104                        "a\xfffd;\xfffd;\xfffd;\xfffd;b\x10000;c")
4105              #t)
4106
4107        (test "utf-8, errors 4"
4108              (string~? (utf8->string '#vu8(#x61                             ; a
4109                                            #xf0 #xbf #xbf #xbf #x64         ; .d
4110                                            #xf0 #xbf #xbf #x65              ; ?e
4111                                            #xf0 #xbf #x66                   ; ?f
4112                                           ))
4113                        "a\x3ffff;d\xfffd;e\xfffd;f")
4114              #t)
4115
4116        (test "utf-8, errors 5"
4117              (string~? (utf8->string '#vu8(#x61                             ; a
4118                                            #xf4 #x8f #xbf #xbf #x62         ; .b
4119                                            #xf4 #x90 #x80 #x80 #x63         ; ????c
4120                                           ))
4121
4122                        "a\x10ffff;b\xfffd;\xfffd;\xfffd;\xfffd;c")
4123              #t)
4124
4125        (test "utf-8, errors 6"
4126              (string~? (utf8->string '#vu8(#x61                             ; a
4127                                            #xf5 #x80 #x80 #x80 #x64         ; ????d
4128                                           ))
4129
4130                        "a\xfffd;\xfffd;\xfffd;\xfffd;d")
4131              #t)
4132
4133        ; ignores BOM signature
4134        ; Officially, there is no BOM signature for UTF-8,
4135        ; so this test is commented out.
4136
4137      #;(test "utf-8, BOM"
4138              (string=? (utf8->string '#vu8(#xef #xbb #xbf #x61 #x62 #x63 #x64))
4139                        "abcd")
4140              #t)
4141
4142        (test-roundtrip (random-bytevector 10) utf8->string string->utf8)
4143
4144        (do ((i 0 (+ i 1)))
4145            ((= i *random-stress-tests*))
4146          (test-roundtrip (random-bytevector *random-stress-test-max-size*)
4147                          utf8->string string->utf8))
4148
4149        (test "utf-16, BMP"
4150              (bytevector=? (string->utf16 "k\x007f;\x0080;\x07ff;\x0800;\xffff;")
4151                            '#vu8(#x00 #x6b
4152                                  #x00 #x7f
4153                                  #x00 #x80
4154                                  #x07 #xff
4155                                  #x08 #x00
4156                                  #xff #xff))
4157              #t)
4158
4159        (test "utf-16le, BMP"
4160              (bytevector=? (string->utf16 "k\x007f;\x0080;\x07ff;\x0800;\xffff;"
4161                                           'little)
4162                            '#vu8(#x6b #x00
4163                                  #x7f #x00
4164                                  #x80 #x00
4165                                  #xff #x07
4166                                  #x00 #x08
4167                                  #xff #xff))
4168              #t)
4169
4170        (test "utf-16, supplemental"
4171              (bytevector=? (string->utf16 "\x010000;\xfdcba;\x10ffff;")
4172                            '#vu8(#xd8 #x00 #xdc #x00
4173                                  #xdb #xb7 #xdc #xba
4174                                  #xdb #xff #xdf #xff))
4175              #t)
4176
4177        (test "utf-16le, supplemental"
4178              (bytevector=? (string->utf16 "\x010000;\xfdcba;\x10ffff;" 'little)
4179                            '#vu8(#x00 #xd8 #x00 #xdc
4180                                  #xb7 #xdb #xba #xdc
4181                                  #xff #xdb #xff #xdf))
4182              #t)
4183
4184        (test "utf-16be"
4185              (bytevector=? (string->utf16 "ab\x010000;\xfdcba;\x10ffff;cd")
4186                            (string->utf16 "ab\x010000;\xfdcba;\x10ffff;cd" 'big))
4187              #t)
4188
4189        (test "utf-16, errors 1"
4190              (string~? "k\x007f;\x0080;\x07ff;\x0800;\xffff;"
4191                        (utf16->string
4192                         '#vu8(#x00 #x6b
4193                               #x00 #x7f
4194                               #x00 #x80
4195                               #x07 #xff
4196                               #x08 #x00
4197                               #xff #xff)
4198                         'big))
4199              #t)
4200
4201        (test "utf-16, errors 2"
4202              (string~? "k\x007f;\x0080;\x07ff;\x0800;\xffff;"
4203                        (utf16->string
4204                         '#vu8(#x00 #x6b
4205                               #x00 #x7f
4206                               #x00 #x80
4207                               #x07 #xff
4208                               #x08 #x00
4209                               #xff #xff)
4210                         'big #t))
4211              #t)
4212
4213        (test "utf-16, errors 3"
4214              (string~? "k\x007f;\x0080;\x07ff;\x0800;\xffff;"
4215                        (utf16->string
4216                         '#vu8(#xfe #xff     ; big-endian BOM
4217                               #x00 #x6b
4218                               #x00 #x7f
4219                               #x00 #x80
4220                               #x07 #xff
4221                               #x08 #x00
4222                               #xff #xff)
4223                         'big))
4224              #t)
4225
4226        (test "utf-16, errors 4"
4227              (string~? "k\x007f;\x0080;\x07ff;\x0800;\xffff;"
4228                        (utf16->string
4229                         '#vu8(#x6b #x00
4230                               #x7f #x00
4231                               #x80 #x00
4232                               #xff #x07
4233                               #x00 #x08
4234                               #xff #xff)
4235                         'little #t))
4236              #t)
4237
4238        (test "utf-16, errors 5"
4239              (string~? "k\x007f;\x0080;\x07ff;\x0800;\xffff;"
4240                        (utf16->string
4241                         '#vu8(#xff #xfe     ; little-endian BOM
4242                               #x6b #x00
4243                               #x7f #x00
4244                               #x80 #x00
4245                               #xff #x07
4246                               #x00 #x08
4247                               #xff #xff)
4248                         'big))
4249              #t)
4250
4251        (let ((tostring        (lambda (bv) (utf16->string bv 'big)))
4252              (tostring-big    (lambda (bv) (utf16->string bv 'big #t)))
4253              (tostring-little (lambda (bv) (utf16->string bv 'little #t)))
4254              (tobvec          string->utf16)
4255              (tobvec-big      (lambda (s) (string->utf16 s 'big)))
4256              (tobvec-little   (lambda (s) (string->utf16 s 'little))))
4257
4258          (do ((i 0 (+ i 1)))
4259              ((= i *random-stress-tests*))
4260            (test-roundtrip (random-bytevector2 *random-stress-test-max-size*)
4261                            tostring tobvec)
4262            (test-roundtrip (random-bytevector2 *random-stress-test-max-size*)
4263                            tostring-big tobvec-big)
4264            (test-roundtrip (random-bytevector2 *random-stress-test-max-size*)
4265                            tostring-little tobvec-little)))
4266
4267        (test "utf-32"
4268              (bytevector=? (string->utf32 "abc")
4269                            '#vu8(#x00 #x00 #x00 #x61
4270                                  #x00 #x00 #x00 #x62
4271                                  #x00 #x00 #x00 #x63))
4272              #t)
4273
4274        (test "utf-32be"
4275              (bytevector=? (string->utf32 "abc" 'big)
4276                            '#vu8(#x00 #x00 #x00 #x61
4277                                  #x00 #x00 #x00 #x62
4278                                  #x00 #x00 #x00 #x63))
4279              #t)
4280
4281        (test "utf-32le"
4282              (bytevector=? (string->utf32 "abc" 'little)
4283                            '#vu8(#x61 #x00 #x00 #x00
4284                                  #x62 #x00 #x00 #x00
4285                                  #x63 #x00 #x00 #x00))
4286              #t)
4287
4288        (test "utf-32, errors 1"
4289              (string~? "a\xfffd;b\xfffd;c\xfffd;d\xfffd;e"
4290                        (utf32->string
4291                         '#vu8(#x00 #x00 #x00 #x61
4292                               #x00 #x00 #xd9 #x00
4293                               #x00 #x00 #x00 #x62
4294                               #x00 #x00 #xdd #xab
4295                               #x00 #x00 #x00 #x63
4296                               #x00 #x11 #x00 #x00
4297                               #x00 #x00 #x00 #x64
4298                               #x01 #x00 #x00 #x65
4299                               #x00 #x00 #x00 #x65)
4300                         'big))
4301              #t)
4302
4303        (test "utf-32, errors 2"
4304              (string~? "a\xfffd;b\xfffd;c\xfffd;d\xfffd;e"
4305                        (utf32->string
4306                         '#vu8(#x00 #x00 #x00 #x61
4307                               #x00 #x00 #xd9 #x00
4308                               #x00 #x00 #x00 #x62
4309                               #x00 #x00 #xdd #xab
4310                               #x00 #x00 #x00 #x63
4311                               #x00 #x11 #x00 #x00
4312                               #x00 #x00 #x00 #x64
4313                               #x01 #x00 #x00 #x65
4314                               #x00 #x00 #x00 #x65)
4315                         'big #t))
4316              #t)
4317
4318        (test "utf-32, errors 3"
4319              (string~? "a\xfffd;b\xfffd;c\xfffd;d\xfffd;e"
4320                        (utf32->string
4321                         '#vu8(#x00 #x00 #xfe #xff   ; big-endian BOM
4322                               #x00 #x00 #x00 #x61
4323                               #x00 #x00 #xd9 #x00
4324                               #x00 #x00 #x00 #x62
4325                               #x00 #x00 #xdd #xab
4326                               #x00 #x00 #x00 #x63
4327                               #x00 #x11 #x00 #x00
4328                               #x00 #x00 #x00 #x64
4329                               #x01 #x00 #x00 #x65
4330                               #x00 #x00 #x00 #x65)
4331                         'big))
4332              #t)
4333
4334        (test "utf-32, errors 4"
4335              (string~? "\xfeff;a\xfffd;b\xfffd;c\xfffd;d\xfffd;e"
4336                        (utf32->string
4337                         '#vu8(#x00 #x00 #xfe #xff   ; big-endian BOM
4338                               #x00 #x00 #x00 #x61
4339                               #x00 #x00 #xd9 #x00
4340                               #x00 #x00 #x00 #x62
4341                               #x00 #x00 #xdd #xab
4342                               #x00 #x00 #x00 #x63
4343                               #x00 #x11 #x00 #x00
4344                               #x00 #x00 #x00 #x64
4345                               #x01 #x00 #x00 #x65
4346                               #x00 #x00 #x00 #x65)
4347                         'big #t))
4348              #t)
4349
4350        (test "utf-32, errors 5"
4351              (string~? "a\xfffd;b\xfffd;c\xfffd;d\xfffd;e"
4352                        (utf32->string
4353                         '#vu8(#x61 #x00 #x00 #x00
4354                               #x00 #xd9 #x00 #x00
4355                               #x62 #x00 #x00 #x00
4356                               #xab #xdd #x00 #x00
4357                               #x63 #x00 #x00 #x00
4358                               #x00 #x00 #x11 #x00
4359                               #x64 #x00 #x00 #x00
4360                               #x65 #x00 #x00 #x01
4361                               #x65 #x00 #x00 #x00)
4362                         'little #t))
4363              #t)
4364
4365        (test "utf-32, errors 6"
4366              (string~? "a\xfffd;b\xfffd;c\xfffd;d\xfffd;e"
4367                        (utf32->string
4368                         '#vu8(#xff #xfe #x00 #x00   ; little-endian BOM
4369                               #x61 #x00 #x00 #x00
4370                               #x00 #xd9 #x00 #x00
4371                               #x62 #x00 #x00 #x00
4372                               #xab #xdd #x00 #x00
4373                               #x63 #x00 #x00 #x00
4374                               #x00 #x00 #x11 #x00
4375                               #x64 #x00 #x00 #x00
4376                               #x65 #x00 #x00 #x01
4377                               #x65 #x00 #x00 #x00)
4378                         'big))
4379              #t)
4380
4381        (test "utf-32, errors 7"
4382              (string~? "\xfeff;a\xfffd;b\xfffd;c\xfffd;d\xfffd;e"
4383                        (utf32->string
4384                         '#vu8(#xff #xfe #x00 #x00   ; little-endian BOM
4385                               #x61 #x00 #x00 #x00
4386                               #x00 #xd9 #x00 #x00
4387                               #x62 #x00 #x00 #x00
4388                               #xab #xdd #x00 #x00
4389                               #x63 #x00 #x00 #x00
4390                               #x00 #x00 #x11 #x00
4391                               #x64 #x00 #x00 #x00
4392                               #x65 #x00 #x00 #x01
4393                               #x65 #x00 #x00 #x00)
4394                         'little #t))
4395              #t)
4396
4397        (let ((tostring        (lambda (bv) (utf32->string bv 'big)))
4398              (tostring-big    (lambda (bv) (utf32->string bv 'big #t)))
4399              (tostring-little (lambda (bv) (utf32->string bv 'little #t)))
4400              (tobvec          string->utf32)
4401              (tobvec-big      (lambda (s) (string->utf32 s 'big)))
4402              (tobvec-little   (lambda (s) (string->utf32 s 'little))))
4403
4404          (do ((i 0 (+ i 1)))
4405              ((= i *random-stress-tests*))
4406            (test-roundtrip (random-bytevector4 *random-stress-test-max-size*)
4407                            tostring tobvec)
4408            (test-roundtrip (random-bytevector4 *random-stress-test-max-size*)
4409                            tostring-big tobvec-big)
4410            (test-roundtrip (random-bytevector4 *random-stress-test-max-size*)
4411                            tostring-little tobvec-little)))
4412
4413      )
4414
4415      ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4416      ;
4417      ; Exhaustive tests.
4418      ;
4419      ; Tests string <-> bytevector conversion on strings
4420      ; that contain every Unicode scalar value.
4421      ;
4422      ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4423
4424      (define (exhaustive-string-bytevector-tests)
4425
4426        ; Tests throughout an inclusive range.
4427
4428        (define (test-char-range lo hi tostring tobytevector)
4429          (let* ((n (+ 1 (- hi lo)))
4430                 (s (make-string n))
4431                 (replacement-character (integer->char #xfffd)))
4432            (do ((i lo (+ i 1)))
4433                ((> i hi))
4434              (let ((c (if (or (<= 0 i #xd7ff)
4435                               (<= #xe000 i #x10ffff))
4436                           (integer->char i)
4437                           replacement-character)))
4438                (string-set! s (- i lo) c)))
4439            (test "test of long string conversion"
4440                  (string=? (tostring (tobytevector s)) s) #t)))
4441
4442        (define (test-exhaustively name tostring tobytevector)
4443         ;(display "Testing ")
4444         ;(display name)
4445         ;(display " conversions...")
4446         ;(newline)
4447          (test-char-range 0 #xffff tostring tobytevector)
4448          (test-char-range #x10000 #x1ffff tostring tobytevector)
4449          (test-char-range #x20000 #x2ffff tostring tobytevector)
4450          (test-char-range #x30000 #x3ffff tostring tobytevector)
4451          (test-char-range #x40000 #x4ffff tostring tobytevector)
4452          (test-char-range #x50000 #x5ffff tostring tobytevector)
4453          (test-char-range #x60000 #x6ffff tostring tobytevector)
4454          (test-char-range #x70000 #x7ffff tostring tobytevector)
4455          (test-char-range #x80000 #x8ffff tostring tobytevector)
4456          (test-char-range #x90000 #x9ffff tostring tobytevector)
4457          (test-char-range #xa0000 #xaffff tostring tobytevector)
4458          (test-char-range #xb0000 #xbffff tostring tobytevector)
4459          (test-char-range #xc0000 #xcffff tostring tobytevector)
4460          (test-char-range #xd0000 #xdffff tostring tobytevector)
4461          (test-char-range #xe0000 #xeffff tostring tobytevector)
4462          (test-char-range #xf0000 #xfffff tostring tobytevector)
4463          (test-char-range #x100000 #x10ffff tostring tobytevector))
4464
4465        ; Feel free to replace this with your favorite timing macro.
4466
4467        (define (timeit x) x)
4468
4469        (timeit (test-exhaustively "UTF-8" utf8->string string->utf8))
4470
4471        ; NOTE:  An unfortunate misunderstanding led to a late deletion
4472        ; of single-argument utf16->string from the R6RS.  To get the
4473        ; correct effect of single-argument utf16->string, you have to
4474        ; use two arguments, as below.
4475        ;
4476        ;(timeit (test-exhaustively "UTF-16" utf16->string string->utf16))
4477
4478        (timeit (test-exhaustively "UTF-16"
4479                                   (lambda (bv) (utf16->string bv 'big))
4480                                   string->utf16))
4481
4482        ; NOTE:  To get the correct effect of two-argument utf16->string,
4483        ; you have to use three arguments, as below.
4484
4485        (timeit (test-exhaustively "UTF-16BE"
4486                                   (lambda (bv) (utf16->string bv 'big #t))
4487                                   (lambda (s) (string->utf16 s 'big))))
4488
4489        (timeit (test-exhaustively "UTF-16LE"
4490                                   (lambda (bv) (utf16->string bv 'little #t))
4491                                   (lambda (s) (string->utf16 s 'little))))
4492
4493        ; NOTE:  An unfortunate misunderstanding led to a late deletion
4494        ; of single-argument utf32->string from the R6RS.  To get the
4495        ; correct effect of single-argument utf32->string, you have to
4496        ; use two arguments, as below.
4497        ;
4498        ;(timeit (test-exhaustively "UTF-32" utf32->string string->utf32))
4499
4500        (timeit (test-exhaustively "UTF-32"
4501                                   (lambda (bv) (utf32->string bv 'big))
4502                                   string->utf32))
4503
4504        ; NOTE:  To get the correct effect of two-argument utf32->string,
4505        ; you have to use three arguments, as below.
4506
4507        (timeit (test-exhaustively "UTF-32BE"
4508                                   (lambda (bv) (utf32->string bv 'big #t))
4509                                   (lambda (s) (string->utf32 s 'big))))
4510
4511        (timeit (test-exhaustively "UTF-32LE"
4512                                   (lambda (bv) (utf32->string bv 'little #t))
4513                                   (lambda (s) (string->utf32 s 'little)))))
4514
4515      (define (main p1 p2)
4516        (set! utf8->string p1)
4517        (set! string->utf8 p2)
4518        (string-bytevector-tests 2 1000)
4519        (exhaustive-string-bytevector-tests)))
4520    #t)
4521 ; first test w/built-in utf8->string and string->utf8
4522  (begin
4523    (let () (import (bv2string)) (main utf8->string string->utf8))
4524    #t)
4525 ; next test w/utf8->string and string->utf8 synthesized from utf-8-codec
4526  (let ()
4527    (define (utf8->string bv)
4528      (get-string-all (open-bytevector-input-port bv
4529                        (make-transcoder (utf-8-codec) 'none))))
4530    (define (string->utf8 s)
4531      (let-values ([(op get) (open-bytevector-output-port
4532                               (make-transcoder (utf-8-codec) 'none))])
4533        (put-string op s)
4534        (get)))
4535    (let () (import (bv2string)) (main utf8->string string->utf8))
4536    #t)
4537)
4538
4539(mat open-process-ports ; see also unix.ms (mat nonblocking ...)
4540  (begin
4541    (define ($check-port p xput-port? bt-port?)
4542      (define-syntax err?
4543        (syntax-rules ()
4544          [(_ e1 e2 ...) (guard (c [#t #t]) e1 e2 ... #f)]))
4545      (unless (and (xput-port? p) (bt-port? p) (file-port? p))
4546        (errorf #f "~s is not as it should be" p))
4547      (let ([fd (port-file-descriptor p)])
4548        (unless (fixnum? fd)
4549          (errorf #f "unexpected file descriptor ~s" fd)))
4550      (when (or (port-has-port-position? p)
4551                (port-has-set-port-position!? p)
4552                (port-has-port-length? p)
4553                (port-has-set-port-length!? p))
4554        (errorf #f "unexpected port-has-xxx results for ~s" p))
4555      (unless (and (err? (port-position p))
4556                   (err? (set-port-position! p 0))
4557                   (err? (port-length p))
4558                   (err? (set-port-length! p 0)))
4559        (errorf #f "no error for getting/setting port position/length on ~s" p)))
4560    (define $emit-dot
4561      (let ([n 0])
4562        (lambda ()
4563          (display ".")
4564          (set! n (modulo (+ n 1) 72))
4565          (when (= n 0) (newline))
4566          (flush-output-port))))
4567    #t)
4568 ; test binary ports
4569  (let-values ([(to-stdin from-stdout from-stderr pid)
4570                (open-process-ports (patch-exec-path $cat_flush))])
4571    (define put-string
4572      (lambda (bp s)
4573        (put-bytevector bp (string->utf8 s))))
4574    (define get-string-some
4575      (lambda (bp)
4576        (let ([x (get-bytevector-some bp)])
4577          (if (eof-object? x) x (utf8->string x)))))
4578    (define get-string-n
4579      (lambda (bp n)
4580        (let ([x (get-bytevector-n bp n)])
4581          (if (eof-object? x) x (utf8->string x)))))
4582    (dynamic-wind
4583      void
4584      (lambda ()
4585        (put-string to-stdin "life in the fast lane\n")
4586        (flush-output-port to-stdin)
4587        (let f ()
4588          ($check-port to-stdin output-port? binary-port?)
4589          ($check-port from-stdout input-port? binary-port?)
4590          ($check-port from-stderr input-port? binary-port?)
4591          (when (input-port-ready? from-stderr)
4592            (errorf #f "input ready on from-stderr ~s" (get-string-some from-stderr)))
4593          (if (input-port-ready? from-stdout)
4594              (let ([s (get-string-n from-stdout 10)])
4595                (unless (equal? s "life in th")
4596                  (errorf #f "unexpected from-stdout string ~s" s)))
4597              (begin
4598                ($emit-dot)
4599                (f))))
4600        (let f ([all ""])
4601          (unless (equal? all "e fast lane\n")
4602            (when (input-port-ready? from-stderr)
4603              (errorf #f "input ready on from-stderr ~s" (get-string-some from-stderr)))
4604            (let ([s (get-string-some from-stdout)])
4605              ($emit-dot)
4606              (f (string-append all s)))))
4607        (and
4608          (not (input-port-ready? from-stderr))
4609          (not (input-port-ready? from-stdout))
4610          (begin
4611            (close-port to-stdin)
4612            (let f ()
4613              (unless (and (port-eof? from-stdout) (port-eof? from-stderr))
4614                ($emit-dot)
4615                (f)))
4616            #t)))
4617      (lambda ()
4618        (close-port to-stdin)
4619        (close-port from-stdout)
4620        (close-port from-stderr))))
4621 ; test binary ports w/buffer-mode none
4622  (let-values ([(to-stdin from-stdout from-stderr pid)
4623                (open-process-ports (patch-exec-path $cat_flush) (buffer-mode none))])
4624    (define put-string
4625      (lambda (bp s)
4626        (put-bytevector bp (string->utf8 s))))
4627    (define get-string-some
4628      (lambda (bp)
4629        (let ([x (get-bytevector-some bp)])
4630          (if (eof-object? x) x (utf8->string x)))))
4631    (define get-string-n
4632      (lambda (bp n)
4633        (let ([x (get-bytevector-n bp n)])
4634          (if (eof-object? x) x (utf8->string x)))))
4635    (dynamic-wind
4636      void
4637      (lambda ()
4638        ($check-port to-stdin output-port? binary-port?)
4639        ($check-port from-stdout input-port? binary-port?)
4640        ($check-port from-stderr input-port? binary-port?)
4641        (put-string to-stdin "life in the fast lane\n")
4642        (flush-output-port to-stdin)
4643        (let f ()
4644          (when (input-port-ready? from-stderr)
4645            (errorf #f "input ready on from-stderr ~s" (get-string-some from-stderr)))
4646          (if (input-port-ready? from-stdout)
4647              (let ([s (get-string-n from-stdout 10)])
4648                (unless (equal? s "life in th")
4649                  (errorf #f "unexpected from-stdout string ~s" s)))
4650              (begin
4651                ($emit-dot)
4652                (f))))
4653        (let f ([all ""])
4654          (unless (equal? all "e fast lane\n")
4655            (when (input-port-ready? from-stderr)
4656              (errorf #f "input ready on from-stderr ~s" (get-string-some from-stderr)))
4657            (let ([s (get-string-some from-stdout)])
4658              ($emit-dot)
4659              (f (string-append all s)))))
4660        (and
4661          (not (input-port-ready? from-stderr))
4662          (not (input-port-ready? from-stdout))
4663          (begin
4664            (close-port to-stdin)
4665            (let f ()
4666              (unless (and (port-eof? from-stdout) (port-eof? from-stderr))
4667                ($emit-dot)
4668                (f)))
4669            #t)))
4670      (lambda ()
4671        (close-port to-stdin)
4672        (close-port from-stdout)
4673        (close-port from-stderr))))
4674 ; test textual ports
4675  (let-values ([(to-stdin from-stdout from-stderr pid)
4676                (open-process-ports (patch-exec-path $cat_flush) (buffer-mode block) (native-transcoder))])
4677    (dynamic-wind
4678      void
4679      (lambda ()
4680        ($check-port to-stdin output-port? textual-port?)
4681        ($check-port from-stdout input-port? textual-port?)
4682        ($check-port from-stderr input-port? textual-port?)
4683        (put-string to-stdin "life in the fast lane\n")
4684        (flush-output-port to-stdin)
4685        (let f ()
4686          (when (input-port-ready? from-stderr)
4687            (errorf #f "input ready on from-stderr ~s" (get-string-some from-stderr)))
4688          (if (input-port-ready? from-stdout)
4689              (let ([s (get-string-n from-stdout 10)])
4690                (unless (equal? s "life in th")
4691                  (errorf #f "unexpected from-stdout string ~s" s)))
4692              (begin
4693                ($emit-dot)
4694                (f))))
4695        (let f ([all ""])
4696          (unless (equal? all "e fast lane\n")
4697            (when (input-port-ready? from-stderr)
4698              (errorf #f "input ready on from-stderr ~s" (get-string-some from-stderr)))
4699            (let ([s (get-string-some from-stdout)])
4700              ($emit-dot)
4701              (f (string-append all s)))))
4702        (and
4703          (not (input-port-ready? from-stderr))
4704          (not (input-port-ready? from-stdout))
4705          (begin
4706            (close-port to-stdin)
4707            (let f ()
4708              (unless (and (port-eof? from-stdout) (port-eof? from-stderr))
4709                ($emit-dot)
4710                (f)))
4711            #t)))
4712      (lambda ()
4713        (close-port to-stdin)
4714        (close-port from-stdout)
4715        (close-port from-stderr))))
4716 ; test textual ports w/buffer-mode none
4717  (let-values ([(to-stdin from-stdout from-stderr pid)
4718                (open-process-ports (patch-exec-path $cat_flush) (buffer-mode none) (native-transcoder))])
4719    (dynamic-wind
4720      void
4721      (lambda ()
4722        ($check-port to-stdin output-port? textual-port?)
4723        ($check-port from-stdout input-port? textual-port?)
4724        ($check-port from-stderr input-port? textual-port?)
4725        (put-string to-stdin "life in the fast lane\n")
4726        (flush-output-port to-stdin)
4727        (let f ()
4728          (when (input-port-ready? from-stderr)
4729            (errorf #f "input ready on from-stderr ~s" (get-string-some from-stderr)))
4730          (if (input-port-ready? from-stdout)
4731              (let ([s (get-string-n from-stdout 10)])
4732                (unless (equal? s "life in th")
4733                  (errorf #f "unexpected from-stdout string ~s" s)))
4734              (begin
4735                ($emit-dot)
4736                (f))))
4737        (let f ([all ""])
4738          (unless (equal? all "e fast lane\n")
4739            (when (input-port-ready? from-stderr)
4740              (errorf #f "input ready on from-stderr ~s" (get-string-some from-stderr)))
4741            (let ([s (get-string-some from-stdout)])
4742              ($emit-dot)
4743              (f (string-append all s)))))
4744        (and
4745          (not (input-port-ready? from-stderr))
4746          (not (input-port-ready? from-stdout))
4747          (begin
4748            (close-port to-stdin)
4749            (let f ()
4750              (unless (and (port-eof? from-stdout) (port-eof? from-stderr))
4751                ($emit-dot)
4752                (f)))
4753            #t)))
4754      (lambda ()
4755        (close-port to-stdin)
4756        (close-port from-stdout)
4757        (close-port from-stderr))))
4758 ; test textual ports w/buffer-mode line
4759  (let-values ([(to-stdin from-stdout from-stderr pid)
4760                (open-process-ports (patch-exec-path $cat_flush) (buffer-mode line) (native-transcoder))])
4761    (dynamic-wind
4762      void
4763      (lambda ()
4764        ($check-port to-stdin output-port? textual-port?)
4765        ($check-port from-stdout input-port? textual-port?)
4766        ($check-port from-stderr input-port? textual-port?)
4767        (put-string to-stdin "life in the fast lane\n")
4768        (flush-output-port to-stdin)
4769        (let f ()
4770          (when (input-port-ready? from-stderr)
4771            (errorf #f "input ready on from-stderr ~s" (get-string-some from-stderr)))
4772          (if (input-port-ready? from-stdout)
4773              (let ([s (get-string-n from-stdout 10)])
4774                (unless (equal? s "life in th")
4775                  (errorf #f "unexpected from-stdout string ~s" s)))
4776              (begin
4777                ($emit-dot)
4778                (f))))
4779        (let f ([all ""])
4780          (unless (equal? all "e fast lane\n")
4781            (when (input-port-ready? from-stderr)
4782              (errorf #f "input ready on from-stderr ~s" (get-string-some from-stderr)))
4783            (let ([s (get-string-some from-stdout)])
4784              ($emit-dot)
4785              (f (string-append all s)))))
4786        (and
4787          (not (input-port-ready? from-stderr))
4788          (not (input-port-ready? from-stdout))
4789          (begin
4790            (close-port to-stdin)
4791            (let f ()
4792              (unless (and (port-eof? from-stdout) (port-eof? from-stderr))
4793                ($emit-dot)
4794                (f)))
4795            #t)))
4796      (lambda ()
4797        (close-port to-stdin)
4798        (close-port from-stdout)
4799        (close-port from-stderr))))
4800)
4801
4802(mat to-fold-or-not-to-fold
4803  (begin
4804    (define ($readit cs? s)
4805      (define (string-append* s1 . ls)
4806        (let f ([s1 s1] [ls ls] [n 0])
4807          (let ([n1 (string-length s1)])
4808            (if (null? ls)
4809                (let ([s (make-string (fx+ n n1))])
4810                  (string-copy! s1 0 s n n1)
4811                  s)
4812                (let ([s (f (car ls) (cdr ls) (fx+ n n1 1))])
4813                  (string-copy! s1 0 s n n1)
4814                  (string-set! s (fx+ n n1) #\$)
4815                  s)))))
4816      (apply string-append*
4817        (let ([sip (open-input-string s)])
4818          (parameterize ([case-sensitive cs?])
4819            (let f ()
4820              (let ([x (get-datum sip)])
4821                (if (eof-object? x)
4822                    '()
4823                    (cons (cond
4824                            [(gensym? x)
4825                             (string-append (symbol->string x) "%"
4826                               (gensym->unique-string x))]
4827                            [(symbol? x) (symbol->string x)]
4828                            [(char? x) (string x)]
4829                            [else (error 'string-append* "unexpected ~s" x)])
4830                          (f)))))))))
4831    #t)
4832  (case-sensitive)
4833  (equal?
4834    ($readit #t "To be or NOT to bE")
4835    "To$be$or$NOT$to$bE")
4836  (equal?
4837    ($readit #f "To be or NOT to bE")
4838    "to$be$or$not$to$be")
4839  (equal?
4840    ($readit #t "To be #!no-fold-case or NOT #!fold-case to bE")
4841    "To$be$or$NOT$to$be")
4842  (equal?
4843    ($readit #t "To be #!fold-case or NOT #!no-fold-case to bE")
4844    "To$be$or$not$to$bE")
4845  (equal?
4846    ($readit #f "To be #!no-fold-case or NOT #!fold-case to bE")
4847    "to$be$or$NOT$to$be")
4848  (equal?
4849    ($readit #f "To be #!fold-case or NOT #!no-fold-case to bE")
4850    "to$be$or$not$to$bE")
4851 ; check delimiting
4852  (equal?
4853    ($readit #f "To be#!fold-caseor NOT#!no-fold-caseto bE")
4854    "to$be$or$not$to$bE")
4855 ; verify case folding is not disabled when Unicode hex escape seen
4856  (equal?
4857    ($readit #t "ab\\x43;de")
4858    "abCde")
4859  (equal?
4860    ($readit #f "ab\\x43;de")
4861    "abcde")
4862  (equal?
4863    ($readit #t "#!fold-case ab\\x43;de")
4864    "abcde")
4865  (equal?
4866    ($readit #f "#!fold-case ab\\x43;de")
4867    "abcde")
4868  (equal?
4869    ($readit #t "#!no-fold-case ab\\x43;de")
4870    "abCde")
4871  (equal?
4872    ($readit #f "#!no-fold-case ab\\x43;de")
4873    "abCde")
4874 ; verify case folding still works when string changes size
4875  (equal?
4876    ($readit #t "Stra\xDF;e #!no-fold-case Stra\xDF;e #!fold-case Stra\xDF;e")
4877    "Stra\xDF;e$Stra\xDF;e$strasse")
4878  (equal?
4879    ($readit #f "Stra\xDF;e #!no-fold-case Stra\xDF;e #!fold-case Stra\xDF;e")
4880    "strasse$Stra\xDF;e$strasse")
4881  (equal?
4882    ($readit #t "Stra\xDF;e #!fold-case Stra\xDF;e #!no-fold-case Stra\xDF;e")
4883    "Stra\xDF;e$strasse$Stra\xDF;e")
4884  (equal?
4885    ($readit #f "Stra\xDF;e #!fold-case Stra\xDF;e #!no-fold-case Stra\xDF;e")
4886    "strasse$strasse$Stra\xDF;e")
4887  (equal?
4888    ($readit #t "Aa|b C|dE abC|D e|Fg \\#Ab\\ C a\\B\\ cd")
4889    "Aab CdE$abCD eFg$#Ab C$aB cd")
4890 ; verify case folding is disabled when vertical bars or backslashes
4891 ; (other than those for Unicode hex escapes) appear
4892  (equal?
4893    ($readit #f "Aa|b C|dE abC|D e|Fg \\#Ab\\ C a\\B\\ cd")
4894    "Aab CdE$abCD eFg$#Ab C$aB cd")
4895  (equal?
4896    ($readit #t "#!fold-case Aa|b C|dE abC|D e|Fg \\#Ab\\ C a\\B\\ cd")
4897    "Aab CdE$abCD eFg$#Ab C$aB cd")
4898  (equal?
4899    ($readit #f "#!fold-case Aa|b C|dE abC|D e|Fg \\#Ab\\ C a\\B\\ cd")
4900    "Aab CdE$abCD eFg$#Ab C$aB cd")
4901  (equal?
4902    ($readit #t "#!no-fold-case Aa|b C|dE abC|D e|Fg \\#Ab\\ C a\\B\\ cd")
4903    "Aab CdE$abCD eFg$#Ab C$aB cd")
4904  (equal?
4905    ($readit #f "#!no-fold-case Aa|b C|dE abC|D e|Fg \\#Ab\\ C a\\B\\ cd")
4906    "Aab CdE$abCD eFg$#Ab C$aB cd")
4907 ; verify proper case folding for gensyms
4908  (equal?
4909    ($readit #t "#{aBc DeF1}")
4910    "aBc%DeF1")
4911  (equal?
4912    ($readit #f "#{aBc DeF2}")
4913    "abc%def2")
4914  (equal?
4915    ($readit #t "#!fold-case #{aBc DeF3}")
4916    "abc%def3")
4917  (equal?
4918    ($readit #f "#!fold-case #{aBc DeF4}")
4919    "abc%def4")
4920  (equal?
4921    ($readit #t "#!no-fold-case #{aBc DeF5}")
4922    "aBc%DeF5")
4923  (equal?
4924    ($readit #f "#!no-fold-case #{aBc DeF6}")
4925    "aBc%DeF6")
4926  (equal?
4927    ($readit #t "#{aBc De\\F7}")
4928    "aBc%DeF7")
4929  (equal?
4930    ($readit #f "#{aBc De\\F8}")
4931    "abc%DeF8")
4932  (equal?
4933    ($readit #t "#!fold-case #{aBc De\\F9}")
4934    "abc%DeF9")
4935  (equal?
4936    ($readit #f "#!fold-case #{aBc De\\F10}")
4937    "abc%DeF10")
4938  (equal?
4939    ($readit #t "#!no-fold-case #{aBc De\\F11}")
4940    "aBc%DeF11")
4941  (equal?
4942    ($readit #f "#!no-fold-case #{aBc De\\F12}")
4943    "aBc%DeF12")
4944  (equal?
4945    ($readit #t "#{a\\Bc DeF13}")
4946    "aBc%DeF13")
4947  (equal?
4948    ($readit #f "#{a\\Bc DeF14}")
4949    "aBc%def14")
4950  (equal?
4951    ($readit #t "#!fold-case #{a\\Bc DeF15}")
4952    "aBc%def15")
4953  (equal?
4954    ($readit #f "#!fold-case #{a\\Bc DeF16}")
4955    "aBc%def16")
4956  (equal?
4957    ($readit #t "#!no-fold-case #{a\\Bc DeF17}")
4958    "aBc%DeF17")
4959  (equal?
4960    ($readit #f "#!no-fold-case #{a\\Bc DeF18}")
4961    "aBc%DeF18")
4962  (equal?
4963    ($readit #t "#{a\\Bc De\\F19}")
4964    "aBc%DeF19")
4965  (equal?
4966    ($readit #f "#{a\\Bc De\\F20}")
4967    "aBc%DeF20")
4968  (equal?
4969    ($readit #t "#!fold-case #{a\\Bc De\\F21}")
4970    "aBc%DeF21")
4971  (equal?
4972    ($readit #f "#!fold-case #{a\\Bc De\\F22}")
4973    "aBc%DeF22")
4974  (equal?
4975    ($readit #t "#!no-fold-case #{a\\Bc De\\F23}")
4976    "aBc%DeF23")
4977  (equal?
4978    ($readit #f "#!no-fold-case #{a\\Bc De\\F24}")
4979    "aBc%DeF24")
4980  (equal?
4981    ($readit #t "#\\newline")
4982    "\n")
4983  (equal?
4984    ($readit #f "#\\newline")
4985    "\n")
4986  (equal?
4987    ($readit #f "#!fold-case #\\newline")
4988    "\n")
4989  (equal?
4990    ($readit #f "#!fold-case #\\newline")
4991    "\n")
4992  (equal?
4993    ($readit #f "#!no-fold-case #\\newline")
4994    "\n")
4995  (equal?
4996    ($readit #f "#!no-fold-case #\\newline")
4997    "\n")
4998  (error? ($readit #t "#\\newLine"))
4999  (equal?
5000    ($readit #f "#\\newLine")
5001    "\n")
5002  (equal?
5003    ($readit #t "#!fold-case #\\newLine")
5004    "\n")
5005  (equal?
5006    ($readit #f "#!fold-case #\\newLine")
5007    "\n")
5008  (error? ($readit #t "#!no-fold-case #\\newLine"))
5009  (error? ($readit #f "#!no-fold-case #\\newLine"))
5010)
5011