Category : Modula II Source Code
Archive   : M2TUTOR.ZIP
Filename : CHAP08.TXT

Output of file : CHAP08.TXT contained in archive : M2TUTOR.ZIP

Chapter 8



Examine the file named SIMPLOUT.MOD for an ================
example of the simple output functions. SIMPLOUT.MOD
This program is limited to writing only to ================
the monitor but we will get to files and
printer output shortly. First we must establish some basic
principles for use with library procedures.

The first line of the declaration part of the program imports
our two familiar procedures WriteString and WriteLn in the
same manner we are used to. The next line imports every
procedure in InOut and makes them available for use in the
program without specifically naming each one in the import
list. The third line imports every procedure from Terminal
so that they too are available for our use. The procedures
that are imported explicitly can be used in exactly the same
manner that we have been using them all along, simply name the
procedure with any arguments they use. The procedures
imported as a part of a complete module can only be used with
a qualifier that tells which library module they come from.

An example is the easiest way to describe their use so refer
to the program before you. Line 11 uses the explicitly
imported procedure from InOut, line 12 uses the same procedure
from InOut, and line 15 uses the procedure of the same name
from Terminal. Line 11 uses the unqualified procedure call
to the procedure in InOut, and lines 12 and 15 use the
qualified method of calling the procedures from both library

In this case, the two procedures do the same thing, but it is
not required by Modula-2 that procedures with the same name
do the same thing. By adding the library module name to the
front of the procedure name with a period between them, we
tell the system which of the two procedures we wish to use.
If we tried to explicitly import the WriteString procedures
from both library modules, we would get a compile error, so
this is the only way to use both procedures with the same name
from different modules.


What we have been calling a library module is more properly
termed a "module" and is the biggest benefit that Modula-2
enjoys over many of the other available programming languages.
This is the quality that gives Modula-2 the ability to have


Chapter 8 - Input/Output

separately compiled modules, because a module is a compilation
unit. When you get to Part III of this tutorial, you will
learn how to write your own modules containing your own
favorite procedures, and call them in any program in the same
manner that you have been calling the procedures provided by
your compiler writer, such as WriteString, WriteLn, etc.

None of the procedures you have been importing are part of the
Modula-2 language, they are extensions to the language
provided for you by your compiler writer. Since they are not
standard parts of the language, they may vary from compiler
to compiler. For that reason, in this tutorial, we have tried
to use those defined by Niklaus Wirth in his definition of the
language, and no others.


This would be an excellent place for you to stop and spend
some time reading your reference manual to gain some
familiarity with your particular compiler's capability. Look
up the section in your manual that is probably called the
Library and read through some of the details given there. You
will find that there are many things listed there that you
will not understand at this point, but you will also find many
things there that you do understand. Each module will have
a number of procedures that are exported so that you can
import them and use them. Each procedure will have a
definition of what arguments are required in order to use it.
Most of these definitions should be understandable to you.
One thing you will find is that only the procedure header is
given along with the formal parameters, with the actual code
of the procedure omitted. We will study about this in Part
III of this tutorial. The part that is shown is the
definition module which only gives the calling requirements
which the user must know in order to use the system. The
implementation module which gives the actual program code of
the procedure is usually not given by compiler writers, and
is not needed by users anyway.

As you study the library modules, you will find procedures to
handle strings and variables and procedures to do conversions
between the two. You will find mouse drivers, BIOS calls to
the inner workings of your operating system, and many other
kinds of procedures. All of these procedures are available
for you to use in your programs. They have been written,
debugged, and documented for your use once you learn to use
them. In addition, you will have the ability to add to this
list by creating your own modules containing your own


Chapter 8 - Input/Output


Notice that in lines 13, 17, and 22, three different ways are
used to call a procedure named WriteLn, even though there are
actually only two procedures (that happen to do the same
thing). The observant student will realize that lines 17 and
22 are calling the same procedure, the one in the InOut
module, and line 13 is calling a procedure in the Terminal
module. A little time spent here will be time well spent in
preparing for the next few programs. When you think you
understand this program, compile and execute it.


