1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
; Part of Scheme 48 1.9. See file COPYING for notices and license.
; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Martin Gasbichler
; Implementation of OS channels in Scheme.
;
; A channel an index into a vector of ports in the underlying Scheme
; implementation.
; Vector mapping indicies to ports.
(define *channels* '#())
(define (vector-posq vec thing)
(let loop ((i 0))
(cond ((= i (vector-length vec))
#f)
((eq? thing (vector-ref vec i))
i)
(else
(loop (+ i 1))))))
(define (channel->port channel)
(vector-ref *channels* channel))
(define input-channel->port channel->port)
(define output-channel->port channel->port)
(define (port->channel port)
(or (vector-posq *channels* port)
(make-channel port)))
(define input-port->channel port->channel)
(define output-port->channel port->channel)
; Add PORT to the vector of channels, reusing a slot if possible.
(define (make-channel port)
(let ((channel (or (vector-posq *channels* #f)
(let ((channel (vector-length *channels*)))
(set! *channels* (list->vector
(append (vector->list *channels*)
(list #f #f #f #f))))
channel))))
(vector-set! *channels* channel port)
channel))
; The default ports
(define (current-input-channel)
(port->channel (current-input-port)))
(define (current-output-channel)
(port->channel (current-output-port)))
(define (current-error-channel)
(port->channel (current-error-port)))
; These just open or close the appropriate port and coerce it to a channel.
(define (open-input-file-channel filename)
(receive (port status)
(prescheme:open-input-file filename)
(if (eq? status (enum prescheme:errors no-errors))
(values (port->channel port) status)
(values #f status))))
(define (open-output-file-channel filename)
(receive (port status)
(prescheme:open-output-file filename)
(if (eq? status (enum prescheme:errors no-errors))
(values (port->channel port) status)
(values #f status))))
(define (close-input-channel channel)
(prescheme:close-input-port (channel->port channel)))
(define (close-output-channel channel)
(prescheme:close-output-port (channel->port channel)))
(define (channel-ready? channel read?)
(values (if read?
(char-ready? (channel->port channel))
#t)
(enum prescheme:errors no-errors)))
(define (channel-crlf?) #f)
;----------------
; Non-blocking I/O (implemented using CHAR-READY?)
;
; We keep a list of channels for which the user is waiting. These will
; all be input channels as CHAR-READY? only works on input ports.
(define *pending-channels* '())
(define (channel-read-block channel start count wait?)
(cond ((char-ready? (channel->port channel))
(receive (count eof? status)
(read-block (channel->port channel) start count)
(values count eof? #f status)))
(wait?
(set! *pending-channels* (cons channel *pending-channels*))
(values 0 #f #t (enum prescheme:errors no-errors)))
(else
(values 0 #f #f (enum prescheme:errors no-errors)))))
(define (channel-write-block channel start count)
(values count #f (write-block (channel->port channel) start count)))
(define (channel-buffer-size) 4096)
(define (channel-console-encoding channel) "ISO8859-1")
(define (channel-abort channel)
(set! *pending-channels* (delq channel *pending-channels*))
0)
;----------------
; Events
;
; A keyboard interrupt can be generated by setting the following to #t.
(define *pending-keyboard-interrupt?* #f)
(define (initialize-events)
(set! *channels* (make-vector 10 #f))
(set! *pending-channels* '())
(set! *pending-keyboard-interrupt?* #f))
(define (pending-event?)
(or *pending-keyboard-interrupt?*
(any? (lambda (channel)
(char-ready? (channel->port channel)))
*pending-channels*)))
; The event enumeration is copied from the C version of this code.
(define-enumeration events
(keyboard-interrupt-event
io-completion-event
io-error-event
alarm-event
os-signal-event
error-event
external-event
no-event
))
(define (get-next-event)
(cond (*pending-keyboard-interrupt?*
(set! *pending-keyboard-interrupt?* #f)
(values (enum events keyboard-interrupt-event) #f #f))
((any (lambda (channel)
(char-ready? (channel->port channel)))
*pending-channels*)
=> (lambda (channel)
(set! *pending-channels* (delq channel *pending-channels*))
(values (enum events io-completion-event)
channel
0)))
(else
(values (enum events no-event) #f #f))))
(define (wait-for-event max-wait minutes?)
(breakpoint "Waiting"))
|