Input and Output |
7 |
![]() |
Input and Output Routines
Pascal supports all standard input and output routines, plus the extensions listed in Table 7-1. For a complete description of the routines, refer to Chapter 6, "Built-In Procedures and Functions."
Table 7-1 Extensions to Input/Output Routines
eof and eoln Functions
A common problem encountered by new users of Pascal, especially in the interactive environment of the operating system, relates to eof and eoln. These functions are supposed to be defined at the beginning of execution of a Pascal program, indicating whether the input device is at the end of a line (eoln) or the end of a file (eof).
"I don't know yet; if you ask me I'll have to find out." All files remain in this last, indeterminate state until the program requires a value for eof or eoln, either explicitly or implicitly; for example, in a call to read. If you force Pascal to determine whether the input is at the end of the file or the end of the line, it must attempt to read from the input.
At first glance, this may appear to be a correct program for requesting, reading, and echoing numbers. However, the while loop asks whether eof is true before the request is printed. Thus, this system is forced to decide whether the input is at the end of the file. It gives no messages; it simply waits for the user to type a line, as follows:
The following code avoids this problem by prompting before testing eof:
You must still type a line before the while test is completed, but the prompt asks for it. This example, however, is still not correct, because it is first necessary to know that there is an end-of-line character at the end of each line in a Pascal text file. Each time you test for the end of the file, eof finds the end-of-line character. Then, when read attempts to read a character, it skips past the end-of-line character, and finds the end of the file, which is illegal.
The simplest way to correct the problem in this example is to use the procedure readln instead of read. readln also reads the end-of-line character, and eof finds the end of the file:
The commands to compile and execute eof_example3.p
|
hostname% pc eof_example3.p hostname% a.out Number, please? 23 That was a 23. Number, please? ^D |
In general, unless you test the end-of-file condition both before and after calls to read or readln, there may be input that causes your program to attempt to read past the end-of-file.
More About eoln
To have a good understanding of when eoln is true, remember that in any file text, there is a special character indicating end-of-line. In effect, Pascal always reads one character ahead of the read command.
This code shows the improper use of the eoln function.
|
read(ch); if eoln then Done with line else Normal processing |
This program almost always has the effect of ignoring the last character in the line. The read(ch) belongs as part of the normal processing. In Pascal terms, read(ch) corresponds to ch := input^; get(input).
This code shows the proper use of eoln.
|
read(ch); if eoln then Done with line else begin read(ch); Normal processing end |
Given this framework, the function of a readln call is defined as follows:
while not eoln do get(input); get(input); |
This code advances the file until the blank corresponding to the end of line is the current input symbol and then discards this blank. The next character available from read is the first character of the next line, if one exists.
External Files and Pascal File Variables
In Pascal, most input and output routines have an argument that is a file variable. This system associates these variables with either a permanent or temporary file at compile-time. Permanent Files
Table 7-2 shows how to associate a Pascal file variable with a permanent file.
Table 7-2 Pascal File Variable with a Permanent File
Temporary Files
Table 7-3 shows how to associate a Pascal file variable with a temporary file.
Table 7-3 Pascal File Variable with a Temporary File
input, output, and errout Variables
The input, output, and errout variables are special predefined file variables.
reset(input,'some/existing/file');You must supply a file name for the association to work.
rewrite(output, '/home/willow/test');Now, whenever you direct write or writeln to output, the output is sent to /home/willow/test. This includes the default case, when you write without giving a file variable.
If you call rewrite on output and you haven't associated output with an external file, the program creates a file with a name of the form #tmp.suffix, where suffix is unique to that file. Pascal does not delete this file after the program exits.
rewrite (errout, '/some/new/file');Subsequently, whenever you direct write or writeln to errout, the output is sent to /some/new/file. You obtain the same results when you write a string to errout implicitly, using the message function. See "message" on page 155 for details.
Pascal I/O Library
Each file variable in Pascal is associated with a data structure. The data structure defines the physical Solaris 2.x operating system file with which the variable is associated. It also contains flags that indicate whether the file variable is in an eoln or eof state.
Buffering of File Output
It is extremely inefficient for Pascal to send each character to a terminal as it generates it for output. It is even less efficient if the output is the input of another program, such as the line printer daemon, lpr(1).
for i := 1 to 5 do begin write(i); Compute a lot with no output end; writeln; |
Pascal performs line buffering by default. To change the default, you can compile your program with -b option. When you specify the -b option on the command-line, the compiler turns on block-buffering with a block size of 1,024. You can specify this option in a program comment using one of these formats:
{$b0} |
No buffering. |
{$b1} |
Line buffering. This is the default. |
{$b2} |
Block buffering. The block size is 1,024. Any number greater than 2, for example, {$b5}, is treated as {$b2}. |
This option only has an effect in the main program. The value of the option in effect at the end statement of the main program is used for the entire program.
I/O Error Recovery
When an I/O routine encounters an error, it normally does the following:
With Pascal, you can set I/O trap handlers dynamically in your program. The handler is a user-defined Pascal function.
When an I/O error occurs, Pascal runtime library checks if there is a current active I/O handler. If one does not exist, Pascal prints an error message, invokes a SIGTRAP signal, and terminates.
If a handler is present, the handler is passed the values err_code and filep as in parameters. The parameter err_code is bound to the error value that caused the I/O routine to fail. The parameter filep is bound to the I/O descriptor that getfile returned for the file in which the error occurred. If filep equals nil, no file was associated with the file variable when the error occurred.
The handler returns a boolean value. If the value is false, the program terminates. If the value is true, program execution continues with the statement immediately following the I/O routine that called the trap. The results of the I/O call remain undefined.
You can set the handler to nil to return it to its default state.
The scope of the active handler is determined dynamically. Pascal has restrictions as to the lexical scoping when you declare the handler. The compiler assumes that the handler is a function declared at the outermost level. Providing a nested function as the handler may cause unexpected results. The compiler issues a warning if it attempts to take the address of a nested procedure.
To set an I/O trap handler, you must include the file ioerr.h in your Pascal source file. ioerr.h consists of an enumeration type of all possible I/O error values, a type declaration of an io_handler procedure pointer type, and an external declaration of the set_io_handler routine.
This file resides in the following directory:
|
/opt/SUNWspro/SC4.2/include/pascal |
If the compiler is installed in a non-default location, change /opt/SUNWspro to the location where the compiler is installed.
The following program illustrates how to set an I/O trap routine.