by Clayton Walnum
As promised, this month we'll take a look at a simple but complete program in order to review, as well as to apply, much of what we've learned over the last few installments of BASIC Training. We'll also cover some new material; specifically, simple disk-access techniques and basic error-trapping.
Before we continue, you should type Listing 1, using BASIC Editor II to validate your work. Once you have the program typed properly, save it to disk.
Using the ProgramListing 1 is a simple address-book program that you can use to store addresses and phone numbers on disk. Run the program and press "C." You'll be asked for a filename. Type the filename, including the device (i.e.,D:), and press Return. Now follow the prompts and enter as many addresses as you like. (Make sure you leave the disk in the drive.) To get back to the menu, type Return at one of the prompts.
After you've created your file, you can add more addresses by using the Load option. Press "L", then type in the filename. Enter whatever addresses you want and then press Return at any prompt to get back to the menu.
To see the addresses stored on the disk, press "V." You'll need to type the filename again, after which the addresses will be read in from the disk and displayed, four at a time, on the screen. Keep pressing Return until you've seen all the addresses.
Finally, to exit the program and return to BASIC's READY prompt, press "Q" and Return.
Now it WorksNow that you're familiar with what the program does, let's see what makes it tick. (Do computers tick?)
Lines 10-90 do nothing but identify the program. All of your programs should have a series of remarks like this at the beginning.
Line 100 dimensions the string variables we'll be using in the program.
Lines 110-150 are more remarks.
A block of remarks is useful in partitioning sections of your program so you can more quickly find a particular portion of code. Remarks also help you remember what the program is doing. Every program can be broken up into a series of smaller tasks, just as we've done here. Always comment your programs; you'll be glad you did.
Line 160 clears the screen. (Never mind how it does it for the time being.)
Lines 170-250 print the menu to the screen.
See the question mark at the beginning of each line? That's Atari BASIC's abbreviation for the PRINT command. Also notice how a series of print statements lined up like this shows exactly what will appear on the screen.
Line 260 retrieves a menu selection from the user.
Lines 270-300 examine the user's input and route the program execution to the appropriate section of code.
Notice that, in this IF... THEN statement, we've used the word OR. If either of the expressions separated by the OR is true, the IF evaluates to true, and the THEN portion is executed. If both of the expressions are false, the IF evaluates to false, and program execution drops down to the next line, ignoring the THEN portion.
The opposite of OR is AND. When two expressions are separated by AND in an IF statement, both of them must be true in order for the IF statement to be true.
Confused? Let's look at this in more detail. The following shows what would happen if the user typed an "L" in response to our menu:
Line 270: Is the letter that was typed a "C" or a "c"? No. Drop down to the next line.
Line 280: Is the letter an ` L " or an "l "? Yes! The THEN portion of the statement is performed, causing the program to jump to line 450. (Notice that we don't need a GOTO after a THEN.)
Now let's see what happens when the user types the letter "H," a response not listed in our menu:
Line 270: Is the letter a "C" or a "c"? No. Drop down to next line.
Line 280: Is the letter an "L" or an "l "? No. Drop down to the next line.
Line 290: Is the letter a "Q " or a "q "? No. Drop down to the next line.
Line 300: Is the letter a "V" or a "v"? No. Drop down to the next line.
Line 310: None of the letters matched, so it's back up to Line 260 to get a new input.
You should have learned two things here. First, whenever you ask a user to type something in, you should check for both uppercase and lowercase responses. "C" and "c" are as different to the computer as `A" and "Z." But, because people tend to think of lowercase and uppercase as being the same, we should let them type a response either way.
You should have also noticed that if the user doesn't type one of the choices from the menu, we make him try again. "Error trapping" is an important part of writing user-friendly software. Unfortunately, due to space and time limitations, our program in Listing I is loaded with pitfalls for the user, places where the program may bomb due to incorrect input. (Try typing a filename without the device, for example.) But our menu is not one of them.
Line 370 gets the filename of the file the user wants to open.
Line 380 opens the requested file for output.
OPEN allows us to access files in a number of ways, and, as you can see, it has four parameters. The first parameter, preceded by the pound sign (#), is the channel we want to use as the data stream for our file. We may use any channel from one to seven. Once a file has been open, we use the channel number to refer to it, rather than the filename. The second parameter is a code that tells BASIC the type of operations we want to perform on the file. There are five possible values:
4 - open for input only
6 - open for directory
8 - open for output only
9 - open for append
12 - open for input and output
When a file is opened with a 4, we may read data from the file, but we may not change the file in any way. When opened with a 6, we can read the disk's directory (a special file that contains the names of all the files on the disk). When opened with code 8, the file, if it doesn't already exist, is created on the disk, or, if it does exist, it is erased and restarted. After it is opened with code 8, a file may only have data written to it; we cannot read from the file. When opened with a 9, the file pointer, which marks where on the disk the next data will be written, is moved to the end of the file, where we may add more data. A file opened with code 12 can be used for both input and output operations.
This month we're concerned only with codes 4, 8 and 9. We'll cover the others eventually, but they're too complicated for this discussion, particularly code 12, which is used for random-access files and would require an entire article to explain thoroughly.
The fourth parameter in the OPEN command is the complete filename of the file to open. By complete, I mean that the device (D:, C:, D2:, etc.) must also be included. The filename may be stored in a string variable, as we've done in Line 380, or it may be a string literal, like this:
Notice that when you use a string literal for a filename, it must, just like any other string literal, be enclosed in quotes.
So, Line 380 opens a file for output. Be careful, though. This section of the program really should have some safeguards built in. If the user requests a file that already exists, it will be erased from the disk without any warning. In a complete program, we'd first check to see if the file already existed and, if it did, warn the user, giving him a chance to change his mind.
Line 310 sends program execution to the section of code that retrieves the addresses from the user.
Lines 450-460 get a filename from the user and open that file for append.
AFTER YOU'VE CREATED
YOUR FILE, YOU CAN ADD
MORE ADDRESSES BY
USING THE LOAD OPTION.
YOUR FILE, YOU CAN ADD
MORE ADDRESSES BY
USING THE LOAD OPTION.
After the file is opened, any addresses typed will be added to the end of the file, without changing any of the addresses that were already stored there.
Lines 520-550 get an address from the user.
In order to allow the user to get back to the menu, we're using a statement like this:
|IF NAME$="" THEN 620|
As you can see, there's nothing between the quotes. In English, we're saying "If NAME$ is empty, go to Line 620." A string will be empty if the user presses Return at the prompt without typing anything.
Line 560 prints to the screen the address just entered.
Line 570 asks the user if the information to a complete halt) whenever they encountered runtime errors. With a TRAP, however, we can grab an error before the user is ever aware of it and decide how to handle it ourselves.
The TRAP statement has only one parameter: the line number to which you want program execution to jump whenever an error is encountered. In Line 700, we're telling the computer to jump to Line 760.
Line 710 sets our address counter, COUNT, to zero and clears the screen.
We need to count the addresses displayed because we can fit only four addresses on the screen. After four addresses have been displayed, we want to stop and wait for the user to request more. If we didn't do this, the addresses at the top would scroll off as we added more at the bottom.
Line 720 reads an address from the disk file.
Just as with PRINT, the INPUT commands here work the same as the INPUT we've used to retrieve information from the screen (or from the keyboard, depending on how you look at it), the only difference being the pound sign and channel number. (Notice that we INPUT the addresses in exactly the same way that we PRINTed them.)
Line 730 prints to the screen the strings we retrieved from the file.
Line 740 increments our counter. If COUNT equals 4, we ask the user to press Return when he's ready to see more, after which we go back to the section of code beginning at Line 710, where we set COUNT back to 0 and get the next address.
Line 750 sends the program back to the section of code beginning at Line 720 (after printing a blank line).
The only time we'll get to Line 750 is when COUNT is less than 4. Also notice that by going to Line 720, we are not setting COUNT back to 0.
Line 760 is where the program will go when it encounters an error.
What error are we expecting? The endof-file error, of course, generated whenever we try to read more data than is contained in a file. In this case, without the TRAP statement we'd get an "ERROR 136 AT LINE 720" on the screen, and the program would come to a halt-not an elegant way to treat our program's user. Rather than let this happen, we'll handle the error ourselves by sending the user back to the menu after informing him that we've reached the end of the file. The problem with this method is that any error will trigger the TRAP. We're only assuming the error encountered will be the end-of-file error. In a complete program, that isn't good enough.
Line 770 waits for the user to press Return. Then it closes the open file and returns the user to the menu.
ConclusionThat finishes our discussion for this month. I hope that examining this program has helped you better understand what we've learned over the past few months. Next time, we'll take our simple address program and add enough error-trapping to make it foolproof. See you then.
LISTING 1: BASIC
Blue indicates inverse video
PM 10 REM ***************************
MI 20 REM * BASIC TRAINING *
KW 30 REM * SIMPLE ADDRESS BOOK *
PZ 40 REM * by Clayton Wa)num *
V5 50 REM * *
FG 60 REM * Copyright 1989 *
RT 70 REM * by ANALOG Computing *
PT 80 REM ***************************
BG 90 REM
XR 100 DIM NAME$(30),ADDRESS$(30),CITY$(3
QO 110 REM
YA 120 REM **************************
BC 130 REM * PRINT MENU *
YE 140 REM **************************
QW 150 REM
BE 160 ? CHR$(125)
JA 170 ? "|---------------------|"
IE 180 ? "| CREATE FILE |"
EG 190 ? "| |
QC 200 ? "| LOAD FILE |"
DR 210 ? "| |"
GE 220 ? "| VEIW FILE |"
DV 230 ? "| |"
UP 240 ? "| QUIT |"
JJ 250 ? "|---------------------|
ZU 260 INPUT A$
GO 270 IF A$="C" OR A$="c" THEN 370
RE 280 IF A$="L" OR A$="l" THEN 450
TV 290 IF A$="Q" OR A$="q" THEN END
JO 300 IF A$="V" OR A$="v" THEN 680
OI 310 GOTO 260
Q5 320 REM
YE 330 REM ***************************
WW 340 REM * CREATE FILE *
YI 350 REM ***************************
RA 360 REM
BR 370 ? "FILENAME";:INPUT FILENAME$
AJ 380 OPEN #1,8,0,FILENAME$
OK 390 GOTO 520
OP 400 REM
YB 410 REM ***************************
SI 420 REM * LOAD FILE *
YF 430 REM ***************************
QX 440 REM
BO 450 ? "FILENAME";:INPUT FILENAME$
AT 460 OPEN #1,9,0,FILENAME$
RD 470 REM
YP 480 REM ***************************
UX 490 REM * GET ADDRESS *
YA 500 REM ***************************
QS 510 REM
VR 520 ? :? "NAME:":INPUT NAME$:IF NAME$=
"" THEN 620
FY 530 ? :? "ADDRESS:":INPUT ADDRESS$:IF
ADDRESS$="" THEN 620
MT 540 ? :? "CITY, STATE & ZIP:":INPUT CI
TY$:IF CITY$="" THEN 620
ON 550 ? :? "PHONE:'":INPUT PHONE$:IF PHON
E$="" THEN 620
WI 560 ? :? NAME$:? ADDRESS$:? CITY$:? PH
EK 570 ? :? "IS THE ABOVE ENTRY OKAY (Y/N
FT 580 IF A$=""N" OR AS="n" THEN ? :? "PLE
ASE REENTER THE ADDRESS.":GOTO 520
ST 590 IF A$<>"Y" AND A$<>"y"THEN ? :? "
PLEASE ANSWER Y OR N.":GOTO 570
IG 600 ? #1;NAME$:? #1;ADDRESS$:? #1;CITY
NX 610 GOTO 520
BR 620 CLOSE #1:GOTO 160
QX 630 REM
YJ 640 REM ***************************
MO 650 REM * VIEW FILE *
YN 660 REM ***************************
RF 670 REM
BW 680 ? "FILENAME";:INPUT FILENAME$
YO 690 OPEN #1,4,0,FILENAME$
OS 700 TRAP 760
UQ 710 COUNT=0:? CHRS(125)
ET 720 INPUT #1;NAME$:INPUT #1;ADDRESS$:I
NPUT #1;CITY$:INPUT #1;PHONE$
TR 730 ? NAME$:? ADDRESS$:? CITY$:? PHONE
GN 740 COUNT=COUNT+1:IF COUNT=4 THEN ? :?
"PRESS [RETURN] FOR MORE":INPUT A$:GO
DP 750 ? :GOTO 720
WC 760 ? :? "END OF FILE.":? "PRESS [RETU
RN] FOR MENU."
LS 770 INPUT A$:CLOSE #1:GOTO 160