The previous example resulted in a very inefficient program: reading the entire file to a list and process it afterwards is extremely memory consuming. A far better solution would be to process the file incrementally line by line. This pattern of reading files occurs in fact very often, thus we provide support for it.
In Program the revised formulation of the
Expand procedure is shown. As before the file objects are created,
but now both files inherit from Open.text as well. This class
provides methods for buffered input and output.
local [SPACE TAB BS] = " \t\b" fun {Insert N Is} case N>0 then {Insert N-1 SPACE|Is} else Is end end fun {ScanLine Is TabStop N} case Is of nil then nil [] I|Ir then case I of !TAB then M=TabStop - (N mod TabStop) in {Insert M {ScanLine Ir TabStop M+N}} [] !BS then I|{ScanLine Ir TabStop {Max 0 N-1}} else I|{ScanLine Ir TabStop N+1} end end end fun {Scan Rs TabStop} !Rs=getS(Is)|Rr in case Is==False then Rr=nil nil else putS({ScanLine Is TabStop 0})|{Scan Rr TabStop} end end in proc {Expand TabStop InFile OutFile} Rs in create _ from Open.file Open.text with [init(name:InFile) Rs close] end create _ from Open.file Open.text with [init(name:OutFile flags:[write 'create' truncate]) {Scan Rs TabStop} close] end end end
The function Scan constrains its first argument to a list of tuples of the form getS(Is). This list of tuples is applied as a batch method to the file object for the input file. If the method getS reduces, its argument is constrained to either False, in case the end of the file is reached, or to a string. This string contains exactly one line of the input file (without a new line character). The expansion of TAB characters is done in the function ScanLine as before. The function Scan constrains its output to a list of tuples with label putS. The argument of the tuples are the expanded lines. The entire list built by Scan is processed as a batch method by the file object for the output file.
Open.text is a class, which can be used similarly to the C stdio library [2]. In particular, the class is usable in conjunction with the classes Open.file , Open.unixSocket , Open.internetSocket , and Open.pipe . The class has no public attributes and the following public feature:
feat error: P
As for the class Open.file, see Section.
The class Open.text has the following methods.
getC(?I)
Constrains I to the next character, or to False if the input is at the end. Note that if you create an object which inherits from Open.text as well as from Open.file, the method seek from the class Open.file does not work together with this method.
putC(+I)
Writes the character I.
unGetC
The last character read is written back to the input buffer and may be used again by getC. It is allowed only to unget one character.
getS(?SB)
Constrains SB to the next line of the input as string, or to False if the input is at the end. SB does not contain the new line character. Note that if you create an object which inherits from Open.text as well as from Open.file, the method seek from the class Open.file does not work together with this method.
putS(+V)
Writes the virtual string V. Note that a newline character is appended.
atEnd(?B)
If the end of input is reached, B is constrained to True, otherwise to False.
dOpen(+DescI)See Section.
getDesc(?FileDescIB)See Section.