


                                                       Chapter 14
                                                TEXT INPUT/OUTPUT


ADA IS NOT BIG ON I/O
_________________________________________________________________

Ada was originally designed as a language for embedded real-time
systems rather than as a business oriented language, so input and
output of data is a rather low priority part of the language.  It
may surprise you to know that there are no input or output
instructions available for use within the Ada language itself, the
problem being left to the compiler writers.  However, the designers
of Ada realized that if the entire topic of input and output were
left to the individual compiler writers, users would be left with
a mess trying to use nonstandard methods of input and output.  They
exercised tremendous foresight by defining a standard external
library to be used for input and output of data that must be
available with all Ada compilers that pass the validation suite.

Even though the libraries are defined, the details of their actions
are not precisely defined, so there is still some chance that your
compiler will not behave in exactly the same way as the
descriptions given here.  You will have to check the documentation
packaged with your compiler to discover the exact details of input
and output operation.  You may rest assured however, that the
differences will only be in the smallest details.  With the
preceding disclaimer, let's look at some text output procedures.



FORMATTED OUTPUT DATA
_________________________________________________________________

If you examine the program FORMATS.ADA, you will  ===============
find that it does very little other than            FORMATS.ADA
illustrate the various methods of outputting      ===============
formatted data to the monitor.  Several types
and variables are declared, then six separate
instantiations of Text_IO are declared for use with the six types
used in the program.  Actually, there is nothing here that is new
to you, since we have covered all of these statements before, but
they are included here in order to present an example of all of
them in one place.

A few comments should be made at this point.  Note the six
instantiations of Text_IO packages given in lines 19 through 31.
These are necessary in order to output the various types we are
using in this program.  The package instantiations must be declared
after the various types are declared.  One of the instantiations
could be eliminated by transforming the type of the MY_INTEGER type
variable to type INTEGER prior to outputting it, but this is done
for illustration.  When we instantiate a package, we are actually

                                                        Page 14-1

                                   Chapter 14 - Text Input/Output

using a copy of a generic package, which will be the subject of a
detailed study in part 2 of this tutorial.

After you have studied the program and understand it, compile and
run it for an elaborate set of formatted output examples.  Your
compiler may output the float and fixed outputs slightly
differently than that given in the result of execution due to
different defaults assigned by your compiler.



FORMATTED OUTPUT TO A FILE
_________________________________________________________________

The example file named EASYOUT.ADA contains       ===============
examples of how to use a file in a very easy        EASYOUT.ADA
fashion.  Since there is no standard method       ===============
which is used by all operating systems to name
files, we cannot depend on what the rules will
be in order to use Ada on any system, so we need two file names in
order to write to or read from a file.  We need an internal name,
which will be used by our program to refer to the file, and which
follows the naming rules defined by Ada.  We also need an external
name which will be used by the operating system to refer to the
file and whose name follows the rules dictated by the operating
system.  In addition to having the two names, we need a way to
associate the names with each other, and tell the system that we
wish to use the file so named.  We do all of this with the Create
procedure as shown in line 14 of this program.

The variable Turkey, is the internal file name which we declared
in line 10 to be of type FILE_TYPE, a type exported by the package
Text_IO for just this purpose.  The "with Text_IO;" statement in
line 2 makes the type FILE_TYPE available in this program.  The
last argument, which is either a string constant, as it is in this
case, or a string variable, gives the external name of the file we
wish to create and write to.  Note carefully, that if you have a
file named TEST.TXT in your default directory, it will be erased
when the program is run, because this statement will erase it.  The
second parameter in this procedure call, is either In_File if you
intend to read from the file, or Out_File if you plan to write to
it.  There is no mode using text I/O in which you can both read
from and write to the same file.  In this case, we wish to write
to the file, so we use the mode Out_File and create the file.



WRITING TO THE FILE
_________________________________________________________________

