[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

A few random I/O proposals

   Date: Tue, 26 May 92 17:49:59 -0400
   From: "Guillermo J. Rozas" <jinx@martigny.ai.mit.edu>
   Reply-To: jinx@martigny.ai.mit.edu

   *   * It is impossible to open a file while allowing for the possibility
   *   that it might not be openable.  The section on open-input-file says
   *   that "If the file cannot be opened, an error is signalled"; this may
   *   be okay for some circumstances, but there are times when you want
   *   something better than this.  Two solutions that have been proposed are
   *   to have some other value be returned in this circumstance, #f being
   *   the obvious choice; or to allow the user some way to signal errors.

   I object strongly to the "return #f" solution.  It only leads to code
   dying later in obscure ways because people forget to check.
   An error/condition system can handle this reasonably well.

The current Scheme I/O system is a toy.  It cannot handle read-write
files, positioning files, pipes, and other standard POSIX functions.
Earlier this year I got so annoyed with the Scheme I/O system that I
rewrote SCM's OPEN procedures in terms of ANSI_C/POSIX functions.

My functions return #f for failure.  Despite dire warnings from
several people on comp.lang.scheme, I have NEVER been burnt by this
(and I make lots of mistakes).  It is easy to write the Scheme
standard OPEN- functions in terms of OPEN-FILE.  Here are my
definitions from Init.scm.  COULD-NOT-OPEN handles the error condition
if it is defined.

(define (open-input-file str)
  (or (open-file str OPEN_READ)
      (and (procedure? could-not-open) (could-not-open) #f)
      (error "OPEN-INPUT-FILE couldn't find file " str)))
(define (open-output-file str)
  (or (open-file str OPEN_WRITE)
      (and (procedure? could-not-open) (could-not-open) #f)
      (error "OPEN-OUTPUT-FILE couldn't find file " str)))

(define close-input-port close-port)
(define close-output-port close-port)

(define (file-exists? str)
  (let ((port (open-file str OPEN_READ)))
    (if port (begin (close-port port) #t)

(define load
      (lambda (file)
	(cond ((> (verbose) 0)
	       (display ";loading ")
	       (write file)
	(or (try-load file)
	    ;;HERE is where the suffix gets specified
	    (try-load (string-append file ".scm"))
	    (and (procedure? could-not-open) (could-not-open) #f)
	    (error "LOAD couldn't find file " file))
	(set-errno! 0)
	(cond ((> (verbose) 0)
	       (display ";done loading ")
	       (write file)
(define could-not-open #f)
If anyone is interested, here are my I/O functions:

  (try-load <filename>)					procedure

Filename should be a string.  If filename names an existing file, the
try-load procedure reads Scheme source code expressions and
definintions from the file and evaluates them sequentially and returns
#t.  If not, try-load returns #f.  The try-load procedure does not
affect the values returned by current-input-port and current-output-port.

  (open-file <string> <modes>)				procedure

Returns a port capable of receiving or delivering characters as
specifie by the <modes> string.  If a file cannot be opened #f is

  OPEN_READ						constant
  OPEN_WRITE						constant
  OPEN_BOTH						constant

Contain modes strings specifying that a file is to be opened for
reading, writing, and both reading and writing respectively.

  (file-exists? <filename>)				procedure

Returns #t if the specified file exists.  Otherwise, returns #f.

  (open-pipe <string> <modes>)				procedure

If the string <modes> contains an "r" returns an input port capable of
delivering characters from the standard output of the system command
<string>.  Otherwise, returns an output port capable of receiving
characters which become the standard input of the system command
<string>.  If a pipe cannot be created #f is returned.

  (close-pipe <pipe>)					procedure

Closes the <pipe>, rendering it incapable of delivering or accepting
characters.  This routine has no effect if the pipe has already been
closed.  The value returned is unspecified.

  (file-position <port>)				procedure

Returns the current position of the character in <port> which will
next be read or written.  If <port> is not open to a file the result
is unspecified.

  (file-set-position <port> <integer>)			procedure

Sets the current position in <port> which will next be read or
written.  If <port> is not open to a file the action of
file-set-position is unspecified.  The result of file-set-position is

  (force-output)					procedure
  (force-output <port>)					procedure

Forces any pending output on <port> to be delivered to the output
device and returns an unspecified value.  The <port> argument may be
omitted, in which case it defaults to the value returned by

  (read-string! <string>)				procedure
  (read-string! <string> <port>)			procedure

Reads (string-length <string>) characters from <port>.  If an end of
file is encountered during read-string! the characters up to that
point only are put into string (starting at the beginning) and the
remainder of the string is unchanged.

Read-string! returns the number of characters read.  <Port> may be
omitted, in which case it defaults to the value returned by

  (chdir <filename>)					procedure

Changes the current directory to <filename>.  If <filename> does not
exist or is not a directory, #f is returned.  Otherwise, #t is

  (delete-file <filename>)				procedure

Deletes the file specified by <filename>.  If <filename> can not be
deleted, #f is returned.  Otherwise, #t is returned.

  (rename-file <oldfilename> <newfilename>)		procedure

Renames the file specified by <oldfilename> to <newfilename>.  If the
renaming is successful, #t is returned.  Otherwise, #f is returned.