9.14 Learning to READ

There are times when you do not want to process an entire file all at once. Sometimes, you might want to read only part of a file, other times you might need to read two or more files simultaneously. As an example, suppose you need to find the first subscription to the magazine code "time". Getting the file organized so that you are only looking at "time" subscriptions is easy (you remember SELECT, don t you?). The problem is, how do you get just the first one?

Well, if you sort them by date, then the first record in the file is the first one (ignoring duplicates for the same day). The question still remains, how do you process just that record and not the others? Enter, the READ statement. With this statement, you can now read that one record and ignore the remainder of the file. You can even do another selection on the subscriptions file. A program to do what we have talked about would look like:

/* find first subscription for "time" */

FILE scripts IS "script"

FIELDS IN scripts ARE

subscriber, magazine, started;

MAIN

BEGIN

SELECT FROM scripts

WHERE magazine EQ "time"

SORTED BY started;

READ scripts;

PRINT "First subscriber is ", subscriber, NL;

END

As you might have guessed, this is not a general purpose program. It does illustrate one use of the READ statement. We are going to present another use which is just about as useful as the first, but it also helps illustrate the proper use of the READ statement. This next example duplicates the output of our second program in this chapter without using the FOR statement.

For those of us with short memories, this report produced a listing of the subscribers. All we are going to change is the MAIN procedure. Currently, this procedure looks like

MAIN

BEGIN

AT TOP OF PAGE

DO headings;

SELECT FROM subscribers

SORTED BY subscribers;

FOR EACH subscribers

DO details;

END

The FOR statement is replaced with a loop that reads through the file. In order to be able to loop in the Report Writer, we need the WHILE statement. The WHILE statement looks like

WHILE condition REPEATstatement

This statement evaluates condition. If the result is true, statement is executed. After the statement is executed, the cycle repeats and continues to repeat until the result of condition is false.

For our problem, we want to loop until we reach the end of the file. In English terms, this condition can be stated as

WHILE not at end of file

In order to translate this into Report Writer language, we need some way of telling when the end of a file has been reached. This is provided through the EOF function (which can also be spelled out: END_OF_FILE). This function returns a true/false value that can be tested in a condition. The EOF function requires you to say which file you want to check. A call to this function looks like

EOF ( fname )

Fname is an internal file name declared at the beginning of the program. The function returns true if the end of file has been reached on fname, otherwise it returns false. This makes our condition look like

WHILE NOT EOF (subscribers)

Now, what is it that we repeat? Within the loop we read the file and call the procedure details to print out the subscriber information. The tricky part is to make sure that we only call the detail procedure when we have information to print. This means that we need to read the file before we can print out the detail. Note: the end of file is not detected until a read attempts to read past the end of the file. This gives the following required sequence of events

READ gets record 1

DO details

READ gets record 2

DO details

:

:

READ gets record n (last one in file)

DO details

READ read fails, eof condition now set.

Notice that if the READ fails we don't want to print the subscriber information. Also note that if the file is empty, we are done after the first READ.

This last note implies that maybe we should try to read the file before we begin. That way, the end of file condition is set before we get into the loop. Then, if the file is empty the loop won't execute even once. Doing this also implies that the first thing inside the loop must be to call the detail procedure (if we did another READ first we would lose the first record). The last step of the loop can then be to attempt to read the next record. If another record is read the loop repeats, otherwise it stops. This loop would look like

READ subscribers;

WHILE NOT EOF (subscribers) REPEAT BEGIN

DO details;

READ subscribers;

END

Take a minute and go back to where the FOR statement was first introduced. Notice the similarity of the code above to the process of the main procedure given for that example? This is by no means an accident. The process of the FOR statement is:

read file

while not eof (file) repeat

statement

read file

Thus, we have effectively replaced the FOR statement. The entire program would be

/* list subscribers */

FILE subscribers IS "sub"

FIELDS IN subscribers ARE

subscriber, name, address,

city, state, zip;

MAIN

BEGIN

AT TOP OF PAGE

DO headings;

SELECT FROM subscribers

SORTED BY subscriber;

READ subscribers;

WHILE NOT EOF (subscribers) REPEAT BEGIN

DO details;

READ subscribers;

END

END

PROCEDURE headings /* print page headings */

BEGIN

PRINT TAB (15), "S u b s c r i b e r L i s t",

TAB (60), $todays_date, NL;

PRINT "Subscriber", TAB (20), "Name and address",

NL, NL;

END

PROCEDURE details /* print one subscriber */

BEGIN

PRINT subscriber, TAB (20), name, NL,

TAB (20), address [1], NL;

IF address [2] NE "" THEN

PRINT TAB (20), address [2], NL;

PRINT TAB (20), city, ", ", state, " ",

zip, NL, NL;

END

The above example illustrates how the READ statement works; however, the real reason for having this statement is to allow for reading multiple files. Unfortunately, the demo system is not complex enough to properly show the need for such a statement. One use we had in mind for this statement is that of printing customer statements. In this case, you would have a cash receipts file, an invoice file, and the customer master file. The idea is to sort both the cash receipts and invoice files by customer and date. Then the READ statement can be used to process through the files together.