1999-09-14 09:32:05 -04:00
;;; A Unix file port system to completely replace S48 file ports.
;;; We use S48 extensible ports.
;;; Copyright (c) 1993 by Olin Shivers.
( define-record fdport-data
channel
revealed )
; This stuff is _weak_.
; Vector of weak pointers mapping fd -> fdport.
2001-06-21 04:30:51 -04:00
( define fdports ( make-integer-table ) )
1999-09-14 09:32:05 -04:00
( define ( install-fdport fdport )
( let* ( ( fdport* ( fdport-data fdport ) )
( ch ( fdport-data:channel fdport* ) )
1999-09-24 19:52:32 -04:00
( ch-number ( channel-os-index ch ) ) )
2001-03-23 05:59:07 -05:00
( if ( not ( = ( fdport-data:revealed fdport* ) 0 ) )
2001-06-21 04:30:51 -04:00
( table-set! fdports ch-number fdport )
( weak-table-set! fdports ch-number fdport ) ) ) )
1999-09-14 09:32:05 -04:00
( define ( maybe-fdes->port fdes )
2001-06-21 04:30:51 -04:00
( weak-table-ref fdports fdes ) )
1999-09-14 09:32:05 -04:00
;Hmm... these shouldn't be necessary. But still.
;Fake defrec routines for backwards compatibility.
( define ( fdport-data:fd fdport* )
1999-10-08 12:43:39 -04:00
( channel-os-index ( fdport-data:channel fdport* ) ) )
1999-09-14 09:32:05 -04:00
( define ( fdport-data:closed? fdport* )
( eq? ( channel-status ( fdport-data:channel fdport* ) )
( enum channel-status-option closed ) ) )
2001-03-23 05:59:07 -05:00
;;; Support for channel-ready?
;;; This applies to input- and output-ports
2001-04-09 03:55:50 -04:00
( define ( fdport-channel-ready? fdport )
( channel-ready? ( fdport-data:channel ( port-data fdport ) ) ) )
2001-03-23 05:59:07 -05:00
1999-09-14 09:32:05 -04:00
;Arbitrary, for now.
( define buffer-size 255 )
( define open-fdchannel open-channel )
( define ( make-input-fdchannel fd )
( open-fdchannel fd ( enum channel-status-option input ) ) )
( define ( make-output-fdchannel fd )
( open-fdchannel fd ( enum channel-status-option output ) ) )
;The two following routines are to build ports from stdin and stdout channels.
( define ( channel-port->input-fdport channel-port )
2001-03-23 05:59:07 -05:00
( let ( ( p ( make-buffered-input-port input-fdport-handler
( make-fdport-data
( channel-cell-ref ( port-data channel-port ) ) 1 )
1999-11-02 17:41:05 -05:00
( make-byte-vector buffer-size 0 ) 0 0 ) ) )
1999-09-14 09:32:05 -04:00
( obtain-port-lock channel-port )
( set-port-lock! p ( port-lock channel-port ) )
( set-port-locked?! p ( port-locked? channel-port ) )
( install-fdport p )
( release-port-lock channel-port )
p ) )
( define ( channel-port->output-fdport channel-port )
2001-03-23 05:59:07 -05:00
( let ( ( p ( make-buffered-output-port
output-fdport-handler
( make-fdport-data ( channel-cell-ref ( port-data channel-port ) ) 1 )
( make-byte-vector buffer-size 0 ) 0 buffer-size ) ) )
1999-09-14 09:32:05 -04:00
( obtain-port-lock channel-port )
( set-port-lock! p ( port-lock channel-port ) )
( set-port-locked?! p ( port-locked? channel-port ) )
( install-fdport p )
( periodically-force-output! p )
( release-port-lock channel-port )
p ) )
1999-10-22 17:35:54 -04:00
( define ( channel-port->unbuffered-output-fdport channel-port )
( let ( ( p ( make-unbuffered-output-port unbuffered-output-fdport-handler
2001-03-23 05:59:07 -05:00
( make-fdport-data
( channel-cell-ref ( port-data channel-port ) ) 1 ) ) ) )
1999-10-22 17:35:54 -04:00
( obtain-port-lock channel-port )
( set-port-lock! p ( port-lock channel-port ) )
( set-port-locked?! p ( port-locked? channel-port ) )
( install-fdport p )
2001-03-23 05:59:07 -05:00
( periodically-force-output! p )
1999-10-22 17:35:54 -04:00
( release-port-lock channel-port )
p ) )
1999-09-14 09:32:05 -04:00
( define ( alloc-input-fdport fd revealed )
2001-03-23 05:59:07 -05:00
( make-buffered-input-port input-fdport-handler
1999-09-14 09:32:05 -04:00
( make-fdport-data ( make-input-fdchannel fd ) revealed )
1999-11-02 17:41:05 -05:00
( make-byte-vector buffer-size 0 ) 0 0 ) )
1999-09-14 09:32:05 -04:00
( define ( alloc-output-fdport fd revealed )
2001-03-23 05:59:07 -05:00
( make-buffered-output-port output-fdport-handler
1999-09-14 09:32:05 -04:00
( make-fdport-data ( make-output-fdchannel fd ) revealed )
1999-11-02 17:41:05 -05:00
( make-byte-vector buffer-size 0 ) 0 buffer-size ) )
1999-09-14 09:32:05 -04:00
( define ( make-input-fdport fd revealed )
( let ( ( p ( alloc-input-fdport fd revealed ) ) )
( install-fdport p )
p ) )
( define ( make-output-fdport fd revealed )
( let ( ( p ( alloc-output-fdport fd revealed ) ) )
2001-03-23 05:59:07 -05:00
( periodically-force-output! p )
1999-09-14 09:32:05 -04:00
( install-fdport p )
p ) )
( define ( fdport? x )
( cond ( ( or ( and ( input-port? x ) ( port-data x ) )
( and ( output-port? x ) ( port-data x ) ) )
=> ( lambda ( d ) ( fdport-data? d ) ) )
( else #f ) ) )
( define fdport-null-method ( lambda ( x ) x #f ) )
( define null-func ( lambda args #t ) )
( define ( close-fdport* fdport* )
2001-06-21 04:30:51 -04:00
( table-set! fdports ( channel-os-index ( fdport-data:channel fdport* ) ) #f )
1999-09-14 09:32:05 -04:00
( close-channel ( fdport-data:channel fdport* ) ) )
;The handlers drop straight through to the convenient channel routines.
1999-10-22 17:35:54 -04:00
( define ( make-input-fdport-handler bufferproc )
2001-03-23 05:59:07 -05:00
( make-buffered-input-port-handler
1999-09-14 09:32:05 -04:00
( lambda ( fdport* )
( list 'input-fdport ( fdport-data:channel fdport* ) ) )
close-fdport*
1999-10-22 17:35:54 -04:00
bufferproc
2001-03-23 05:59:07 -05:00
fdport-channel-ready?
1999-09-14 09:32:05 -04:00
( lambda ( fdport* owner )
( steal-channel! ( fdport-data:channel fdport* ) owner ) ) ) )
1999-10-22 17:35:54 -04:00
( define input-fdport-handler
( make-input-fdport-handler
( lambda ( fdport* buffer start needed )
( channel-read buffer start needed ( fdport-data:channel fdport* ) ) ) ) )
( define ( make-output-fdport-handler bufferproc )
2001-03-23 05:59:07 -05:00
( make-buffered-output-port-handler
1999-09-14 09:32:05 -04:00
( lambda ( fdport* )
( list 'output-fdport ( fdport-data:channel fdport* ) ) )
close-fdport*
1999-10-22 17:35:54 -04:00
bufferproc
2001-03-23 05:59:07 -05:00
fdport-channel-ready?
1999-09-14 09:32:05 -04:00
( lambda ( fdport* owner )
( steal-channel! ( fdport-data:channel fdport* ) owner ) ) ) )
1999-10-22 17:35:54 -04:00
( define output-fdport-handler
( make-output-fdport-handler
( lambda ( fdport* buffer start count )
( channel-write buffer start count ( fdport-data:channel fdport* ) ) ) ) )
( define unbuffered-output-fdport-handler
1999-11-02 17:41:05 -05:00
( let ( ( buffer ( make-byte-vector 1 0 ) ) )
1999-10-22 17:35:54 -04:00
( make-output-fdport-handler
( lambda ( fdport* char )
1999-11-02 17:41:05 -05:00
( byte-vector-set! buffer 0 ( char->ascii char ) )
1999-10-22 17:35:54 -04:00
( channel-write buffer 0 1 ( fdport-data:channel fdport* ) ) ) ) ) )
1999-09-14 09:32:05 -04:00
( define fdport-data port-data )
; That was easy.
2001-04-09 03:55:50 -04:00
( define ( guess-output-policy port )
( if ( = 0 ( port-limit port ) )
bufpol/none
bufpol/block ) )
1999-10-22 17:35:54 -04:00
1999-10-08 12:43:39 -04:00
( define ( set-port-buffering port policy . maybe-size )
1999-10-22 17:35:54 -04:00
( cond ( ( and ( fdport? port ) ( open-input-port? port ) )
( let ( ( size ( if ( pair? maybe-size ) ( car maybe-size ) 255 ) ) )
( set-input-port-buffering port policy size ) ) )
( ( and ( fdport? port ) ( open-output-port? port ) )
( let ( ( size ( if ( pair? maybe-size ) ( car maybe-size ) 255 ) ) )
( if ( <= size 0 ) ( error "size must be at least 1" ) )
( set-output-port-buffering port policy size ) ) )
( else
2001-03-23 05:59:07 -05:00
( warn "port-type not supported" port ) ) ) )
1999-10-22 17:35:54 -04:00
( define ( set-output-port-buffering port policy size )
2001-03-23 05:59:07 -05:00
( cond ( ( eq? policy bufpol/none )
1999-10-22 17:35:54 -04:00
( install-nullbuffer port unbuffered-output-fdport-handler ) )
2001-03-23 05:59:07 -05:00
( ( eq? policy bufpol/block )
1999-11-02 17:41:05 -05:00
( let ( ( old-size ( byte-vector-length ( port-buffer port ) ) )
( new-buffer ( make-byte-vector size 0 ) ) )
1999-10-22 17:35:54 -04:00
( if ( < size old-size )
( begin
( really-force-output port )
( obtain-port-lock port )
( set-port-index! port 0 ) )
( begin
( obtain-port-lock port )
( copy-bytes! ( port-buffer port ) 0 new-buffer 0 old-size ) ) )
( install-buffer port new-buffer size )
( release-port-lock port ) ) )
2001-03-23 05:59:07 -05:00
( ( eq? policy bufpol/line )
1999-10-22 17:35:54 -04:00
( install-nullbuffer port ( make-line-output-proc size ) ) )
( else ( warn "policy not supported " policy ) ) ) )
( define ( install-nullbuffer port handler )
( really-force-output port )
( obtain-port-lock port )
( set-port-limit! port 0 )
( set-port-index! port 0 )
1999-11-02 17:41:05 -05:00
( set-port-buffer! port ( make-byte-vector 0 0 ) )
1999-10-22 17:35:54 -04:00
( set-port-handler! port handler )
( release-port-lock port ) )
( define ( install-buffer port new-buffer size )
2001-03-23 05:59:07 -05:00
( if ( eq? bufpol/none ( guess-output-policy port ) )
1999-10-22 17:35:54 -04:00
( set-port-handler! port output-fdport-handler ) )
( set-port-limit! port size )
( set-port-buffer! port new-buffer ) )
2000-06-28 06:27:34 -04:00
; TODO flush on stdinput is required but probably impossible since current-input-port is a fluid and may change without notice. One possibility would be to override (current-input-port)
1999-10-22 17:35:54 -04:00
;;; This port can ONLY be flushed with a newline or a close-output
;;; flush-output won't help
( define ( make-line-output-proc size )
1999-11-02 17:41:05 -05:00
( let ( ( proc-buffer ( make-byte-vector size 0 ) )
1999-10-22 17:35:54 -04:00
( proc-buffer-index 0 ) )
2001-03-23 05:59:07 -05:00
( make-buffered-output-port-handler
1999-10-22 17:35:54 -04:00
( lambda ( fdport* )
( list 'output-fdport ( fdport-data:channel fdport* ) ) )
( lambda ( fdport* )
( channel-write proc-buffer
0
proc-buffer-index
( fdport-data:channel fdport* ) )
( close-fdport* fdport* ) )
( lambda ( fdport* char )
1999-11-02 17:41:05 -05:00
( byte-vector-set! proc-buffer proc-buffer-index ( char->ascii char ) )
1999-10-22 17:35:54 -04:00
( set! proc-buffer-index ( + proc-buffer-index 1 ) )
( cond ( ( or ( eq? char #\newline ) ( = proc-buffer-index size ) )
( channel-write proc-buffer
0
proc-buffer-index
( fdport-data:channel fdport* ) )
( set! proc-buffer-index 0 ) ) ) )
2001-03-23 05:59:07 -05:00
fdport-channel-ready?
1999-10-22 17:35:54 -04:00
( lambda ( fdport* owner )
( steal-channel! ( fdport-data:channel fdport* ) owner ) ) ) ) )
1999-10-08 12:43:39 -04:00
1999-10-22 17:35:54 -04:00
( define ( set-input-port-buffering port policy size )
2001-03-23 05:59:07 -05:00
( cond ( ( eq? policy bufpol/none )
( set-input-port-buffering port bufpol/block 1 ) )
( ( eq? policy bufpol/block )
1999-10-22 17:35:54 -04:00
( if ( <= size 0 ) ( error "size must be at least 1" ) )
( install-input-handler port input-fdport-handler size #t ) )
2001-03-23 05:59:07 -05:00
( ( eq? policy bufpol/line )
1999-11-02 17:41:05 -05:00
( error "bufpol/line not allowed on input" ) )
1999-10-22 17:35:54 -04:00
( else ( warn "policy not supported " policy ) ) ) )
( define ( install-input-handler port new-handler size gentle? )
( obtain-port-lock port )
( let* ( ( old-limit ( port-limit port ) )
( old-index ( port-index port ) )
( old-buffer ( port-buffer port ) )
( old-unread ( - old-limit old-index ) )
( new-unread ( min old-unread size ) )
( throw-away ( max 0 ( - old-unread new-unread ) ) )
1999-11-02 17:41:05 -05:00
( new-buffer ( make-byte-vector size 0 ) ) )
1999-10-22 17:35:54 -04:00
( if ( not gentle? )
( let ( ( ret ( if ( > throw-away 0 )
( let ( ( return-buffer
1999-11-02 17:41:05 -05:00
( make-byte-vector throw-away 0 ) ) )
1999-10-22 17:35:54 -04:00
( copy-bytes! old-buffer old-index
return-buffer 0
throw-away ) return-buffer )
#f ) ) )
( copy-bytes! old-buffer ( + old-index throw-away )
new-buffer 0
new-unread )
( set-port-buffer! port new-buffer )
( set-port-index! port 0 )
( set-port-limit! port new-unread )
( set-port-handler! port new-handler )
( release-port-lock port )
ret )
( begin
( install-drain-port-handler
old-buffer old-index old-limit port new-handler )
( set-port-buffer! port new-buffer )
( set-port-index! port 0 )
( set-port-limit! port 0 )
( release-port-lock port )
#t ) ) ) )
( define ( install-drain-port-handler
old-buffer old-start old-limit port new-handler )
( if ( < 0 ( - old-limit old-start ) )
( set-port-handler! port
( make-drain-port-handler
old-buffer old-start old-limit port new-handler ) )
( set-port-handler! port new-handler ) ) )
;;; TODO: This reference to port will prevent gc !!!
( define ( make-drain-port-handler
very-old-buffer old-start old-limit port new-handler )
1999-11-02 17:41:05 -05:00
( let ( ( old-buffer ( make-byte-vector old-limit 0 ) ) )
1999-10-22 17:35:54 -04:00
( copy-bytes! very-old-buffer 0 old-buffer 0 old-limit )
( make-input-fdport-handler
( lambda ( data buffer start needed )
1999-11-02 17:41:05 -05:00
( let ( ( old-left ( - ( byte-vector-length old-buffer ) old-start ) ) )
1999-10-22 17:35:54 -04:00
( let ( ( size ( cond ( ( or ( eq? needed 'any ) ( eq? needed 'immediate ) )
( min old-left
1999-11-02 17:41:05 -05:00
( byte-vector-length buffer ) ) )
1999-10-22 17:35:54 -04:00
( else ( min needed old-left ) ) ) ) )
( copy-bytes! old-buffer old-start buffer start size )
( set! old-start ( + size old-start ) )
1999-11-02 17:41:05 -05:00
( if ( = old-start ( byte-vector-length old-buffer ) ) ;buffer drained ?
1999-10-22 17:35:54 -04:00
( begin
( set-port-handler! port new-handler )
( if ( and ( integer? needed ) ( > needed size ) )
( + size ( ( port-handler-buffer-proc new-handler )
data buffer ( + start size ) ( - needed size ) ) )
size ) )
size ) ) ) ) ) ) )
1999-11-02 17:41:05 -05:00
1999-09-14 09:32:05 -04:00
;;; Open & Close
;;; ------------
1999-10-22 17:35:54 -04:00
;;; replace rts/channel-port.scm begin
1999-09-14 09:32:05 -04:00
( define ( open-file fname flags . maybe-mode )
2000-06-28 06:27:34 -04:00
( with-cwd-aligned
2001-07-10 10:52:57 -04:00
( with-umask-aligned
( let ( ( fd ( apply open-fdes fname flags maybe-mode ) )
( access ( bitwise-and flags open/access-mask ) ) )
( ( if ( or ( = access open/read ) ( = access open/read+write ) )
make-input-fdport
make-output-fdport )
fd 0 ) ) ) ) )
1999-09-14 09:32:05 -04:00
( define ( open-input-file fname . maybe-flags )
( let ( ( flags ( :optional maybe-flags 0 ) ) )
( open-file fname ( deposit-bit-field flags open/access-mask open/read ) ) ) )
( define ( open-output-file fname . rest )
( let* ( ( flags ( if ( pair? rest ) ( car rest )
( bitwise-ior open/create open/truncate ) ) ) ; default
( maybe-mode ( if ( null? rest ) ' ( ) ( cdr rest ) ) )
( flags ( deposit-bit-field flags open/access-mask open/write ) ) )
( apply open-file fname flags maybe-mode ) ) )
1999-10-22 17:35:54 -04:00
;;; replace rts/channel-port.scm end
1999-09-14 09:32:05 -04:00
;;; All these revealed-count-hacking procs have atomicity problems.
;;; They need to run uninterrupted.
;;; (port-locks should do the trick -df)
;;; (what else has atomicity problems? -df)
( define ( increment-revealed-count port delta )
( obtain-port-lock port )
( let* ( ( data ( fdport-data port ) )
( count ( fdport-data:revealed data ) )
( newcount ( + count delta ) ) )
( set-fdport-data:revealed data newcount )
( if ( and ( zero? count ) ( > newcount 0 ) ) ; We just became revealed,
( begin
2001-06-21 04:30:51 -04:00
( strengthen-weak-table-ref fdports ( fdport-data:fd data ) )
1999-09-14 09:32:05 -04:00
( %set-cloexec ( fdport-data:fd data ) #f ) ) ) ) ; so don't close on exec().
( release-port-lock port ) )
( define ( release-port-handle port )
( check-arg fdport? port port->fdes )
( obtain-port-lock port )
( let* ( ( data ( fdport-data port ) )
( rev ( fdport-data:revealed data ) ) )
( if ( not ( zero? rev ) )
; (set-fdport-data:old-revealed data
; (- (fdport-data:old-revealed data) 1))
( let ( ( new-rev ( - rev 1 ) ) )
( set-fdport-data:revealed data new-rev )
( if ( zero? new-rev ) ; We just became unrevealed, so
( begin ; the fd can be closed on exec.
2001-06-21 04:30:51 -04:00
( weaken-weak-table-ref fdports ( fdport-data:fd data ) )
1999-09-14 09:32:05 -04:00
( %set-cloexec ( fdport-data:fd data ) #t ) ) ) ) ) )
( release-port-lock port ) )
( define ( port-revealed port )
( let ( ( count ( fdport-data:revealed
( fdport-data
( check-arg fdport? port port-revealed ) ) ) ) )
( and ( not ( zero? count ) ) count ) ) )
( define ( fdes->port fd port-maker ) ; local proc.
( cond ( ( maybe-fdes->port fd ) =>
( lambda ( p )
( increment-revealed-count p 1 )
p ) )
( else ( port-maker fd 1 ) ) ) )
( define ( fdes->inport fd ) ( fdes->port fd make-input-fdport ) )
( define ( fdes->outport fd ) ( fdes->port fd make-output-fdport ) )
( define ( port->fdes port )
( check-arg open-fdport? port port->fdes )
( let ( ( data ( fdport-data port ) ) )
( increment-revealed-count port 1 )
( fdport-data:fd data ) ) )
( define ( call/fdes fd/port proc )
( cond ( ( integer? fd/port )
( proc fd/port ) )
( ( fdport? fd/port )
( let ( ( port fd/port ) )
( dynamic-wind
( lambda ( )
( if ( not port ) ( error "Can't throw back into call/fdes." ) ) )
( lambda ( ) ( proc ( port->fdes port ) ) )
( lambda ( )
( release-port-handle port )
( set! port #f ) ) ) ) )
( else ( error "Not a file descriptor or fdport." fd/port ) ) ) )
;;; Don't mess with the revealed count in the port case
;;; -- just sneakily grab the fdes and run.
( define ( sleazy-call/fdes fd/port proc )
( proc ( cond ( ( integer? fd/port ) fd/port )
( ( fdport? fd/port ) ( fdport-data:fd ( fdport-data fd/port ) ) )
( else ( error "Not a file descriptor or fdport." fd/port ) ) ) ) )
;;; Random predicates and arg checkers
;;; ----------------------------------
( define ( open-fdport-data? x )
( and ( fdport-data? x )
( not ( fdport-data:closed? x ) ) ) )
( define ( open-fdport? x )
( and ( fdport? x ) ( or ( open-output-port? x ) ( open-input-port? x ) ) ) )
( define ( fdport-open? port )
( check-arg fdport? port fdport-open? )
( not ( fdport-data:closed? ( port-data port ) ) ) )
;;; Initialise the system
;;; ---------------------
1999-10-08 12:43:39 -04:00
;;; JMG: should be deprecated-proc
( define error-output-port
current-error-port )
1999-09-14 09:32:05 -04:00
( define old-inport #f ) ; Just because.
( define old-outport #f )
( define old-errport #f )
( define ( init-fdports! )
( if ( not ( fdport? ( current-input-port ) ) )
( set! old-inport ( current-input-port ) ) )
( if ( not ( fdport? ( current-output-port ) ) )
( set! old-outport ( current-output-port ) ) )
( if ( not ( fdport? ( current-error-port ) ) )
( set! old-errport ( current-error-port ) ) )
2001-03-23 05:59:07 -05:00
( set-fluid! $current-input-port
( channel-port->input-fdport ( current-input-port ) ) )
( set-fluid! $current-output-port
( channel-port->output-fdport ( current-output-port ) ) )
1999-09-24 19:52:32 -04:00
2001-03-23 05:59:07 -05:00
( set-fluid! $current-error-port
( channel-port->unbuffered-output-fdport ( current-error-port ) ) )
1999-10-08 12:43:39 -04:00
( set-fluid! $current-noise-port ( make-null-output-port ) ) )
1999-09-14 09:32:05 -04:00
;;; Generic port operations
;;; -----------------------
;;; (close-after port f)
;;; Apply F to PORT. When F returns, close PORT, then return F's result.
;;; Does nothing special if you throw out or throw in.
( define ( close-after port f )
( receive vals ( f port )
( close port )
( apply values vals ) ) )
( define ( close port/fd )
( ( cond ( ( integer? port/fd ) close-fdes )
( ( output-port? port/fd ) close-output-port )
( ( input-port? port/fd ) close-input-port )
( else ( error "Not file-descriptor or port" port/fd ) ) ) port/fd ) )
;;; If this fd has an associated input or output port,
;;; move it to a new fd, freeing this one up.
( define ( evict-ports fd )
( cond ( ( maybe-fdes->port fd ) => ; Shouldn't bump the revealed count.
( lambda ( port )
( %move-fdport ( %dup fd ) port 0 ) ) ) ) )
( define ( %move-fdport fd port new-revealed )
( obtain-port-lock port )
( let* ( ( fdport* ( fdport-data port ) )
( ch ( fdport-data:channel fdport* ) )
( old-fd ( channel-os-index ch ) )
2001-07-07 15:29:29 -04:00
( old-vector-ref ( table-ref fdports old-fd ) ) )
1999-09-14 09:32:05 -04:00
( set-fdport-data:revealed fdport* new-revealed )
2001-06-21 04:30:51 -04:00
( table-set! fdports old-fd #f )
1999-09-14 09:32:05 -04:00
( close-channel ch )
2001-04-09 03:55:50 -04:00
( set-fdport-data:channel
1999-09-14 09:32:05 -04:00
fdport*
2001-04-09 03:55:50 -04:00
( make-fd-channel port fd ) )
2001-06-21 04:30:51 -04:00
( table-set! fdports fd old-vector-ref )
1999-09-14 09:32:05 -04:00
( %set-cloexec fd ( not new-revealed ) ) )
1999-10-08 12:43:39 -04:00
( release-port-lock port )
#f ) ; JMG: It used to return #f on succes in 0.5.1, so we do the same
1999-09-14 09:32:05 -04:00
2001-04-09 03:55:50 -04:00
( define ( make-fd-channel port fd )
( ( if ( input-port? port ) make-input-fdchannel make-output-fdchannel ) fd ) )
1999-09-14 09:32:05 -04:00
( define ( close-fdes fd )
( evict-ports fd )
( %close-fdes fd ) )
( define ( flush-fdport fdport )
( check-arg fdport? fdport flush-fdport )
( force-output fdport ) )
( define ( flush-all-ports )
2001-06-21 04:30:51 -04:00
( weak-table-walk
( lambda ( i fdport )
( if ( and fdport ( output-port? fdport ) ) ( flush-fdport fdport ) ) )
fdports ) )
1999-09-14 09:32:05 -04:00
;;; Extend R4RS i/o ops to handle file descriptors.
;;; -----------------------------------------------
( define s48-char-ready? ( structure-ref scheme char-ready? ) )
( define s48-read-char ( structure-ref scheme read-char ) )
( define-simple-syntax
( define-r4rs-input ( name arg . . . ) stream s48name body . . . )
( define ( name arg . . . . maybe-i/o )
( let ( ( stream ( :optional maybe-i/o ( current-input-port ) ) ) )
( cond ( ( input-port? stream ) ( s48name arg . . . stream ) )
( ( integer? stream ) body . . . )
( else ( error "Not a port or file descriptor" stream ) ) ) ) ) )
( define-r4rs-input ( char-ready? ) input s48-char-ready?
( %char-ready-fdes? input ) )
( define-r4rs-input ( read-char ) input s48-read-char
( read-fdes-char input ) )
;structure refs changed to get reference from scheme -dalbertz
( define s48-display ( structure-ref scheme display ) )
( define s48-newline ( structure-ref scheme newline ) )
( define s48-write ( structure-ref scheme write ) )
( define s48-write-char ( structure-ref scheme write-char ) )
( define s48-format ( structure-ref formats format ) )
( define s48-force-output ( structure-ref i/o force-output ) )
( define-simple-syntax
( define-r4rs-output ( name arg . . . ) stream s48name body . . . )
( define ( name arg . . . . maybe-i/o )
( let ( ( stream ( :optional maybe-i/o ( current-output-port ) ) ) )
( cond ( ( output-port? stream ) ( s48name arg . . . stream ) )
( ( integer? stream ) body . . . )
( else ( error "Not a port or file descriptor" stream ) ) ) ) ) )
;;; This one depends upon S48's string ports.
( define-r4rs-output ( display object ) output s48-display
( let ( ( sp ( make-string-output-port ) ) )
( display object sp )
( write-string ( string-output-port-output sp ) output ) ) )
( define-r4rs-output ( newline ) output s48-newline
( write-fdes-char #\newline output ) )
( define-r4rs-output ( write object ) output s48-write
( let ( ( sp ( make-string-output-port ) ) )
( write object sp )
( write-string ( string-output-port-output sp ) output ) ) )
( define-r4rs-output ( write-char char ) output s48-write-char
( write-fdes-char char output ) )
;;; S48's force-output doesn't default to forcing (current-output-port).
( define-r4rs-output ( force-output ) output s48-force-output
( values ) ) ; Do nothing if applied to a file descriptor.
( define ( format dest cstring . args )
( if ( integer? dest )
( write-string ( apply s48-format #f cstring args ) dest )
( apply s48-format dest cstring args ) ) )
;;; with-current-foo-port procs
;;; ---------------------------
( define ( with-current-input-port* port thunk )
( let-fluid $current-input-port port thunk ) )
( define ( with-current-output-port* port thunk )
( let-fluid $current-output-port port thunk ) )
( define ( with-current-error-port* port thunk )
( let-fluid $current-error-port port thunk ) )
( define-simple-syntax ( with-current-input-port port body . . . )
( with-current-input-port* port ( lambda ( ) body . . . ) ) )
( define-simple-syntax ( with-current-output-port port body . . . )
( with-current-output-port* port ( lambda ( ) body . . . ) ) )
( define-simple-syntax ( with-current-error-port port body . . . )
( with-current-error-port* port ( lambda ( ) body . . . ) ) )
;;; set-foo-port! procs
;;; -------------------
;;; Side-effecting variants of with-current-input-port* and friends.
( define ( set-current-input-port! port ) ( set-fluid! $current-input-port port ) )
( define ( set-current-output-port! port ) ( set-fluid! $current-output-port port ) )
( define ( set-current-error-port! port ) ( set-fluid! $current-error-port port ) )
;;; call-with-foo-file with-foo-to-file
;;; -----------------------------------
;;; Copied straight from rts/port.scm, but re-defined in this module,
;;; closed over my versions of open-input-file and open-output-file.
( define ( call-with-mumble-file open close )
( lambda ( string proc )
2000-06-28 06:27:34 -04:00
( with-cwd-aligned
2001-07-10 10:52:57 -04:00
( with-umask-aligned
( let ( ( port #f ) )
( dynamic-wind ( lambda ( )
( if port
( warn "throwing back into a call-with-...put-file"
string )
( set! port ( open string ) ) ) )
( lambda ( ) ( proc port ) )
( lambda ( )
( if port
( close port ) ) ) ) ) ) ) ) )
1999-09-14 09:32:05 -04:00
1999-10-22 17:35:54 -04:00
;;; replace rts/channel-port.scm begin
1999-09-14 09:32:05 -04:00
( define call-with-input-file
( call-with-mumble-file open-input-file close-input-port ) )
( define call-with-output-file
( call-with-mumble-file open-output-file close-output-port ) )
( define ( with-input-from-file string thunk )
( call-with-input-file string
( lambda ( port )
( let-fluid $current-input-port port thunk ) ) ) )
( define ( with-output-to-file string thunk )
( call-with-output-file string
( lambda ( port )
( let-fluid $current-output-port port thunk ) ) ) )
1999-10-22 17:35:54 -04:00
2001-03-23 05:59:07 -05:00
;;; replace rts/channel-port.scm end
2001-04-09 03:55:50 -04:00
( define ( nselect rvec wvec evec timeout )
( let ( ( rlist ( vector->list rvec ) )
( wlist ( vector->list wvec ) ) )
( let ( ( imm-r ( filter char-ready? rlist ) )
( imm-w ( filter output-port-ready? wlist ) ) )
( if ( and ( null? imm-r )
( null? imm-w ) )
( select-threaded rlist wlist timeout )
( values ( list->vector imm-r )
( list->vector imm-w )
' # ( ) ) ) ) ) )
( define ( timeout-thread result-lock timeout )
( lambda ( )
( ( structure-ref threads sleep ) timeout )
( release-lock result-lock ) ) )
( define ( select-threaded rlist wlist timeout )
( let ( ( result-lock ( make-lock ) )
( ready-lock ( make-lock ) )
( read-ready ( cons 'cell ' ( ) ) )
( write-ready ( cons 'cell ' ( ) ) )
( are-we-ready? #f ) )
( let* ( ( port-waiter
( lambda ( ready? ready-list )
( lambda ( port )
( lambda ( )
; ((structure-ref interrupts disable-interrupts!))
; (if (ready? port)
; ((structure-ref interrupts enable-interrupts!))
; (wait-for-channel ; enables interrupts
; (fdport-data:channel
; (fdport-data port))))
( let lp ( )
( if ( ready? port )
( begin
( obtain-lock ready-lock )
( set-cdr! ready-list ( cons port ( cdr ready-list ) ) )
( release-lock ready-lock )
( release-lock result-lock ) )
( if ( not are-we-ready? )
( begin ( ( structure-ref threads sleep ) 20 )
( lp ) ) ) ) ) ) ) ) )
( read-waiter ( port-waiter char-ready? read-ready ) )
( write-waiter ( port-waiter output-port-ready? write-ready ) ) )
( obtain-lock result-lock )
( for-each spawn ( map read-waiter rlist ) )
( for-each spawn ( map write-waiter wlist ) )
( if timeout ( spawn ( timeout-thread result-lock timeout ) ) )
( obtain-lock result-lock )
( set! are-we-ready? #t )
; (relinquish-timeslice)
( values ( cdr read-ready )
( cdr write-ready )
' # ( ) ) ) ) )