port.ss
;;;
;;; <port.ss> ----  Port collection
;;; Time-stamp: <05/12/05 14:56:01 nhw>
;;;
;;; 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 <[email protected]>
;;
;;
;; Commentary:

(module port mzscheme

  (require (lib "port.ss"))
  
  (provide port->list
           port->string
           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)
	(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)
	(let ((output (open-output-string)))
	  (let loop ()
		(let ((char (read-char port)))
		  (if (eof-object? char)
			  (get-output-string output)
			  (begin (display char output)
					 (loop)))))))


  ;;!
  ;; 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)
	(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
  ;;
  ;; This elegant-yet-dirty hack to increase speed
  ;; contributed by Jacob Matthews.
  (define (port->sexp-list port)
    (let-values ([(pin pout) (make-pipe)])
      (thread (lambda () 
                (write-char #\( pout) 
                (copy-port port pout)
                (write-char #\) pout)))
      (read pin)))

  
  ;;!
  ;; 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))))))
                
  )