Line 16 looks rather familiar to us, since it is our old friend
Put_Line with an extra parameter prior to the text we wish to
output.  Since Turkey is of type FILE_TYPE, the system is smart
enough to know that this string will be output to the file with the

                                                        Page 14-2

                                   Chapter 14 - Text Input/Output

internal name of Turkey, and the external name of TEST.TXT, so the
string will be directed there along with the "carriage return/line
feed".  The next line will also be directed there, as will the 2
New_Lines requested in line 18.  Line 19 does not have the filename
of Turkey as a parameter, so it will be directed to the default
output device, the monitor, in the same manner that it has been for
all of this tutorial.



REDIRECTING THE OUTPUT
_________________________________________________________________

Line 21 contains a call to the procedure Set_Output which will make
the filename which is given as the actual parameter the default
filename.  As long as this is in effect, any output without a
filename will be directed to the file with the internal filename
Turkey.  In order to output some data to the monitor, it can still
be done, but it must be directed there by using its internal
filename as a parameter, the internal filename being
Standard_Output.  The group of statements given in lines 22 through
25 do essentially the same thing as those in lines 16 through 19.
The default is returned to the standard output device in line 26,
and the program completes normally.



CLOSING THE FILE
_________________________________________________________________

The simple statement given in line 29 is used to close the file
when we are finished with it.  The system only needs to be given
the internal name of the file, since it knows the corresponding
external filename.  Failure to close the file will do no harm in
such a simple program, because the operating system will close it
automatically, but in a large program, it would be wise to close
a file when it is no longer needed.  There is an upper limit on how
many files can be open at one time, and there is no sense wasting
a file allocation on an unneeded file.

Be sure to compile and run this program, then check your default
directory to see that you have the file named TEST.TXT in it
containing the expected text.


MULTIPLE FILES OPENED AT ONE TIME
_________________________________________________________________

Examine the file MULTOUT.ADA for an example       ===============
program in which we open and use 3 different        MULTOUT.ADA
files plus the monitor.  The three internal       ===============
filenames are declared in line 10, and all three
are opened in the output mode with three
different external names as shown in lines 15, 16, and 17.

                                                        Page 14-3

                                   Chapter 14 - Text Input/Output


We execute the loop in lines 19 through 28, where we write nonsense
data to the three files, output a test string to the display in
line 30, and finally close all three files.  Note that we could
have defined one of the files to be the default file and written
to it without the filename, then used the filename for the standard
output in line 30, achieving the same result.

The program is fairly simple, so after you feel you understand it,
compile and run it.  After a successful run, examine the default
directory to see that the three files exist and contain the
expected results.  Do not erase the generated files, because we
will use them as example input files in the next few programs.



INPUTTING CHARACTERS FROM A FILE
_________________________________________________________________

Examine the file CHARIN.ADA for an example of    ================
how to read CHARACTER type data from a file.  In    CHARIN.ADA
this example the file name My_File is declared   ================
as a FILE_TYPE variable, then used to open
CHARACTS.TXT for reading since the In_File mode
is used.  In this case, the file must exist, or an exception will
be raised.  The file pointer is set to the beginning of the file
by the Open procedure so we will read the first character in the
file the first time we read from the file.

The loop in lines 17 through 21 causes us to read a character from
the file and display it on the monitor each time we pass through
the loop.  The function End_Of_File returns a TRUE when the next
character to be read is the end of file character for your
particular implementation.  We do not need to know what the end of
file character is, it is up to the compiler writer to find out what
it is and return a value of TRUE when the system finds it.  The
entire file is therefore displayed on the monitor by this program,
but with one slight deviation from what you would expect.  Because
of the way Ada is defined, the end of line characters are simply
ignored by the Get procedure, and since they are not read in, they
cannot be output to the monitor either.  The end result is that the
characters are all output in one long string with no line feeds.
You will see this later when you compile and run the program.

We will continue our study in this program and see a much better
way to read and display the data.


THE RESET PROCEDURE
_________________________________________________________________

