~ chicken-core (chicken-5) 3693970dc8b09eabc2c2ba6c04b268edef3ec8fa
commit 3693970dc8b09eabc2c2ba6c04b268edef3ec8fa Author: Evan Hanson <evhan@foldling.org> AuthorDate: Thu Jun 30 20:09:46 2016 +1200 Commit: Peter Bex <peter@more-magic.net> CommitDate: Sat Jul 9 16:26:41 2016 +0200 Add input-port-open? and output-port-open? procedures These test whether a port is open in a specific direction. Signed-off-by: Peter Bex <peter@more-magic.net> diff --git a/NEWS b/NEWS index fa8188c8..775ee576 100644 --- a/NEWS +++ b/NEWS @@ -33,6 +33,8 @@ - `with-error-output-to-port' from the ports module has been renamed to the more common `with-error-to-port', and `with-error-to-string' has been added for completeness (thanks to Michael Silver). + - New `input-port-open?` and `output-port-open?` procedures have been + added for testing whether a port is open in a specific direction. - Module system - The compiler has been modularised, for improved namespacing. This diff --git a/chicken.h b/chicken.h index 509af5c4..fe109ffe 100644 --- a/chicken.h +++ b/chicken.h @@ -1180,8 +1180,6 @@ typedef void (C_ccall *C_proc)(C_word, C_word *) C_noret; #define C_vectorp(x) C_mk_bool(C_header_bits(x) == C_VECTOR_TYPE) #define C_bytevectorp(x) C_mk_bool(C_header_bits(x) == C_BYTEVECTOR_TYPE) #define C_portp(x) C_mk_bool(C_header_bits(x) == C_PORT_TYPE) -#define C_input_portp(x) C_mk_bool(C_header_bits(x) == C_PORT_TYPE && C_block_item(x, 1) & 0x2) -#define C_output_portp(x) C_mk_bool(C_header_bits(x) == C_PORT_TYPE && C_block_item(x, 1) & 0x4) #define C_structurep(x) C_mk_bool(C_header_bits(x) == C_STRUCTURE_TYPE) #define C_locativep(x) C_mk_bool(C_block_header(x) == C_LOCATIVE_TAG) #define C_charp(x) C_mk_bool(((x) & C_IMMEDIATE_TYPE_BITS) == C_CHARACTER_BITS) @@ -1202,6 +1200,14 @@ typedef void (C_ccall *C_proc)(C_word, C_word *) C_noret; #define C_vemptyp(x) C_mk_bool(C_header_size(x) == 0) #define C_notvemptyp(x) C_mk_bool(C_header_size(x) > 0) +#define C_port_typep(x, n) C_mk_bool((C_block_item(x, 1) & n) == n) +#define C_input_portp(x) C_and(C_portp(x), C_port_typep(x, 0x2)) +#define C_output_portp(x) C_and(C_portp(x), C_port_typep(x, 0x4)) + +#define C_port_openp(port, n) C_mk_bool((C_block_item(port, 8) & n) == n) +#define C_input_port_openp(port) C_port_openp(port, 0x2) +#define C_output_port_openp(port) C_port_openp(port, 0x4) + #define C_slot(x, i) C_block_item(x, C_unfix(i)) #define C_subbyte(x, i) C_fix(((C_byte *)C_data_pointer(x))[ C_unfix(i) ] & 0xff) #define C_subchar(x, i) C_make_character(((C_uchar *)C_data_pointer(x))[ C_unfix(i) ]) diff --git a/chicken.import.scm b/chicken.import.scm index 2b30f54f..de0ce6bc 100644 --- a/chicken.import.scm +++ b/chicken.import.scm @@ -114,6 +114,7 @@ getter-with-setter implicit-exit-handler infinite? + input-port-open? (ir-macro-transformer . chicken.expand#ir-macro-transformer) keyword-style (load-library . chicken.eval#load-library) @@ -135,6 +136,7 @@ on-exit open-input-string open-output-string + output-port-open? parentheses-synonyms port-closed? port-name diff --git a/library.scm b/library.scm index 1c24ff19..be9c61ae 100644 --- a/library.scm +++ b/library.scm @@ -2506,6 +2506,14 @@ EOF (and (##core#inline "C_blockp" x) (##core#inline "C_output_portp" x))) +(define (input-port-open? p) + (##sys#check-input-port p 'input-port-open?) + (##core#inline "C_input_port_openp" p)) + +(define (output-port-open? p) + (##sys#check-output-port p 'output-port-open?) + (##core#inline "C_output_port_openp" p)) + (define (port-closed? p) (##sys#check-port p 'port-closed?) (fx= (##sys#slot p 8) 0)) @@ -2761,10 +2769,9 @@ EOF (define (close port inp loc) (##sys#check-port port loc) ; repeated closing is ignored - (let* ((old-closed (##sys#slot port 8)) - (new-closed (fxand old-closed (fxnot (if inp 1 2))))) - (unless (fx= new-closed old-closed) ; already closed? - (##sys#setislot port 8 new-closed) + (let ((direction (if inp 1 2))) + (when (##core#inline "C_port_openp" port direction) + (##sys#setislot port 8 (fxand (##sys#slot port 8) (fxnot direction))) ((##sys#slot (##sys#slot port 2) 4) port inp)))) (set! open-input-file (lambda (name . mode) (open name #t mode 'open-input-file))) @@ -2857,12 +2864,12 @@ EOF (##sys#setslot port 3 name) ) (define (##sys#port-line port) - (and (fxodd? (##sys#slot port 1)) ; input port? + (and (##core#inline "C_input_portp" port) (##sys#slot port 4) ) ) (define (port-position #!optional (port ##sys#standard-input)) (##sys#check-port port 'port-position) - (if (fxodd? (##sys#slot port 1)) ; input port? + (if (##core#inline "C_input_portp" port) (##sys#values (##sys#slot port 4) (##sys#slot port 5)) (##sys#error 'port-position "cannot compute position of port" port) ) ) diff --git a/manual/Unit library b/manual/Unit library index 27f66960..ff93fe9a 100644 --- a/manual/Unit library +++ b/manual/Unit library @@ -341,11 +341,21 @@ different behavior. Write buffered output to the given output-port. {{PORT}} defaults to the value of {{(current-output-port)}}. +==== input-port-open? + +<procedure>(input-port-open? PORT)</procedure> + +Is the given {{PORT}} open for input? + +<procedure>(output-port-open? PORT)</procedure> + +Is the given {{PORT}} open for output? + ==== port-closed? <procedure>(port-closed? PORT)</procedure> -Is the given {{PORT}} closed? +Is the given {{PORT}} closed (in all directions)? ==== port-name diff --git a/tests/port-tests.scm b/tests/port-tests.scm index 49b8e138..2fc19a08 100644 --- a/tests/port-tests.scm +++ b/tests/port-tests.scm @@ -95,6 +95,13 @@ EOF (lambda (in) (read-char in))) (get-output-string out)))) +;; {input,output}-port-open? + +(assert (input-port-open? (open-input-string "abc"))) +(assert (output-port-open? (open-output-string))) +(assert-error (input-port-open? (open-output-string))) +(assert-error (output-port-open? (open-input-string "abc"))) + ;; direction-specific port closure (let* ((n 0) @@ -102,26 +109,26 @@ EOF (constantly #t) (lambda () (set! n (add1 n)))))) (close-output-port p) - (assert (not (port-closed? p))) + (assert (input-port-open? p)) (assert (= n 0)) (close-input-port p) - (assert (port-closed? p)) + (assert (not (input-port-open? p))) (assert (= n 1)) (close-input-port p) - (assert (port-closed? p)) + (assert (not (input-port-open? p))) (assert (= n 1))) (let* ((n 0) (p (make-output-port (lambda () (display #\a)) (lambda () (set! n (add1 n)))))) (close-input-port p) - (assert (not (port-closed? p))) + (assert (output-port-open? p)) (assert (= n 0)) (close-output-port p) - (assert (port-closed? p)) + (assert (not (output-port-open? p))) (assert (= n 1)) (close-output-port p) - (assert (port-closed? p)) + (assert (not (output-port-open? p))) (assert (= n 1))) ;; fill buffers diff --git a/types.db b/types.db index dc070f75..259f191e 100644 --- a/types.db +++ b/types.db @@ -756,6 +756,9 @@ (open-output-file (#(procedure #:clean #:enforce) open-output-file (string #!rest symbol) output-port)) (close-input-port (#(procedure #:enforce) close-input-port (input-port) undefined)) (close-output-port (#(procedure #:enforce) close-output-port (output-port) undefined)) +(input-port-open? (#(procedure #:enforce) input-port-open? (input-port) boolean)) +(output-port-open? (#(procedure #:enforce) output-port-open? (output-port) boolean)) + (read (#(procedure #:enforce) read (#!optional input-port) *)) (eof-object? (#(procedure #:pure #:predicate eof) eof-object? (*) boolean))Trap