Examine the program named SIMPLIN.MOD for ===============
our first example of a program with some SIMPLIN.MOD
data input procedures. In every program ===============
we have run so far in this tutorial, all
data has been stored right in the program statements. It
would be a very sad computer that did not have the ability to
read variable data in from the keyboard and files. This is
our first program that has the ability to read from an
external device, and it will be limited to reading from the

This program is broken up into four groups of statements, each
illustrating some aspect of reading data from the keyboard.
This could have been four separate files but it will be easier
to compile and run one file.

Beginning with line 14 we have an example of the ReadString
procedure which reads characters until it receives a space,
a tab, a return, or some other nonprintable character. This
loop will read three words on one line, one word on each of
three lines, or any combination to get three words or groups
of printable ASCII characters. After each word or group is
read, it is simply displayed on the monitor for your


The group of statements in lines 26 through 29 is a loop in
which 50 ASCII characters are read in and immediately echoed
out to the monitor. It should be evident to you that the
characters are read one at a time, and since the same variable
is used for each character, they are not stored or saved in
any way. In actual practice, the characters would be stored
for whatever purpose you intend to use them for. When you run
this part of the program, it will seem like the computer is


Chapter 8 - Input/Output

simply acting like a word processor, echoing your input back
to the monitor.


The next section, beginning in line 32, reads in a full line
before writing it out to the monitor. In this program we are
introduced to the EOL which is a constant defined by the
system for our use. It must be imported from InOut just like
the procedures are, and it is a constant that is equal to the
ASCII value that is returned when we hit the return key. It
is therefore equal to the End-Of-Line character, which
explains how it got its name. If we compare the input
character to it, we can determine when we get to the
End-Of-Line. That is exactly what this loop does. It
continues to read characters until we find an EOL, then it
terminates the input loop and displays the line of data.
Notice that this time we do not simply read the data and
ignore it but instead add it character by character to the
array named StringOfData. Of course, the next time through
the loop we overwrite it. The careful student will also
notice that, in line 45 we wrote a zero character in the
character of the line just past the end of the line. The zero
is to indicate the end-of-string for the string handling
procedures. This portion of the program is easy, but will
require a little time on your part to completely dissect it.


Beginning in line 51, we have an example of reading 6 cardinal
type numbers in a loop. The procedure ReadCard will, when
invoked by your program, read as many digits as you give it.
When it reads any character other than a 0 through 9, it will
terminate reading and return the number to your calling
program. Notice that this time all 6 numbers are read in,
stored, and when all are in, they are all displayed on one
line. This should be easy for you to decipher.


There is no program that you have studied here that is as
important for you to compile and run as this one is. You
should spend considerable time running this program and
comparing the results with the listing. Enter some invalid
data when you are running the ReadCard portion of it to see
what it does. When you are running the "line at a time"
portion, try to enter more than 80 characters to see what it
will do with it. This is a good point for you to learn what


Chapter 8 - Input/Output

happens when errors occur. After you understand what this
program does, we will proceed to a study of input and output
of data to or from a file.


Examine the file named FILEIO.MOD for your ================
first example of file reading and writing. FILEIO.MOD
The library module named InOut has the ================
ability to either read and write from/to
the keyboard and monitor, or to read and write from/to files.
The present example program redirects the input and output to
files for an illustration of how to do it. Note that there
is a much more general method of file input and output
available which will be illustrated in the next few example

Line 16 requests the operator, namely you, to enter a filename
to be used for input. There is nothing different about this
statement than the others you have been using. The next line
requests the system to open a file for inputting, and part of
the procedure OpenInput is to go to the keyboard waiting for
the filename to be typed in. So the message in line 16 is in
preparation for what we know will happen in line 17. Whatever
filename is typed in is opened for reading if it is found on
the disk. The "MOD" in the parentheses is a default extension
supplied, (this can be any extension you desire). If no
extension is supplied by the operator, and if the filename
does not have a period following it, ".MOD" will be added to
the filename. If the system can find the requested
filename.extension, the Done flag is made true and we can test
it. In this example, if the flag is returned false, we ask
the operator to try again until he finally inputs a filename
that exists on the default disk/directory.


