Database

Developer(s): Ben H. Jackson
Date: 1985
Type: Program
Platform(s): TS 2068

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:

ModuleAddress RangePurpose
findv54000–54599Variable/array locator; also contains esc (54532–54562) for escape handling
bubl54600–54840Bubble-sort (referenced in memory map, called implicitly)
create54850–56021Record creation, deletion, file-count management
PR CODE64246–64939Printer 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:

FieldBase Line
Names8000
Street8250
City8500
Telephone8750
Children9000
Birthdays9250
Activities9500

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.

Content

Appears On

This tape is a compilation of programs from user group members (Robert Burton, David Baulch, Frank Bouldin, Chuck Dawson, Ryan

Related Products

Related Articles

Related Content

Image Gallery

Database

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.

Scroll to Top