From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Andreas Rottmann Newsgroups: gmane.lisp.guile.devel Subject: [PATCH 3/4] Work towards a more complete implementation of `(rnrs io ports)' Date: Sun, 21 Nov 2010 23:17:53 +0100 Message-ID: <1290377874-13808-3-git-send-email-a.rottmann@gmx.at> References: <87d3pyz5yo.fsf@delenn.lan> NNTP-Posting-Host: lo.gmane.org X-Trace: dough.gmane.org 1290377929 28152 80.91.229.12 (21 Nov 2010 22:18:49 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Sun, 21 Nov 2010 22:18:49 +0000 (UTC) To: Guile Development Original-X-From: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Sun Nov 21 23:18:45 2010 Return-path: Envelope-to: guile-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1PKIF9-00028t-Rd for guile-devel@m.gmane.org; Sun, 21 Nov 2010 23:18:45 +0100 Original-Received: from localhost ([127.0.0.1]:53322 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PKIF8-0000xE-Lk for guile-devel@m.gmane.org; Sun, 21 Nov 2010 17:18:42 -0500 Original-Received: from [140.186.70.92] (port=58696 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PKIEf-0000jW-7N for guile-devel@gnu.org; Sun, 21 Nov 2010 17:18:15 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PKIEd-0006yI-9w for guile-devel@gnu.org; Sun, 21 Nov 2010 17:18:12 -0500 Original-Received: from mailout-de.gmx.net ([213.165.64.22]:58401 helo=mail.gmx.net) by eggs.gnu.org with smtp (Exim 4.71) (envelope-from ) id 1PKIEc-0006y9-Tx for guile-devel@gnu.org; Sun, 21 Nov 2010 17:18:11 -0500 Original-Received: (qmail invoked by alias); 21 Nov 2010 22:18:09 -0000 Original-Received: from 83-215-154-5.hage.dyn.salzburg-online.at (EHLO nathot.lan) [83.215.154.5] by mail.gmx.net (mp070) with SMTP; 21 Nov 2010 23:18:09 +0100 X-Authenticated: #3102804 X-Provags-ID: V01U2FsdGVkX19ZTqphtLdZlnEL04vFqO/a/bXiafMxgls3dzKIS3 0CzKaU+VLTTvBS Original-Received: from localhost (localhost.localdomain [127.0.0.1]) by nathot.lan (Postfix) with ESMTP id 790B93A693 for ; Sun, 21 Nov 2010 23:18:09 +0100 (CET) Original-Received: from nathot.lan ([127.0.0.1]) by localhost (nathot.lan [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id SXL6MxoZJLRI for ; Sun, 21 Nov 2010 23:18:02 +0100 (CET) Original-Received: from delenn.lan (delenn.lan [192.168.3.11]) by nathot.lan (Postfix) with ESMTP id ACFE63A6A1 for ; Sun, 21 Nov 2010 23:17:54 +0100 (CET) Original-Received: by delenn.lan (Postfix, from userid 1000) id 64E0D2C05BE; Sun, 21 Nov 2010 23:17:54 +0100 (CET) X-Mailer: git-send-email 1.7.2.3 In-Reply-To: <87d3pyz5yo.fsf@delenn.lan> X-Y-GMX-Trusted: 0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-BeenThere: guile-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Developers list for Guile, the GNU extensibility library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Errors-To: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.devel:11185 Archived-At: * module/rnrs/io/ports.scm: (file-options, buffer-mode, eol-style) (error-handling-mode, make-transcoder, native-transcoder) (latin-1-codec, utf-8-codec, utf-16-codec) (call-with-bytevector-output-port, open-file-input-port) (open-file-output-port, make-custom-textual-output-port) (flush-output-port, put-char, put-datum, put-string, get-char) (get-datum, get-line, get-string-all, lookahead-char) (standard-input-port, standard-output-port, standard-error-port): Define all of these. (call-with-port): Don't use `dynamic-wind', as it is against its specification in R6RS 8.2.6. * module/rnrs.scm: Export procedures added. * module/rnrs/io/simple.scm (call-with-input-file) (call-with-output-file): Define these in terms of R6RS procedures to get correct exception behavior. --- module/rnrs.scm | 20 ++++- module/rnrs/io/ports.scm | 238 ++++++++++++++++++++++++++++++++++++++++++-- module/rnrs/io/simple.scm | 23 +++-- 3 files changed, 260 insertions(+), 21 deletions(-) diff --git a/module/rnrs.scm b/module/rnrs.scm index 14218f0..e10967b 100644 --- a/module/rnrs.scm +++ b/module/rnrs.scm @@ -160,15 +160,31 @@ ;; (rnrs io ports) + file-options buffer-mode buffer-mode? + eol-style native-eol-style error-handling-mode + make-transcoder transcoder-codec native-transcoder + latin-1-codec utf-8-codec utf-16-codec + eof-object? port? input-port? output-port? eof-object port-transcoder binary-port? transcoded-port port-position set-port-position! - port-has-port-position? port-has-set-port-position!? call-with-port + port-has-port-position? port-has-set-port-position!? + close-port call-with-port open-bytevector-input-port make-custom-binary-input-port get-u8 lookahead-u8 get-bytevector-n get-bytevector-n! get-bytevector-some get-bytevector-all open-bytevector-output-port make-custom-binary-output-port put-u8 put-bytevector open-string-input-port open-string-output-port - + call-with-bytevector-output-port + call-with-string-output-port + latin-1-codec utf-8-codec utf-16-codec + open-file-input-port open-file-output-port + make-custom-textual-output-port + call-with-string-output-port + flush-output-port put-string + get-char get-datum get-line get-string-all lookahead-char + put-char put-datum put-string + standard-input-port standard-output-port standard-error-port + ;; (rnrs io simple) call-with-input-file call-with-output-file current-input-port diff --git a/module/rnrs/io/ports.scm b/module/rnrs/io/ports.scm index 2246049..31c1e29 100644 --- a/module/rnrs/io/ports.scm +++ b/module/rnrs/io/ports.scm @@ -29,16 +29,23 @@ (library (rnrs io ports (6)) (export eof-object eof-object? + ;; auxiliary types + file-options buffer-mode buffer-mode? + eol-style native-eol-style error-handling-mode + make-transcoder transcoder-codec native-transcoder + latin-1-codec utf-8-codec utf-16-codec + ;; input & output ports port? input-port? output-port? port-transcoder binary-port? transcoded-port port-position set-port-position! port-has-port-position? port-has-set-port-position!? - call-with-port + call-with-port close-port ;; input ports open-bytevector-input-port open-string-input-port + open-file-input-port make-custom-binary-input-port ;; binary input @@ -49,11 +56,52 @@ ;; output ports open-bytevector-output-port open-string-output-port + open-file-output-port make-custom-binary-output-port - + call-with-bytevector-output-port + call-with-string-output-port + make-custom-textual-output-port + flush-output-port + ;; binary output - put-u8 put-bytevector) - (import (guile)) + put-u8 put-bytevector + + ;; textual input + get-char get-datum get-line get-string-all lookahead-char + + ;; textual output + put-char put-datum put-string + + ;; standard ports + standard-input-port standard-output-port standard-error-port + + ;; condition types + &i/o i/o-error? make-i/o-error + &i/o-read i/o-read-error? make-i/o-read-error + &i/o-write i/o-write-error? make-i/o-write-error + &i/o-invalid-position i/o-invalid-position-error? + make-i/o-invalid-position-error + &i/o-filename i/o-filename-error? make-i/o-filename-error + i/o-error-filename + &i/o-file-protection i/o-file-protection-error? + make-i/o-file-protection-error + &i/o-file-is-read-only i/o-file-is-read-only-error? + make-i/o-file-is-read-only-error + &i/o-file-already-exists i/o-file-already-exists-error? + make-i/o-file-already-exists-error + &i/o-file-does-not-exist i/o-file-does-not-exist-error? + make-i/o-file-does-not-exist-error + &i/o-port i/o-port-error? make-i/o-port-error + i/o-error-port) + (import (only (rnrs base) assertion-violation) + (rnrs enums) + (rnrs records syntactic) + (rnrs exceptions) + (rnrs conditions) + (rnrs files) ;for the condition types + (srfi srfi-8) + (ice-9 rdelim) + (except (guile) raise)) (load-extension (string-append "libguile-" (effective-version)) "scm_init_r6rs_ports") @@ -61,6 +109,78 @@ ;;; +;;; Auxiliary types +;;; + +(define-enumeration file-option + (no-create no-fail no-truncate) + file-options) + +(define-enumeration buffer-mode + (none line block) + buffer-modes) + +(define (buffer-mode? symbol) + (enum-set-member? symbol (enum-set-universe (buffer-modes)))) + +(define-enumeration eol-style + (lf cr crlf nel crnel ls) + eol-styles) + +(define (native-eol-style) + (eol-style lf)) + +(define-enumeration error-handling-mode + (ignore raise replace) + error-handling-modes) + +(define-record-type (transcoder %make-transcoder transcoder?) + (fields codec eol-style error-handling-mode)) + +(define* (make-transcoder codec + #:optional + (eol-style (native-eol-style)) + (handling-mode (error-handling-mode replace))) + (%make-transcoder codec eol-style handling-mode)) + +(define (native-transcoder) + (make-transcoder (or (fluid-ref %default-port-encoding) + (latin-1-codec)))) + +(define (latin-1-codec) + "ISO-8859-1") + +(define (utf-8-codec) + "UTF-8") + +(define (utf-16-codec) + "UTF-16") + + +;;; +;;; Internal helpers +;;; + +(define (with-i/o-filename-conditions filename thunk) + (catch 'system-error + thunk + (lambda args + (let ((errno (system-error-errno args))) + (let ((construct-condition + (cond ((= errno EACCES) + make-i/o-file-protection-error) + ((= errno EEXIST) + make-i/o-file-already-exists-error) + ((= errno ENOENT) + make-i/o-file-does-not-exist-error) + ((= errno EROFS) + make-i/o-file-is-read-only-error) + (else + make-i/o-filename-error)))) + (raise (construct-condition filename))))))) + + +;;; ;;; Input and output ports. ;;; @@ -100,19 +220,33 @@ read from/written to in @var{port}." (define (call-with-port port proc) "Call @var{proc}, passing it @var{port} and closing @var{port} upon exit of @var{proc}. Return the return values of @var{proc}." - (dynamic-wind - (lambda () - #t) - (lambda () - (proc port)) - (lambda () - (close-port port)))) + (call-with-values + (lambda () (proc port)) + (lambda vals + (close-port port) + (apply values vals)))) + +(define* (call-with-bytevector-output-port proc #:optional (transcoder #f)) + (receive (port extract) (open-bytevector-output-port transcoder) + (call-with-port port proc) + (extract))) (define (open-string-input-port str) "Open an input port that will read from @var{str}." (with-fluids ((%default-port-encoding "UTF-8")) (open-input-string str))) +(define* (open-file-input-port filename + #:optional + (file-options (file-options)) + (buffer-mode (buffer-mode block)) + maybe-transcoder) + (let ((port (with-i/o-filename-conditions filename + (lambda () (open filename O_RDONLY))))) + (cond (maybe-transcoder + (set-port-encoding! port (transcoder-codec maybe-transcoder)))) + port)) + (define (open-string-output-port) "Return two values: an output port that will collect characters written to it as a string, and a thunk to retrieve the characters associated with that port." @@ -121,6 +255,88 @@ as a string, and a thunk to retrieve the characters associated with that port." (values port (lambda () (get-output-string port))))) +(define* (open-file-output-port filename + #:optional + (file-options (file-options)) + (buffer-mode (buffer-mode block)) + maybe-transcoder) + (let* ((flags (logior O_WRONLY + (if (enum-set-member? 'no-create file-options) + 0 + O_CREAT) + (if (enum-set-member? 'no-truncate file-options) + 0 + O_TRUNC))) + (port (with-i/o-filename-conditions filename + (lambda () (open filename flags))))) + (cond (maybe-transcoder + (set-port-encoding! port (transcoder-codec maybe-transcoder)))) + port)) + +(define (call-with-string-output-port proc) + "Call @var{proc}, passing it a string output port. When @var{proc} returns, +return the characters accumulated in that port." + (let ((port (open-output-string))) + (proc port) + (get-output-string port))) + +(define (make-custom-textual-output-port id + write! + get-position + set-position! + close) + (make-soft-port (vector (lambda (c) (write! (string c) 0 1)) + (lambda (s) (write! s 0 (string-length s))) + #f ;flush + #f ;read character + close) + "w")) + +(define (flush-output-port port) + (force-output port)) + +(define (put-char port char) + (write-char char port)) + +(define (put-datum port datum) + (write datum port)) + +(define* (put-string port s #:optional start count) + (cond ((not (string? s)) + (assertion-violation 'put-string "expected string" s)) + ((and start count) + (display (substring/shared s start (+ start count)) port)) + (start + (display (substring/shared s start (string-length s)) port)) + (else + (display s port)))) + +(define (get-char port) + (read-char port)) + +(define (get-datum port) + (read port)) + +(define (get-line port) + (read-line port 'trim)) + +(define (get-string-all port) + (read-delimited "" port 'concat)) + +(define (lookahead-char port) + (peek-char port)) + + + +(define (standard-input-port) + (dup->inport 0)) + +(define (standard-output-port) + (dup->outport 1)) + +(define (standard-error-port) + (dup->outport 2)) + ) ;;; ports.scm ends here diff --git a/module/rnrs/io/simple.scm b/module/rnrs/io/simple.scm index 17acdf1..59e614d 100644 --- a/module/rnrs/io/simple.scm +++ b/module/rnrs/io/simple.scm @@ -83,15 +83,16 @@ i/o-port-error? i/o-error-port) - (import (only (rnrs io ports) eof-object - eof-object? - - input-port? - output-port?) + (import (only (rnrs io ports) + call-with-port + open-file-input-port + open-file-output-port + eof-object + eof-object? + + input-port? + output-port?) (only (guile) @@ - call-with-input-file - call-with-output-file - current-input-port current-output-port current-error-port @@ -115,5 +116,11 @@ (rnrs base (6)) (rnrs files (6)) ;for the condition types ) + + (define (call-with-input-file filename proc) + (call-with-port (open-file-input-port filename) proc)) + + (define (call-with-output-file filename proc) + (call-with-port (open-file-output-port filename) proc)) ) -- 1.7.2.3