Once again, in line 21, we request a filename for output
anticipating the operation of the OpenOutput in line 22. Line
22 waits for a keyboard input of a filename and if the
filename entered has no extension, it adds the extension
".DOG" and attempts to open the file for writing. When you
input the filename, adding a period to the end of the filename
will prevent the extension being added. If the
filename.extension does not exist, it will be created for you.
If it does exist, it's contents will be erased.

It is nearly assured that the file will be created and the
Done flag will be supplied as true, but it is good practice
to check the flag anyway. It will be apparent when we get to


Chapter 8 - Input/Output

the program on printer output, that it is impossible to open
a file with certain names, one being PRN, because the name is
reserved for printer identification and the Done flag will be
returned false.

When we arrive at line 25, we should have 2 files ready for
use, one being an input file and the outer being an output


Anytime you use this technique to open a file for writing, any
output procedure from InOut will now be redirected to that
file. Anytime you use this technique to open a file for
reading, any input procedure from InOut will access the file
named instead of the keyboard. In addition, the library
module named RealInOut will also be redirected with InOut.
Any time you read or write, instead of using the keyboard and
monitor, the input and output files will be used. The input
and output will be the same except for where it goes to and
comes from, and it is possible to only open one and leave the
other intact. Thus input can be from a file, and output can
still go to the monitor.

When I/O is redirected, the module Terminal is still available
for use with the monitor and keyboard because I/O using this
module can not be redirected. The module named Terminal does
not have the flexibility of input and output that is found in
InOut so it is a little more difficult to use. There is a
major drawback when using InOut with the I/O redirected. You
are limited to one file for input and one file for output at
one time. Finally, this method cannot be used to open a
"fixed" or prenamed file, since it always surveys the keyboard
for the filename. It will probably come as no surprise to you
that all of these limitations will be overcome with another
method given in the next two programs.

The program itself should be easy to follow, once you realize
that the flag named Done returns true when a valid character
is found following a Read, and false when an End-Of-File (EOF)
is detected. The Done flag is set up following each operation
so its use is dictated by which procedure was called last.
The program simply copies all characters from one file to
another. When completed, the two procedures named CloseInput
and CloseOutput are called to do just that, to close the files
and once again make the I/O available to the keyboard and
monitor. In this case, however, we immediately terminate the
program without taking advantage of the return to normal.

Compile and run this program, being careful not to give it the
name of an existing file for output, or it will overwrite the
old data in the file and copy new data into it. That is the


Chapter 8 - Input/Output

reason for the silly file extension, DOG. Few people will
have a file with that extension. For input, use the present
filename (FILEIO.MOD), for output, use STUFF, STUFF., and
STUFF.STU, observing the resulting new filename each time.


Examine the file named VARYFILE.MOD for an ================
example using the complete FileSystem VARYFILE.MOD
module. As stated earlier, Modula-2 does ================
not have any input/output methods defined
as part of the language. This is because the I/O available
on computers is so diverse, there would be no way of defining
a method that could be used on all computers. To eliminate
the problem, Niklaus Wirth simply defined no I/O as part of
the language, but he did suggest a few standard modules to
perform the basic I/O tasks. Since they are only suggestions,
compiler writers are not constrained to follow them, but in
the interest of portability, most will. A very limited subset
of all of the procedures are the only ones that will be used
in the tutorial portion of this course. (A few other
procedures will be used in the example programs given in
chapters 9 and 16.) It will be up to you to see that the
procedure calls are in order with your compiler, and where
they differ, to modify them.


