2BSD/doc/px/pxin3.n

.if !\n(xx .so tmac.p
.nr H1 2
.if n .ND
.NH
Input/output
.NH 2
The files structure
.PP
Each file in the Pascal environment is represented by a pointer
to a
.I files
structure in the heap.
At the location addressed by the pointer is the element
in the file's window variable.
Behind this window variable is information about the file,
at the following offsets:
.TS
center;
n l l.
\-14	FBUF	Pointer to i/o buffer
\-12	FCHAIN	Chain to next file
\-10	FLEV	Pointer to associated block mark
\-8	PFNAME	Name of file for error messages
\-6	FNAME	Name of associated file
\-4	FUNIT	Unit number packed with flags
\-2	FSIZE	Size of elements in the file
0		File window element
.TE
.PP
Here
.SM FBUF
is a pointer to the input or output buffer for the file.
The standard system routines
.I getc
and
.I putc
are used and provide block buffered input/output,
with 512 characters normally transferred at each read or write.
.PP
The files in the
Pascal environment,
with the exception of
.I input
and
.I output
are all linked together on a single file chain through the
.SM FCHAIN
links.
For each file the
.SM FLEV
pointer gives its associated block mark.
These are used to free files at block exit as described in section 3.3
below.
.PP
The
NAME
and
PFNAME
give the associated
file name for the file and the name to be used when printing
error diagnostics respectively.
Although these names are usually the same,
.I input
and
.I output
usually have no associated
file name so the distinction is necessary.
.PP
The
FUNIT
word contains the
unit number on which the file is open as well as a set of flags.
These flags and their representations are:
.TS
center;
l l l.
EOF	00400	At end-of-file
EOLN	01000	At end-of-line
SYNC	02000	File window is out of sync
TEMP	04000	File is temporary
FREAD	02000	File is open for reading
FWRITE	04000	File is open for writing
FTEXT	08000	File is a text file; process EOLN
.TE
.PP
The
EOF
and
EOLN
bits here reflect the associated built-in function values.
TEMP
indicates that the file has a generated temporary name and that
it should therefore be removed when its block exits.
FREAD
and
FWRITE
indicate that
.I reset
and
.I rewrite
respectively have been performed on the file so that
input or output operations should be attempted.
FTEXT
indicates the file is a text file so that
EOLN
processing should be done,
with newline characters turned into blanks, etc.
.PP
The
SYNC
bit,
when true,
indicates that there is no usable image in the file buffer window.
As discussed in the
.I "Berkeley Pascal User's Manual,"
it is necessary,
because of the interactive environment,
to have ``input^'' essentially undefined at the beginning
of execution so that a program may print a prompt
before the user is required to type input.
The
SYNC
bit implements this.
When it is set,
it indicates that before the element in the window
can be used the Pascal system must actually put something there.
This is never done until necessary.
.NH 2
Initialization of files
.PP
All the variables in the Pascal runtime environment are cleared to zero on
block entry.
This is necessary for simple processing of files.
If a file is unused, its pointer will be
.B nil.
All references to an inactive file are thus references through a
.B nil
pointer.
If the Pascal system did not clear storage to zero before execution
it would not be possible to detect inactive files in this simple way;
it would probably be necessary to generate (possibly complicated)
code to initialize
each file on block entry.
.PP
When a file is first mentioned in a
.I reset
or
.I rewrite
call,
a buffer of the form described above is associated with it,
and the necessary information about the file is placed in this
buffer.
The file is also linked into the active file chain.
This chain is kept sorted by block mark address, the
FLEV
entries.
.NH 2
Block exit
.PP
When block exit occurs the interpreter must free the files which are in
use in the block
and their associated buffers.
This is simple and efficient because the files in the active file chain are 
sorted by increasing block mark address.
This means that the files for the current block will be at the front
of the chain.
For each file which is no longer accessible
the interpreter first flushes the files buffer
if it is an output file.
The interpreter then returns the file buffer and the files structure and window
to the free space in the heap and removes the file from the active file chain.
.NH 2
Flushing
.PP
Flushing all the file buffers at abnormal termination,
or on a call to the procedure
.I flush
or
.I message
is quite easy.
The Pascal system simply flushes the file
.I output
and each file on the file chain which has the
FWRITE
bit set in its flags word.
.NH 2
The active file
.PP
For the purposes of input-output,
.I px
maintains a notion of an active file.
Each operation which references a file makes the file
it will be using the active file and then performs its operation.
A subtle point here is that one may do a procedure call to
.I write
which involves a call to a function which references another file,
thereby destroying the active file set up before the
.I write.
For this reason,
the active file is saved at block entry
in the block mark and restored at block exit.\*(Dg
.FS
\*(dgIt would probably be better to dispense with the notion of
active file and use another mechanism which did not involve extra
overhead on each procedure and function call.
.FE
.NH 2
File operations
.PP
Files in Pascal can be used in two distinct ways:
as the object of
.I read,
.I write,
.I get,
and
.I put
calls, or indirectly as though they were pointers.
It should be noted that the second use as pointers must be careful
not to destroy the active file in a reference such as
.LS
write(output, input\(ua)
.LE
or the system would end up writing on the input device.
.PP
The fundamental operator related to the use of a file is
FNIL.
This takes the file variable, as a pointer,
insures that the pointer is not
.B nil,
and also that a usable image is in the file window,
by forcing the
SYNC
bit to be cleared.
.PP
The rest of the uses of files and the file operations may be summarized
by a simple example:
.LS
write('*')
.LE
which generates the code
.LS
\s-2UNITOUT\s0
\s-2CONC\s0	'*'
\s-2WRITC\s0
.LE
Here the operator
.SM UNITOUT
is an abbreviated form of the operator
.SM UNIT
which sets the active file,
when the file to be made active is
.I output.
Thus to write a character to the file
.I output
it is only necessary to make
.I output
the active file,
to place the character to be output
on the stack,
and to do a
.SM WRITC
write character operation.
.PP
Files other than
.I output
differ from this example only in that the operator
.op UNIT
is used preceded by an evaluation of the file variable expression.
Thus
.LS
writeln(f)
.LE
produces
.LS
\s-2RV\s0	\fIf\fP
\s-2UNIT\s0
\s-2WRITELN\s0
.LE
.PP
Write widths are easily handled here by packing information
about the presence or absence of width specifications and their
types into the sub-operation code and pushing the values
of the write widths onto the top of the stack.
.PP
One other operation worth mentioning is
.SM DEFNAME
which is used to implement the program statement association of
file names.
.SM DEFNAME
simply allocates the
.I files
(section 3.1) area for the given file as though
it had been the object of a
.I reset
or
.I rewrite
call, initializing the
FNAME
field, but omitting the system interactions associated with
and actual
.I reset
or
.I rewrite.