2378 lines
		
	
	
		
			84 KiB
		
	
	
	
		
			Scheme
		
	
	
	
			
		
		
	
	
			2378 lines
		
	
	
		
			84 KiB
		
	
	
	
		
			Scheme
		
	
	
	
;;; Ikarus Scheme -- A compiler for R6RS Scheme.
 | 
						|
;;; Copyright (C) 2006,2007,2008  Abdulaziz Ghuloum
 | 
						|
;;; 
 | 
						|
;;; This program is free software: you can redistribute it and/or modify
 | 
						|
;;; it under the terms of the GNU General Public License version 3 as
 | 
						|
;;; published by the Free Software Foundation.
 | 
						|
;;; 
 | 
						|
;;; This program is distributed in the hope that it will be useful, but
 | 
						|
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
;;; General Public License for more details.
 | 
						|
;;; 
 | 
						|
;;; You should have received a copy of the GNU General Public License
 | 
						|
;;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 | 
						|
 | 
						|
(library (io-spec) 
 | 
						|
  
 | 
						|
  (export 
 | 
						|
    port? input-port? output-port? textual-port? binary-port?
 | 
						|
    open-file-input-port open-input-file 
 | 
						|
    call-with-input-file with-input-from-file
 | 
						|
    standard-input-port current-input-port
 | 
						|
    open-bytevector-input-port
 | 
						|
    open-string-input-port with-input-from-string
 | 
						|
    make-custom-binary-input-port 
 | 
						|
    make-custom-binary-output-port 
 | 
						|
    make-custom-textual-input-port 
 | 
						|
    make-custom-textual-output-port 
 | 
						|
    transcoded-port port-transcoder
 | 
						|
    close-port port-closed? close-input-port close-output-port
 | 
						|
    port-eof?
 | 
						|
    get-char lookahead-char read-char peek-char
 | 
						|
    get-string-n get-string-n! get-string-all get-line
 | 
						|
    get-u8 lookahead-u8 
 | 
						|
    get-bytevector-n get-bytevector-n!
 | 
						|
    get-bytevector-some get-bytevector-all 
 | 
						|
    ;port-has-port-position? port-position
 | 
						|
    ;port-has-set-port-position!? set-port-position!
 | 
						|
    call-with-port
 | 
						|
    flush-output-port
 | 
						|
    put-u8 put-bytevector
 | 
						|
    put-char write-char
 | 
						|
    put-string
 | 
						|
    open-bytevector-output-port
 | 
						|
    call-with-bytevector-output-port
 | 
						|
    open-string-output-port with-output-to-string
 | 
						|
    with-output-to-port
 | 
						|
    call-with-string-output-port 
 | 
						|
    open-output-string get-output-string
 | 
						|
    standard-output-port standard-error-port
 | 
						|
    current-output-port current-error-port
 | 
						|
    open-file-output-port open-output-file 
 | 
						|
    call-with-output-file with-output-to-file
 | 
						|
    console-output-port
 | 
						|
    console-error-port
 | 
						|
    console-input-port
 | 
						|
    newline
 | 
						|
    port-mode set-port-mode!
 | 
						|
    reset-input-port!
 | 
						|
    reset-output-port!
 | 
						|
    port-id
 | 
						|
    input-port-byte-position
 | 
						|
    process process-nonblocking
 | 
						|
    
 | 
						|
    tcp-connect tcp-connect-nonblocking
 | 
						|
    udp-connect udp-connect-nonblocking
 | 
						|
    tcp-server-socket tcp-server-socket-nonblocking
 | 
						|
    accept-connection accept-connection-nonblocking
 | 
						|
    close-tcp-server-socket 
 | 
						|
    register-callback
 | 
						|
    input-socket-buffer-size output-socket-buffer-size
 | 
						|
    )
 | 
						|
 | 
						|
  
 | 
						|
  (import 
 | 
						|
    (ikarus system $io)
 | 
						|
 | 
						|
    (except (ikarus)
 | 
						|
      port? input-port? output-port? textual-port? binary-port? 
 | 
						|
      open-file-input-port open-input-file 
 | 
						|
      call-with-input-file with-input-from-file
 | 
						|
      standard-input-port current-input-port
 | 
						|
      open-bytevector-input-port
 | 
						|
      open-string-input-port with-input-from-string
 | 
						|
      make-custom-binary-input-port
 | 
						|
      make-custom-binary-output-port 
 | 
						|
      make-custom-textual-input-port 
 | 
						|
      make-custom-textual-output-port 
 | 
						|
      transcoded-port port-transcoder
 | 
						|
      close-port port-closed? close-input-port close-output-port
 | 
						|
      port-eof?
 | 
						|
      get-char lookahead-char read-char peek-char
 | 
						|
      get-string-n get-string-n! get-string-all get-line
 | 
						|
      get-u8 lookahead-u8 
 | 
						|
      get-bytevector-n get-bytevector-n!
 | 
						|
      get-bytevector-some get-bytevector-all 
 | 
						|
      ;port-has-port-position? port-position
 | 
						|
      ;port-has-set-port-position!? set-port-position!
 | 
						|
      call-with-port
 | 
						|
      flush-output-port
 | 
						|
      put-u8 put-bytevector
 | 
						|
      put-char write-char
 | 
						|
      put-string
 | 
						|
      open-bytevector-output-port
 | 
						|
      call-with-bytevector-output-port
 | 
						|
      open-string-output-port with-output-to-string
 | 
						|
      call-with-string-output-port
 | 
						|
      open-output-string get-output-string
 | 
						|
      standard-output-port standard-error-port
 | 
						|
      current-output-port current-error-port
 | 
						|
      open-file-output-port open-output-file 
 | 
						|
      call-with-output-file with-output-to-file
 | 
						|
      with-output-to-port
 | 
						|
      console-output-port
 | 
						|
      console-input-port
 | 
						|
      console-error-port
 | 
						|
      newline
 | 
						|
      port-mode set-port-mode!
 | 
						|
      reset-input-port!
 | 
						|
      reset-output-port!
 | 
						|
      port-id
 | 
						|
      input-port-byte-position
 | 
						|
      process process-nonblocking
 | 
						|
      tcp-connect tcp-connect-nonblocking
 | 
						|
      udp-connect udp-connect-nonblocking
 | 
						|
      tcp-server-socket tcp-server-socket-nonblocking
 | 
						|
      accept-connection accept-connection-nonblocking
 | 
						|
      close-tcp-server-socket 
 | 
						|
      register-callback
 | 
						|
      input-socket-buffer-size output-socket-buffer-size
 | 
						|
      ))
 | 
						|
 | 
						|
  (module UNSAFE  
 | 
						|
    (fx< fx<= fx> fx>= fx= fx+ fx-
 | 
						|
     fxior fxand fxsra fxsll
 | 
						|
     integer->char char->integer
 | 
						|
     string-ref string-set! string-length
 | 
						|
     bytevector-u8-ref bytevector-u8-set!)
 | 
						|
    (import 
 | 
						|
      (rename (ikarus system $strings)
 | 
						|
        ($string-length string-length)
 | 
						|
        ($string-ref    string-ref)
 | 
						|
        ($string-set!   string-set!))
 | 
						|
      (rename (ikarus system $chars)
 | 
						|
        ($char->fixnum char->integer)
 | 
						|
        ($fixnum->char integer->char))
 | 
						|
      (rename (ikarus system $bytevectors)
 | 
						|
        ($bytevector-set!   bytevector-u8-set!)
 | 
						|
        ($bytevector-u8-ref bytevector-u8-ref))
 | 
						|
      (rename (ikarus system $fx) 
 | 
						|
        ($fxsra    fxsra)
 | 
						|
        ($fxsll    fxsll)
 | 
						|
        ($fxlogor  fxior)
 | 
						|
        ($fxlogand fxand)
 | 
						|
        ($fx+      fx+)
 | 
						|
        ($fx-      fx-)
 | 
						|
        ($fx<      fx<)
 | 
						|
        ($fx>      fx>)
 | 
						|
        ($fx>=     fx>=)
 | 
						|
        ($fx<=     fx<=)
 | 
						|
        ($fx=      fx=))))
 | 
						|
 | 
						|
  (define (port? x)
 | 
						|
    (import (only (ikarus) port?))
 | 
						|
    (port? x))
 | 
						|
 | 
						|
  (define-syntax define-rrr
 | 
						|
    (syntax-rules ()
 | 
						|
      [(_ name)
 | 
						|
       (define (name . args) 
 | 
						|
         (apply die 'name "not implemented" args))]))
 | 
						|
 
 | 
						|
  (define-syntax u8?
 | 
						|
    (let ()
 | 
						|
      (import (ikarus system $fx))
 | 
						|
      (syntax-rules ()
 | 
						|
        [(_ x) 
 | 
						|
         ($fxzero? ($fxlogand x -256))])))
 | 
						|
 | 
						|
  ;(define (u8? x) (and (fixnum? x) (fx>= x 0) (fx< x 256)))
 | 
						|
  
 | 
						|
  (define (textual-port? x) 
 | 
						|
    (fx= (fxand ($port-tag x) textual-port-tag) textual-port-tag))
 | 
						|
 | 
						|
  (define (binary-port? x) 
 | 
						|
    (fx= (fxand ($port-tag x) binary-port-tag) binary-port-tag))
 | 
						|
 | 
						|
  (define (output-port? x) 
 | 
						|
    (fx= (fxand ($port-tag x) output-port-tag) output-port-tag))
 | 
						|
 | 
						|
  (define (input-port? x)
 | 
						|
    (fx= (fxand ($port-tag x) input-port-tag) input-port-tag))
 | 
						|
 | 
						|
  ;;; everything above this line will turn into primitive
 | 
						|
  ;;; ----------------------------------------------------------
 | 
						|
  
 | 
						|
  (define input-port-tag           #b00000000000001)
 | 
						|
  (define output-port-tag          #b00000000000010)
 | 
						|
  (define textual-port-tag         #b00000000000100)
 | 
						|
  (define binary-port-tag          #b00000000001000)
 | 
						|
  (define fast-char-text-tag       #b00000000010000)
 | 
						|
  (define fast-u7-text-tag         #b00000000100000)
 | 
						|
  (define fast-u8-text-tag         #b00000001100000)
 | 
						|
  (define r6rs-mode-tag            #b01000000000000)
 | 
						|
  (define closed-port-tag          #b10000000000000)
 | 
						|
 | 
						|
  (define port-type-mask           #b00000000001111)
 | 
						|
  (define binary-input-port-bits   #b00000000001001)
 | 
						|
  (define binary-output-port-bits  #b00000000001010)
 | 
						|
  (define textual-input-port-bits  #b00000000000101)
 | 
						|
  (define textual-output-port-bits #b00000000000110)
 | 
						|
 | 
						|
  (define fast-get-byte-tag        #b00000000001001)
 | 
						|
  (define fast-get-char-tag        #b00000000010101)
 | 
						|
  (define fast-get-utf8-tag        #b00000000100101)
 | 
						|
  (define fast-get-latin-tag       #b00000001100101)
 | 
						|
 | 
						|
  (define fast-put-byte-tag        #b00000000001010)
 | 
						|
  (define fast-put-char-tag        #b00000000010110)
 | 
						|
  (define fast-put-utf8-tag        #b00000000100110)
 | 
						|
  (define fast-put-latin-tag       #b00000001100110)
 | 
						|
 | 
						|
  (define fast-attrs-mask          #xFFF)
 | 
						|
  (define-syntax $port-fast-attrs
 | 
						|
    (identifier-syntax
 | 
						|
      (lambda (x) 
 | 
						|
        (import (ikarus system $fx))
 | 
						|
        ($fxlogand ($port-tag x) fast-attrs-mask))))
 | 
						|
 | 
						|
  (define (port-id p)
 | 
						|
    (if (port? p) 
 | 
						|
        ($port-id p)
 | 
						|
        (die 'port-id "not a port" p)))
 | 
						|
 | 
						|
  (define (input-port-byte-position p)
 | 
						|
    (if (input-port? p) 
 | 
						|
        (let ([pos ($port-position p)])
 | 
						|
          (and pos (fx+ pos (fx+ ($port-index p) 1))))
 | 
						|
        (error 'input-port-byte-position "not an input port" p)))
 | 
						|
 | 
						|
  (define guarded-port
 | 
						|
    (let ([G (make-guardian)])
 | 
						|
      (define (clean-up)
 | 
						|
        (cond
 | 
						|
          [(G) =>
 | 
						|
           (lambda (p)
 | 
						|
             (close-port p)
 | 
						|
             (clean-up))]))
 | 
						|
      (lambda (p)
 | 
						|
        (clean-up)
 | 
						|
        (when (fixnum? ($port-cookie p))
 | 
						|
          (G p))
 | 
						|
        p)))
 | 
						|
 | 
						|
  (define ($make-custom-binary-port attrs init-size id 
 | 
						|
            read! write! get-position set-position! close buffer-size)
 | 
						|
    (let ([bv (make-bytevector buffer-size)])
 | 
						|
      ($make-port attrs 0 init-size bv #f id read! write! 
 | 
						|
                  #f #f close #f)))
 | 
						|
 | 
						|
  (define ($make-custom-textual-port attrs init-size id 
 | 
						|
            read! write! get-position set-position! close buffer-size)
 | 
						|
    (let ([bv (make-string buffer-size)])
 | 
						|
      ($make-port attrs 0 init-size bv #t id read! write! 
 | 
						|
                  #f #f close #f)))
 | 
						|
 | 
						|
  (define (make-custom-binary-input-port id 
 | 
						|
            read! get-position set-position! close)
 | 
						|
    ;;; FIXME: get-position and set-position! are ignored for now
 | 
						|
    (define who 'make-custom-binary-input-port)
 | 
						|
    (unless (string? id)
 | 
						|
      (die who "id is not a string" id))
 | 
						|
    (unless (procedure? read!)
 | 
						|
      (die who "read! is not a procedure" read!))
 | 
						|
    (unless (or (procedure? close) (not close))
 | 
						|
      (die who "close should be either a procedure or #f" close))
 | 
						|
    ($make-custom-binary-port 
 | 
						|
      binary-input-port-bits
 | 
						|
      0
 | 
						|
      id read! #f get-position
 | 
						|
      set-position! close 256))
 | 
						|
 | 
						|
  (define (make-custom-binary-output-port id 
 | 
						|
            write! get-position set-position! close)
 | 
						|
    ;;; FIXME: get-position and set-position! are ignored for now
 | 
						|
    (define who 'make-custom-binary-output-port)
 | 
						|
    (unless (string? id)
 | 
						|
      (die who "id is not a string" id))
 | 
						|
    (unless (procedure? write!)
 | 
						|
      (die who "write! is not a procedure" write!))
 | 
						|
    (unless (or (procedure? close) (not close))
 | 
						|
      (die who "close should be either a procedure or #f" close))
 | 
						|
    ($make-custom-binary-port 
 | 
						|
      binary-output-port-bits
 | 
						|
      256
 | 
						|
      id #f write! get-position
 | 
						|
      set-position! close 256))
 | 
						|
 | 
						|
  (define (make-custom-textual-input-port id 
 | 
						|
            read! get-position set-position! close)
 | 
						|
    ;;; FIXME: get-position and set-position! are ignored for now
 | 
						|
    (define who 'make-custom-textual-input-port)
 | 
						|
    (unless (string? id)
 | 
						|
      (die who "id is not a string" id))
 | 
						|
    (unless (procedure? read!)
 | 
						|
      (die who "read! is not a procedure" read!))
 | 
						|
    (unless (or (procedure? close) (not close))
 | 
						|
      (die who "close should be either a procedure or #f" close))
 | 
						|
    ($make-custom-textual-port 
 | 
						|
      (fxior textual-input-port-bits fast-char-text-tag)
 | 
						|
      0
 | 
						|
      id read! #f get-position
 | 
						|
      set-position! close 256))
 | 
						|
 | 
						|
  (define (make-custom-textual-output-port id 
 | 
						|
            write! get-position set-position! close)
 | 
						|
    ;;; FIXME: get-position and set-position! are ignored for now
 | 
						|
    (define who 'make-custom-textual-output-port)
 | 
						|
    (unless (string? id)
 | 
						|
      (die who "id is not a string" id))
 | 
						|
    (unless (procedure? write!)
 | 
						|
      (die who "write! is not a procedure" write!))
 | 
						|
    (unless (or (procedure? close) (not close))
 | 
						|
      (die who "close should be either a procedure or #f" close))
 | 
						|
    ($make-custom-textual-port 
 | 
						|
      (fxior textual-output-port-bits fast-char-text-tag)
 | 
						|
      256
 | 
						|
      id #f write! get-position
 | 
						|
      set-position! close 256))
 | 
						|
 | 
						|
 | 
						|
 | 
						|
  (define (input-transcoder-attrs x who)
 | 
						|
    (cond
 | 
						|
      [(not x) ;;; binary input port
 | 
						|
       binary-input-port-bits]
 | 
						|
      [(not (eq? 'none (transcoder-eol-style x)))
 | 
						|
       (die who "unsupported transcoder eol-style" 
 | 
						|
            (transcoder-eol-style x))]
 | 
						|
      [(eq? 'latin-1-codec (transcoder-codec x))
 | 
						|
       (fxior textual-input-port-bits fast-u8-text-tag)]
 | 
						|
      ;;; attrs for utf-8-codec are set as part of the 
 | 
						|
      ;;; bom-reading dance when the first char is read.
 | 
						|
      [else textual-input-port-bits]))
 | 
						|
 | 
						|
  (define (output-transcoder-attrs x who)
 | 
						|
    (cond
 | 
						|
      [(not x) ;;; binary input port
 | 
						|
       binary-output-port-bits]
 | 
						|
      [(not (eq? 'none (transcoder-eol-style x)))
 | 
						|
       (die who "unsupported transcoder eol-style" 
 | 
						|
            (transcoder-eol-style x))]
 | 
						|
      [(eq? 'latin-1-codec (transcoder-codec x))
 | 
						|
       (fxior textual-output-port-bits fast-u8-text-tag)]
 | 
						|
      [(eq? 'utf-8-codec (transcoder-codec x))
 | 
						|
       (fxior textual-output-port-bits fast-u7-text-tag)]
 | 
						|
      [else textual-output-port-bits]))
 | 
						|
 | 
						|
  (define open-bytevector-input-port
 | 
						|
    (case-lambda
 | 
						|
      [(bv) (open-bytevector-input-port bv #f)]
 | 
						|
      [(bv maybe-transcoder) 
 | 
						|
       (unless (bytevector? bv) 
 | 
						|
         (die 'open-bytevector-input-port 
 | 
						|
                "not a bytevector" bv))
 | 
						|
       (when (and maybe-transcoder
 | 
						|
                  (not (transcoder? maybe-transcoder)))
 | 
						|
         (die 'open-bytevector-input-port 
 | 
						|
                "not a transcoder" maybe-transcoder))
 | 
						|
       ($make-port 
 | 
						|
          (input-transcoder-attrs maybe-transcoder
 | 
						|
            'open-bytevector-output-port)
 | 
						|
          0 (bytevector-length bv) bv 
 | 
						|
          maybe-transcoder 
 | 
						|
          "*bytevector-input-port*" 
 | 
						|
          (lambda (bv i c) 0) ;;; read!
 | 
						|
          #f ;;; write!
 | 
						|
          #f ;;; FIXME: get-position
 | 
						|
          #f ;;; FIXME: set-position!
 | 
						|
          #f ;;; close
 | 
						|
          #f)]))
 | 
						|
 | 
						|
  (define open-bytevector-output-port
 | 
						|
    (case-lambda
 | 
						|
      [() (open-bytevector-output-port #f)]
 | 
						|
      [(transcoder) 
 | 
						|
       (define who 'open-bytevector-output-port)
 | 
						|
       (unless (or (not transcoder) (transcoder? transcoder))
 | 
						|
         (die who "invalid transcoder value" transcoder))
 | 
						|
       (let ([buf* '()] [buffer-size 256])
 | 
						|
         (let ([p 
 | 
						|
                ($make-port 
 | 
						|
                   (output-transcoder-attrs transcoder
 | 
						|
                     'open-bytevector-output-port)
 | 
						|
                   0 buffer-size (make-bytevector buffer-size)
 | 
						|
                   transcoder
 | 
						|
                   "*bytevector-output-port*"
 | 
						|
                   #f
 | 
						|
                   (lambda (bv i c) 
 | 
						|
                     (unless (= c 0) 
 | 
						|
                       (let ([x (make-bytevector c)])
 | 
						|
                         (bytevector-copy! bv i x 0 c)
 | 
						|
                         (set! buf* (cons x buf*))))
 | 
						|
                     c)
 | 
						|
                   #f  ;;; FIXME: get-position
 | 
						|
                   #f  ;;; FIXME: set-position!
 | 
						|
                   #f
 | 
						|
                   #f)])
 | 
						|
           (values
 | 
						|
             p
 | 
						|
             (lambda () 
 | 
						|
               (define (append-bv-buf* ls) 
 | 
						|
                 (let f ([ls ls] [i 0])
 | 
						|
                   (cond
 | 
						|
                     [(null? ls) 
 | 
						|
                      (values (make-bytevector i) 0)]
 | 
						|
                     [else 
 | 
						|
                      (let* ([a (car ls)]
 | 
						|
                             [n (bytevector-length a)])
 | 
						|
                        (let-values ([(bv i) (f (cdr ls) (fx+ i n))])
 | 
						|
                          (bytevector-copy! a 0 bv i n)
 | 
						|
                          (values bv (fx+ i n))))])))
 | 
						|
               (unless ($port-closed? p)
 | 
						|
                 (flush-output-port p))
 | 
						|
               (let-values ([(bv len) (append-bv-buf* buf*)])
 | 
						|
                 (set! buf* '())
 | 
						|
                 bv)))))]))
 | 
						|
 | 
						|
  (define call-with-bytevector-output-port
 | 
						|
    (case-lambda
 | 
						|
      [(proc) (call-with-bytevector-output-port proc #f)]
 | 
						|
      [(proc transcoder) 
 | 
						|
       (define who 'call-with-bytevector-output-port)
 | 
						|
       (unless (procedure? proc) 
 | 
						|
         (die who "not a procedure" proc))
 | 
						|
       (unless (or (not transcoder) (transcoder? transcoder))
 | 
						|
         (die who "invalid transcoder argument" transcoder))
 | 
						|
       (let-values ([(p extract) 
 | 
						|
                     (open-bytevector-output-port transcoder)])
 | 
						|
         (proc p)
 | 
						|
         (extract))]))
 | 
						|
 | 
						|
  (define (call-with-string-output-port proc)
 | 
						|
    (define who 'call-with-string-output-port)
 | 
						|
    (unless (procedure? proc) 
 | 
						|
      (die who "not a procedure" proc))
 | 
						|
    (let-values ([(p extract) (open-string-output-port)])
 | 
						|
      (proc p)
 | 
						|
      (extract)))
 | 
						|
 | 
						|
  (define (with-output-to-string proc) 
 | 
						|
    (define who 'with-output-to-string)
 | 
						|
    (unless (procedure? proc) 
 | 
						|
      (die who "not a procedure" proc))
 | 
						|
    (let-values ([(p extract) (open-string-output-port)])
 | 
						|
      (parameterize ([*the-output-port* p])
 | 
						|
        (proc))
 | 
						|
      (extract)))
 | 
						|
 | 
						|
  (define (with-output-to-port p proc)
 | 
						|
    (define who 'with-output-to-port)
 | 
						|
    (unless (procedure? proc)
 | 
						|
      (die who "not a procedure" proc))
 | 
						|
    (unless (output-port? p) 
 | 
						|
      (die who "not an output port" p))
 | 
						|
    (unless (textual-port? p)
 | 
						|
      (die who "not a textual port" p))
 | 
						|
    (parameterize ([*the-output-port* p])
 | 
						|
      (proc)))
 | 
						|
 | 
						|
  (define-struct output-string-cookie (strings))
 | 
						|
 | 
						|
 | 
						|
  (define (open-output-string)
 | 
						|
    (define who 'open-output-string)
 | 
						|
    (let ([cookie (make-output-string-cookie '())]
 | 
						|
          [buffer-size 256])
 | 
						|
      ($make-port
 | 
						|
         (fxior textual-output-port-bits fast-char-text-tag)
 | 
						|
         0 buffer-size (make-string buffer-size)
 | 
						|
         #t ;;; transcoder
 | 
						|
         "*string-output-port*"
 | 
						|
         #f
 | 
						|
         (lambda (str i c) 
 | 
						|
           (unless (= c 0) 
 | 
						|
             (let ([x (make-string c)])
 | 
						|
               (string-copy! str i x 0 c)
 | 
						|
               (set-output-string-cookie-strings! cookie
 | 
						|
                 (cons x (output-string-cookie-strings cookie)))))
 | 
						|
           c)
 | 
						|
         #f  ;;; FIXME: get-position
 | 
						|
         #f  ;;; FIXME: set-position!
 | 
						|
         #f
 | 
						|
         cookie)))
 | 
						|
 | 
						|
  (define (open-string-output-port)
 | 
						|
    (let ([p (open-output-string)])
 | 
						|
      (values
 | 
						|
        p
 | 
						|
        (lambda ()
 | 
						|
          (let ([str (get-output-string p)])
 | 
						|
            (set-output-string-cookie-strings!  ($port-cookie p) '())
 | 
						|
            str)))))
 | 
						|
 | 
						|
  (define (get-output-string-cookie-data cookie)
 | 
						|
    (define (append-str-buf* ls) 
 | 
						|
      (let f ([ls ls] [i 0])
 | 
						|
        (cond
 | 
						|
          [(null? ls) 
 | 
						|
           (values (make-string i) 0)]
 | 
						|
          [else 
 | 
						|
           (let* ([a (car ls)]
 | 
						|
                  [n (string-length a)])
 | 
						|
             (let-values ([(bv i) (f (cdr ls) (fx+ i n))])
 | 
						|
               (string-copy! a 0 bv i n)
 | 
						|
               (values bv (fx+ i n))))])))
 | 
						|
      (let ([buf* (output-string-cookie-strings cookie)])
 | 
						|
        (let-values ([(bv len) (append-str-buf* buf*)])
 | 
						|
          bv)))
 | 
						|
 | 
						|
  (define (get-output-string p)
 | 
						|
    (if (port? p) 
 | 
						|
        (let ([cookie ($port-cookie p)])
 | 
						|
          (cond
 | 
						|
            [(output-string-cookie? cookie)
 | 
						|
             (unless ($port-closed? p)
 | 
						|
               (flush-output-port p))
 | 
						|
             (get-output-string-cookie-data cookie)]
 | 
						|
            [else
 | 
						|
             (die 'get-output-string "not an output-string port" p)]))
 | 
						|
        (die 'get-output-string "not a port" p)))
 | 
						|
 | 
						|
  (define (open-string-input-port str)
 | 
						|
    (unless (string? str) 
 | 
						|
      (die 'open-string-input-port "not a string" str))
 | 
						|
    ($make-port 
 | 
						|
       (fxior textual-input-port-bits fast-char-text-tag)
 | 
						|
       0 (string-length str) str
 | 
						|
       #t ;;; transcoder
 | 
						|
       "*string-input-port*" 
 | 
						|
       (lambda (str i c) 0) ;;; read!
 | 
						|
       #f ;;; write!
 | 
						|
       #f ;;; FIXME: get-position
 | 
						|
       #f ;;; FIXME: set-position!
 | 
						|
       #f ;;; close
 | 
						|
       #f))
 | 
						|
    
 | 
						|
 | 
						|
  (define (transcoded-port p transcoder)
 | 
						|
    (define who 'transcoded-port)
 | 
						|
    (unless (transcoder? transcoder)
 | 
						|
      (die who "not a transcoder" transcoder))
 | 
						|
    (unless (port? p) (die who "not a port" p))
 | 
						|
    (when ($port-transcoder p) (die who "not a binary port" p))
 | 
						|
    (when ($port-closed? p) (die who "cannot transcode closed port" p))
 | 
						|
    (let ([read! ($port-read! p)]
 | 
						|
          [write! ($port-write! p)])
 | 
						|
      ($mark-port-closed! p)
 | 
						|
      (guarded-port
 | 
						|
        ($make-port 
 | 
						|
          (cond
 | 
						|
            [read! (input-transcoder-attrs transcoder
 | 
						|
                     'transcoded-port)]
 | 
						|
            [write! (output-transcoder-attrs transcoder
 | 
						|
                      'transcoded-port)]
 | 
						|
            [else
 | 
						|
             (die 'transcoded-port 
 | 
						|
               "port is neither input nor output!")])
 | 
						|
          ($port-index p)
 | 
						|
          ($port-size p)
 | 
						|
          ($port-buffer p)
 | 
						|
          transcoder
 | 
						|
          ($port-id p)
 | 
						|
          read!
 | 
						|
          write!
 | 
						|
          ($port-get-position p)
 | 
						|
          ($port-set-position! p)
 | 
						|
          ($port-close p)
 | 
						|
          ($port-cookie p)))))
 | 
						|
 | 
						|
  (define (reset-input-port! p)
 | 
						|
    (if (input-port? p) 
 | 
						|
        (begin
 | 
						|
          ($set-port-index! p ($port-size p))
 | 
						|
          (unregister-callback p))
 | 
						|
        (die 'reset-input-port! "not an input port" p)))
 | 
						|
 | 
						|
  (define (reset-output-port! p)
 | 
						|
    (if (output-port? p) 
 | 
						|
        (begin
 | 
						|
          ($set-port-index! p 0)
 | 
						|
          (unregister-callback p))
 | 
						|
        (die 'reset-output-port! "not an output port" p)))
 | 
						|
 | 
						|
 | 
						|
  (define (port-transcoder p)
 | 
						|
    (if (port? p)
 | 
						|
        (let ([tr ($port-transcoder p)])
 | 
						|
          (and (transcoder? tr) tr))
 | 
						|
        (die 'port-transcoder "not a port" p)))
 | 
						|
              
 | 
						|
  (define ($port-closed? p) 
 | 
						|
    (import UNSAFE)
 | 
						|
    (not (fx= (fxand ($port-attrs p) closed-port-tag) 0)))
 | 
						|
 | 
						|
  (define (port-closed? p) 
 | 
						|
    (if (port? p) 
 | 
						|
        ($port-closed? p) 
 | 
						|
        (error 'port-closed? "not a port" p)))
 | 
						|
 | 
						|
  (define ($mark-port-closed! p) 
 | 
						|
    ($set-port-attrs! p 
 | 
						|
      (fxior closed-port-tag 
 | 
						|
             (fxand ($port-attrs p) port-type-mask))))
 | 
						|
 | 
						|
 | 
						|
  (define (port-mode p)
 | 
						|
    (if (port? p) 
 | 
						|
        (if (fxzero? (fxand ($port-attrs p) r6rs-mode-tag))
 | 
						|
            'ikarus-mode
 | 
						|
            'r6rs-mode)
 | 
						|
        (die 'port-mode "not a port" p)))
 | 
						|
 | 
						|
  (define (set-port-mode! p mode)
 | 
						|
    (if (port? p) 
 | 
						|
        (case mode
 | 
						|
          [(r6rs-mode) 
 | 
						|
           ($set-port-attrs! p
 | 
						|
             (fxior ($port-attrs p) r6rs-mode-tag))]
 | 
						|
          [(ikarus-mode)
 | 
						|
           ($set-port-attrs! p
 | 
						|
             (fxand ($port-attrs p) (fxnot r6rs-mode-tag)))]
 | 
						|
          [else (die 'set-port-mode! "invalid mode" mode)])
 | 
						|
        (die 'set-port-mode! "not a port" p)))
 | 
						|
 | 
						|
 | 
						|
  (define flush-output-port
 | 
						|
    (case-lambda
 | 
						|
      [() (flush-output-port (*the-output-port*))] 
 | 
						|
      [(p)
 | 
						|
       (import UNSAFE)
 | 
						|
       (unless (output-port? p) 
 | 
						|
         (die 'flush-output-port "not an output port" p))
 | 
						|
       (when ($port-closed? p) 
 | 
						|
         (die 'flush-output-port "port is closed" p))
 | 
						|
       (let ([idx ($port-index p)]
 | 
						|
             [buf ($port-buffer p)])
 | 
						|
         (unless (fx= idx 0)
 | 
						|
           (let ([bytes (($port-write! p) buf 0 idx)])
 | 
						|
             (unless (and (fixnum? bytes) (fx>= bytes 0) (fx<= bytes idx))
 | 
						|
               (die 'flush-output-port 
 | 
						|
                      "write! returned an invalid value" 
 | 
						|
                      bytes))
 | 
						|
             (cond
 | 
						|
               [(fx= bytes idx) 
 | 
						|
                ($set-port-index! p 0)]
 | 
						|
               [(fx= bytes 0) 
 | 
						|
                ($mark-port-closed! p)
 | 
						|
                (die 'flush-output-port "could not write bytes to sink")]
 | 
						|
               [else
 | 
						|
                (bytevector-copy! buf bytes buf 0 (fx- idx bytes))
 | 
						|
                ($set-port-index! p (fx- idx bytes))
 | 
						|
                (flush-output-port p)]))))]))
 | 
						|
 | 
						|
  (define ($close-port p)
 | 
						|
    (cond
 | 
						|
      [($port-closed? p) (void)]
 | 
						|
      [else
 | 
						|
       (when ($port-write! p)
 | 
						|
         (flush-output-port p))
 | 
						|
       ($mark-port-closed! p)
 | 
						|
       (let ([close ($port-close p)])
 | 
						|
         (when (procedure? close)
 | 
						|
           (close)))]))
 | 
						|
 | 
						|
  (define (close-port p)
 | 
						|
    (unless (port? p)
 | 
						|
       (die 'close-port "not a port" p))
 | 
						|
    ($close-port p))
 | 
						|
 | 
						|
  (define (close-input-port p)
 | 
						|
    (unless (input-port? p)
 | 
						|
       (die 'close-input-port "not an input port" p))
 | 
						|
    ($close-port p))
 | 
						|
 | 
						|
  (define (close-output-port p)
 | 
						|
    (unless (output-port? p)
 | 
						|
       (die 'close-output-port "not an output port" p))
 | 
						|
    ($close-port p))
 | 
						|
 | 
						|
  ;(define-rrr port-has-port-position?)
 | 
						|
  ;(define-rrr port-position)
 | 
						|
  ;(define-rrr port-has-set-port-position!?)
 | 
						|
  ;(define-rrr set-port-position!)
 | 
						|
 | 
						|
  (define (refill-bv-buffer p who)
 | 
						|
    (when ($port-closed? p) (die who "port is closed" p))
 | 
						|
    (let ([bv ($port-buffer p)] [i ($port-index p)] [j ($port-size p)])
 | 
						|
      (let ([c0 (fx- j i)])
 | 
						|
        (unless (fx= c0 0) (bytevector-copy! bv i bv 0 c0))
 | 
						|
        (let ([pos ($port-position p)])
 | 
						|
          (when pos
 | 
						|
            ($set-port-position! p (fx+ pos i))))
 | 
						|
        (let* ([max (fx- (bytevector-length bv) c0)]
 | 
						|
               [c1 (($port-read! p) bv c0 max)])
 | 
						|
          (unless (fixnum? c1)
 | 
						|
            (die who "invalid return value from read! procedure" c1))
 | 
						|
          (cond
 | 
						|
            [(fx>= j 0)
 | 
						|
             (unless (fx<= j max)
 | 
						|
               (die who "read! returned a value out of range" j))
 | 
						|
             ($set-port-index! p c0)
 | 
						|
             ($set-port-size! p (fx+ c1 c0))
 | 
						|
             c1]
 | 
						|
            [else 
 | 
						|
             (die who "read! returned a value out of range" c1)])))))
 | 
						|
 | 
						|
  ;;; ----------------------------------------------------------
 | 
						|
  (module (read-char get-char lookahead-char)
 | 
						|
    (import UNSAFE)
 | 
						|
    (define (get-char-latin-mode p who inc)
 | 
						|
      (let ([n (refill-bv-buffer p who)])
 | 
						|
        (cond
 | 
						|
          [(fx= n 0) (eof-object)]
 | 
						|
          [else 
 | 
						|
           (let ([idx ($port-index p)])
 | 
						|
             ($set-port-index! p (fx+ idx inc))
 | 
						|
             (integer->char (bytevector-u8-ref ($port-buffer p) idx)))])))
 | 
						|
    (define (get-char-utf8-mode p who)
 | 
						|
      (define (do-error p who)
 | 
						|
        (case (transcoder-error-handling-mode ($port-transcoder p))
 | 
						|
          [(ignore)  (get-char p)]
 | 
						|
          [(replace) #\xFFFD]
 | 
						|
          [(raise)
 | 
						|
           (raise (make-i/o-decoding-error p))]
 | 
						|
          [else (die who "cannot happen")]))
 | 
						|
      (let ([i ($port-index p)] 
 | 
						|
            [j ($port-size p)]
 | 
						|
            [buf ($port-buffer p)])
 | 
						|
        (cond
 | 
						|
          [(fx= i j) ;;; exhausted
 | 
						|
           (let ([bytes (refill-bv-buffer p who)])
 | 
						|
             (cond
 | 
						|
               [(fx= bytes 0) (eof-object)]
 | 
						|
               [else (get-char p)]))]
 | 
						|
          [else
 | 
						|
           (let ([b0 (bytevector-u8-ref buf i)])
 | 
						|
             (cond
 | 
						|
               [(fx= (fxsra b0 5) #b110) ;;; two-byte-encoding
 | 
						|
                (let ([i (fx+ i 1)])
 | 
						|
                  (cond
 | 
						|
                    [(fx< i j) 
 | 
						|
                     (let ([b1 (bytevector-u8-ref buf i)])
 | 
						|
                       (cond
 | 
						|
                         [(fx= (fxsra b1 6) #b10)
 | 
						|
                          ($set-port-index! p (fx+ i 1))
 | 
						|
                          (integer->char
 | 
						|
                            (fxior (fxand b1 #b111111)
 | 
						|
                                   (fxsll (fxand b0 #b11111) 6)))]
 | 
						|
                         [else
 | 
						|
                          ($set-port-index! p i)
 | 
						|
                          (do-error p who)]))]
 | 
						|
                    [else
 | 
						|
                     (let ([bytes (refill-bv-buffer p who)])
 | 
						|
                       (cond
 | 
						|
                         [(fx= bytes 0) 
 | 
						|
                          ($set-port-index! p (fx+ ($port-index p) 1))
 | 
						|
                          (do-error p who)]
 | 
						|
                         [else (get-char-utf8-mode p who)]))]))]
 | 
						|
               [(fx= (fxsra b0 4) #b1110) ;;; three-byte-encoding
 | 
						|
                (cond
 | 
						|
                  [(fx< (fx+ i 2) j) 
 | 
						|
                   (let ([b1 (bytevector-u8-ref buf (fx+ i 1))]
 | 
						|
                         [b2 (bytevector-u8-ref buf (fx+ i 2))])
 | 
						|
                     (cond
 | 
						|
                       [(fx= (fxsra (fxlogor b1 b2) 6) #b10) 
 | 
						|
                        (let ([n (fxlogor 
 | 
						|
                                   (fxsll (fxand b0 #b1111) 12)
 | 
						|
                                   (fxsll (fxand b1 #b111111) 6)
 | 
						|
                                   (fxand b2 #b111111))])
 | 
						|
                          (cond
 | 
						|
                            [(and (fx<= #xD800 n) (fx<= n #xDFFF))
 | 
						|
                             ($set-port-index! p (fx+ i 1))
 | 
						|
                             (do-error p who)]
 | 
						|
                            [else
 | 
						|
                             ($set-port-index! p (fx+ i 3))
 | 
						|
                             (integer->char n)]))]
 | 
						|
                       [else
 | 
						|
                        ($set-port-index! p (fx+ i 1))
 | 
						|
                        (do-error p who)]))]
 | 
						|
                  [else
 | 
						|
                   (let ([bytes (refill-bv-buffer p who)])
 | 
						|
                     (cond
 | 
						|
                       [(fx= bytes 0)
 | 
						|
                        ($set-port-index! p (fx+ ($port-index p) 1))
 | 
						|
                        (do-error p who)]
 | 
						|
                       [else (get-char-utf8-mode p who)]))])]
 | 
						|
               [(fx= (fxsra b0 3) #b11110) ;;; four-byte-encoding
 | 
						|
                (cond
 | 
						|
                  [(fx< (fx+ i 3) j) 
 | 
						|
                   (let ([b1 (bytevector-u8-ref buf (fx+ i 1))]
 | 
						|
                         [b2 (bytevector-u8-ref buf (fx+ i 2))]
 | 
						|
                         [b3 (bytevector-u8-ref buf (fx+ i 3))])
 | 
						|
                     (cond
 | 
						|
                       [(fx= (fxsra (fxlogor b1 b2 b3) 6) #b10)
 | 
						|
                        (let ([n (fxlogor 
 | 
						|
                                   (fxsll (fxand b0 #b111) 18)
 | 
						|
                                   (fxsll (fxand b1 #b111111) 12)
 | 
						|
                                   (fxsll (fxand b2 #b111111) 6)
 | 
						|
                                   (fxand b3 #b111111))])
 | 
						|
                          (cond
 | 
						|
                            [(and (fx<= #x10000 n) (fx<= n #x10FFFF))
 | 
						|
                             ($set-port-index! p (fx+ i 4))
 | 
						|
                             (integer->char n)]
 | 
						|
                            [else
 | 
						|
                             ($set-port-index! p (fx+ i 1))
 | 
						|
                             (do-error p who)]))]
 | 
						|
                       [else
 | 
						|
                        ($set-port-index! p (fx+ i 1))
 | 
						|
                        (do-error p who)]))]
 | 
						|
                  [else
 | 
						|
                   (let ([bytes (refill-bv-buffer p who)])
 | 
						|
                     (cond
 | 
						|
                       [(fx= bytes 0)
 | 
						|
                        ($set-port-index! p (fx+ ($port-index p) 1))
 | 
						|
                        (do-error p who)]
 | 
						|
                       [else (get-char-utf8-mode p who)]))])]
 | 
						|
               [else 
 | 
						|
                ($set-port-index! p (fx+ i 1))
 | 
						|
                (do-error p who)]))])))
 | 
						|
    
 | 
						|
    (define (lookahead-char-utf8-mode p who)
 | 
						|
      (define (do-error p who)
 | 
						|
        (case (transcoder-error-handling-mode ($port-transcoder p))
 | 
						|
          [(ignore)  (get-char p)]
 | 
						|
          [(replace) #\xFFFD]
 | 
						|
          [(raise)
 | 
						|
           (raise (make-i/o-decoding-error p))]
 | 
						|
          [else (die who "cannot happen")]))
 | 
						|
      (let ([i ($port-index p)] 
 | 
						|
            [j ($port-size p)]
 | 
						|
            [buf ($port-buffer p)])
 | 
						|
        (cond
 | 
						|
          [(fx= i j) ;;; exhausted
 | 
						|
           (let ([bytes (refill-bv-buffer p who)])
 | 
						|
             (cond
 | 
						|
               [(fx= bytes 0) (eof-object)]
 | 
						|
               [else (lookahead-char p)]))]
 | 
						|
          [else
 | 
						|
           (let ([b0 (bytevector-u8-ref buf i)])
 | 
						|
             (cond
 | 
						|
               [(fx= (fxsra b0 5) #b110) ;;; two-byte-encoding
 | 
						|
                (let ([i (fx+ i 1)])
 | 
						|
                  (cond
 | 
						|
                    [(fx< i j) 
 | 
						|
                     (let ([b1 (bytevector-u8-ref buf i)])
 | 
						|
                       (cond
 | 
						|
                         [(fx= (fxsra b1 6) #b10)
 | 
						|
                          (integer->char
 | 
						|
                            (fxior (fxand b1 #b111111)
 | 
						|
                                   (fxsll (fxand b0 #b11111) 6)))]
 | 
						|
                         [else
 | 
						|
                          (do-error p who)]))]
 | 
						|
                    [else
 | 
						|
                     (let ([bytes (refill-bv-buffer p who)])
 | 
						|
                       (cond
 | 
						|
                         [(fx= bytes 0) (do-error p who)]
 | 
						|
                         [else (lookahead-char-utf8-mode p who)]))]))]
 | 
						|
               [(fx= (fxsra b0 4) #b1110) ;;; three-byte-encoding
 | 
						|
                (cond
 | 
						|
                  [(fx< (fx+ i 2) j) 
 | 
						|
                   (let ([b1 (bytevector-u8-ref buf (fx+ i 1))]
 | 
						|
                         [b2 (bytevector-u8-ref buf (fx+ i 2))])
 | 
						|
                     (cond
 | 
						|
                       [(fx= (fxsra (fxlogor b1 b2) 6) #b10) 
 | 
						|
                        (let ([n (fxlogor 
 | 
						|
                                   (fxsll (fxand b0 #b1111) 12)
 | 
						|
                                   (fxsll (fxand b1 #b111111) 6)
 | 
						|
                                   (fxand b2 #b111111))])
 | 
						|
                          (cond
 | 
						|
                            [(and (fx<= #xD800 n) (fx<= n #xDFFF))
 | 
						|
                             (do-error p who)]
 | 
						|
                            [else (integer->char n)]))]
 | 
						|
                       [else (do-error p who)]))]
 | 
						|
                  [else
 | 
						|
                   (let ([bytes (refill-bv-buffer p who)])
 | 
						|
                     (cond
 | 
						|
                       [(fx= bytes 0) (do-error p who)]
 | 
						|
                       [else (lookahead-char-utf8-mode p who)]))])]
 | 
						|
               [(fx= (fxsra b0 3) #b11110) ;;; four-byte-encoding
 | 
						|
                (cond
 | 
						|
                  [(fx< (fx+ i 3) j) 
 | 
						|
                   (let ([b1 (bytevector-u8-ref buf (fx+ i 1))]
 | 
						|
                         [b2 (bytevector-u8-ref buf (fx+ i 2))]
 | 
						|
                         [b3 (bytevector-u8-ref buf (fx+ i 3))])
 | 
						|
                     (cond
 | 
						|
                       [(fx= (fxsra (fxlogor b1 b2 b3) 6) #b10)
 | 
						|
                        (let ([n (fxlogor 
 | 
						|
                                   (fxsll (fxand b0 #b111) 18)
 | 
						|
                                   (fxsll (fxand b1 #b111111) 12)
 | 
						|
                                   (fxsll (fxand b2 #b111111) 6)
 | 
						|
                                   (fxand b3 #b111111))])
 | 
						|
                          (cond
 | 
						|
                            [(and (fx<= #x10000 n) (fx<= n #x10FFFF))
 | 
						|
                             (integer->char n)]
 | 
						|
                            [else
 | 
						|
                             (do-error p who)]))]
 | 
						|
                       [else
 | 
						|
                        (do-error p who)]))]
 | 
						|
                  [else
 | 
						|
                   (let ([bytes (refill-bv-buffer p who)])
 | 
						|
                     (cond
 | 
						|
                       [(fx= bytes 0)
 | 
						|
                        (do-error p who)]
 | 
						|
                       [else (lookahead-char-utf8-mode p who)]))])]
 | 
						|
               [else (do-error p who)]))])))
 | 
						|
    ;;;
 | 
						|
    (define (advance-bom p who bom-seq)
 | 
						|
      ;;; return eof if port is eof, 
 | 
						|
      ;;; #t if a bom is present, updating the port index to 
 | 
						|
      ;;;    point just past the bom.
 | 
						|
      ;;; #f otherwise. 
 | 
						|
      (cond
 | 
						|
        [(fx< ($port-index p) ($port-size p))
 | 
						|
         (let f ([i 0] [ls bom-seq])
 | 
						|
           (cond
 | 
						|
             [(null? ls)
 | 
						|
              ($set-port-index! p (fx+ ($port-index p) i))
 | 
						|
              #t]
 | 
						|
             [else
 | 
						|
              (let ([idx (fx+ i ($port-index p))])
 | 
						|
                (cond
 | 
						|
                  [(fx< idx ($port-size p))
 | 
						|
                   (if (fx=? (car ls)
 | 
						|
                         (bytevector-u8-ref ($port-buffer p) idx))
 | 
						|
                       (f (fx+ i 1) (cdr ls))
 | 
						|
                       #f)]
 | 
						|
                  [else
 | 
						|
                   (let ([bytes (refill-bv-buffer p who)])
 | 
						|
                     (if (fx= bytes 0)
 | 
						|
                         #f
 | 
						|
                         (f i ls)))]))]))]
 | 
						|
        [else 
 | 
						|
         (let ([bytes (refill-bv-buffer p who)])
 | 
						|
           (if (fx= bytes 0)
 | 
						|
               (eof-object)
 | 
						|
               (advance-bom p who bom-seq)))]))
 | 
						|
    ;;;
 | 
						|
    (define (speedup-input-port p who)
 | 
						|
      ;;; returns #t if port is eof, #f otherwise
 | 
						|
      (unless (input-port? p) 
 | 
						|
        (die who "not an input port" p))
 | 
						|
      (let ([tr ($port-transcoder p)])
 | 
						|
        (unless tr 
 | 
						|
          (die who "not a textual port" p))
 | 
						|
        (case (transcoder-codec tr)
 | 
						|
          [(utf-8-codec)
 | 
						|
           ;;;
 | 
						|
           ($set-port-attrs! p 
 | 
						|
             (fxior textual-input-port-bits fast-u7-text-tag))
 | 
						|
           (eof-object? (advance-bom p who '(#xEF #xBB #xBF)))]
 | 
						|
          [else 
 | 
						|
           (die 'slow-get-char
 | 
						|
              "BUG: codec not handled"
 | 
						|
              (transcoder-codec tr))])))
 | 
						|
    ;;;
 | 
						|
    (define (lookahead-char-char-mode p who)
 | 
						|
      (let ([str ($port-buffer p)]
 | 
						|
            [read! ($port-read! p)])
 | 
						|
        (let ([n (read! str 0 (string-length str))])
 | 
						|
          (unless (fixnum? n) 
 | 
						|
            (die who "invalid return value from read!" n))
 | 
						|
          (unless (<= 0 n (string-length str))
 | 
						|
            (die who "return value from read! is out of range" n))
 | 
						|
          ($set-port-index! p 0) 
 | 
						|
          ($set-port-size! p n)
 | 
						|
          (cond
 | 
						|
            [(fx= n 0)
 | 
						|
             (eof-object)]
 | 
						|
            [else
 | 
						|
             (string-ref str 0)]))))
 | 
						|
    ;;;
 | 
						|
    (define (lookahead-char p)
 | 
						|
      (define who 'lookahead-char)
 | 
						|
      (let ([m ($port-fast-attrs p)])
 | 
						|
        (cond
 | 
						|
          [(eq? m fast-get-utf8-tag)
 | 
						|
           (let ([i ($port-index p)])
 | 
						|
             (cond
 | 
						|
               [(fx< i ($port-size p))
 | 
						|
                (let ([b (bytevector-u8-ref ($port-buffer p) i)])
 | 
						|
                  (cond
 | 
						|
                    [(fx< b 128) (integer->char b)]
 | 
						|
                    [else (lookahead-char-utf8-mode p who)]))]
 | 
						|
               [else
 | 
						|
                (lookahead-char-utf8-mode p who)]))]
 | 
						|
          [(eq? m fast-get-char-tag)
 | 
						|
           (let ([i ($port-index p)])
 | 
						|
             (cond
 | 
						|
               [(fx< i ($port-size p))
 | 
						|
                (string-ref ($port-buffer p) i)]
 | 
						|
               [else
 | 
						|
                (lookahead-char-char-mode p who)]))]
 | 
						|
          [(eq? m fast-get-latin-tag)
 | 
						|
           (let ([i ($port-index p)])
 | 
						|
             (cond
 | 
						|
               [(fx< i ($port-size p))
 | 
						|
                (integer->char 
 | 
						|
                  (bytevector-u8-ref ($port-buffer p) i))]
 | 
						|
               [else
 | 
						|
                (get-char-latin-mode p who 0)]))]
 | 
						|
          [else 
 | 
						|
           (if (speedup-input-port p who)
 | 
						|
               (eof-object)
 | 
						|
               (lookahead-char p))])))
 | 
						|
    ;;;
 | 
						|
    (define (get-char-char-mode p who)
 | 
						|
      (let ([str ($port-buffer p)]
 | 
						|
            [read! ($port-read! p)])
 | 
						|
        (let ([n (read! str 0 (string-length str))])
 | 
						|
          (unless (fixnum? n) 
 | 
						|
            (die who "invalid return value from read!" n))
 | 
						|
          (unless (<= 0 n (string-length str))
 | 
						|
            (die who "return value from read! is out of range" n))
 | 
						|
          ($set-port-size! p n)
 | 
						|
          (cond
 | 
						|
            [(fx= n 0)
 | 
						|
             ($set-port-index! p 0)
 | 
						|
             (eof-object)]
 | 
						|
            [else
 | 
						|
             ($set-port-index! p 1) 
 | 
						|
             (string-ref str 0)]))))
 | 
						|
    (define read-char
 | 
						|
      (case-lambda
 | 
						|
        [(p) 
 | 
						|
         (define who 'read-char)
 | 
						|
         (let ([m ($port-fast-attrs p)])
 | 
						|
           (cond
 | 
						|
             [(eq? m fast-get-utf8-tag)
 | 
						|
              (let ([i ($port-index p)])
 | 
						|
                (cond
 | 
						|
                  [(fx< i ($port-size p))
 | 
						|
                   (let ([b (bytevector-u8-ref ($port-buffer p) i)])
 | 
						|
                     (cond
 | 
						|
                       [(fx< b 128) 
 | 
						|
                        ($set-port-index! p (fx+ i 1))
 | 
						|
                        (integer->char b)]
 | 
						|
                       [else (get-char-utf8-mode p who)]))]
 | 
						|
                  [else
 | 
						|
                   (get-char-utf8-mode p who)]))]
 | 
						|
             [(eq? m fast-get-char-tag)
 | 
						|
              (let ([i ($port-index p)])
 | 
						|
                (cond
 | 
						|
                  [(fx< i ($port-size p))
 | 
						|
                   ($set-port-index! p (fx+ i 1))
 | 
						|
                   (string-ref ($port-buffer p) i)]
 | 
						|
                  [else (get-char-char-mode p who)]))]
 | 
						|
             [(eq? m fast-get-latin-tag)
 | 
						|
              (let ([i ($port-index p)])
 | 
						|
                (cond
 | 
						|
                  [(fx< i ($port-size p))
 | 
						|
                   ($set-port-index! p (fx+ i 1))
 | 
						|
                   (integer->char 
 | 
						|
                     (bytevector-u8-ref ($port-buffer p) i))]
 | 
						|
                  [else
 | 
						|
                   (get-char-latin-mode p who 1)]))]
 | 
						|
             [else 
 | 
						|
              (if (speedup-input-port p who)
 | 
						|
                  (eof-object)
 | 
						|
                  (get-char p))]))]
 | 
						|
        [() (read-char (current-input-port))]))
 | 
						|
    (define (get-char p)
 | 
						|
      (define who 'get-char)
 | 
						|
      (let ([m ($port-fast-attrs p)])
 | 
						|
        (cond
 | 
						|
          [(eq? m fast-get-utf8-tag)
 | 
						|
           (let ([i ($port-index p)])
 | 
						|
             (cond
 | 
						|
               [(fx< i ($port-size p))
 | 
						|
                (let ([b (bytevector-u8-ref ($port-buffer p) i)])
 | 
						|
                  (cond
 | 
						|
                    [(fx< b 128) 
 | 
						|
                     ($set-port-index! p (fx+ i 1))
 | 
						|
                     (integer->char b)]
 | 
						|
                    [else (get-char-utf8-mode p who)]))]
 | 
						|
               [else
 | 
						|
                (get-char-utf8-mode p who)]))]
 | 
						|
          [(eq? m fast-get-char-tag)
 | 
						|
           (let ([i ($port-index p)])
 | 
						|
             (cond
 | 
						|
               [(fx< i ($port-size p))
 | 
						|
                ($set-port-index! p (fx+ i 1))
 | 
						|
                (string-ref ($port-buffer p) i)]
 | 
						|
               [else (get-char-char-mode p who)]))]
 | 
						|
          [(eq? m fast-get-latin-tag)
 | 
						|
           (let ([i ($port-index p)])
 | 
						|
             (cond
 | 
						|
               [(fx< i ($port-size p))
 | 
						|
                ($set-port-index! p (fx+ i 1))
 | 
						|
                (integer->char 
 | 
						|
                  (bytevector-u8-ref ($port-buffer p) i))]
 | 
						|
               [else
 | 
						|
                (get-char-latin-mode p who 1)]))]
 | 
						|
          [else 
 | 
						|
           (if (speedup-input-port p who)
 | 
						|
               (eof-object)
 | 
						|
               (get-char p))]))))
 | 
						|
 | 
						|
  ;;; ----------------------------------------------------------
 | 
						|
  (define (assert-binary-input-port p who)
 | 
						|
    (unless (port? p) (die who "not a port" p))
 | 
						|
    (when ($port-closed? p) (die who "port is closed" p))
 | 
						|
    (when ($port-transcoder p) (die who "port is not binary" p))
 | 
						|
    (unless ($port-read! p)
 | 
						|
      (die who "port is not an input port" p)))
 | 
						|
 | 
						|
  (module (get-u8 lookahead-u8)
 | 
						|
    (import UNSAFE)
 | 
						|
    (define (get-u8-byte-mode p who start) 
 | 
						|
      (when ($port-closed? p) (die who "port is closed" p))
 | 
						|
      (let* ([bv ($port-buffer p)]
 | 
						|
             [n (bytevector-length bv)])
 | 
						|
        (let ([j (($port-read! p) bv 0 n)])
 | 
						|
          (unless (fixnum? j)
 | 
						|
            (die who "invalid return value from read! procedure" j))
 | 
						|
          (cond
 | 
						|
            [(fx> j 0) 
 | 
						|
             (unless (fx<= j n)
 | 
						|
               (die who "read! returned a value out of range" j))
 | 
						|
             ($set-port-index! p start) 
 | 
						|
             ($set-port-size! p j)
 | 
						|
             (bytevector-u8-ref bv 0)]
 | 
						|
            [(fx= j 0) (eof-object)]
 | 
						|
            [else 
 | 
						|
             (die who "read! returned a value out of range" j)]))))
 | 
						|
    (define (slow-get-u8 p who start) 
 | 
						|
      (assert-binary-input-port p who)
 | 
						|
      ($set-port-attrs! p fast-get-byte-tag)
 | 
						|
      (get-u8-byte-mode p who start))
 | 
						|
    ;;;
 | 
						|
    (define (get-u8 p)
 | 
						|
      (define who 'get-u8)
 | 
						|
      (let ([m ($port-fast-attrs p)])
 | 
						|
        (cond
 | 
						|
          [(eq? m fast-get-byte-tag)
 | 
						|
           (let ([i ($port-index p)])
 | 
						|
             (cond
 | 
						|
               [(fx< i ($port-size p))
 | 
						|
                ($set-port-index! p (fx+ i 1))
 | 
						|
                (bytevector-u8-ref ($port-buffer p) i)]
 | 
						|
               [else (get-u8-byte-mode p who 1)]))]
 | 
						|
          [else (slow-get-u8 p who 1)])))
 | 
						|
    (define (lookahead-u8 p)
 | 
						|
      (define who 'lookahead-u8)
 | 
						|
      (let ([m ($port-fast-attrs p)])
 | 
						|
        (cond
 | 
						|
          [(eq? m fast-get-byte-tag)
 | 
						|
           (let ([i ($port-index p)])
 | 
						|
             (cond
 | 
						|
               [(fx< i ($port-size p))
 | 
						|
                (bytevector-u8-ref ($port-buffer p) i)]
 | 
						|
               [else (get-u8-byte-mode p who 0)]))]
 | 
						|
          [else (slow-get-u8 p who 0)]))))
 | 
						|
 | 
						|
  (define (port-eof? p)
 | 
						|
    (import UNSAFE)
 | 
						|
    (define who 'port-eof?)
 | 
						|
    (let ([m ($port-fast-attrs p)])
 | 
						|
      (cond
 | 
						|
        [(not (eq? m 0))
 | 
						|
         (if (fx< ($port-index p) ($port-size p))
 | 
						|
             #f
 | 
						|
             (if ($port-transcoder p) 
 | 
						|
                 (eof-object? (lookahead-char p))
 | 
						|
                 (eof-object? (lookahead-u8 p))))]
 | 
						|
        [(input-port? p)
 | 
						|
         (when ($port-closed? p) 
 | 
						|
           (die 'port-eof? "port is closed" p))
 | 
						|
         (if (textual-port? p) 
 | 
						|
             (eof-object? (lookahead-char p))
 | 
						|
             (eof-object? (lookahead-u8 p)))]
 | 
						|
        [else (die 'port-eof? "not an input port" p)])))
 | 
						|
 | 
						|
  (define EAGAIN-error-code -22) ;;; from ikarus-io.c
 | 
						|
  (define io-errors-vec
 | 
						|
    '#(#|  0 |# "unknown error"
 | 
						|
       #|  1 |# "bad file name"
 | 
						|
       #|  2 |# "operation interrupted"
 | 
						|
       #|  3 |# "not a directory"
 | 
						|
       #|  4 |# "file name too long"
 | 
						|
       #|  5 |# "missing entities"
 | 
						|
       #|  6 |# "insufficient access privileges"
 | 
						|
       #|  7 |# "circular path"
 | 
						|
       #|  8 |# "file is a directory"
 | 
						|
       #|  9 |# "file system is read-only"
 | 
						|
       #| 10 |# "maximum open files reached"
 | 
						|
       #| 11 |# "maximum open files reached"
 | 
						|
       #| 12 |# "ENXIO"
 | 
						|
       #| 13 |# "operation not supported"
 | 
						|
       #| 14 |# "not enough space on device"
 | 
						|
       #| 15 |# "quota exceeded"
 | 
						|
       #| 16 |# "io error"
 | 
						|
       #| 17 |# "device is busy"
 | 
						|
       #| 18 |# "access fault"
 | 
						|
       #| 19 |# "file already exists"
 | 
						|
       #| 20 |# "invalid file name"
 | 
						|
       #| 21 |# "non-blocking operation would block"
 | 
						|
       #| 22 |# "broken pipe (e.g., writing to a closed process or socket)"
 | 
						|
       #| 23 |# "connection refused"
 | 
						|
       #| 24 |# "not a socket"
 | 
						|
       #| 25 |# "not enough memory to perform operation"
 | 
						|
       ))
 | 
						|
 | 
						|
  (define (io-error who id err . other-conditions)
 | 
						|
    (let ([err (fxnot err)])
 | 
						|
      (let ([msg 
 | 
						|
             (cond
 | 
						|
               [(fx< err (vector-length io-errors-vec))
 | 
						|
                (vector-ref io-errors-vec err)]
 | 
						|
               [else "unknown error"])])
 | 
						|
        (raise 
 | 
						|
          (apply condition
 | 
						|
            (make-who-condition who)
 | 
						|
            (make-i/o-error)
 | 
						|
            (case err
 | 
						|
              [(6 9 18) (make-i/o-file-protection-error)]
 | 
						|
              [(19)     (make-i/o-file-already-exists-error id)]
 | 
						|
              [else     (condition)])
 | 
						|
            (make-message-condition msg)
 | 
						|
            (make-i/o-filename-error id)
 | 
						|
            other-conditions)))))
 | 
						|
 | 
						|
  ;(define block-size 4096)
 | 
						|
  ;(define block-size (* 4 4096))
 | 
						|
  (define input-block-size (* 4 4096))
 | 
						|
  (define output-block-size (* 4 4096))
 | 
						|
 | 
						|
  (define input-file-buffer-size (+ input-block-size 128))
 | 
						|
  (define output-file-buffer-size output-block-size)
 | 
						|
 | 
						|
  (define input-socket-buffer-size 
 | 
						|
    (make-parameter (+ input-block-size 128)
 | 
						|
      (lambda (x) 
 | 
						|
        (import (ikarus system $fx))
 | 
						|
        (if (and (fixnum? x) ($fx>= x 128))
 | 
						|
            x
 | 
						|
            (error 'input-socket-buffer-size 
 | 
						|
              "buffer size should be a fixnum >= 128"
 | 
						|
              x)))))
 | 
						|
 | 
						|
  (define output-socket-buffer-size 
 | 
						|
    (make-parameter output-block-size
 | 
						|
      (lambda (x) 
 | 
						|
        (import (ikarus system $fx))
 | 
						|
        (if (and (fixnum? x) ($fx> x 0))
 | 
						|
            x
 | 
						|
            (error 'output-socket-buffer-size 
 | 
						|
              "buffer size should be a positive fixnum"
 | 
						|
              x)))))
 | 
						|
 | 
						|
  (define (fh->input-port fd id size transcoder close who)
 | 
						|
    (letrec ([port
 | 
						|
              ($make-port 
 | 
						|
                (input-transcoder-attrs transcoder who)
 | 
						|
                0 0 (make-bytevector size)
 | 
						|
                transcoder
 | 
						|
                id
 | 
						|
                (letrec ([refill
 | 
						|
                          (lambda (bv idx cnt) 
 | 
						|
                            (import UNSAFE)
 | 
						|
                            (let ([bytes
 | 
						|
                                   (foreign-call "ikrt_read_fd" fd bv idx 
 | 
						|
                                      (if (fx< input-block-size cnt)
 | 
						|
                                          input-block-size
 | 
						|
                                          cnt))])
 | 
						|
                              (cond
 | 
						|
                                [(fx>= bytes 0) bytes]
 | 
						|
                                [(fx= bytes EAGAIN-error-code)
 | 
						|
                                 ;(raise-continuable 
 | 
						|
                                 ;  (make-i/o-would-block-condition port))
 | 
						|
                                 (call/cc 
 | 
						|
                                   (lambda (k) 
 | 
						|
                                     (add-io-event fd k 'r)
 | 
						|
                                     (process-events)))
 | 
						|
                                 (refill bv idx cnt)]
 | 
						|
                                [else 
 | 
						|
                                 (io-error 'read id bytes
 | 
						|
                                   (make-i/o-write-error))])))])
 | 
						|
                  refill)
 | 
						|
                #f ;;; write!
 | 
						|
                #f ;;; get-position
 | 
						|
                #f ;;; set-position!
 | 
						|
                (cond
 | 
						|
                  [(procedure? close) close]
 | 
						|
                  [(eqv? close #t) (file-close-proc id fd)]
 | 
						|
                  [else #f])
 | 
						|
                fd)])
 | 
						|
    (guarded-port port)))
 | 
						|
 | 
						|
  (define (fh->output-port fd id size transcoder close who)
 | 
						|
    (letrec ([port
 | 
						|
              ($make-port 
 | 
						|
                (output-transcoder-attrs transcoder who)
 | 
						|
                0 size (make-bytevector size)
 | 
						|
                transcoder
 | 
						|
                id
 | 
						|
                #f
 | 
						|
                (letrec ([refill
 | 
						|
                          (lambda (bv idx cnt) 
 | 
						|
                            (import UNSAFE)
 | 
						|
                            (let ([bytes
 | 
						|
                                   (foreign-call "ikrt_write_fd" fd bv idx
 | 
						|
                                     (if (fx< output-block-size cnt)
 | 
						|
                                         output-block-size
 | 
						|
                                         cnt))])
 | 
						|
 | 
						|
                              (cond
 | 
						|
                                [(fx>= bytes 0) bytes]
 | 
						|
                                [(fx= bytes EAGAIN-error-code)
 | 
						|
                                 ;(raise-continuable 
 | 
						|
                                 ;  (make-i/o-would-block-condition port))
 | 
						|
                                 (call/cc 
 | 
						|
                                   (lambda (k)
 | 
						|
                                     (add-io-event fd k 'w)
 | 
						|
                                     (process-events)))
 | 
						|
                                 (refill bv idx cnt)]
 | 
						|
                                [else 
 | 
						|
                                 (io-error 'write id bytes
 | 
						|
                                    (make-i/o-write-error))])))])
 | 
						|
                  refill)
 | 
						|
                #f ;;; get-position
 | 
						|
                #f ;;; set-position!
 | 
						|
                (cond
 | 
						|
                  [(procedure? close) close]
 | 
						|
                  [(eqv? close #t) (file-close-proc id fd)]
 | 
						|
                  [else #f])
 | 
						|
                fd)])
 | 
						|
      (guarded-port port)))
 | 
						|
 | 
						|
  (define (file-close-proc id fd)
 | 
						|
    (lambda () 
 | 
						|
      (cond
 | 
						|
        [(foreign-call "ikrt_close_fd" fd) =>
 | 
						|
         (lambda (err) 
 | 
						|
           (io-error 'close id err))])))
 | 
						|
 | 
						|
  (define (open-input-file-handle filename who)
 | 
						|
    (let ([fh (foreign-call "ikrt_open_input_fd"
 | 
						|
                 (string->utf8 filename))])
 | 
						|
      (cond
 | 
						|
        [(fx< fh 0) (io-error who filename fh)]
 | 
						|
        [else fh])))
 | 
						|
  
 | 
						|
  (define (open-output-file-handle filename file-options who)
 | 
						|
    (let ([opt (case file-options
 | 
						|
                 [(fo:default)                       0]
 | 
						|
                 [(fo:no-create)                     1]
 | 
						|
                 [(fo:no-fail)                       2]
 | 
						|
                 [(fo:no-fail/no-create)             3]
 | 
						|
                 [(fo:no-truncate)                   4]
 | 
						|
                 [(fo:no-truncate/no-create)         5]
 | 
						|
                 [(fo:no-truncate/no-fail)           6]
 | 
						|
                 [(fo:no-truncate/no-fail/no-create) 7]
 | 
						|
                 [else (die who "invalid file option" file-options)])])
 | 
						|
      (let ([fh (foreign-call "ikrt_open_output_fd"
 | 
						|
                   (string->utf8 filename)
 | 
						|
                   opt)])
 | 
						|
        (cond
 | 
						|
          [(fx< fh 0) (io-error who filename fh)]
 | 
						|
          [else fh]))))
 | 
						|
 | 
						|
  (define open-file-input-port
 | 
						|
    (case-lambda
 | 
						|
      [(filename) 
 | 
						|
       (open-file-input-port filename (file-options) 'block #f)]
 | 
						|
      [(filename file-options) 
 | 
						|
       (open-file-input-port filename file-options 'block #f)]
 | 
						|
      [(filename file-options buffer-mode) 
 | 
						|
       (open-file-input-port filename file-options buffer-mode #f)]
 | 
						|
      [(filename file-options buffer-mode transcoder)
 | 
						|
       (unless (string? filename)
 | 
						|
         (die 'open-file-input-port "invalid filename" filename))
 | 
						|
       (unless (or (not transcoder) (transcoder? transcoder)) 
 | 
						|
         (die 'open-file-input-port "invalid transcoder" transcoder))
 | 
						|
       ; FIXME: file-options ignored
 | 
						|
       ; FIXME: buffer-mode ignored
 | 
						|
       (fh->input-port 
 | 
						|
         (open-input-file-handle filename 'open-file-input-port)
 | 
						|
         filename
 | 
						|
         input-file-buffer-size
 | 
						|
         transcoder
 | 
						|
         #t
 | 
						|
         'open-file-input-port)]))
 | 
						|
 | 
						|
 | 
						|
  (define open-file-output-port
 | 
						|
    (case-lambda
 | 
						|
      [(filename) 
 | 
						|
       (open-file-output-port filename (file-options) 'block #f)]
 | 
						|
      [(filename file-options) 
 | 
						|
       (open-file-output-port filename file-options 'block #f)]
 | 
						|
      [(filename file-options buffer-mode) 
 | 
						|
       (open-file-output-port filename file-options buffer-mode #f)]
 | 
						|
      [(filename file-options buffer-mode transcoder)
 | 
						|
       (unless (string? filename)
 | 
						|
         (die 'open-file-output-port "invalid filename" filename))
 | 
						|
       ; FIXME: file-options ignored
 | 
						|
       ; FIXME: buffer-mode ignored
 | 
						|
       (unless (or (not transcoder) (transcoder? transcoder)) 
 | 
						|
         (die 'open-file-output-port "invalid transcoder" transcoder))
 | 
						|
       (fh->output-port
 | 
						|
         (open-output-file-handle filename file-options 
 | 
						|
            'open-file-output-port)
 | 
						|
         filename
 | 
						|
         output-file-buffer-size
 | 
						|
         transcoder
 | 
						|
         #t
 | 
						|
         'open-file-output-port)]))
 | 
						|
 | 
						|
  (define (open-output-file filename)
 | 
						|
    (unless (string? filename)
 | 
						|
      (die 'open-output-file "invalid filename" filename))
 | 
						|
    (fh->output-port 
 | 
						|
       (open-output-file-handle filename (file-options) 
 | 
						|
          'open-output-file)
 | 
						|
       filename
 | 
						|
       output-file-buffer-size
 | 
						|
       (native-transcoder)
 | 
						|
       #t
 | 
						|
       'open-output-file))
 | 
						|
 | 
						|
  (define (open-input-file filename)
 | 
						|
    (unless (string? filename)
 | 
						|
      (die 'open-input-file "invalid filename" filename))
 | 
						|
    (fh->input-port 
 | 
						|
       (open-input-file-handle filename 'open-input-file) 
 | 
						|
       filename
 | 
						|
       input-file-buffer-size
 | 
						|
       (native-transcoder)
 | 
						|
       #t
 | 
						|
       'open-input-file))
 | 
						|
 | 
						|
 | 
						|
  (define (with-output-to-file filename proc)
 | 
						|
    (unless (string? filename)
 | 
						|
      (die 'with-output-to-file "invalid filename" filename))
 | 
						|
    (unless (procedure? proc)
 | 
						|
      (die 'with-output-to-file "not a procedure" proc))
 | 
						|
    (call-with-port
 | 
						|
      (fh->output-port
 | 
						|
        (open-output-file-handle filename (file-options) 
 | 
						|
          'with-output-to-file)
 | 
						|
        filename
 | 
						|
        output-file-buffer-size
 | 
						|
        (native-transcoder)
 | 
						|
        #t
 | 
						|
        'with-output-to-file)
 | 
						|
      (lambda (p)
 | 
						|
        (parameterize ([*the-output-port* p])
 | 
						|
          (proc)))))
 | 
						|
 | 
						|
  (define (call-with-output-file filename proc)
 | 
						|
    (unless (string? filename)
 | 
						|
      (die 'call-with-output-file "invalid filename" filename))
 | 
						|
    (unless (procedure? proc)
 | 
						|
      (die 'call-with-output-file "not a procedure" proc))
 | 
						|
    (call-with-port
 | 
						|
      (fh->output-port
 | 
						|
        (open-output-file-handle filename (file-options) 
 | 
						|
          'call-with-output-file)
 | 
						|
        filename
 | 
						|
        output-file-buffer-size
 | 
						|
        (native-transcoder)
 | 
						|
        #t
 | 
						|
        'call-with-output-file)
 | 
						|
      proc))
 | 
						|
 | 
						|
  (define (call-with-input-file filename proc)
 | 
						|
    (unless (string? filename)
 | 
						|
      (die 'call-with-input-file "invalid filename" filename))
 | 
						|
    (unless (procedure? proc)
 | 
						|
      (die 'call-with-input-file "not a procedure" proc))
 | 
						|
    (call-with-port
 | 
						|
      (fh->input-port 
 | 
						|
        (open-input-file-handle filename 'call-with-input-file) 
 | 
						|
        filename
 | 
						|
        input-file-buffer-size
 | 
						|
        (native-transcoder)
 | 
						|
        #t
 | 
						|
        'call-with-input-file)
 | 
						|
      proc))
 | 
						|
 | 
						|
  (define (with-input-from-file filename proc)
 | 
						|
    (unless (string? filename)
 | 
						|
      (die 'with-input-from-file "invalid filename" filename))
 | 
						|
    (unless (procedure? proc)
 | 
						|
      (die 'with-input-from-file "not a procedure" proc))
 | 
						|
    (call-with-port
 | 
						|
      (fh->input-port 
 | 
						|
        (open-input-file-handle filename 'with-input-from-file)
 | 
						|
        filename
 | 
						|
        input-file-buffer-size
 | 
						|
        (native-transcoder)
 | 
						|
        #t
 | 
						|
        'with-input-from-file)
 | 
						|
      (lambda (p)
 | 
						|
        (parameterize ([*the-input-port* p])
 | 
						|
          (proc)))))
 | 
						|
 | 
						|
  (define (with-input-from-string string proc)
 | 
						|
    (unless (string? string)
 | 
						|
      (die 'with-input-from-string "not a string" string))
 | 
						|
    (unless (procedure? proc)
 | 
						|
      (die 'with-input-from-string "not a procedure" proc))
 | 
						|
    (parameterize ([*the-input-port*
 | 
						|
                    (open-string-input-port string)])
 | 
						|
      (proc)))
 | 
						|
 | 
						|
  (define (standard-input-port)
 | 
						|
    (fh->input-port 0 '*stdin* 256 #f #f 'standard-input-port))
 | 
						|
 | 
						|
  (define (standard-output-port)
 | 
						|
    (fh->output-port 1 '*stdout* 256 #f #f 'standard-output-port))
 | 
						|
  
 | 
						|
  (define (standard-error-port)
 | 
						|
    (fh->output-port 2 '*stderr* 256 #f #f 'standard-error-port))
 | 
						|
 | 
						|
  (define *the-input-port* 
 | 
						|
    (make-parameter
 | 
						|
      (transcoded-port 
 | 
						|
        (fh->input-port 0 '*stdin* input-file-buffer-size #f #f #f)
 | 
						|
        (native-transcoder))))
 | 
						|
 | 
						|
  (define *the-output-port* 
 | 
						|
    (make-parameter
 | 
						|
      (transcoded-port
 | 
						|
        (fh->output-port 1 '*stdout* output-file-buffer-size #f #f #f)
 | 
						|
        (native-transcoder))))
 | 
						|
  
 | 
						|
  (define *the-error-port* 
 | 
						|
    (make-parameter
 | 
						|
      (transcoded-port 
 | 
						|
        (fh->output-port 2 '*stderr* output-file-buffer-size #f #f #f)
 | 
						|
        (native-transcoder))))
 | 
						|
 | 
						|
  (define console-output-port
 | 
						|
    (let ([p (*the-output-port*)])
 | 
						|
      (lambda () p)))
 | 
						|
 | 
						|
  (define console-error-port
 | 
						|
    (let ([p (*the-error-port*)])
 | 
						|
      (lambda () p)))
 | 
						|
 | 
						|
  (define console-input-port
 | 
						|
    (let ([p (*the-input-port*)])
 | 
						|
      (lambda () p)))
 | 
						|
 | 
						|
  (define (current-input-port) (*the-input-port*))
 | 
						|
  (define (current-output-port) (*the-output-port*))
 | 
						|
  (define (current-error-port) (*the-error-port*))
 | 
						|
 | 
						|
  (define (call-with-port p proc)
 | 
						|
    (if (port? p) 
 | 
						|
        (if (procedure? proc) 
 | 
						|
            (dynamic-wind
 | 
						|
              void
 | 
						|
              (lambda () (proc p))
 | 
						|
              (lambda () (close-port p)))
 | 
						|
            (die 'call-with-port "not a procedure" proc))
 | 
						|
        (die 'call-with-port "not a port" p)))
 | 
						|
 | 
						|
  ;;;
 | 
						|
  (define peek-char
 | 
						|
    (case-lambda
 | 
						|
      [() (lookahead-char (*the-input-port*))]
 | 
						|
      [(p)
 | 
						|
       (if (input-port? p)
 | 
						|
           (if (textual-port? p)
 | 
						|
               (lookahead-char p)
 | 
						|
               (die 'peek-char "not a textual port" p))
 | 
						|
           (die 'peek-char "not an input-port" p))]))
 | 
						|
 | 
						|
  (define (get-bytevector-n p n) 
 | 
						|
    (import (ikarus system $fx) (ikarus system $bytevectors))
 | 
						|
    (define (subbytevector s n)
 | 
						|
      (let ([p ($make-bytevector n)])
 | 
						|
        (let f ([s s] [n n] [p p])
 | 
						|
          (let ([n ($fx- n 1)])
 | 
						|
            ($bytevector-set! p n ($bytevector-u8-ref s n))
 | 
						|
            (if ($fx= n 0) 
 | 
						|
                p
 | 
						|
                (f s n p))))))
 | 
						|
    (unless (input-port? p) 
 | 
						|
      (die 'get-bytevector-n "not an input port" p))
 | 
						|
    (unless (binary-port? p)
 | 
						|
      (die 'get-bytevector-n "not a binary port" p))
 | 
						|
    (unless (fixnum? n) 
 | 
						|
      (die 'get-bytevector-n "count is not a fixnum" n))
 | 
						|
    (cond
 | 
						|
      [($fx> n 0) 
 | 
						|
       (let ([s ($make-bytevector n)])
 | 
						|
         (let f ([p p] [n n] [s s] [i 0])
 | 
						|
           (let ([x (get-u8 p)])
 | 
						|
             (cond
 | 
						|
               [(eof-object? x) 
 | 
						|
                (if ($fx= i 0) 
 | 
						|
                    (eof-object)
 | 
						|
                    (subbytevector s i))]
 | 
						|
               [else
 | 
						|
                ($bytevector-set! s i x)
 | 
						|
                (let ([i ($fxadd1 i)])
 | 
						|
                  (if ($fx= i n) 
 | 
						|
                      s
 | 
						|
                      (f p n s i)))]))))]
 | 
						|
      [($fx= n 0) '#vu8()]
 | 
						|
      [else (die 'get-bytevector-n "count is negative" n)]))
 | 
						|
 | 
						|
  (define (get-bytevector-n! p s i c) 
 | 
						|
    (import (ikarus system $fx) (ikarus system $bytevectors))
 | 
						|
    (unless (input-port? p) 
 | 
						|
      (die 'get-bytevector-n! "not an input port" p))
 | 
						|
    (unless (binary-port? p)
 | 
						|
      (die 'get-bytevector-n! "not a binary port" p))
 | 
						|
    (unless (bytevector? s) 
 | 
						|
      (die 'get-bytevector-n! "not a bytevector" s))
 | 
						|
    (let ([len ($bytevector-length s)])
 | 
						|
      (unless (fixnum? i) 
 | 
						|
        (die 'get-bytevector-n! "starting index is not a fixnum" i))
 | 
						|
      (when (or ($fx< i 0) ($fx> i len))
 | 
						|
        (die 'get-bytevector-n! 
 | 
						|
          (format "starting index is out of range 0..~a" len)
 | 
						|
          i))
 | 
						|
      (unless (fixnum? c)
 | 
						|
        (die 'get-bytevector-n! "count is not a fixnum" c))
 | 
						|
      (cond
 | 
						|
        [($fx> c 0)
 | 
						|
         (let ([j (+ i c)])
 | 
						|
           (when (> j len)
 | 
						|
             (die 'get-bytevector-n! 
 | 
						|
               (format "count is out of range 0..~a" (- len i))
 | 
						|
               c))
 | 
						|
           (let ([x (get-u8 p)])
 | 
						|
             (cond
 | 
						|
               [(eof-object? x) x]
 | 
						|
               [else
 | 
						|
                ($bytevector-set! s i x)
 | 
						|
                (let f ([p p] [s s] [start i] [i 1] [c c])
 | 
						|
                  (let ([x (get-u8 p)])
 | 
						|
                    (cond
 | 
						|
                      [(eof-object? x) i]
 | 
						|
                      [else
 | 
						|
                       ($bytevector-set! s ($fx+ start i) x)
 | 
						|
                       (let ([i ($fxadd1 i)])
 | 
						|
                         (if ($fx= i c)
 | 
						|
                             i
 | 
						|
                             (f p s start i c)))])))])))]
 | 
						|
        [($fx= c 0) 0]
 | 
						|
        [else (die 'get-bytevector-n! "count is negative" c)])))
 | 
						|
 | 
						|
  (define (get-bytevector-some p)
 | 
						|
    (define who 'get-bytevector-some)
 | 
						|
;    (import UNSAFE)
 | 
						|
    (let ([m ($port-fast-attrs p)])
 | 
						|
      (cond
 | 
						|
        [(eq? m fast-get-byte-tag)
 | 
						|
         (let ([i ($port-index p)] [j ($port-size p)])
 | 
						|
           (let ([cnt (fx- j i)])
 | 
						|
             (cond
 | 
						|
               [(fx> cnt 0)
 | 
						|
                (let f ([bv (make-bytevector cnt)]
 | 
						|
                        [buf ($port-buffer p)]
 | 
						|
                        [i i] [j j] [idx 0])
 | 
						|
                  (cond
 | 
						|
                    [(fx= i j)
 | 
						|
                     ($set-port-index! p j)
 | 
						|
                     bv]
 | 
						|
                    [else
 | 
						|
                     (bytevector-u8-set! bv idx (bytevector-u8-ref buf i))
 | 
						|
                     (f bv buf (fx+ i 1) j (fx+ idx 1))]))]
 | 
						|
               [else 
 | 
						|
                (refill-bv-buffer p who)
 | 
						|
                (if (fx= ($port-index p) ($port-size p))
 | 
						|
                    (eof-object)
 | 
						|
                    (get-bytevector-some p))])))]
 | 
						|
        [else (die who "invalid port argument" p)])))
 | 
						|
 | 
						|
  (define (get-bytevector-all p)
 | 
						|
    (define (get-it p)
 | 
						|
      (let f ([p p] [n 0] [ac '()])
 | 
						|
        (let ([x (get-u8 p)])
 | 
						|
          (cond
 | 
						|
            [(eof-object? x)
 | 
						|
             (if (null? ac) 
 | 
						|
                 (eof-object)
 | 
						|
                 (make-it n ac))]
 | 
						|
            [else (f p (+ n 1) (cons x ac))]))))
 | 
						|
    (define (make-it n revls)
 | 
						|
      (let f ([s (make-bytevector n)] [i (- n 1)] [ls revls])
 | 
						|
        (cond
 | 
						|
          [(pair? ls)
 | 
						|
           (bytevector-u8-set! s i (car ls))
 | 
						|
           (f s (- i 1) (cdr ls))]
 | 
						|
          [else s])))
 | 
						|
    (if (input-port? p)
 | 
						|
        (if (binary-port? p)
 | 
						|
            (get-it p)
 | 
						|
            (die 'get-bytevector-all "not a binary port" p))
 | 
						|
        (die 'get-bytevector-all "not an input port" p)))
 | 
						|
 | 
						|
  (define (get-string-n p n) 
 | 
						|
    (import (ikarus system $fx) (ikarus system $strings))
 | 
						|
    (unless (input-port? p) 
 | 
						|
      (die 'get-string-n "not an input port" p))
 | 
						|
    (unless (textual-port? p) 
 | 
						|
      (die 'get-string-n "not a textual port" p))
 | 
						|
    (unless (fixnum? n) 
 | 
						|
      (die 'get-string-n "count is not a fixnum" n))
 | 
						|
    (cond
 | 
						|
      [($fx> n 0) 
 | 
						|
       (let ([s ($make-string n)])
 | 
						|
         (let f ([p p] [n n] [s s] [i 0])
 | 
						|
           (let ([x (get-char p)])
 | 
						|
             (cond
 | 
						|
               [(eof-object? x) 
 | 
						|
                (if ($fx= i 0) 
 | 
						|
                    (eof-object)
 | 
						|
                    (substring s 0 i))]
 | 
						|
               [else
 | 
						|
                ($string-set! s i x) 
 | 
						|
                (let ([i ($fxadd1 i)])
 | 
						|
                  (if ($fx= i n) 
 | 
						|
                      s
 | 
						|
                      (f p n s i)))]))))]
 | 
						|
      [($fx= n 0) ""]
 | 
						|
      [else (die 'get-string-n "count is negative" n)]))
 | 
						|
 | 
						|
  (define (get-string-n! p s i c) 
 | 
						|
    (import (ikarus system $fx) (ikarus system $strings))
 | 
						|
    (unless (input-port? p) 
 | 
						|
      (die 'get-string-n! "not an input port" p))
 | 
						|
    (unless (textual-port? p) 
 | 
						|
      (die 'get-string-n! "not a textual port" p))
 | 
						|
    (unless (string? s) 
 | 
						|
      (die 'get-string-n! "not a string" s))
 | 
						|
    (let ([len ($string-length s)])
 | 
						|
      (unless (fixnum? i) 
 | 
						|
        (die 'get-string-n! "starting index is not a fixnum" i))
 | 
						|
      (when (or ($fx< i 0) ($fx> i len))
 | 
						|
        (die 'get-string-n! 
 | 
						|
          (format "starting index is out of range 0..~a" len)
 | 
						|
          i))
 | 
						|
      (unless (fixnum? c) 
 | 
						|
        (die 'get-string-n! "count is not a fixnum" c))
 | 
						|
      (cond
 | 
						|
        [($fx> c 0)
 | 
						|
         (let ([j (+ i c)])
 | 
						|
           (when (> j len)
 | 
						|
             (die 'get-string-n! 
 | 
						|
               (format "count is out of range 0..~a" (- len i))
 | 
						|
               c))
 | 
						|
           (let ([x (get-char p)])
 | 
						|
             (cond
 | 
						|
               [(eof-object? x) x]
 | 
						|
               [else
 | 
						|
                ($string-set! s i x)
 | 
						|
                (let f ([p p] [s s] [start i] [i 1] [c c])
 | 
						|
                  (let ([x (get-char p)])
 | 
						|
                    (cond
 | 
						|
                      [(eof-object? x) i]
 | 
						|
                      [else
 | 
						|
                       ($string-set! s ($fx+ start i) x)
 | 
						|
                       (let ([i ($fxadd1 i)])
 | 
						|
                         (if ($fx= i c)
 | 
						|
                             i
 | 
						|
                             (f p s start i c)))])))])))]
 | 
						|
        [($fx= c 0) 0]
 | 
						|
        [else (die 'get-string-n! "count is negative" c)])))
 | 
						|
 | 
						|
  (define (get-line p)
 | 
						|
    (import UNSAFE)
 | 
						|
    (define (get-it p)
 | 
						|
      (let f ([p p] [n 0] [ac '()])
 | 
						|
        (let ([x (get-char p)])
 | 
						|
          (cond
 | 
						|
            [(eqv? x #\newline) 
 | 
						|
             (make-it n ac)]
 | 
						|
            [(eof-object? x) 
 | 
						|
             (if (null? ac) x (make-it n ac))]
 | 
						|
            [else (f p (fx+ n 1) (cons x ac))]))))
 | 
						|
    (define (make-it n revls)
 | 
						|
      (let f ([s (make-string n)] [i (fx- n 1)] [ls revls])
 | 
						|
        (cond
 | 
						|
          [(pair? ls)
 | 
						|
           (string-set! s i (car ls))
 | 
						|
           (f s (fx- i 1) (cdr ls))]
 | 
						|
          [else s])))
 | 
						|
    (if (input-port? p)
 | 
						|
        (if (textual-port? p)
 | 
						|
            (get-it p)
 | 
						|
            (die 'get-line "not a textual port" p))
 | 
						|
        (die 'get-line "not an input port" p)))
 | 
						|
 | 
						|
 | 
						|
  (define (get-string-all p)
 | 
						|
    (define (get-it p)
 | 
						|
      (let f ([p p] [n 0] [ac '()])
 | 
						|
        (let ([x (get-char p)])
 | 
						|
          (cond
 | 
						|
            [(eof-object? x)
 | 
						|
             (if (null? ac) 
 | 
						|
                 (eof-object)
 | 
						|
                 (make-it n ac))]
 | 
						|
            [else (f p (+ n 1) (cons x ac))]))))
 | 
						|
    (define (make-it n revls)
 | 
						|
      (let f ([s (make-string n)] [i (- n 1)] [ls revls])
 | 
						|
        (cond
 | 
						|
          [(pair? ls)
 | 
						|
           (string-set! s i (car ls))
 | 
						|
           (f s (- i 1) (cdr ls))]
 | 
						|
          [else s])))
 | 
						|
    (if (input-port? p)
 | 
						|
        (if (textual-port? p)
 | 
						|
            (get-it p)
 | 
						|
            (die 'get-string-all "not a textual port" p))
 | 
						|
        (die 'get-string-all "not an input port" p)))
 | 
						|
 | 
						|
 | 
						|
 | 
						|
  ;;; ----------------------------------------------------------
 | 
						|
  
 | 
						|
  (module (put-char write-char put-string)
 | 
						|
    (import UNSAFE)
 | 
						|
    (define (put-char-utf8-mode p b who) 
 | 
						|
      (cond
 | 
						|
        [(fx< b 128) 
 | 
						|
         (flush-output-port p) 
 | 
						|
         (let ([i ($port-index p)] [j ($port-size p)])
 | 
						|
           (cond
 | 
						|
             [(fx< i j) 
 | 
						|
              (bytevector-u8-set! ($port-buffer p) i b) 
 | 
						|
              ($set-port-index! p (fx+ i 1))]
 | 
						|
             [else
 | 
						|
              (die who "insufficient space on port" p)]))]
 | 
						|
        [(fx<= b #x7FF) 
 | 
						|
         (let ([i ($port-index p)] 
 | 
						|
               [j ($port-size p)]
 | 
						|
               [buf ($port-buffer p)])
 | 
						|
           (cond
 | 
						|
             [(fx< (fx+ i 1) j) 
 | 
						|
              (bytevector-u8-set! buf i 
 | 
						|
                (fxior #b11000000 (fxsra b 6)))
 | 
						|
              (bytevector-u8-set! buf (fx+ i 1) 
 | 
						|
                (fxior #b10000000 (fxand b #b111111)))
 | 
						|
              ($set-port-index! p (fx+ i 2))]
 | 
						|
             [else 
 | 
						|
              (flush-output-port p) 
 | 
						|
              (put-char-utf8-mode p b who)]))]
 | 
						|
        [(fx<= b #xFFFF) 
 | 
						|
         (let ([i ($port-index p)] 
 | 
						|
               [j ($port-size p)]
 | 
						|
               [buf ($port-buffer p)])
 | 
						|
           (cond
 | 
						|
             [(fx< (fx+ i 2) j) 
 | 
						|
              (bytevector-u8-set! buf i 
 | 
						|
                (fxior #b11100000 (fxsra b 12)))
 | 
						|
              (bytevector-u8-set! buf (fx+ i 1) 
 | 
						|
                (fxior #b10000000 (fxand (fxsra b 6) #b111111)))
 | 
						|
              (bytevector-u8-set! buf (fx+ i 2) 
 | 
						|
                (fxior #b10000000 (fxand b #b111111)))
 | 
						|
              ($set-port-index! p (fx+ i 3))]
 | 
						|
             [else 
 | 
						|
              (flush-output-port p) 
 | 
						|
              (put-char-utf8-mode p b who)]))]
 | 
						|
        [else
 | 
						|
         (let ([i ($port-index p)] 
 | 
						|
               [j ($port-size p)]
 | 
						|
               [buf ($port-buffer p)])
 | 
						|
           (cond
 | 
						|
             [(fx< (fx+ i 3) j) 
 | 
						|
              (bytevector-u8-set! buf i 
 | 
						|
                (fxior #b11110000 (fxsra b 18)))
 | 
						|
              (bytevector-u8-set! buf (fx+ i 1)
 | 
						|
                (fxior #b10000000 (fxand (fxsra b 12) #b111111)))
 | 
						|
              (bytevector-u8-set! buf (fx+ i 2)
 | 
						|
                (fxior #b10000000 (fxand (fxsra b 6) #b111111)))
 | 
						|
              (bytevector-u8-set! buf (fx+ i 3) 
 | 
						|
                (fxior #b10000000 (fxand b #b111111)))
 | 
						|
              ($set-port-index! p (fx+ i 4))]
 | 
						|
             [else 
 | 
						|
              (flush-output-port p) 
 | 
						|
              (put-char-utf8-mode p b who)]))]))
 | 
						|
    (define (put-char-latin-mode p b who) 
 | 
						|
      (cond
 | 
						|
        [(fx< b 256) 
 | 
						|
         (flush-output-port p)
 | 
						|
         (let ([i ($port-index p)] [j ($port-size p)])
 | 
						|
           (cond
 | 
						|
             [(fx< i j) 
 | 
						|
              (bytevector-u8-set! ($port-buffer p) i b)
 | 
						|
              ($set-port-index! p (fx+ i 1))]
 | 
						|
             [else 
 | 
						|
              (die who "insufficient space in port" p)]))]
 | 
						|
        [else
 | 
						|
         (case (transcoder-error-handling-mode (port-transcoder p))
 | 
						|
           [(ignore) (void)]
 | 
						|
           [(replace) (put-char p #\?)]
 | 
						|
           [(raise) 
 | 
						|
            (raise (make-i/o-encoding-error p))]
 | 
						|
           [else (die who "BUG: invalid die handling mode" p)])]))
 | 
						|
    (define (put-char-char-mode p c who)
 | 
						|
      (flush-output-port p)
 | 
						|
      (let ([i ($port-index p)] [j ($port-size p)])
 | 
						|
        (cond
 | 
						|
          [(fx< i j) 
 | 
						|
           (string-set! ($port-buffer p) i c)
 | 
						|
           ($set-port-index! p (fx+ i 1))]
 | 
						|
          [else 
 | 
						|
           (die who "insufficient space in port" p)])))
 | 
						|
    ;;;
 | 
						|
    (define write-char
 | 
						|
      (case-lambda
 | 
						|
        [(c p) (do-put-char p c 'write-char)]
 | 
						|
        [(c) (do-put-char (*the-output-port*) c 'write-char)]))
 | 
						|
    (define (put-char p c) 
 | 
						|
      (do-put-char p c 'put-char))
 | 
						|
    (define (put-string p str)
 | 
						|
      (unless (string? str) (die 'put-string "not a string" str))
 | 
						|
      (unless (output-port? p)
 | 
						|
        (die 'put-string "not an output port" p))
 | 
						|
      (unless (textual-port? p)
 | 
						|
        (die 'put-string "not a textual port" p))
 | 
						|
      (let f ([i 0] [n (string-length str)])
 | 
						|
        (unless (fx= i n)
 | 
						|
          (do-put-char p (string-ref str i) 'put-string)
 | 
						|
          (f (fx+ i 1) n))))
 | 
						|
    (define (do-put-char p c who)
 | 
						|
      (unless (char? c) (die who "not a char" c))
 | 
						|
      (let ([m ($port-fast-attrs p)])
 | 
						|
        (cond
 | 
						|
          [(eq? m fast-put-utf8-tag)
 | 
						|
           (let ([i ($port-index p)])
 | 
						|
             (let ([b (char->integer c)])
 | 
						|
               (cond
 | 
						|
                 [(and (fx< i ($port-size p)) (fx< b 128))
 | 
						|
                  (bytevector-u8-set! ($port-buffer p) i b)
 | 
						|
                  ($set-port-index! p (fx+ i 1))]
 | 
						|
                 [else
 | 
						|
                  (put-char-utf8-mode p b who)])))]
 | 
						|
          [(eq? m fast-put-char-tag)
 | 
						|
           (let ([i ($port-index p)])
 | 
						|
             (cond
 | 
						|
               [(fx< i ($port-size p))
 | 
						|
                ($set-port-index! p (fx+ i 1))
 | 
						|
                (string-set! ($port-buffer p) i c)]
 | 
						|
               [else
 | 
						|
                (put-char-char-mode p c who)]))]
 | 
						|
          [(eq? m fast-put-latin-tag)
 | 
						|
           (let ([i ($port-index p)])
 | 
						|
             (let ([b (char->integer c)])
 | 
						|
               (cond
 | 
						|
                 [(and (fx< i ($port-size p)) (fx< b 256))
 | 
						|
                  (bytevector-u8-set! ($port-buffer p) i b)
 | 
						|
                  ($set-port-index! p (fx+ i 1))]
 | 
						|
                 [else
 | 
						|
                  (put-char-latin-mode p b who)])))]
 | 
						|
          [else 
 | 
						|
           (if (output-port? p)
 | 
						|
               (if (textual-port? p) 
 | 
						|
                   (if (port-closed? p)
 | 
						|
                       (die who "port is closed" p)
 | 
						|
                       (die who "unsupported port" p))
 | 
						|
                   (die who "not a textual port" p))
 | 
						|
               (die who "not an output port" p))]))))
 | 
						|
 | 
						|
  (define newline
 | 
						|
    (case-lambda
 | 
						|
      [() 
 | 
						|
       (put-char (*the-output-port*) #\newline)
 | 
						|
       (flush-output-port (*the-output-port*))]
 | 
						|
      [(p)
 | 
						|
       (unless (output-port? p) 
 | 
						|
         (die 'newline "not an output port" p))
 | 
						|
       (unless (textual-port? p) 
 | 
						|
         (die 'newline "not a textual port" p))
 | 
						|
       (when ($port-closed? p)
 | 
						|
         (die 'newline "port is closed" p))
 | 
						|
       (put-char p #\newline)
 | 
						|
       (flush-output-port p)]))
 | 
						|
       
 | 
						|
 | 
						|
       
 | 
						|
  (module (put-u8 put-bytevector)
 | 
						|
    (import UNSAFE)
 | 
						|
    (define (put-u8-byte-mode p b who)
 | 
						|
      (let ([write! ($port-write! p)])
 | 
						|
        (let ([i ($port-index p)] 
 | 
						|
              [buf ($port-buffer p)])
 | 
						|
          (let ([bytes (write! buf 0 i)])
 | 
						|
            (when (or (not (fixnum? bytes))
 | 
						|
                      (fx< bytes 0)
 | 
						|
                      (fx> bytes i))
 | 
						|
              (die who "write! returned an invalid value" bytes))
 | 
						|
            (cond
 | 
						|
              [(fx= bytes i) 
 | 
						|
               (bytevector-u8-set! buf 0 b)
 | 
						|
               ($set-port-index! p 1)]
 | 
						|
              [(fx= bytes 0) 
 | 
						|
               (die who "could not write bytes to sink")]
 | 
						|
              [else
 | 
						|
               (let ([i (fx- i bytes)])
 | 
						|
                 (bytevector-copy! buf bytes buf 0 i)
 | 
						|
                 (bytevector-u8-set! buf i b)
 | 
						|
                 ($set-port-index! p (fx+ i 1)))])))))
 | 
						|
    ;;;
 | 
						|
    (define (put-u8 p b)
 | 
						|
      (define who 'put-u8)
 | 
						|
      (unless (u8? b) (die who "not a u8" b))
 | 
						|
      (let ([m ($port-fast-attrs p)])
 | 
						|
        (cond
 | 
						|
          [(eq? m fast-put-byte-tag)
 | 
						|
           (let ([i ($port-index p)])
 | 
						|
             (cond
 | 
						|
               [(fx< i ($port-size p))
 | 
						|
                ($set-port-index! p (fx+ i 1))
 | 
						|
                (bytevector-u8-set! ($port-buffer p) i b)]
 | 
						|
               [else
 | 
						|
                (put-u8-byte-mode p b who)]))]
 | 
						|
          [else 
 | 
						|
           (if (output-port? p)
 | 
						|
               (die who "not a binary port" p)
 | 
						|
               (die who "not an output port" p))])))
 | 
						|
    ;;;
 | 
						|
    (define ($put-bytevector p bv i c) 
 | 
						|
      (define who 'put-bytevector)
 | 
						|
      (define (copy! src dst si di c)
 | 
						|
        (when (fx> c 0) 
 | 
						|
          (bytevector-u8-set! dst di (bytevector-u8-ref src si))
 | 
						|
          (copy! src dst (fx+ si 1) (fx+ di 1) (fx- c 1))))
 | 
						|
      (let ([m ($port-fast-attrs p)])
 | 
						|
        (cond
 | 
						|
          [(eq? m fast-put-byte-tag)
 | 
						|
           (let ([idx ($port-index p)])
 | 
						|
             (let ([room (fx- ($port-size p) idx)])
 | 
						|
               (cond
 | 
						|
                 [(fx>= room c)
 | 
						|
                  ;; hurray
 | 
						|
                  ($set-port-index! p (fx+ idx c))
 | 
						|
                  (copy! bv ($port-buffer p) i idx c)]
 | 
						|
                 [else
 | 
						|
                  ($set-port-index! p (fx+ idx room))
 | 
						|
                  (copy! bv ($port-buffer p) i idx room)
 | 
						|
                  (flush-output-port p)
 | 
						|
                  ($put-bytevector p bv (fx+ i room) (fx- c room))])))]
 | 
						|
          [else
 | 
						|
           (if (output-port? p)
 | 
						|
               (die who "not a binary port" p)
 | 
						|
               (die who "not an output port" p))])))
 | 
						|
    (define put-bytevector
 | 
						|
      (case-lambda
 | 
						|
        [(p bv) 
 | 
						|
         (if (bytevector? bv) 
 | 
						|
             ($put-bytevector p bv 0 (bytevector-length bv))
 | 
						|
             (die 'put-bytevector "not a bytevector" bv))]
 | 
						|
        [(p bv i) 
 | 
						|
         (if (bytevector? bv) 
 | 
						|
             (if (fixnum? i) 
 | 
						|
                 (let ([n (bytevector-length bv)])
 | 
						|
                   (if (and (fx< i n) (fx>= i 0))
 | 
						|
                       ($put-bytevector p bv i (fx- n i))
 | 
						|
                       (die 'put-bytevector "index out of range" i)))
 | 
						|
                 (die 'put-bytevector "invalid index" i))
 | 
						|
             (die 'put-bytevector "not a bytevector" bv))]
 | 
						|
        [(p bv i c) 
 | 
						|
         (if (bytevector? bv) 
 | 
						|
             (if (fixnum? i) 
 | 
						|
                 (let ([n (bytevector-length bv)])
 | 
						|
                   (if (and (fx< i n) (fx>= i 0))
 | 
						|
                       (if (fixnum? c) 
 | 
						|
                           (if (and (fx>= c 0) (fx>= (fx- n c) i))
 | 
						|
                               ($put-bytevector p bv i c)
 | 
						|
                               (die 'put-bytevector "count out of range" c))
 | 
						|
                           (die 'put-bytevector "invalid count" c))
 | 
						|
                       (die 'put-bytevector "index out of range" i)))
 | 
						|
                 (die 'put-bytevector "invalid index" i))
 | 
						|
             (die 'put-bytevector "not a bytevector" bv))]))
 | 
						|
    ;;; module 
 | 
						|
    )
 | 
						|
 | 
						|
 | 
						|
 | 
						|
  (define (process cmd . args)
 | 
						|
    (define who 'process)
 | 
						|
    (unless (string? cmd)
 | 
						|
      (die who "command is not a string" cmd))
 | 
						|
    (unless (andmap string? args) 
 | 
						|
      (die who "all arguments must be strings"))
 | 
						|
    (let ([r (foreign-call "ikrt_process" 
 | 
						|
                (make-vector 4)
 | 
						|
                (string->utf8 cmd)
 | 
						|
                (map string->utf8 (cons cmd args)))])
 | 
						|
      (if (fixnum? r) 
 | 
						|
          (io-error who cmd r)
 | 
						|
          (values
 | 
						|
            (vector-ref r 0) ; pid
 | 
						|
            (fh->output-port (vector-ref r 1) 
 | 
						|
                cmd output-file-buffer-size #f #t
 | 
						|
                'process)
 | 
						|
            (fh->input-port (vector-ref r 2) 
 | 
						|
                cmd input-file-buffer-size #f #t
 | 
						|
                'process)
 | 
						|
            (fh->input-port (vector-ref r 3) 
 | 
						|
                cmd input-file-buffer-size #f #t
 | 
						|
                'process)))))
 | 
						|
 | 
						|
 | 
						|
  (define (process-nonblocking cmd . args)
 | 
						|
    (define who 'process-nonblocking)
 | 
						|
    (unless (string? cmd)
 | 
						|
      (die who "command is not a string" cmd))
 | 
						|
    (unless (andmap string? args) 
 | 
						|
      (die who "all arguments must be strings"))
 | 
						|
    (let ([r (foreign-call "ikrt_process" 
 | 
						|
                (make-vector 4)
 | 
						|
                (string->utf8 cmd)
 | 
						|
                (map string->utf8 (cons cmd args)))])
 | 
						|
      (if (fixnum? r) 
 | 
						|
          (io-error who cmd r)
 | 
						|
          (begin 
 | 
						|
            (set-fd-nonblocking (vector-ref r 1) who cmd)
 | 
						|
            (set-fd-nonblocking (vector-ref r 2) who cmd)
 | 
						|
            (set-fd-nonblocking (vector-ref r 3) who cmd)
 | 
						|
            (values
 | 
						|
              (vector-ref r 0) ; pid
 | 
						|
              (fh->output-port (vector-ref r 1) 
 | 
						|
                  cmd output-file-buffer-size #f #t
 | 
						|
                  'process)
 | 
						|
              (fh->input-port (vector-ref r 2) 
 | 
						|
                  cmd input-file-buffer-size #f #t
 | 
						|
                  'process)
 | 
						|
              (fh->input-port (vector-ref r 3) 
 | 
						|
                  cmd input-file-buffer-size #f #t
 | 
						|
                  'process))))))
 | 
						|
 | 
						|
 | 
						|
  (define (set-fd-nonblocking fd who id)
 | 
						|
    (let ([rv (foreign-call "ikrt_make_fd_nonblocking" fd)])
 | 
						|
      (unless (eq? rv 0) 
 | 
						|
        (io-error who id rv))))
 | 
						|
 | 
						|
  (define (socket->ports socket who id block?)
 | 
						|
    (if (< socket 0)
 | 
						|
        (io-error who id socket)
 | 
						|
        (let ([close
 | 
						|
               (let ([closed-once? #f])
 | 
						|
                 (lambda () 
 | 
						|
                   (if closed-once?
 | 
						|
                       ((file-close-proc id socket))
 | 
						|
                       (set! closed-once? #t))))])
 | 
						|
          (unless block?
 | 
						|
            (set-fd-nonblocking socket who id))
 | 
						|
          (values 
 | 
						|
            (fh->output-port socket
 | 
						|
               id (output-socket-buffer-size) #f close who)
 | 
						|
            (fh->input-port socket
 | 
						|
               id (input-socket-buffer-size) #f close who)))))
 | 
						|
 | 
						|
  (define-syntax define-connector 
 | 
						|
    (syntax-rules ()
 | 
						|
      [(_ who foreign-name block?)
 | 
						|
       (define (who host srvc)
 | 
						|
         (unless (and (string? host) (string? srvc))
 | 
						|
           (die 'who "host and service must both be strings" host srvc))
 | 
						|
         (socket->ports 
 | 
						|
           (foreign-call foreign-name
 | 
						|
             (string->utf8 host) (string->utf8 srvc))
 | 
						|
           'who
 | 
						|
           (string-append host ":" srvc)
 | 
						|
           block?))]))
 | 
						|
 | 
						|
  (define-connector tcp-connect             "ikrt_tcp_connect" #t)
 | 
						|
  (define-connector udp-connect             "ikrt_udp_connect" #t)
 | 
						|
  (define-connector tcp-connect-nonblocking "ikrt_tcp_connect" #f)
 | 
						|
  (define-connector udp-connect-nonblocking "ikrt_udp_connect" #f)
 | 
						|
 | 
						|
  (module (add-io-event rem-io-event process-events)
 | 
						|
    (define-struct t (fd proc type))
 | 
						|
    ;;; callbacks
 | 
						|
    (define pending '())
 | 
						|
    (define out-queue '())
 | 
						|
    (define in-queue '())
 | 
						|
 | 
						|
    (define (process-events) 
 | 
						|
      (if (null? out-queue) 
 | 
						|
          (if (null? in-queue) 
 | 
						|
              (if (null? pending) 
 | 
						|
                  (error 'process-events "no more events")
 | 
						|
                  (begin 
 | 
						|
                    (do-select) 
 | 
						|
                    (process-events)))
 | 
						|
              (begin
 | 
						|
                (set! out-queue (reverse in-queue))
 | 
						|
                (set! in-queue '())
 | 
						|
                (process-events)))
 | 
						|
          (let ([t (car out-queue)])
 | 
						|
            (set! out-queue (cdr out-queue))
 | 
						|
            ((t-proc t))
 | 
						|
            (process-events))))
 | 
						|
 | 
						|
    (define (add-io-event fd proc event-type) 
 | 
						|
      (set! pending 
 | 
						|
        (cons (make-t fd proc event-type) pending)))
 | 
						|
 | 
						|
    (define (rem-io-event fd) 
 | 
						|
      (define (p x) (eq? (t-fd x) fd))
 | 
						|
      (set! pending (remp p pending))
 | 
						|
      (set! out-queue (remp p out-queue))
 | 
						|
      (set! in-queue (remp p in-queue)))
 | 
						|
    
 | 
						|
    (define (get-max-fd)
 | 
						|
      (assert (pair? pending))
 | 
						|
      (let f ([m (t-fd (car pending))]
 | 
						|
              [ls (cdr pending)])
 | 
						|
        (cond
 | 
						|
          [(null? ls) m]
 | 
						|
          [else (f (max m (t-fd (car ls))) (cdr ls))])))
 | 
						|
 | 
						|
    (define (do-select)
 | 
						|
      (let ([n (add1 (get-max-fd))])
 | 
						|
        (let ([rbv (make-bytevector n 0)]
 | 
						|
              [wbv (make-bytevector n 0)]
 | 
						|
              [xbv (make-bytevector n 0)])
 | 
						|
          ;;; add all fds to their bytevectors depending on type
 | 
						|
          (for-each 
 | 
						|
            (lambda (t) 
 | 
						|
              (let ([fd (t-fd t)])
 | 
						|
                (let ([i (div fd 8)] [j (mod fd 8)])
 | 
						|
                  (let ([bv (case (t-type t)
 | 
						|
                              [(r) rbv]
 | 
						|
                              [(w) wbv]
 | 
						|
                              [(x) xbv]
 | 
						|
                              [else 
 | 
						|
                               (error 'do-select "invalid type" t)])])
 | 
						|
                    (bytevector-u8-set! bv i 
 | 
						|
                      (fxlogor (fxsll 1 j) 
 | 
						|
                        (bytevector-u8-ref bv i)))))))
 | 
						|
            pending)
 | 
						|
          ;;; do select
 | 
						|
          (let ([rv (foreign-call "ikrt_select" n rbv wbv xbv)])
 | 
						|
            (when (< rv 0) 
 | 
						|
              (die 'select "error selecting from fds")))
 | 
						|
          ;;; go through fds again and see if they're selected
 | 
						|
          (for-each 
 | 
						|
            (lambda (t) 
 | 
						|
              (let ([fd (t-fd t)])
 | 
						|
                (let ([i (div fd 8)] [j (mod fd 8)])
 | 
						|
                  (let ([bv (case (t-type t)
 | 
						|
                              [(r) rbv]
 | 
						|
                              [(w) wbv]
 | 
						|
                              [(x) xbv]
 | 
						|
                              [else 
 | 
						|
                               (error 'do-select "invalid type" t)])])
 | 
						|
                    (cond
 | 
						|
                      [(fxzero? 
 | 
						|
                         (fxlogand (fxsll 1 j) 
 | 
						|
                           (bytevector-u8-ref bv i)))
 | 
						|
                       ;;; not selected
 | 
						|
                       (set! pending (cons t pending))]
 | 
						|
                      [else 
 | 
						|
                       ;;; ready
 | 
						|
                       (set! in-queue (cons t in-queue))])))))
 | 
						|
            (let ([ls pending])
 | 
						|
              (set! pending '())
 | 
						|
              ls)))))
 | 
						|
    )
 | 
						|
 | 
						|
  
 | 
						|
  (define-struct tcp-server (portnum fd))
 | 
						|
  
 | 
						|
  (define (tcp-server-socket portnum) 
 | 
						|
    (unless (fixnum? portnum)
 | 
						|
      (error 'tcp-server-socket "not a fixnum" portnum))
 | 
						|
    (let ([sock (foreign-call "ikrt_listen" portnum)])
 | 
						|
      (cond
 | 
						|
        [(fx>= sock 0) (make-tcp-server portnum sock)]
 | 
						|
        [else (die 'tcp-server-socket "failed to start server")])))
 | 
						|
  
 | 
						|
  (define (tcp-server-socket-nonblocking portnum) 
 | 
						|
    (let ([s (tcp-server-socket portnum)])
 | 
						|
      (set-fd-nonblocking (tcp-server-fd s) 
 | 
						|
        'tcp-server-socket-nonblocking
 | 
						|
        '#f)
 | 
						|
      s))
 | 
						|
 | 
						|
 | 
						|
  (define (do-accept-connection s who blocking?)
 | 
						|
    (define (make-socket-info x) 
 | 
						|
      (unless (= (bytevector-length x) 16) 
 | 
						|
        (error who "BUG: unexpected return value" x))
 | 
						|
      (format "~s.~s.~s.~s:~s" 
 | 
						|
        (bytevector-u8-ref x 4)
 | 
						|
        (bytevector-u8-ref x 5)
 | 
						|
        (bytevector-u8-ref x 6)
 | 
						|
        (bytevector-u8-ref x 7)
 | 
						|
        (+ (* 256 (bytevector-u8-ref x 2))
 | 
						|
           (bytevector-u8-ref x 3))))
 | 
						|
    (unless (tcp-server? s) 
 | 
						|
      (die who "not a tcp server" s))
 | 
						|
    (let ([fd (tcp-server-fd s)] [bv (make-bytevector 16)])
 | 
						|
      (unless fd 
 | 
						|
        (die who "server is closed" s))
 | 
						|
      (let ([sock (foreign-call "ikrt_accept" fd bv)])
 | 
						|
        (cond
 | 
						|
          [(eq? sock EAGAIN-error-code)
 | 
						|
           (call/cc 
 | 
						|
             (lambda (k) 
 | 
						|
               (add-io-event fd k 'r)
 | 
						|
               (process-events)))
 | 
						|
           (do-accept-connection s who blocking?)]
 | 
						|
          [(< sock 0)
 | 
						|
           (io-error who s sock)]
 | 
						|
          [else
 | 
						|
           (socket->ports sock who (make-socket-info bv) blocking?)]))))
 | 
						|
 | 
						|
  (define (accept-connection s)
 | 
						|
    (do-accept-connection s 'accept-connection #t))
 | 
						|
 | 
						|
  (define (accept-connection-nonblocking s)
 | 
						|
    (do-accept-connection s 'accept-connection-nonblocking #f))
 | 
						|
 | 
						|
  (define (close-tcp-server-socket s)
 | 
						|
    (define who 'close-tcp-server-socket)
 | 
						|
    (unless (tcp-server? s) 
 | 
						|
      (die who "not a tcp server" s))
 | 
						|
    (let ([fd (tcp-server-fd s)])
 | 
						|
      (unless fd 
 | 
						|
        (die who "server is closed" s))
 | 
						|
      (let ([rv (foreign-call "ikrt_shutdown" fd)])
 | 
						|
        (when (fx< rv 0)
 | 
						|
          (die who "failed to shutdown")))))
 | 
						|
 | 
						|
  (define (unregister-callback what)
 | 
						|
    (define who 'unregister-callback)
 | 
						|
    (cond
 | 
						|
      [(output-port? what)
 | 
						|
       (let ([c ($port-cookie what)])
 | 
						|
         (unless (fixnum? c) (die who "not a file-based port" what))
 | 
						|
         (rem-io-event c))]
 | 
						|
      [(input-port? what)
 | 
						|
       (let ([c ($port-cookie what)])
 | 
						|
         (unless (fixnum? c) (die who "not a file-based port" what))
 | 
						|
         (rem-io-event c))]
 | 
						|
      [(tcp-server? what)
 | 
						|
       (rem-io-event (tcp-server-fd what))]
 | 
						|
      [else (die who "invalid argument" what)]))
 | 
						|
 | 
						|
  (define (register-callback what proc)
 | 
						|
    (define who 'register-callback) 
 | 
						|
    (unless (procedure? proc) 
 | 
						|
      (die who "not a procedure" proc))
 | 
						|
    (cond
 | 
						|
      [(output-port? what) 
 | 
						|
       (let ([c ($port-cookie what)])
 | 
						|
         (unless (fixnum? c) (die who "not a file-based port" what))
 | 
						|
         (add-io-event c proc 'w))]
 | 
						|
      [(input-port? what) 
 | 
						|
       (let ([c ($port-cookie what)])
 | 
						|
         (unless (fixnum? c) (die who "not a file-based port" what))
 | 
						|
         (add-io-event c proc 'r))]
 | 
						|
      [(tcp-server? what)
 | 
						|
       (add-io-event (tcp-server-fd what) proc 'r)]
 | 
						|
      [else (die who "invalid argument" what)]))
 | 
						|
 | 
						|
 | 
						|
  ;(set-fd-nonblocking 0 'init '*stdin*)
 | 
						|
  )
 | 
						|
 |