The Reset procedure in line 24 resets the file named as a
parameter, which simply means that the file pointer is moved to the
first character once again.  The file is ready to be read in

                                                        Page 14-4

                                   Chapter 14 - Text Input/Output

another time.  The loop in lines 26 through 35 is the same as the
previous loop except for the addition of another new function.
When the end of a line is found, the function End_Of_Line returns
a TRUE, and the program displays the special little message in line
30.  In addition to the message, the New_Line procedure is called
to supply the otherwise missing end of line.  Unfortunately, we
still have a problem because the End_Of_Line is actually a
lookahead function and becomes TRUE when the next character in the
buffer is an end of line character.  When the program is executed,
we find that it does not output the last character of each line in
this loop, because we never execute the else clause in the if
statement for that character.  When the program is executed, you
will notice that the periods at the end of the sentences are not
displayed.  The next loop in this program will illustrate how to
input and output the data correctly considering all of the Ada
idiosyncrasies.

If you recall, we stated at the beginning of this lesson that input
and output programming in Ada was at best a compromise.  Don't
worry, you will be able to input or output anything you wish to
very soon.



A CORRECT CHARACTER INPUT/OUTPUT LOOP
_________________________________________________________________

The file is once again reset in line 38, and a third loop in lines
41 through 49 reads and displays the file on the monitor.  This
time when we go through the loop, we recognize that the end of line
is reading one character ahead in the input file, not the one we
just read, and we adjust the program accordingly.  We output the
character, then check for end of line, and call the New_Line
procedure if we detect an end of line.  You will see, when you run
it, that the last character on the line will be displayed as
desired.

It should be pointed out to you that the End_Of_File is another
lookahead function and must be tested after we output the last
character read in.  This loop does just that, because the end of
file is acted on after the character is output.

Be sure to compile and run this program.  It would be interesting
to edit the input file, CHARACTS.TXT, adding a few characters, then
rerunning the program to see how it handles the new data.



STRING INPUT AND OUTPUT
_________________________________________________________________

The next example program, STRINGIN.ADA, illustrates how to read a
string from an input file.  In much the same manner as for the
character, the end of line character is ignored when encountered

                                                        Page 14-5

                                   Chapter 14 - Text Input/Output

in the input file.  The result is that when the  ================
first loop is run, no "carriage returns" are       STRINGIN.ADA
issued and the text is all run together.  The    ================
second loop, however, uses the lookahead method
and calls the New_Line procedure when it detects
the end of line in the input stream.
The big difference in this program and the last is the fact that
a STRING type variable is used for input here and a CHARACTER type
variable was used in the last one.


I PLAYED A TRICK ON YOU
_________________________________________________________________

This program has a bit of a trick in it.  The input file contains
an exact multiple of 10 characters in each line, and the input
variable, of type STRING, has ten characters in it.  There is
therefore no real problem in reading into the ten character string,
but if the lines were not exact multiples of ten characters, we
would have gotten an input error.  If you remember how difficult
the STRING variable was to work with when we studied strings, you
will understand that we have the same problem here.  When we get
to chapter 16 with its example programs, we will see how we can
greatly improve the string capability with an add-on library of
dynamic string routines.  Until then, simply realize that string
input is possible, but don't get too excited about it.

Be sure to compile and run this program, then add a few characters
to some of the lines in the file named CHARACTS.TXT to see the
result of trying to read in an odd group of extra characters.


NOW TO READ IN SOME NUMBERS
_________________________________________________________________

Computers are very good at working with numbers,  ===============
and in order to work with them, we must have a       INTIN.ADA
way to get them into the computer.  The example   ===============
file INTIN.ADA illustrates how to read INTEGER
type data into the computer from a file.  Much
like the last two programs, we open a file for reading, and begin
executing a loop where we read an INTEGER type number as input each
time through the loop.  We are reading an INTEGER type number
because that is the type of Index, the second actual parameter in
the Get procedure call.  Since it is an INTEGER type number, the
system will begin scanning until it finds a valid INTEGER type
number terminated by a space.  It will then return that number, in
the computer's internal format, assigned to the variable we
supplied to it, and make it available for our use like any other
INTEGER type variable.  If any data other than INTEGER type data
were to be encountered in the input file before it found a valid
INTEGER value, an exception would be raised, and the program would
be terminated.


                                                        Page 14-6

                                   Chapter 14 - Text Input/Output

