############################################################################
#
# File: bufread.icn
#
# Subject: Procedures for buffered read and lookahead
#
# Author: Charles A. Shartsis
#
# Date: March 11,1995
#
############################################################################
#
# This file is in the public domain.
#
############################################################################
#
# Version: 1.0
#
############################################################################
#
# Synopsis:
#
# bufopen(s) Open a file name s for buffered read and lookahead
# bufread(f) Read the next line from file f
# bufnext(f, n) Return the next nth record from file f
# without changing the next record to be read by
# bufread
# bufclose(f) Close file f
#
############################################################################
#
# These procedures provide a mechanism for looking ahead an
# arbitrary number of records in an open file while still
# keeping track of the logical current record and end-of-file.
# Although similar in intent to the procedures in buffer.icn, these
# procedures are used differently. The procedures bufopen,
# bufread, and bufclose were designed to closely mirror the
# built-in open, read, and close.
#
# A code segment like
#
# file := open("name", "r") | stop("open failed")
# while line := read(file) do {
# ...process current line...
# }
# close(file)
#
# can be changed to the following with no difference in behavior:
#
# file := bufopen("name", "r") | stop("open failed")
# while line := bufread(file) do {
# ...process current line...
# }
# bufclose(file)
#
# However in addition to processing the current line, one may
# also process subsequent lines BEFORE they are logically
# read:
#
# file := bufopen("name", "r") | stop("open failed")
# while line := bufread(file) do {
# ...process current line...
# line := bufnext(file,1) # return next line
# ...process next line...
# line := bufnext(file,2) # return 2nd next line
# ...process 2nd next line...
# ...etc...
# }
# bufclose(file)
#
# In the code above, calls to bufnext do not affect the results of
# subsequent bufread's. The bufread procedure always steps through
# the input file a line at a time without skipping lines whether or
# not bufnext is called.
#
############################################################################
#
# Here is a more detailed description of the procedures:
#
# bufopen(s)
# ==========
# Produces a file resulting from opening s for reading ("r" option),
# but fails if the file cannot be opened. if s is missing or
# the value of s is &null, then standard input is opened and
# &input is returned. Unlike the Icon open function, bufopen()
# can and must be called prior to any call to bufread or bufnext
# involving standard input. Unlike named files, only one buffered
# standard input may be open at any given time.
#
# Default:
# s &null (indicates &input should be opened for buffered
# reading)
#
# Errors (from open):
# 103 s not string
#
# Errors (new):
# Attempt to open standard input when currently open
#
#
# bufread(f)
# ==========
# Produces a string consisting of the next line from f, but fails on
# end of file. Calls to bufnext do not affect the results of
# subsequent bufread's. The procedure bufread always steps
# through a file a line at a time without skipping lines. The
# procedure bufread fails when a logical end of file is
# reached, i.e., when the physical end of file has
# been reached AND the internal buffer is empty.
#
# Default:
# f &input
#
# Errors:
# f is not a file
# f not opened for buffered reads (includes &input)
#
#
# bufnext(f, n)
# =============
# Produces a string consisting of the nth next line from f after
# the current line. It fails when the physical end of file
# has been reached.
#
# Default:
# f &input
# n 1 (the next line after the current one)
#
# Errors:
# f is not a file
# f not opened for buffered reads (includes &input)
# n not convertible to integer
# n not positive
#
#
# bufclose(f)
# ===========
# Produces f after closing it. Standard input must
# be closed before it can be reopened using bufopen.
# If standard input is closed, all lines read using bufnext
# are lost when it is reopened. In general, there is no
# practical reason to bufclose and then bufopen standard input.
# One may want to bufclose standard input to release its
# internal buffer for garbage collection.
#
# Default:
# f &input
#
# Errors (from close):
# 105 f not file
#
############################################################################
global __buf
procedure bufopen(fname)
local file
if /__buf then
__buf := table(&null)
if /fname then {
/__buf[&input] | stop("bufopen: Standard input is already open")
__buf[&input] := []
return &input
}
else
if file := open(fname, "r") then {
__buf[file] := []
return file
}
else fail
end
procedure bufclose(file)
if /__buf then
__buf := table(&null)
if /file then {
__buf[&input] := &null
return &input
}
else {
close(file)
__buf[file] := &null
return file
}
end
procedure bufread(file)
local buf
if /__buf then
__buf := table(&null)
if /file then
file := &input
type(file) == "file" | stop("bufread: Parameter is not a file")
buf := \__buf[file] | stop("bufread: File not open for buffered reads")
return get(buf) | read(file)
end
procedure bufnext(file, n)
local buf
if /__buf then
__buf := table(&null)
if /file then
file := &input
if /n then
n := 1
type(file) == "file" | stop("bufnext: Parameter is not a file")
integer(n) | stop("bufnext: Look ahead count was not convertible to integer")
(n > 0) | stop("bufnext: Look ahead count was non-positive")
buf := \__buf[file] | stop("bufnext: File not open for buffered reads")
return buf[n] |
(
while *buf < n do
(put(buf, read(file)) | break &fail)
) |
buf[n]
end
This page produced by UniDoc on 2021/04/15 @ 23:59:45.