Random (Relative) FIles
Introduction
There are three example random file programs. The first is very simple, but it demonstrates the principle of random access files. The second expands the first into quite a useful database program. The final example is an inventory program. Although it does not provide application dependent features, it would serve as it stands and it is sufficiently well structured to be expanded without too many problems.
Designing the File
Unlike other versions of BASIC, there is no formalised record structure in BBC BASIC. A file is considered to be a continuous stream of bytes (characters) and you can directly access any byte of the file. This approach has many advantages, but most files are logically considered as a sequence of records (some of which may be empty). How then do we create this structure and access our logical records?
Record Structure
Creating the structure is quite simple. You need to decide what information you want to hold and the order in which you want store it. In the first example, for instance, we have two items of information (fields) per logical record; the name and the remarks. The name can be a maximum of 30 characters long and the remarks a maximum of 50 characters. So our logical record has two fields, one 30 characters long and the other 50 characters long. When the name string is written to disk it will be terminated by a CR - and so will the remarks string. So each record will be a maximum of 82 characters long.
We haven’t finished yet, however. We need to be able to tell whether any one record is 'live' or empty (or deleted). To do this we need an extra byte at the start of each record which we set to one value for 'empty' and another for 'live'. In all the examples we use 0 to indicate 'empty' and NOT 0 to indicate 'live'. We are writing character data to the file so we could use the first byte of the name string as the indicator because the lowest ASCII code we will be storing is 32 (space). You can’t do this for mixed data files because this byte could hold a data value of zero. Because of this, we have chosen to use an additional byte for the indicator in all the examples.
Our logical record thus consists of:
1 |
indicator byte |
31 |
bytes for the name |
51 |
bytes for the remarks |
Thus the maximum amount of data in each record is 83 bytes. Because we cannot tell in advance how big each record needs to be (and we may want to change it later), we must assume that ALL the records will be this length. Since most of the records will be smaller than this, we are going to waste quite a lot of space in our random access file, but this is the penalty we pay for convenience and comparative simplicity.
When we write the data to the file, we could insist that each field was treated as a fixed length field by packing each string out with spaces to make it the 'correct' length. This would force each field to start at its 'proper' byte within the record. We don’t need to do this, however, because we aren’t going to randomly access the fields within the record; we know the order of the fields within the record and we are going to read them sequentially into appropriately named variables. We can write the fields to the file with each field following on immediately behind the previous one. All the 'spare' room is now left at the end of the record and not split up at the end of each field.
Accessing The Records
In order to access any particular record, you need to set PTR# to the first byte of that record. Remember, you can’t tell BBC BASIC (Z80) that you want 'record 5', because it knows nothing of your file and record structure. You need to calculate the position of the first byte of 'record 5' and set PTR# to this value.
To start with, let’s call the first record on the file 'record zero', the second record 'record 1', the third record 'record 2', etc. The first byte of 'record zero' is at byte zero on the file. The first byte of 'record 1' is at byte 83 on the file. The first byte of 'record 2' is at byte 166 (2*83) on the file. And so on. So, the start point of any record can be calculated by:
first_byte= 83*record_number
Now, we need to set PTR# to the position of this byte in order to access the record. If the record number was held in 'recno' and the file handle in 'fnum', we could do this directly by:
PTR#fnum=83*recno
However, we may want to do this in several places in the program so it would be better to define and use a function to set PTR# as illustrated below.
190 ...
200 PTR#fnum=FN_ptr(recno)
210 ...
etc
900 DEF FN_ptr(record)=83*record
Whilst the computer is quite happy with the first record being 'record zero', us mere humans find it a little confusing. What we need is to be able to call the first record 'record 1', etc. We could do this without altering the function which calculates the start position of each record, but we would waste the space allocated to 'record 0' since we would never use it. We want to call it 'record 1' and the program wants to call it 'record 0'. We can change the function to cater for this. If we subtract 1 from the record number before we multiply it by the record length, we will get the result we want. Record 1 will start at byte zero, record 2 will start at byte 83, etc. Our function now looks like this:
DEF FN_ptr(record)=83*(record-1)
In our example so far we have used a record length of 83. If we replace this with a variable 'rec_len' we have a general function which we can use to calculate the start position of any record in the file in any program. (You will need to set rec_len to the appropriate value at the start of the program.) The function now becomes:
DEF FN_ptr(record)=rec_len*(record-1)
We use this function (or something very similar to it) in the following three example programs using random access files.
Ex 9 - Simple Random Access File
10 REM F-RAND1
20 :
30 REM VERY SIMPLE RANDOM ACCESS PROGRAM
40 :
50 REM This program maintains a random access
60 REM file of names and remarks. There is
70 REM room for a maximum of 20 entries. Each
80 REM name can be up to a max of 30 chars
90 REM long and each remark up to 50 chars.
100 REM The first byte of the record is set non
110 REM zero (in fact &FF) if there is a record
120 REM present. This gives a maximum record
130 REM length of 1+31+51=83. (Including CRs)
140 :
150 bell$=CHR$(7)
160 temp$=STRING$(50," ")
170 maxrec=20
180 rec_len=83
190 ans$=""
200 CLS
210 WIDTH 0
220 fnum=OPENUP "RANDONE"
230 IF fnum=0 fnum=FN_setup("RANDONE")
240 REPEAT
250 REPEAT
260 INPUT '"Enter record number: "ans$
270 IF ans$="0" CLOSE#fnum:CLS:END
280 IF ans$="" record=record+1 ELSE record=VAL(ans$)
290 IF record<1 OR record>maxrec PRINT bell$;
300 UNTIL record>0 AND record<=maxrec
310 PTR#fnum=FN_ptr(record)
320 PROC_display
330 INPUT '"Do you wish to change this record" ,ans$
340 PTR#fnum=FN_ptr(record)
350 IF FN_test(ans$) PROC_modify
360 UNTIL FALSE
370 END
380 :
390 :
400 DEF FN_test(A$) =LEFT$(A$,1)="Y" OR LEFT$(A$,1)="y"
410 :
420 :
430 DEF FN_ptr(record)=rec_len*(record-1)
440 REM This makes record 1 start at PTR# = 0
450 :
460 :
470 DEF PROC_display
480 PRINT '"Record number ";record'
490 flag=BGET#fnum
500 IF flag=0 PROC_clear:ENDPROC
510 INPUT#fnum,name$,remark$
520 PRINT name$;" ";remark$ '
530 ENDPROC
540 :
550 :
560 DEF PROC_clear
570 PRINT "Record empty"
580 name$=""
590 remark$=""
600 ENDPROC
610 :
620 :
630 DEF PROC_modify
640 PRINT '"(Enter <Enter> for no change or DELETE to delete)"'
650 INPUT "Name ",temp$
660 temp$=LEFT$(temp$,30)
670 IF temp$<>"" name$=temp$
680 INPUT "Remark ",temp$
690 temp$=LEFT$(temp$,50)
700 IF temp$<>"" remark$=temp$
710 INPUT '"Confirm update record",ans$
720 IF NOT FN_test(ans$) ENDPROC
730 IF name$="DELETE" BPUT#fnum,0:ENDPROC
740 BPUT#fnum,255
750 PRINT#fnum,name$,remark$
760 ENDPROC
770 :
780 :
790 DEF FN_setup(fname$)
800 PRINT "Setting up the database file"
810 fnum=OPENOUT(fname$)
820 FOR record=1 TO maxrec
830 PTR#fnum=FN_ptr(record)
840 BPUT#fnum,0
850 NEXT
860 =fnum
Ex 10 - Simple Random Access Database
The second program in this sub-section expands the previous program into a simple, but quite versatile, database program. A setup procedure has been added which allows you to specify the file name. If it is a new file, you are then allowed to specify the number of records and the number, name and size of the fields you wish to use. This information is stored at the start of the file. If the file already exists this data is read from the records at the beginning of the file. The function for calculating the start position of each record is modified to take into account the room used at the front of the file to store information about the database.
10 REM F-RAN
20 REM SIMPLE DATABASE PROGRAM
30 REM Written by R T Russell Jan 1983
40 REM Mod for BBC BASIC (Z80): D Mounter Dec 1985
50 :
60 REM This is a simple database program. You
70 REM are asked for the name of the file you
80 REM wish to use. If the file does not
90 REM already exist, you are asked to enter
100 REM the number and format of the records.
110 REM If the file does already exist, the file
120 REM specification is read from the file.
130 :
140 @%=&90A
150 bell$=CHR$(7)
160 CLS
170 WIDTH 0
180 INPUT '"Enter the filename of the data file: "filename$
190 fnum=OPENUP(filename$)
200 IF fnum=0 fnum=FN_setup(filename$) ELSE PROC_readgen
210 PRINT
220 :
230 REPEAT
240 REPEAT
250 INPUT '"Enter record number: "ans$
260 IF ans$="0" CLOSE#fnum:CLS:END
270 IF ans$="" record=record+1 ELSE record=VAL(ans$)
280 IF record<1 OR record>maxrec PRINT bell$;
290 UNTIL record>0 AND record<=maxrec
300 PTR#fnum=FN_ptr(record)
310 PROC_display
320 INPUT '"Do you wish to change this record" ,ans$
330 PTR#fnum=FN_ptr(record)
340 IF FN_test(ans$) PROC_modify
350 UNTIL FALSE
360 END
370 :
380 :
390 DEF FN_test(A$) =LEFT$(A$,1)="Y" OR LEFT$(A$,1)="y"
400 :
410 :
420 DEF FN_ptr(record)=base+rec_len*(record-1)
430 :
440 :
450 DEF FN_setup(filename$)
460 PRINT "New file."
470 fnum=OPENOUT(filename$)
480 REPEAT
490 INPUT "Enter the number of records (max 1000): "maxrec
500 UNTIL maxrec>0 AND maxrec<1001
510 REPEAT
520 INPUT "Enter number of fields per record (max 20): "fields
530 UNTIL fields>0 AND fields<21
540 DIM title$(fields),size(fields),A$(fields)
550 FOR field=1 TO fields
560 PRINT '"Enter title of field number ";field;": ";
570 INPUT ""title$(field)
580 PRINT
590 REPEAT
600 INPUT "Max size of field (characters)",size(field)
610 UNTIL size(field)>0 AND size(field)<256
620 NEXT field
630 rec_len=1
640 PRINT#fnum,maxrec,fields
650 FOR field=1 TO fields
660 PRINT#fnum,title$(field),size(field)
670 rec_len=rec_len+size(field)+1
680 NEXT field
690 base=PTR#fnum
700 :
710 FOR record=1 TO maxrec
720 PTR#fnum=FN_ptr(record)
730 BPUT#fnum,0
740 NEXT
750 =fnum
760 :
770 :
780 DEF PROC_readgen
790 rec_len=1
800 INPUT#fnum,maxrec,fields
810 DIM title$(fields),size(fields),A$(fields)
820 FOR field=1 TO fields
830 INPUT#fnum,title$(field),size(field)
840 rec_len=rec_len+size(field)+1
850 NEXT field
860 base=PTR#fnum
870 ENDPROC
880 :
890 :
900 DEF PROC_display
910 PRINT '"Record number ";record'
920 flag=BGET#fnum
930 IF flag=0 PROC_clear:ENDPROC
940 FOR field=1 TO fields
950 INPUT#fnum,A$(field)
960 PRINT title$(field);" ";A$(field)
970 NEXT field
980 ENDPROC
990 :
1000 :
1010 DEF PROC_clear
1020 FOR field=1 TO fields
1030 A$(field)=""
1040 NEXT
1050 ENDPROC
1060 :
1070 :
1080 DEF PROC_modify
1090 PRINT '"(Enter <Enter> for no change)"'
1100 FOR field=1 TO fields
1110 REPEAT
1120 PRINT title$(field);" ";
1130 INPUT LINE ""A$
1140 IF A$="" PRINT TAB(POS,VPOS-1)title$(field);" ";A$(field)
1150 REM TAB(POS,VPOS-1) moves the cursor up 1 line
1160 UNTIL LEN(A$)<=size(field)
1170 IF A$<>"" A$(field)=A$
1180 NEXT field
1190 INPUT '"Confirm update record",ans$
1200 IF NOT FN_test(ans$) ENDPROC
1210 IF A$(1)="DELETE" BPUT#fnum,0:ENDPROC
1220 BPUT#fnum,255
1230 FOR field=1 TO fields
1240 PRINT#fnum,A$(field)
1250 NEXT field
1260 ENDPROC
Ex 11 - Random Access Inventory Program
The final example in this sub-section is a full-blown inventory program. Rather than go through all its aspects at the start, they are discussed at the appropriate point in the listing. (These comments do not have line numbers and are not, of course, part of the program.)
10 REM F-RAND
20 :
30 REM Written by Doug Mounter Jan 1982
40 REM Modified for BBC BASIC (Z80) Dec 1985
50 :
60 REM EXAMPLE OF A RANDOM ACCESS FILE
70 :
80 REM This is a simple inventory program. It
90 REM uses the item's part number as the key
92 REM and stores:
100 REM The item description - char max len 30
110 REM The quantity in stock - numeric
120 REM The re-order level - numeric
130 REM The unit price - numeric
140 REM In addition, the first byte of the rec
150 REM is used as a valid data flag. Set to 0
160 REM if empty, D if the record has been
170 REM deleted or V if the record is valid.
180 REM This gives a MAX record len of 47 bytes
190 REM (Don't forget the CR after the string)
200 :
210 PROC_initialise
220 inventry=FN_open("INVENTRY"
The following section of code is the command loop. You are offered a choice of functions until you eventually select function 0. The more traditional ON GOSUB statement has been used for menu selection processing. The newer ON PROC statement is illustrated in the indexed file example which follows. There are some forward jumps within procedures, etc to overcome the lack of a multi line IF statement. It would have been possible to have used further procedures, but the whole thing would have become rather laboured.
230 REPEAT
240 CLS
250 PRINT TAB(5,3);"If you want to:-"'
260 PRINT TAB(10);"End This Session";TAB(55);"Type 0"
270 PRINT TAB(10);"Amend or Create an Entry";TAB(55);"Type 1"
280 PRINT TAB(10);"Disp Inventory for One Part";TAB(55);"Type 2"
290 PRINT TAB(10);"Alter Stock of One Part";TAB(55);"Type 3"
300 PRINT TAB(10);"Disp Items to Reorder";TAB(55);"Type 4"
310 PRINT TAB(10);"Recover a Deleted Item";TAB(55);"Type 5"
320 PRINT TAB(10);"List Deleted Items";TAB(55);"Type 6"
330 PRINT TAB(10);"Set Up a New Inventory";TAB(55);"Type 9"
340 REPEAT
350 PRINT TAB(5,15);bell$;
360 PRINT "Please enter selection (0 to 6 or 9) ";
370 function$=GET$
380 UNTIL function$>"/" AND function$<"8" OR function$="9"
390 function=VAL(function$)
400 ON function GOSUB 500,670,810,1100,1350,1540,1770,1790,1840 ELSE
410 UNTIL function=0
420 CLS
430 PRINT "Inventory File Closed" ''
440 CLOSE#inventry
450 END
460 :
470 :
480 REM AMEND/CREATE AN ENTRY
This is the data entry function. You can delete or amend an entry or enter a new one. Have a look at the definition of FN_getrec for an explanation of the ASC"V" in its parameters.
490 :
500 REPEAT
510 CLS
520 PRINT "AMEND/CREATE"
530 partno=FN_getpartno
540 flag=FN_getrec(partno,ASC"V")
550 PROC_display(flag)
560 PRINT'"Do you wish to ";
570 IF flag PRINT "change this entry ? "; ELSE PRINT "enter data ? ";
580 IF GET$<>"N" flag=FN_amend(partno):PROC_cteos
590 PROC_write(partno,flag,type)
600 PRINT bell$;"Do you wish to amend/create another record ? ";
610 UNTIL GET$="N"
620 RETURN
630 :
640 :
650 REM DISPLAY AN ENTRY
This subroutine allows you to look at a record without the ability to change or delete it.
660 :
670 REPEAT
680 CLS
690 PRINT "DISPLAY"
700 partno=FN_getpartno
710 flag=FN_getrec(partno,ASC"V")
720 PROC_display(flag)
730 PRINT '
740 PRINT "Do you wish to view another part?";
750 UNTIL GET$="N"
760 RETURN
770 :
780 :
790 REM CHANGE THE STOCK LEVEL FOR ONE PART
The purpose of this subroutine is to allow you to update the stock level without having to amend the rest of the record.
800 :
810 REPEAT
820 CLS
830 PRINT "CHANGE STOCK"
840 partno=FN_getpartno
850 flag=FN_getrec(partno,ASC"V")
860 REPEAT
870 PROC_display(flag)
880 PROC_cteos
890 REPEAT
900 PRINT TAB(0,12);:PROC_cteol
910 INPUT "What is the change ? " temp$
920 change=VAL(temp$)
930 UNTIL INT(change)=change AND stock+change>=0
940 IF temp$="" flag=FALSE:GOTO 1000
950 stock=stock+change
960 PROC_display(flag)
970 PRINT'"Is this correct ? ";
980 temp$=GET$
990 :
1000 UNTIL NOT flag OR temp$="Y"
1010 PROC_write(partno,flag,ASC"V")
1020 PRINT return$;bell$;
1030 PRINT "Do you want any more updates ? ";
1040 UNTIL GET$="N"
1050 RETURN
1060 :
1070 :
1080 REM DISPLAY ITEMS BELOW REORDER LEVEL
This subroutine goes through the file in stock number order and lists all those items where the current stock is below the reorder level. You can interrupt the process at any time by pushing a key.
1090 :
1100 partno=1
1110 REPEAT
1120 CLS
1130 PRINT "ITEMS BELOW REORDER LEVEL"'
1140 line_count=2
1150 REPEAT
1160 flag=FN_getrec(partno,ASC"V")
1170 IF NOT(flag AND stock<reord) THEN 1230
1180 PRINT "Part Number ";partno
1190 PRINT desc$;" Stock ";stock;" Reorder Level ";reord
1200 PRINT
1210 line_count=line_count+3
1220 :
1230 partno=partno+1
1240 temp$=INKEY$(0)
1250 UNTIL partno>maxpartno OR line_count>20 OR temp$<>""
1260 PRINT TAB(0,23);bell$;"Push any key to continue or E to end ";
1270 temp$=GET$
1280 UNTIL partno>maxpartno OR temp$="E"
1290 partno=0
1300 RETURN
1310 :
1320 :
1330 REM RECOVER A DELETED ENTRY
Deleted entries are not actually removed from the file, just marked as deleted. This subroutine makes it possible for you to correct the mistake you made by deleting data you really wanted. If you have never used this type of program seriously, you won’t believe how useful this is.
1340 :
1350 REPEAT
1360 CLS
1370 PRINT "RECOVER DELETED RECORDS"
1380 partno=FN_getpartno
1390 flag=FN_getrec(partno,ASC"D")
1400 PROC_display(flag)
1410 PRINT
1420 IF NOT flag THEN 1470
1430 PRINT "If you wish to recover this entry type Y ";
1440 temp$=GET$
1450 IF temp$="Y"PROC_write(partno,flag,ASC"V")
1460 :
1470 PRINT return$;bell$;"Do you wish to recover another record ? ";
1480 UNTIL GET$="N"
1490 RETURN
1500 :
1510 :
1520 REM LIST DELETED ENTRIES
This subroutine lists all the deleted entries so you can check you really don’t want the data.
1530 :
1540 partno=1
1550 REPEAT
1560 CLS
1570 PRINT "DELETED ITEMS"'
1580 line_count=2
1590 REPEAT
1600 flag=FN_getrec(partno,ASC"D")
1610 IF NOT flag THEN 1660
1620 PRINT "Part Number ";partno
1630 PRINT "Description ";desc$'
1640 line_count=line_count+3
1650 :
1660 partno=partno+1
1670 temp$=INKEY$(0)
1680 UNTIL partno>maxpartno OR line_count>20 OR temp$<>""
1690 PRINT TAB(0,23);bell$;"Push any key to continue or E to end ";
1700 UNTIL partno>maxpartno OR GET$="E"
1710 partno=0
1720 RETURN
1730 :
1740 :
1750 REM DUMMY RETURNS FOR INVALID FUNCTION NUMs
1760 :
1770 RETURN
1780 :
1790 RETURN
1800 :
1810 :
1820 REM REINITIALISE THE INVENTORY DATA FILE
1830 :
1840 CLS
1850 PRINT TAB(0,3);bell$;"Are you sure you want to set up a new inventory?"
1860 PRINT "You will DESTROY ALL THE DATA YOU HAVE ACCUMULATED so far."
1870 PRINT '"It would be safer to use a new disk in drive B and start a new"
1880 PRINT "inventory file."'
1890 PRINT "If you are SURE you want to do it, enter YES"
1900 PRINT "If you want to start a new inventory file, enter NEW"
1910 INPUT "Otherwise, just hit return ",temp$
1920 IF temp$="YES" PROC_setup(inventry)
1930 IF temp$="NEW" function=0
1940 RETURN
1950 :
1960 :
1970 REM INITIALISE ALL THE VARIOUS PRESETS ETC
This is where all the variables that you usually write as CHR$(#) go. Then you can find them if you want to change them.
1980 :
1990 DEF PROC_initialise
2010 bell$=CHR$(7)
2020 return$=CHR$(13)
2030 rec_length=47
2040 partno=0
If you initially set strings to the maximum length you will ever use, you will save prevent the generation of 'garbage'.
2050 desc$=STRING$(30," ")
2060 temp$=STRING$(40," ")
2070 WIDTH 0
2130 REM OPEN FILE AND RETURN THE FILE HANDLE
2140 :
2150 REM If the file already exists, the largest permitted
2160 REM part number is read into maxpartno.
2170 REM If it is a new file, the file is
2180 REM initialised and the largest part
2190 REM number is written as the first record.
2200 :
2210 DEF FN_open(name$)
2220 fnum=OPENUP(name$)
2230 IF fnum>0 INPUT#fnum,maxpartno: =fnum
2240 fnum=OPENOUT(name$)
2250 CLS
It’s a new file, so we won’t go through the warning bit.
2260 PROC_setup(fnum)
2270 =fnum
2280 :
2290 REM SET UP THE FILE
2300 :
2310 REM Ask for maximum part number required,
2320 REM write it as the first record and then
2330 REM write 0 in to first byte of each rec.
2340 :
2350 DEF PROC_setup(fnum)
2360 REPEAT
2370 PRINT TAB(0,12);bell$;:PROC_cteos
2380 INPUT "What is the highest part number required (Max 5000)",maxpartno
2390 UNTIL maxpartno>0 AND maxpartno<5000 AND INT(maxpartno)=maxpartno
2400 PTR#fnum=0
2410 PRINT#fnum,maxpartno
2420 FOR partno=1 TO maxpartno
2430 PTR#fnum=FN_ptr(partno)
2440 BPUT#fnum,0
2450 NEXT
2460 partno=0
2470 ENDPROC
2480 :
2490 :
2500 REM GET AND RETURN THE REQUIRED PART NUMBER
Ask for the required part number. If a null is entered, make the next part number one more than the last.
2510 :
2520 DEF FN_getpartno
2530 REPEAT
2540 PRINT TAB(0,5);bell$;:PROC_cteos
2550 PRINT "Enter a Part Number Between 1 and ";maxpartno '
2560 IF partno=maxpartno THEN 2590
2570 PRINT "The Next Part Number is ";partno+1;
2580 PRINT " Just hit RETURN to get this"'
2590 :
2600 INPUT "What is the Part Number You Want ", partno$
2610 IF partno$<>"" partno=VAL(partno$):GOTO 2630
2620 IF partno=maxpartno partno=0 ELSE partno=partno+1
2630 :
2640 PRINT TAB(35,9);partno;:PROC_cteol
2650 UNTIL partno>0 AND partno<maxpartno+1 AND INT(partno)=partno
2660 =partno
2670 :
2680 :
2690 REM GET THE RECORD FOR THE PART NUMBER
2700 :
2710 REM Return TRUE if the record exists and
2720 REM FALSE if not If the record does not
2730 REM exist, load desc$ with "No Record" The
2740 REM remainder of the record is set to 0.
2742 :
2750 DEF FN_getrec(partno,type)
2760 stock=0
2770 reord=0
2780 price=0
2790 PTR#inventry=FN_ptr(partno)
2800 test=BGET#inventry
2810 IF test=0 desc$="No Record": =FALSE
2820 IF test=type THEN 2850
2830 IF type=86 desc$="Record Deleted" ELSE desc$="Record Exists"
2840 =FALSE
2850 :
2860 INPUT#inventry,desc$
2870 INPUT#inventry,stock,reord,price
2880 =TRUE
2890 :
2900 :
2910 REM CALCULATE THE VALUE OF PTR FOR THIS REC
Part numbers run from 1 up. The record for part number 1 starts at byte 5 of the file. The start position could have been calculated as (part-no -1) *record_length + 5. The expression below works out to the same thing, but it executes quicker.
2920 :
2930 DEF FN_ptr(partno)=partno*rec_length+5-rec_length
2940 :
2950 :
2960 REM AMEND THE RECORD
This function amends the record as required and returns with flag=TRUE if any amendment has taken place. It also sets the record type indicator (valid deleted or no record) to ASC"V" or ASC"D" as appropriate.
2970 :
2980 DEF FN_amend(partno)
2990 PRINT return$;:PROC_cteol:PRINT TAB(0,4);
3000 PRINT "Please Complete the Details for Part Number ";partno
3010 PRINT "Just hit Return to leave the entry as it is"'
3020 flag=FALSE
3030 type=ASC"V"
3040 INPUT "Description - Max 30 Chars " temp$
3050 IF temp$="DELETE" type=ASC"D": =TRUE
3060 temp$=LEFT$(temp$,30)
3070 IF temp$<>"" desc$=temp$:flag=TRUE
3080 IF desc$="No Record" OR desc$="Record Deleted" =FALSE
3090 INPUT "Current Stock Level " temp$
3100 IF temp$<>"" stock=VAL(temp$):flag=TRUE
3110 INPUT "Reorder Level " temp$
3120 IF temp$<>"" reord=VAL(temp$):flag=TRUE
3130 INPUT "Unit Price " temp$
3140 IF temp$<>"" price=VAL(temp$):flag=TRUE
3150 =flag
3160 :
3170 :
3180 REM WRITE THE RECORD
Write the record to the file if necessary (flag=TRUE)
3190 :
3200 DEF PROC_write(partno,flag,type)
3210 IF NOT flag ENDPROC
3220 PTR#inventry=FN_ptr(partno)
3230 BPUT#inventry,type
3240 PRINT#inventry,desc$,stock,reord,price
3250 ENDPROC
3260 :
3270 :
3280 REM DISPLAY THE RECORD DETAILS
Print the record details to the screen. If the record is not of the required type (V or D) or it does not exist, stop after printing the description. The description holds "Record Exists" or "Record Deleted" or valid data as set by FN_getrec.
3290 :
3300 DEF PROC_display(flag)
3310 PRINT TAB(0,5);:PROC_cteos
3320 PRINT "Part Number ";partno'
3330 PRINT "Description ";desc$
3340 IF NOT flag ENDPROC
3350 PRINT "Current Stock Level ";stock
3360 PRINT "Reorder Level ";reord
3370 PRINT "Unit Price ";price
3380 ENDPROC
3390 :
3400 :
The two following procedures rely on the screen width being 80 characters:
3410 REM There are no 'native' clear to end of
3420 REM line/screen vdu procedures. The
3430 REM following two procedures clear to the
3440 REM end of the line/screen.
3450 DEF PROC_cteol
3460 LOCAL x,y
3470 x=POS:y=VPOS
3480 IF y=31 PRINT SPC(79-x); ELSE PRINT SPC(80-x);
3490 PRINT TAB(x,y);
3500 ENDPROC
3510 :
3520 :
3530 DEF PROC_cteos
3540 LOCAL I,x,y
3550 x=POS:y=VPOS
3560 IF y<31 FOR I=y TO 30:PRINT SPC(80);:NEXT
3570 PRINT SPC(79-x);TAB(x,y);
3580 ENDPROC