This program is a personal-information database manager for a church Sunday School department, storing up to 250 family records across seven data fields (name, street, city, telephone, children, birthdays, and activities) spread across numbered DATA statements from line 8000 to 9502. It loads two machine-code modules at startup — “findv” at address 54000 and “create” at 54850 — which handle variable location, string squishing, and record creation/deletion via direct POKE and USR calls. Records are organized by storing each field’s data at a fixed line-number base plus a file-number offset (e.g., name at 8000+FNO, street at 8250+FNO), and a bubble-sort lookup (“bubl” at 54600) is referenced in the memory map. The RESTORE/READ mechanism is used as a database engine, with machine code patching the RESTORE target address directly into memory via POKE to locations 54894–54895.
Program Structure
The program is divided into clearly delineated functional blocks:
- Lines 1–9: Initialisation, error-code documentation, memory map, and variable glossary in REMs.
- Lines 10–26: Entry point and the “string filter” subroutine (squishes/normalises input for comparison).
- Lines 900–988: Low-level subroutines — add-data, BOOK fill (POKEs DATA addresses into machine code), and STMT fill.
- Lines 949–971: DATA statements listing the start line numbers for each of the seven field blocks.
- Lines 1000–1028: Main menu dispatcher.
- Lines 1050–1295: Add file and delete file routines.
- Lines 2000–2150: Search and save routines.
- Lines 3000–3035: Modify/data-entry routine.
- Lines 4000–4220: Printout routine (alphabetical and by class).
- Lines 8000–9502: Actual database storage in DATA statements, pre-loaded with one sample record and one sentinel record.
Machine Code Modules
Two binary files are loaded at startup into high RAM:
| Module | Address Range | Purpose |
|---|---|---|
findv | 54000–54599 | Variable/array locator; also contains esc (54532–54562) for escape handling |
bubl | 54600–54840 | Bubble-sort (referenced in memory map, called implicitly) |
create | 54850–56021 | Record creation, deletion, file-count management |
PR CODE | 64246–64939 | Printer driver for Olivetti ink jet; loaded separately via CAT at line 4001 |
The BASIC program communicates with machine code by setting named variables (FCNT, FNO, MODE, N$, R$, S$, M, L) before calling USR, relying on findv to locate them in the variables area at runtime. This is a common technique to avoid hard-coding variable addresses.
Database Engine: RESTORE/READ as Record Access
Each of the seven fields occupies a block of 250 DATA statements starting at a specific base line number. File record n is at line BASE+n:
| Field | Base Line |
|---|---|
| Names | 8000 |
| Street | 8250 |
| City | 8500 |
| Telephone | 8750 |
| Children | 9000 |
| Birthdays | 9250 |
| Activities | 9500 |
Accessing a record is done with RESTORE (BASE+FNO): READ F$. To pass a dynamic RESTORE target into machine code, subroutine 985 splits a line number into low and high bytes and POKEs them directly into the create module at addresses 54894–54895, patching the machine code’s internal RESTORE pointer on the fly.
BOOK Fill Routine (Lines 975–983)
The subroutine at line 975 reads the seven base line numbers from the DATA block at lines 950–971 and encodes each as a two-byte little-endian value POKEd into the create module starting at address 54850 (two bytes per entry, up to 20 sets). This gives the machine-code module a runtime table of all field base addresses without requiring recompilation if the DATA layout changes.
String Squishing / Normalisation
Before any name comparison, the subroutine at lines 20–26 is called. It sets R$ to the input and calls USR 54000 (findv) followed by RANDOMIZE USR 55700 (within the create module region) to produce a squished/canonicalised string in S$ of length L (retrieved via PEEK 54900). This allows case- and space-insensitive comparison for searching and sorted insertion.
Sorted Insertion and Binary Search
When adding or searching, the program iterates through existing name records (lines 1061–1064 or 2020–2050), squishing each stored name and comparing it against the squished input using P$<=R$ string comparison to find the correct sorted insertion point or match position. This is a linear scan rather than a true binary search, so performance degrades with more records.
Key BASIC Idioms and Techniques
RESTORE (expression)with a computed line number is used throughout as the primary record-access mechanism — a non-standard TS2068 extension.DELETE BEGONE,BEGONEat lines 909 and 1264 uses the TS2068DELETEcommand to remove a single DATA statement (a line range of one line), effectively erasing a record.VAL K$is used to convert user input strings to file numbers, with a guardCODE (Z$)>47 AND CODE (Z$)<58at line 3013 to validate digit input before conversion.LET B$="..."at line 1002 initialises a 43-space buffer string used by the squish routine as working space (S$=B$(1 TO M)at line 21).RANDOMIZE USRis used (instead of plainUSR) where the return value is unneeded, discarding it into the randomiser seed rather than requiring an assignment.
Printout Routine (Lines 4000–4220)
The printout section initialises the Olivetti ink-jet printer via specific POKE and LPRINT escape sequences (CHR$ 27;CHR$ 0;CHR$ 127) and POKEs at 26703, 26704, 64259, 64256. It supports two print modes: alphabetical (all records in file order) and by class/grade (filtering on the first two characters of the Activities field interpreted as a class number via VAL A$). An INKEY$="0" check at lines 4115 and 4215 provides an emergency abort during printing.
Content
Source Code
1 LOAD "findv"CODE 54000,600: LOAD "create"CODE 54850,1175: REM "datab" © by Ben H. Jackson, 6/28/85; ALL RIGHRS RESERVED: REM Type GOTO 2 for re-start instead of RUN
2 LET ERROR=0: GO TO 10
3 REM --ERROR CODES 1--VAR NOT IN REM STMT findv 2--UNDEF VAR IN REM STMT findv 3--ARRAY NOT IN VLT findv 4--DATA STMT NOT FOUND finds 5--EXCEEDED MAX SETS(20) creat 6--NAME FILE TOO LONG creat 7--ILLEG CHAR IN I/P squish
4 REM 8--OUT OF MEMORY creat 9--MAX FILE CNT [250] creat
5 PRINT "ERROR=";ERROR: STOP
6 REM --MEMORY ALLOCATION "findv"--54000 TO 54599 "esc" --54532 TO 54562 "bubl" --54600 TO 54840 "create"-54850 TO 56021 "PR CODE"64246 TO 64939
7 REM --variables N$----Name register K$----dummy variable FCNT--File Count=no. files FNO---File No.=file of int MODE--flg 0=cre 1=del P$ ---squished N$ file
10 DIM X(10)
15 GO TO 1000
20 REM "STRING FILTER" ROUTINE S$=squished name string R$=input string M=Length of input string L=Length of S$
21 LET M=LEN R$: LET L=M: LET S$=B$(1 TO M)
22 LET V=USR 54000: REM R$,S$,M,L
23 RANDOMIZE USR 55700
24 LET L=PEEK 54900
25 LET S$=S$(1 TO L)
26 RETURN
900 REM --add data rtn--
901 IF nr=1 THEN PRINT "OLD ";A$;"= EMPTY": GO TO 903
902 RESTORE (BASE+FNO): READ F$: PRINT "OLD ";A$;"=";F$
903 PRINT A$;';" ['ENT'if no chg]=": INPUT N$: IF N$="" THEN RETURN
904 LET STMT=BASE: GO SUB 985
905 LET BEGONE=BASE+FNO
906 PRINT "NEW";A$;"=";N$;';" [0 TO fix]": INPUT z$
907 IF z$="0" THEN GO TO 902
909 DELETE BEGONE,BEGONE
910 LET V=USR 54000: REM Fcnt,N$,Fno,Mode
911 RANDOMIZE USR 54948
912 IF old=1 THEN LET nr=1
913 RETURN
949 REM --DATA SET START STNOS
950 DATA 8000: REM "NAMES"
951 DATA 8250: REM "STREET"
952 DATA 8500: REM "CITY"
953 DATA 8750: REM "TELE"
954 DATA 9000: REM "CHILDREN"
955 DATA 9250: REM "BIRTHDAYS"
956 DATA 9500: REM "ACTIVITIES"
971 DATA 0000: REM "EOF"
975 REM --BOOK FILL ROUTINE--
976 RESTORE 950
977 FOR I=0 TO 20
978 READ BOOK: IF BOOK=0 THEN GO TO 983
979 LET BOOKM=INT (BOOK/256): LET BOOKL=256*(BOOK/256-BOOKM)
980 POKE (54850+2*I),BOOKL
981 POKE (54851+2*I),BOOKM
982 NEXT I
983 RETURN
985 REM --STMT FILL--
986 LET BOOKM=INT (STMT/256): LET BOOKL=256*(STMT/256-BOOKM)
987 POKE 54894,BOOKL: POKE 54895,BOOKM
988 RETURN
1000 LET FCNT=002: LET FNO=FCNT: LET old=0: LET MODE=1000
1001 GO SUB 975: REM "LD Books"
1002 LET B$=" "
1005 REM --MENU--
1006 CLS : PRINT AT 1,13;"MENU",,,
1010 PRINT "1. ADD FILE",,"2. DELETE FILE",,"3. MODIFY FILE",,"4. SEARCH",,"5. PRINTOUT (set-up for OLIVETTI INK JET printer. LIST 4000 and change for your printer) ","6. SAVE",,"7. EXIT"
1015 INPUT "SELECTION=";K$
1021 IF K$="1" THEN GO TO 1050
1022 IF K$="2" THEN GO TO 1100
1023 IF K$="3" THEN GO TO 3000
1024 IF K$="4" THEN GO TO 2000
1025 IF K$="5" THEN GO TO 4000
1026 IF K$="6" THEN GO TO 2100
1027 IF K$="7" THEN GO TO 9999
1028 GO TO 1000
1050 REM --ADD FILES ENTRY PT--
1055 CLS : PRINT AT 1,5;"ADDING FILE"
1056 INPUT "NEW NAME [0 to esc]=";N$: IF N$="0" THEN GO TO 1000
1057 LET R$=N$: GO SUB 21: LET P$=S$: LET L=LEN S$
1061 LET I=1
1062 READ R$: GO SUB 21: LET R$=S$: IF LEN S$>L THEN LET R$=S$(1 TO L)
1063 IF P$<=R$ THEN LET FNO=I: PRINT "fno=";fno: GO TO 1065
1064 LET I=I+1: IF I<=FCNT THEN GO TO 1062
1065 LET FNO=i: LET MODE=0: REM "CREATE"
1066 RESTORE 950: READ STMT: GO SUB 985
1070 LET v=USR 54000: REM Fcnt,N$,Fno,Mode
1080 RANDOMIZE USR 54948
1090 LET MODE=8: GO TO 3000
1100 REM --DELETE FILE ENTRY PT-
1105 CLS : PRINT AT 1,5;"DELETING FILE"
1110 INPUT "NAME TO BE DELETED[0 TO esc]=";N$: IF N$="0" THEN GO TO 1000
1111 LET R$=N$: GO SUB 21: LET P$=S$: LET L=LEN S$
1115 RESTORE 950: READ STMT: GO SUB 985: RESTORE STMT
1120 FOR I=1 TO FCNT
1130 READ R$: GO SUB 21: LET R$=S$: IF LEN S$>L THEN LET R$=S$(1 TO L)
1140 IF P$<=S$ THEN LET FNO=I: GO TO 1155
1150 NEXT I
1155 LET BK0=PEEK 54850+256*PEEK 54851
1160 RESTORE BK0+FNO: READ F$: PRINT FNO;" ";F$
1200 INPUT "FILE NO TO BE DELETED=[0 TO esc]";K$: IF K$="" THEN LET FNO=FNO+1: GO TO 1160
1201 IF K$="0" THEN GO TO 1000
1202 LET FNO=VAL K$
1210 RESTORE BK0+FNO: READ F$
1220 PRINT "DELETE ";F$;" ? [0 TO esc ]"
1230 INPUT K$
1240 IF K$="0" THEN GO TO 1000
1250 LET MODE=1
1260 RESTORE 950
1261 FOR I=0 TO 20
1262 READ BOOK: IF BOOK = 0 THEN GO TO 1280
1263 LET BEGONE=BOOK+FNO
1264 DELETE BEGONE,BEGONE
1265 NEXT I
1280 LET V=USR 54000: REM Fcnt,N$,Fno,Mode
1290 RANDOMIZE USR 54948
1295 GO TO 1000
2000 REM "SEARCH"
2005 CLS : PRINT AT 1,5;"SEARCH"
2010 INPUT "NAME TO BE FOUND[0 TO esc]=";N$: IF N$="0" THEN GO TO 1000
2011 LET R$=N$: GO SUB 21: LET P$=S$: LET L=LEN S$
2015 RESTORE 950: READ STMT: GO SUB 985: RESTORE STMT
2020 FOR I=1 TO FCNT
2030 READ R$: GO SUB 21: LET R$=S$: IF LEN S$>L THEN LET R$=S$(1 TO L)
2040 IF P$<=S$ THEN LET FNO=I: GO TO 2055
2050 NEXT I
2055 LET BK0=PEEK 54850+256*PEEK 54851
2060 RESTORE BK0+FNO: READ F$: PRINT FNO;" ";F$
2070 INPUT "FILE NO TO BE DISPLAYED=[0 TO esc]";K$: IF K$="" THEN LET FNO=FNO+1: GO TO 2060
2071 IF K$="0" THEN GO TO 1000
2072 LET FNO=VAL K$
2075 CLS
2080 FOR I=0 TO 6:
2081 RESTORE (8000+I*250+FNO)
2082 READ F$: PRINT F$
2083 NEXT I
2090 INPUT "0=MENU 1=PRINT 2=SEARCH";';"'SELECTION'=";Z$
2091 IF Z$="0" THEN GO TO 1000
2092 IF Z$="2" THEN GO TO 2000
2093 IF Z$="1" THEN LPRINT
2094 FOR I=0 TO 6
2095 RESTORE (8000+I*250+FNO)
2096 READ F$: LPRINT F$
2097 NEXT I
2099 GO TO 2090
2100 REM "SAVE"
2110 CLS : PRINT AT 1,10 ;"SAVING"
2120 INPUT "start the tape to SAVE program.";z$
2130 SAVE "TELE"
2140 PRINT "PROGRAM SAVED": PAUSE 10
2145 CLS
2150 GO TO 1000
3000 REM --MODIFY DATA--
3001 IF MODE=8 THEN LET MODE=2: LET z$="": GO TO 3012
3005 LET MODE=2
3010 INPUT "ENTER FILE NO[same='ENT',esc=0]=";z$
3011 IF Z$="0" THEN GO TO 1000
3012 IF Z$="" THEN LET old=1: GO TO 3015
3013 IF CODE (Z$)>47 AND CODE (Z$)<58 THEN LET FNO=VAL (Z$): GO TO 3015
3014 PRINT "ILLEGAL ENTRY,TRY AGAIN": GO TO 3010
3015 LET BK0=PEEK 54850+256*PEEK 54851
3016 RESTORE BK0+FNO: READ N$
3019 PRINT BK0+FNO;" ";N$
3020 LET A$="Name": LET BASE=8000: LET nr=0: GO SUB 900
3021 LET A$="Street": LET BASE=8250: GO SUB 900
3022 LET A$="City": LET BASE=8500: GO SUB 900
3023 LET A$="Tele": LET BASE=8750: GO SUB 900
3024 LET A$="Children": LET BASE=9000: GO SUB 900
3025 LET A$="Birthdays": LET BASE=9250: GO SUB 900
3026 LET A$="Activ": LET BASE=9500: GO SUB 900
3029 CLS : PRINT "FILE # ";FNO;''
3030 FOR I=0 TO 6:
3031 RESTORE (8000+I*250+FNO)
3032 READ F$: PRINT F$
3033 NEXT I
3034 INPUT "DEPRESS 'ENT' TO CONTIN";Z$
3035 GO TO 1000
4000 REM --PRINTOUT--
4001 CLS : PRINT AT 1,5;"PRINTOUT": CAT "PRCODE.BIN",
4002 POKE 26703,5: POKE 26704,251: POKE 64259,79: POKE 64256,0: LPRINT CHR$ 27;CHR$ 0;CHR$ 127: POKE 64256,1
4003 LPRINT TAB 35;"GAMBRELL SS DEPT BOYS";'''
4010 PRINT "1. ALPHABETICAL";';"2. CLASS"
4011 INPUT "ENTER SELECTION=";Z$
4015 IF Z$="1" THEN GO TO 4100
4016 IF Z$="2" THEN GO TO 4200
4017 GO TO 4011
4100 FOR I=1 TO FCNT
4101 RESTORE 8000+I: READ N$
4102 RESTORE 8250+I: READ S$
4103 RESTORE 8750+I: READ T$
4104 RESTORE 9250+I: READ B$
4105 RESTORE 9500+I: READ A$: LET A$=A$(1 TO 2)
4110 LPRINT N$;TAB 22;S$;TAB 45;T$;TAB 65;B$;TAB 77;A$
4115 IF INKEY$="0" THEN STOP
4116 IF I=60 THEN STOP
4120 NEXT I
4200 INPUT "CLASS [1 TO 12]=";C
4201 LPRINT "GRADE ";C
4202 FOR I=1 TO FCNT
4203 RESTORE 9500+I: READ A$: LET A$=A$(1 TO 2): LET AC=VAL A$
4204 IF AC<>C THEN GO TO 4220
4205 RESTORE 8000+I: READ N$
4206 RESTORE 8250+I: READ S$
4207 RESTORE 8750+I: READ T$
4208 RESTORE 9250+I: READ B$
4210 LPRINT N$;TAB 22;S$;TAB 45;T$;TAB 65;B$;TAB 77;A$
4215 IF INKEY$="0" THEN STOP
4220 NEXT I
8000 REM --NAMES--
8001 DATA "John & Jane Doe"
8002 DATA "ZZZZZZZZZZZZZZZZZZZZ"
8250 REM --STREET--
8251 DATA "2101 Run Down St."
8252 DATA "XXXX SSSSSSSSSSSSSSS"
8500 REM "CITY"
8501 DATA "Shanty Town, NY. 11111"
8502 DATA "CITY,ST. ZIP"
8750 REM "TELE"
8751 DATA "(000) 555-4444 Bus.(111) 555-2222"
8752 DATA "(AC.)XXX-XXXX"
9000 REM --PARENTS OF:--
9001 DATA "Brat"
9002 DATA "XXXX & YYYYY ZZZZZZ"
9250 REM --BIRTHDAY--
9251 DATA "926.49 530.56 531.82"
9252 DATA "MMDD.YYYY"
9500 REM --ACTIVITIES--
9501 DATA "Anniv 621.80"
9502 DATA "WHATEVER"
9999 STOP
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
