Atari Diskfile Tutorial - Part I
Many new computer owners are anxious to learn how to write their own useful programs. After reading the literature packed with the machine, the new owner is often overwhelmed. Realizing that one does not learn any programming language overnight, a seemingly endless period of trial and error usually follows. The "hacker" is often seen burning the midnight oil and arguing with a defenseless TV or monitor.
If he perseveres long enough, reasonably simple programs are written. The new programmer is now ready for bigger and better things.
Assuming he has a disk drive, our "hacker" gains experience with DOS and the loading and saving of programs. Now he is ready to write a database program.
The datafile may consist of a simple list of record albums for a start, to be followed by the inevitable Personal Finance System. If you are at this point in your programming career, or think you might be in the near future, read on.
Start with something very simple. Don't try to write that financial package yet. There is much to learn first about file structure and I/O. I/O stands for Input/ Output. Input is data being read by a program. Output is data being created by a program. A file consists of one or more records, and a record is an item within a file. Records may be broken down further into fields. We will be using simple records containing a single 20-character field as our record, and create a sample 10-record datafile.
To understand data processing techniques, it is often easier to grasp reality than it is to learn by reading. I have found that doing is the best way to learn, and that Atari Basic can be easy to understand if it is explained in English.
Atari Basic allows variable names of any length, plus REM or remark statements. Remarks or comments within a program help identify routines and explain exactly what the program is doing.
Meaningful variable names also make program reading much easier. For example, the sample Diskfile program uses the variable RECNUM to store the current total of records. RECNUM is an abbreviation I used to mean record number. So why didn't I use the variable RECORDNUMBER you ask? RECNUM is a compromise between that 12-letter name and the other extreme which could have been R.
The RECNUM variable is used often. The tradeoff is readability against the programmer's keystrokes and sometimes program efficiency. If R is used instead of RECORDNUMBER, and that variable is used ten times, using R saves 110 keystrokes. In a tutorial program such as this one, RECNUM is the acceptable compromise.
The Diskfile tutorial program demonstrates many of the common functions required in a simple database type program. By using the program and studying the program code, you will learn how datafiles may be handled in Atari Basic. Once you have entered the program and corrected any typing errors, run through each of the options beginning with number one.
It is important to understand the terminology used here. CREATE means just that. In this case it means create from scratch. Note that the create routine actually begins at line 1000 and that line 1010 contains an OPEN command. The number 8 in that command means write only. If a file is opened using this variable, and a file with the exact same name is found on your diskette, the old file will be deleted automatically.
Using option two, a file is read from disk and displayed on the screen. This does not in any way alter the disk file.
Option three is used to ADD data to an existing disk file only. The term APPEND is often used in this case. In plain English, the term APPEND means, "add to the end of this file."
Option four is used to UPDATE the records of an existing file. This means you will alter, correct, or change a record. This procedure is a bit more complicated than the others since we do not know in advance which record the user may choose to update. The technique used in this demo program is known as Random Access Updating. An index consisting of SECTOR and BYTE locations is created and stored in an array. This gives us the exact spot at which each record begins.
Since we are using fixed length records of 20 characters each, we can read a specific record into a string, change it in the string, then rewrite the string onto the disk. This becomes a real time saver when many records must be updated in a large disk file.
Option five is used to READ and display a specific file called the DIRECTORY FILE. This DOS-generated file contains the table of contents of your diskette. This file is also known as the VTOC or Volume Table Of Contents. For display only, this routine does the same thing as DOS option A.
Although some error trapping has been built in, many possible error conditions are not corrected or fully explained by this program. Error trapping and human engineering account for a great deal of planning and program code. This is not a cop out on my part. I plan to cover this subject in a future article. The point here is to provide an example of diskfile handling. Accounting for all possible errors could easily double the size of the program.
That's about it for now. I suggest you use my program as is, then experiment by making minor changes and noting the results. When you're ready to write your own diskfile handling program, feel free to use these routines.
0 REM FILES (c) 1981 by Jerry White 1 REM ATARI DISKFILE TUTORIAL DEMO 2 REM 100 DIM DRIVE$(3),FILE$(12),DRIVEFILE$(15),RECORD$(10),ANSWER$(1) 110 DIM SECTOR(20),BYTE(20),DIRECTORY$(20):REM DIMENSION STRINGS AND ARRAYS 111 REM 120 GRAPHICS 0:POKE 82,2:POKE 83,39:REM CLEAR SCREEN AND SET MARGINS 130 POKE 201,5:REM SET PRINT TAB WIDTH TO 5 SPACES 140 ? :? "TYPE OPTION NUMBER THEN PRESS RETURN" 150 ? :? ,"(1) CREATE A DISK FILE ":REM GOTO 1000 160 ? :? ,"(2) READ A DISK FILE":REM GOTO 2000 170 ? :? ,"(3) ADD TO A DISK FILE":REM GOTO 3000 180 ? :? ,"(4) UPDATE A DISK FILE":REM GOTO 4000 190 ? :? ,"(5) DISPLAY DISK DIRECTORY":REM GOTO 5000 200 ? :? ,"(6) END PROGRAM":REM GOTO 9140 210 ? :? "YOUR CHOICE";:GOSUB 7000 220 TRAP 8000:LINE=120:HIGHNUMBER=6:NUMBER=VAL(ANSWER$) 230 IF NUMBER<1 OR NUMBER>6 THEN GOTO 8000 240 ON NUMBER GOTO 1000,2000,3000,4000,5000,9140 250 REM 1000 LINE=6100:GOSUB 7100:TRAP 9100:GRAPHICS 0 1010 CLOSE #1:OPEN #1,8,0,DRIVEFILE$ 1020 ? :? "CREATING ";DRIVEFILE$:? :RECORD$="1234567890" 1030 FOR DEMO=1 TO 10 1040 ? #1;RECORD$ 1050 ? "WRITING RECORD NUMBER ";DEMO 1060 NEXT DEMO 1070 ? :? "10 RECORD DEMO FILE CREATED" 1080 ? :? "CLOSING ";DRIVEFILE$ 1090 CLOSE #1 1100 GOTO 6100 1110 REM 2000 LINE=6100:GOSUB 7100:TRAP 9100:GRAPHICS 0 2010 CLOSE #1:OPEN #2,4,0,DRIVEFILE$:RECNUM=0:LINE=6100 2020 INPUT #2,RECORD$ 2030 RECNUM=RECNUM+1 2040 ? "RECORD NUMBER ";RECNUM; 2050 ? ,RECORD$ 2060 GOTO 2020 2070 REM 3000 LINE=3000:GOSUB 7100:TRAP 9100:GRAPHICS 0 3010 CLOSE #3:OPEN #3,9,0,DRIVEFILE$ 3020 GRAPHICS 0:? :? "ADD RECORD(S) ROUTINE:" 3030 ? :? "ENTER 10 CHARACER RECORD" 3040 ? :? ,"OR JUST PRESS RETURN TO EXIT":? :GOSUB 6000 3050 RECLEN=LEN(RECORD$):IF RECLEN=0 THEN 3200 3060 IF RECLEN=10 THEN 3090 3070 FOR BLANK=RECLEN+1 TO 10:RECORD$(LEN(RECORD$)+1)=" ":NEXT BLANK 3090 PRINT #3;RECORD$ 3100 ? :? "PRESS START TO ENTER ANOTHER RECORD" 3110 ? :? "PRESS OPTION FOR OTHER OPTIONS..."; 3120 IF PEEK(53279)=6 THEN 3020 3130 IF PEEK(53279)=3 THEN 3200 3140 GOTO 3120 3200 ? :? :? "ADDING RECORD(S) TO DISK":CLOSE #3:GOTO 120 3210 REM 4000 LINE=4100:GOSUB 7100:TRAP 9100:GRAPHICS 0 4010 CLOSE #4:OPEN #4,12,0,DRIVEFILE$:LINE=4100 4020 ? :? ,,"CREATING INDEX":RECNUM=0 4030 NOTE #4,SECTOR,BYTE 4040 RECNUM=RECNUM+1 4050 SECTOR(RECNUM)=SECTOR:BYTE(RECNUM)=BYTE 4060 INPUT #4,RECORD$:? ," RECORD ";RECNUM,RECORD$ 4070 ? ,"SECTOR=";SECTOR,"BYTE=";BYTE 4080 ? :GOTO 4030 4100 RECNUM=RECNUM-1 4110 ? :? "PRESS START TO UPDATE A RECORD" 4120 ? :? "PRESS OPTION FOR OTHER OPTIONS"; 4130 IF PEEK(53279)=6 THEN 4200 4140 IF PEEK(53279)=3 THEN CLOSE #4:GOTO 120 4150 GOTO 4130 4200 GRAPHICS 0:REM RANDOM ACCESS RECORD UPDATE ROUTINE 4210 ? :? "DISKFILE CONTAINS ";RECNUM;" RECORDS" 4220 ? :? "ENTER RECORD NUMBER TO BE UPDATED"; 4230 TRAP 4220:INPUT UPDATE:TRAP 40000 4240 UPDATE=INT(UPDATE):IF UPDATE<1 OR UPDATE>RECNUM THEN 4230 4250 POINT #4,SECTOR(UPDATE),BYTE(UPDATE) 4260 INPUT #4,RECORD$:? :? RECORD$ 4270 ? :? "ENTER NEW RECORD #";UPDATE$;:INPUT RECORD$ 4280 RECLEN=LEN(RECORD$):IF RECLEN=10 THEN 4300 4290 FOR BLANK=RECLEN+1 TO 10:RECORD$(LEN(RECORD$)+1)=" ":NEXT BLANK 4300 POINT #4,SECTOR(UPDATE),BYTE(UPDATE) 4310 PRINT #4;RECORD$:? :? ,"RECORD HAS BEEN UPDATED" 4320 GOTO 4110 4330 REM 5000 GRAPHICS 0:POKE 201,10:? :? ," DISK DIRECTORY":? :TRAP 9100 5010 CLOSE #5:OPEN #5,6,0,"D:*.*":REM OPEN DISK DIRECTORY FOR ALL ENTRIES 5020 LINE=6100 5030 INPUT #5,DIRECTORY$ 5040 ? ,DIRECTORY$ 5050 GOTO 5030 5060 REM 6000 RECORD$="":POKE 764,255:REM RECORD STRING AND LAST KEY PRESSED-NULL 6010 INPUT RECORD$:RETURN 6020 REM 6100 FOR FILE=1 TO 5:CLOSE #FILE:NEXT FILE:REM CLOSE ALL FILES 6110 POKE 201,5:? :? "PRESS RETURN FOR OPTIONS"; 6120 GOSUB 7000:GOTO 120:REM PAUSE TO READ SCREEN THEN GO TO OPTIONS 6130 REM 7000 ANSWER$="":POKE 744,255:INPUT ANSWER$:RETURN :REM 1 CHARACTER INPUT 7010 REM 7100 GRAPHICS 0:REM DRIVE NUMBER AND FILENAME INPUT ROUTINE 7110 ? :? "TYPE DISK DRIVE NUMBER (1-4)";:HIGHNUMBER=4:GOSUB 7000 7120 LINE=7110:TRAP 8000:NUMBER=VAL(ANSWER$):TRAP 9100 7130 IF NUMBER<1 OR NUMBER>4 THEN 8000 7140 DRIVE$="D":DRIVE$(LEN(DRIVE$)+1)=ANSWER$ 7150 DRIVE$(LEN(DRIVE$)+1)=":" 7200 ? :? "TYPE FILE NAME;:INPUT FILE$:IF LEN(FILE$)=0 THEN 7200 " 7210 DRIVEFILE$=DRIVE$ 7220 DRIVEFILE$(LEN(DRIVEFILE$)+1)=FILE$:RETURN 7230 REM 8000 ? :? "PLEASE TYPE A NUMBER FROM 1 THRU ";HIGHNUMBER:REM ERROR ROUTINE 8010 GOSUB 9000:GOTO LINE:REM GO BACK TO LINE NUMBER (LINE) 9000 ? CHR$(253):REM RING ERROR BELL 9010 FOR COUNT=1 TO 300:NEXT COUNT:RETURN 9020 REM 9100 IF PEEK(195)=136 THEN GOTO LINE:REM ERROR WAS END OF FILE 9110 REM DISPLAY ERROR NUMBER AND LINE AT WHICH ERROR OCCURRED THEN END 9120 ? :? "ERROR ";PEEK(195);" AT LINE ";PEEK(186)+PEEK(187)*256 9130 LIST PEEK(186)+PEEK(187)*256:GOSUB 9000 9140 TRAP 40000:END :REM ELIMINATE ANY PREVIOUSLY SET TRAP AND END PROGRAM
Jerry White, 18 Hickory Lane, Levittown, NY 11756.