--- title: "Database" id: 60855 type: "computer_media" slug: "database" url: "http://localhost/computer_media/database/" markdown_url: "http://localhost/computer_media/database.md" published_at: "2025-10-06T12:24:21+00:00" modified_at: "2026-03-30T21:41:38+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2025/10/database-ben-jackson.png" excerpt: "A full seven-field contact database for a church department, driven by machine-code modules that patch RESTORE addresses on the fly to navigate records stored in DATA statements." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Ben H. Jackson" slug: "ben-h-jackson" taxonomy: "indiv" url: "http://localhost/indiv/ben-h-jackson/" genre: - name: "Database" slug: "database" taxonomy: "genre" url: "http://localhost/type/database/" media_contents: - id: 60550 title: "Fort Worth TS2068 Club Library Tape" type: "computer_media" url: "http://localhost/computer_media/fort-worth-ts2068-club-library-tape/" media_type: "Program" programmers: - name: "Ben H. Jackson" slug: "ben-h-jackson" taxonomy: "indiv" url: "http://localhost/indiv/ben-h-jackson/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Database%20%281985%29%28Jackson%2C%20Ben%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "1985" images: - url: "http://localhost/wp-content/uploads/2025/10/database-ben-jackson.png" media_type_tags: "Database" --- # Database 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: 1. **Lines 1–9:** Initialisation, error-code documentation, memory map, and variable glossary in REMs. 2. **Lines 10–26:** Entry point and the “string filter” subroutine (squishes/normalises input for comparison). 3. **Lines 900–988:** Low-level subroutines — add-data, BOOK fill (POKEs DATA addresses into machine code), and STMT fill. 4. **Lines 949–971:** DATA statements listing the start line numbers for each of the seven field blocks. 5. **Lines 1000–1028:** Main menu dispatcher. 6. **Lines 1050–1295:** Add file and delete file routines. 7. **Lines 2000–2150:** Search and save routines. 8. **Lines 3000–3035:** Modify/data-entry routine. 9. **Lines 4000–4220:** Printout routine (alphabetical and by class). 10. **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,BEGONE` at lines 909 and 1264 uses the TS2068 `DELETE` command 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 guard `CODE (Z$)>47 AND CODE (Z$)<58` at 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 USR` is used (instead of plain `USR`) 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. ## 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 ```