The loop continues in much the same manner as the last two programs
until it detects the end of file, at which time it stops.  There
is one other slight difference when using numeric inputs, the
system does not read over the end of line character, because it
doesn't know how to get across it.  It gets stuck trying to read
the next data point but never gets to it because the end of line
is blocking it.  When the end of line is detected, or at any other
time, you can issue the function Skip_Line which tells it to go to
the beginning of the next line for its next input data.  At any
time then, you can begin reading on the next line for your next
data point.

Be sure to compile and run this program, then change the spacing
of some of the numbers in the input file to see that they are read
in with a free form spacing.


WHAT ABOUT FLOATING POINT DATA INPUTS?
_________________________________________________________________

Once you understand the method of reading INTEGER type data in, you
can read any other types in by using the same methods.  Just
remember that the data you read in must be of the same type as the
variable into which it is being read and you will have little
difficulty.


WHAT ABOUT READING FROM THE KEYBOARD?
_________________________________________________________________

Reading from the keyboard is similar to reading from a file, except
that it uses the predefined internal filename, Standard_Input, and
if you omit a filename reference, the input will come from the
keyboard.  It should be pointed out that the operating system will
probably buffer the input data automatically and give it to your
program as a complete string when you hit the return key.  It will
allow you to enter a complete string of as many integer values as
you desire, and when you hit the return, the entire string will be
input and processed.

Modify the last file to read from the keyboard, and enter some
numbers after compiling and running it.  Note that there is no
End_Of_File when reading from the keyboard.  Use a loop with a
fixed number of passes, or use an infinite loop and quit when a
certain number is input such as -1.

HOW DO WE PRINT DATA ON THE PRINTER?
_________________________________________________________________

The program named PRINTOUT.ADA illustrates how   ================
to send data to your printer.  The only            PRINTOUT.ADA
difference in sending data to the printer, from  ================
sending data to a disk file, is the use of the
predefined name LPT1 for the external file name.

                                                        Page 14-7

                                   Chapter 14 - Text Input/Output

This file is defined as the printer rather than a file, and as you
can see from the program, it operates no differently than any other
file.

Other names may be applicable for the printer also, such as PRN,
COM1, etc.  Check your documentation for the predefined names that
mimic a file.

Be sure your printer is on line, then compile and run this program.


TEXT IO PRAGMAS
_________________________________________________________________

A pragma is a suggestion to the compiler and can be ignored by any
implementation according to the definition of Ada.  Refer to
appendix B of the LRM for the definition of the predefined pragmas
LIST and PAGE.  Since these may not be available with any
particular compiler, their use should be discouraged in order to
attain a high degree of program portability.


PAGE AND LINE CONTROL SUBPROGRAMS
_________________________________________________________________

Refer to the definition of Text_IO in the LRM for a large
assortment of page and line control subprograms for use with text
I/O.  These are required to be available with every compiler, so
you should study them to gain an insight into the page and line
control subprograms available to you in any Ada program.  There
should not be anything too difficult for you to understand in these
definitions.


PROGRAMMING EXERCISES
_________________________________________________________________

1.   Modify CHARIN.ADA to read from the keyboard and echo data to
     the monitor until a Q is entered.

2.   Write a program named FLOATIN.ADA that reads floating point
     data from a file and displays it.  There is no standard on
     floating point input.  Some compilers require a decimal point
     with at least one digit before and after the decimal point.
     Some may not even require a decimal point but will supply it
     to an input that looks like an INTEGER value.  Experiment and
     determine the characteristics of your compiler.






                                                        Page 14-8