This time we import several procedures from the library module
named FileSystem for I/O use. We ask for the input filename
and store it internally in a string variable. This implies
that we can also define the filename as a constant that is
carried in the program, making it possible to use a certain
preprogrammed filename for input. We use the procedure Lookup
to open the file. This procedure uses three arguments within
the parentheses, the first being the internal filename which
is a record of information about the file. (We will come to
records later, don't worry too much about it at this point.)
The second argument is the name of the file on disk we wish
to access, the external filename, and the third argument is
a boolean variable or constant. If it is true, and the file
name is not found, a new file of that name will be created.
If it is false, and the file is not found, a new file will not
be created, and the record variable name InFile.res will
return the value notdone. (That refers to one variable named
res which is a part of the record InFile.)


Chapter 8 - Input/Output


Two filenames are required in order to make Modula-2 available
on a wide variety of computers. In this case we are using the
name InFile for our internal filename and this name must
follow all of the Modula-2 rules for naming an identifier.
The external name however must follow all the rules for naming
a file as dictated by the particular operating system, we only
store it in the string named NameOfFile. Each compiler must
tell you how to name an external file to be compatible with
their particular implementation. The procedure named Lookup
associates the internal and external filenames with each

Note that the variable named InFile is a record composed of
many parts, but for the immediate future we only need to be
concerned with its definition. It is defined as a variable
of type File which is imported from the module named
FileSystem. Until you study the lesson in this tutorial on
records, simply copy the method used here for file

Once the file is opened, you can use any of the procedures
included in the FileSystem module, being careful to follow the
rules given in your library documentation. Of course, each
procedure you wish to use must be imported properly. The
remainder of the program should be self-explanatory and will
be left to your inspection. With this example in hand, spend
some time studying your FileSystem module to become familiar
with it, then compile the program and execute it to observe
its operation.


Examine the file named PRINTFLE.MOD for an ================
example program that uses 4 files at once, PRINTFLE.MOD
and still writes to the monitor. This ================
program is very similar to the last in
that it opens one file for reading, but it opens three files
for writing. Each of the four files has its own internal
filename identifier, a record of type File, and each has its
own external filename. The three output files are firmly
fixed to certain filenames, rather than ask the operator for
names, and the third filename, listed in line 26, is a very
special name, PRN. This is not a file but is the access to
the printer. Anything written to this file will go to your
line printer, so you should turn your printer on in
anticipation of running it. Your compiler may also allow a
few other names such as LPT0, LPT1, etc, and there may be
other names reserved for serial I/O such as to talk to a


Chapter 8 - Input/Output

modem, a joystick, etc. You will need to consult your
compiler documentation for a complete list of special names.

The program itself is very simple and similar to the last one.
A character is read from the input file, and output to the
three output files and to the monitor. In the case of
CapFile, the character is capitalized before it is output
simply to indicate to you that the files are indeed different.
Study it until you understand it, then compile and run it.
Look at the contents of the new files to see if they are


There are many more things that you can do with the FileSystem
module. It is possible to open a file, begin reading until
you come to a selected position, and change to a write file
to overwrite some of the data with new data. You can write
to a file, change it to a read file, reset it to the
beginning, and read the data back out. You can rename a file,
or delete it. It will be up to you to study the documentation
for your FileSystem module, and learn how to use it


With the completion of this chapter, you have arrived at a
very special point in your study of Modula-2. Many people
arrive at this point in a language and quit studying,
preferring to use the language in a somewhat limited sense
rather than to go on and learn the advanced topics. If your
needs are few, you can quit here also and be well assured that
you can write many programs with Modula-2. In fact there will
be very few times when you cannot do all that you wish to do
provided that your programs are not too large. However, if
you choose to go on to the advanced topics, you will find that
some of the programming chores will be greatly simplified.

Whether you decide to go on to the advanced topics or not, it
would be wise for you to stop at this point and begin using
what you have learned to actually write some programs for your
own personal use. Everybody has need occasionally for a
program to do some sort of translation of data in a text file
for example. Write programs to do some data shuffling from
file to file changing the format in some way. You should be
able to think up several programs that you would find useful.

Spend some time studying and running the programs in the next
chapter, then modify them to suit your needs, building up a


Chapter 8 - Input/Output

few utilities for your software collection. The best way to
learn to program is to program. You have all of the tools you
need to get started, so you would do well to get started.
Adding some programming experience will be a big help if you
decide to continue your study into the advanced features of


1. Write a program that reads any Modula-2 source file and
lists it on the monitor with the number of characters in
each line. List the number of lines in the program also.

2. Write a program that reads any Modula-2 source file and
counts the number of times the word END appears in the
source file.


  3 Responses to “Category : Modula II Source Code
Archive   : M2TUTOR.ZIP
Filename : CHAP08.TXT

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: