port.ss
;;;
;;; <port.ss> ----  Port collection
;;; Time-stamp: <2008-11-10 17:16:41 noel>
;;;
;;; Copyright (C) 2002-2004 by Noel Welsh.
;;;
;;; This file is part of Port collection.

;;; Port collection is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU Lesser General Public
;;; License as published by the Free Software Foundation; either
;;; version 2.1 of the License, or (at your option) any later version.

;;; Port collection is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; Lesser General Public License for more details.

;;; You should have received a copy of the GNU Lesser General Public
;;; License along with Port collection; if not, write to the Free Software
;;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA

;;; Author: Noel Welsh <noelwelsh@yahoo.com>
;;
;;
;; Commentary:

#lang scheme/base

(require scheme/port)

(provide port->list
         port->string
         port->bytes
         port->string-list
         port->sexp-list
         port-fold)

;;!
;; Contract: ((Port) -> Any) Port -> (listof Any)
;; (port->list reader port) -> list
;;
;; Apply reader to port, accumulating results till the eof-object is
;; reached.
(define (port->list reader [port (current-input-port)])
  (let ([result (reader port)])
    (if (eof-object? result)
        '()
        (cons result (port->list reader port)))))

;;!
;; Contract : Port -> String
;; (port->string port) -> string
;;
;; Reads all characters from the port until eof and returns the
;; accumulated string
(define (port->string [port (current-input-port)])
  (let ([output (open-output-string)])
    (copy-port port output)
    (get-output-string output)))

;; port->bytes : port -> bytes
;;
;; Read all bytes from the port till eof and returns the accumulated bytes
(define (port->bytes [port (current-input-port)])
  (let ([output (open-output-bytes)])
    (copy-port port output)
    (get-output-bytes output)))
  
;;!
;; Contract: Port -> (listof String)
;; (port->string-list port) -> list
;;
;; Repeatedly reads newline-terminated strings from the port unti eof,
;; then returns the accumulated list of strings.
(define (port->string-list [port (current-input-port)])
  (port->list read-line port))
  
;;!
;; Contract: Port -> (listof Any)
;; (port->sexp-list port) -> list
;;
;; Repeatedly reads data from the port until eof, then returns the
;; accumulated list of terms
(define (port->sexp-list [port (current-input-port)])
  (port->list read port))
  
;;!
;; Contract: Port (Port -> 'a) ('a Any ... -> Any ...) Any ...
;; (port-fold port reader op . seeds) -> seeds
(define (port-fold port reader op . seeds)
  (let ([result (reader port)])
    (if (eof-object? result)
        (apply values seeds)
        (call-with-values
            (lambda ()
              (apply op result seeds))
          (lambda values
            (apply port-fold port reader op values))))))