home *** CD-ROM | disk | FTP | other *** search
- .\" Copyright (c) 1980 The Regents of the University of California.
- .\" All rights reserved.
- .\"
- .\" Redistribution and use in source and binary forms, with or without
- .\" modification, are permitted provided that the following conditions
- .\" are met:
- .\" 1. Redistributions of source code must retain the above copyright
- .\" notice, this list of conditions and the following disclaimer.
- .\" 2. Redistributions in binary form must reproduce the above copyright
- .\" notice, this list of conditions and the following disclaimer in the
- .\" documentation and/or other materials provided with the distribution.
- .\" 3. All advertising materials mentioning features or use of this software
- .\" must display the following acknowledgement:
- .\" This product includes software developed by the University of
- .\" California, Berkeley and its contributors.
- .\" 4. Neither the name of the University nor the names of its contributors
- .\" may be used to endorse or promote products derived from this software
- .\" without specific prior written permission.
- .\"
- .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- .\" SUCH DAMAGE.
- .\"
- .\" @(#)puman4.n 6.3 (Berkeley) 4/17/91
- .\"
- .if !\n(xx \{\
- .so tmac.p \}
- .nr H1 3
- .if n 'ND
- .NH
- Input/output
- .PP
- This section describes features of the Pascal input/output environment,
- with special consideration of the features peculiar to an
- interactive implementation.
- .NH 2
- Introduction
- .PP
- Our first sample programs, in section 2, used the file
- .I output .
- We gave examples there of redirecting the output to a file and to the line
- printer using the shell.
- Similarly, we can read the input from a file or another program.
- Consider the following Pascal program which is similar to the program
- .I cat
- (1).
- .LS
- % \*bpix -l kat.p <primes\fR
- .so katout
- %
- .LE
- Here we have used the shell's syntax to redirect the program input from
- a file in
- .I primes
- in which we had placed the output of our prime number program of section 2.6.
- It is also possible to
- `pipe' input to this program much as we piped input
- to the line printer daemon
- .I lpr
- (1)
- before.
- Thus, the same output as above would be produced by
- .LS
- % \*bcat primes | pix -l kat.p\fR
- .LE
- .PP
- All of these examples use the shell to control the input and output
- from files.
- One very simple way to associate Pascal files with named
- .UX
- files is to place the file name in the
- .B program
- statement.
- For example, suppose we have previously created the file
- .I data.
- We then use it as input to another version of a listing program.
- .LS
- % \*bcat data\fR
- .so data
- % \*bpix -l copydata.p\fR
- .so copydataout
- %
- .LE
- By mentioning the file
- .I data
- in the
- .B program
- statement, we have indicated that we wish it
- to correspond to the
- .UX
- file
- .I data .
- Then, when we
- `reset(data)',
- the Pascal system opens our file `data' for reading.
- More sophisticated, but less portable, examples of using
- .UX
- files will be given in sections 4.5 and 4.6.
- There is a portability problem even with this simple example.
- Some Pascal systems attach meaning to the ordering of the file in the
- .B program
- statement file list.
- .UP
- does not do so.
- .NH 2
- Eof and eoln
- .PP
- An extremely common problem encountered by new users of Pascal, especially
- in the interactive environment offered by
- .UX ,
- relates to the definitions of
- .I eof
- and
- .I 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 or the end of a file.
- Setting
- .I eof
- or
- .I eoln
- actually corresponds to an implicit read in which the input is
- inspected, but no input is ``used up''.
- In fact, there is no way the system can know whether the input is
- at the end-of-file or the end-of-line unless it attempts to read a line from it.
- If the input is from a previously created file,
- then this reading can take place without run-time action by the user.
- However, if the input is from a terminal, then the input
- is what the user types.\*(dg
- If the system were to do an initial read
- automatically at the beginning of program execution,
- and if the input were a terminal,
- the user would have to type some input before execution could begin.
- .FS
- \*(dgIt is not possible to determine whether the input is
- a terminal, as the input may appear to be a file but actually be a
- .I pipe,
- the output of a program which is reading from the terminal.
- .FE
- This would make it impossible for the program to begin by prompting
- for input or printing a herald.
- .PP
- .UP
- has been designed so that an initial read is not necessary.
- At any given time, the Pascal system may or may not know whether the
- end-of-file or end-of-line conditions are true.
- Thus, internally, these functions can have three values \-
- true, false, and ``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 Pascal
- program requires a value for
- .I eof
- or
- .I eoln
- either explicitly or implicitly, e.g. in a call to
- .I read .
- The important point to note here is that if you force the Pascal
- system to determine whether the input is at the end-of-file or the end-of-line,
- it will be necessary for it to attempt to read from the input.
- .PP
- Thus consider the following example code
- .LS
- \*bwhile not\fP eof \*bdo\fP \*bbegin\fP
- write('number, please? ');
- read(i);
- writeln('that was a ', i: 2)
- \*bend\fP
- .LE
- At first glance, this may be appear to be a correct program
- for requesting, reading and echoing numbers.
- Notice, however, that the
- .B while
- loop asks whether
- .I eof
- is true
- .I before
- the request is printed.
- This will force the Pascal system to decide whether the input is at the
- end-of-file.
- The Pascal system will give no messages;
- it will simply wait for the user to type a line.
- By producing the desired prompting before testing
- .I eof,
- the following code avoids this problem:
- .LS
- write('number, please ?');
- \*bwhile not\fP eof \*bdo\fP \*bbegin\fP
- read(i);
- writeln('that was a ', i:2);
- write('number, please ?')
- \*bend\fP
- .LE
- The user must still type a line before the
- .B while
- test is completed, but the prompt will ask for it.
- This example, however, is still not correct.
- To understand why, it is first necessary to know, as we will discuss below,
- that there is a blank character at the end of each line in a Pascal text
- file.
- The
- .I read
- procedure, when reading integers or real numbers,
- is defined so that,
- if there are only blanks left in the file,
- it will return a zero value and set the end-of-file condition.
- If, however, there is a number remaining in the file, the end-of-file
- condition will not be set even if it is the last number, as
- .I read
- never reads the blanks after the number, and there is always at least
- one blank.
- Thus the modified code will still put out a spurious
- .LS
- that was a 0
- .LE
- at the end of a session with it when the end-of-file is reached.
- The simplest way to correct the problem in this example is to use the procedure
- .I readln
- instead of
- .I read
- here.
- In general, unless we test the end-of-file condition both before and
- after calls to
- .I read
- or
- .I readln ,
- there will be inputs for which our program will attempt
- to read past end-of-file.
- .NH 2
- More about eoln
- .PP
- To have a good understanding of when
- .I eoln
- will be true it is necessary to know that in any file
- there is a special character indicating end-of-line,
- and that, in effect, the Pascal system always reads one character ahead of the
- Pascal
- .I read
- commands.\*(dg
- .FS
- \*(dgIn Pascal terms,
- `read(ch)'
- corresponds to
- `ch := input^; get(input)'
- .FE
- For instance,
- in response to `read(ch)',
- the system sets
- .I ch
- to the current input character and gets the next input character.
- If the current input character is the last character of the line,
- then the next input character from the file is the new-line character,
- the normal
- .UX
- line separator.
- When the read routine gets the new-line character,
- it replaces that character by a blank
- (causing every line to end with a blank)
- and sets
- .I eoln
- to true.
- .I Eoln
- will be true as soon as we read the last character of the line and
- .B before
- we read the blank character corresponding to the end of line.
- Thus it is almost always a mistake to write a program which deals with
- input in the following way:
- .LS
- read(ch);
- \*bif\fP eoln \*bthen\fP
- \fIDone with line\fP
- \*belse\fP
- \fINormal processing\fP
- .LE
- as this will almost surely have the effect of ignoring the last character
- in the line.
- The `read(ch)' belongs as part of the normal processing.
- .PP
- Given this framework, it is not hard to explain the function of a
- .I readln
- call, which is defined as:
- .LS
- \*bwhile not\fP eoln \*bdo\fP
- get(input);
- get(input);
- .LE
- This 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
- .I read
- will therefore be the first character of the next line,
- if one exists.
- .NH 2
- Output buffering
- .PP
- A final point about Pascal input-output must be noted here.
- This concerns the buffering of the file
- .I output .
- It is extremely inefficient for the Pascal system to send each character
- to the user's terminal as the program generates it for output;
- even less efficient if the output is the input of another
- program such as the line printer daemon
- .I lpr
- (1).
- To gain efficiency, the Pascal system ``buffers'' the output characters
- (i.e. it saves them in memory until the buffer is full and then emits
- the entire buffer in one system interaction.)
- However, to allow interactive prompting to work as in the example given
- above, this prompt must be printed before the Pascal system waits for a
- response.
- For this reason, Pascal normally prints all the output which has
- been generated for the file
- .I output
- whenever
- .HP
- .RS
- .IP 1)
- A
- .I writeln
- occurs, or
- .IP 2)
- The program reads from the terminal, or
- .IP 3)
- The procedure
- .I message
- or
- .I flush
- is called.
- .RE
- .LP
- Thus, in the code sequence
- .ne 5
- .LS
- \*bfor\fP i := 1 to 5 \*bdo begin\fP
- write(i: 2);
- \fICompute a lot with no output\fP
- \*bend;\fP
- writeln
- .LE
- the output integers will not print until the
- .I writeln
- occurs.
- The delay can be somewhat disconcerting, and you should be aware
- that it will occur.
- By setting the
- .B b
- option to 0 before the
- .B program
- statement by inserting a comment of the form
- .LS
- (*$b0*)
- .LE
- we can cause
- .I output
- to be completely unbuffered, with a corresponding horrendous degradation
- in program efficiency.
- Option control in comments is discussed in section 5.
- .NH 2
- Files, reset, and rewrite
- .PP
- It is possible to use extended forms of the built-in functions
- .I reset
- and
- .I rewrite
- to get more general associations of
- .UX
- file names with Pascal file variables.
- When a file other than
- .I input
- or
- .I output
- is to be read or written, then the reading or writing must be preceded
- by a
- .I reset
- or
- .I rewrite
- call.
- In general, if the Pascal file variable has never been used before,
- there will be no
- .UX
- filename associated with it.
- As we saw in section 2.9,
- by mentioning the file in the
- .B program
- statement,
- we could cause a
- .UX
- file with the same name as the Pascal variable to be associated with it.
- If we do not mention a file in the
- .B program
- statement and use it for the first time with the statement
- .LS
- reset(f)
- .LE
- or
- .LS
- rewrite(f)
- .LE
- then the Pascal system will generate a temporary name of the form
- `tmp.x'
- for some character `x',
- and associate this
- .UX
- file name name with the Pascal file.
- The first such generated name will be `tmp.1'
- and the names continue by incrementing their last character through the
- .SM ASCII
- set.
- The advantage of using such temporary files is that they are automatically
- .I remove d
- by the Pascal system as soon as they become inaccessible.
- They are not removed, however, if a runtime error causes termination
- while they are in scope.
- .PP
- To cause a particular
- .UX
- pathname to be associated with a Pascal file variable
- we can give that name in the
- .I reset
- or
- .I rewrite
- call, e.g. we could have associated the Pascal file
- .I data
- with the file
- `primes'
- in our example in section 3.1 by doing:
- .LS
- reset(data, 'primes')
- .LE
- instead of a simple
- .LS
- reset(data)
- .LE
- In this case it is not essential to mention `data'
- in the program statement, but it is still a good idea
- because is serves as an aid to program documentation.
- The second parameter to
- .I reset
- and
- .I rewrite
- may be any string value, including a variable.
- Thus the names of
- .UX
- files to be associated with Pascal file variables can be read
- in at run time.
- Full details on file name/file variable associations are given in
- section A.3.
- .NH 2
- Argc and argv
- .PP
- Each
- .UX
- process receives a variable
- length sequence of arguments each of which is a variable length
- character string.
- The built-in function
- .I argc
- and the built-in procedure
- .I argv
- can be used to access and process these arguments.
- The value of the function
- .I argc
- is the number of arguments to the process.
- By convention,
- the arguments are treated as an array,
- and indexed from 0 to
- .I argc \-1,
- with the zeroth argument being the name of the program being executed.
- The rest of the
- arguments are those passed to the command on the command line.
- Thus, the command
- .LS
- % \*bobj /etc/motd /usr/dict/words hello\fR
- .LE
- will invoke the program in the file
- .I obj
- with
- .I argc
- having a value of 4.
- The zeroth element accessed by
- .I argv
- will be `obj', the first `/etc/motd', etc.
- .PP
- Pascal does not provide variable size arrays, nor does it allow
- character strings of varying length.
- For this reason,
- .I argv
- is a procedure and has the syntax
- .LS
- argv(i, a)
- .LE
- where
- .I i
- is an integer and
- .I a
- is a string variable.
- This procedure call assigns the (possibly truncated or blank padded)
- .I i \|'th
- argument of the current process to the string variable
- .I a .
- The file manipulation routines
- .I reset
- and
- .I rewrite
- will strip trailing blanks from their optional second arguments
- so that this blank padding is not a problem in the usual case
- where the arguments are file names.
- .PP
- We are now ready to give a
- Berkeley
- Pascal program `kat',
- based on that given in section 3.1 above,
- which can be used with the same syntax as the
- .UX
- system program
- .I cat
- (1).
- .LS
- % \*bcat kat.p\fR
- .so kat3.p
- %
- .LE
- Note that the
- .I reset
- call to the file
- .I input
- here, which is necessary for a clear program,
- may be disallowed on other systems.
- As this program deals mostly with
- .I argc
- and
- .I argv
- and
- .UX
- system dependent considerations,
- portability is of little concern.
- .PP
- If this program is in the file `kat.p', then we can do
- .LS
- % \*bpi kat.p\fR
- % \*bmv obj kat\fR
- % \*bkat primes\fR
- .so kat2out
- % \*bkat\fR
- .so katscript
- %
- .LE
- Thus we see that, if it is given arguments, `kat' will,
- like
- .I cat,
- copy each one in turn.
- If no arguments are given, it copies from the standard input.
- Thus it will work as it did before, with
- .LS
- % \*bkat < primes\fR
- .LE
- now equivalent to
- .LS
- % \*bkat primes\fR
- .LE
- although the mechanisms are quite different in the two cases.
- Note that if `kat' is given a bad file name, for example:
- .LS
- % \*bkat xxxxqqq\fR
- .so xxxxqqqout
- %
- .LE
- it will give a diagnostic and a post-mortem control flow backtrace
- for debugging.
- If we were going to use `kat', we might want to translate it
- differently, e.g.:
- .LS
- % \*bpi -pb kat.p\fR
- % \*bmv obj kat\fR
- .LE
- Here we have disabled the post-mortem statistics printing, so
- as not to get the statistics or the full traceback on error.
- The
- .B b
- option will cause the system to block buffer the input/output so that
- the program will run more efficiently on large files.
- We could have also specified the
- .B t
- option to turn off runtime tests if that was felt to be a speed hindrance
- to the program.
- Thus we can try the last examples again:
- .LS
- % \*bkat xxxxqqq\fR
- .so xxxxqqqout2
- % \*bkat primes\fR
- .so primes-d
- %
- .LE
- .PP
- The interested reader may wish to try writing a program which
- accepts command line arguments like
- .PI
- does, using
- .I argc
- and
- .I argv
- to process them.
-