Mini Data Base

This file is part of and Timex Sinclair Public Domain Library Tape 1006. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 1000
Tags: Database

This program implements a flat-file mini database for the ZX81/TS1000 that stores all records in a single string variable A$, using CHR$ 111 (“o”) as a record separator and CHR$ 67–70 as field delimiters within each record. It supports five operations: data entry (up to four fields per record), deletion, editing, keyword search, and saving the data string to cassette tape. The menu dispatches to subroutines using the idiom GOTO VAL Y$*1000, where the user’s key press (codes 29–34 representing digits 1–5 in ZX81 character set) selects the 1000-level line block. The search routine includes a COPY command triggered by pressing “Z” to produce a printer hard copy of found records.


Program Analysis

Program Structure

The program is organised into discrete 1000-line blocks, each corresponding to a menu option. The main menu occupies lines 100–260, and execution branches via GOTO VAL Y$*1000 at line 260, dispatching to one of five routines:

  1. Lines 1000–1430: Data entry
  2. Lines 2000–2320: Delete a data block
  3. Lines 3000–3720: Edit a data block
  4. Lines 4000–4799: Keyword search
  5. Lines 5000–5080: Save data to cassette

Lines 5060–5080 (CLEAR, SAVE "1025", RUN) appear after the SAVE routine’s GOTO 100 and are therefore unreachable during normal execution. They likely represent a vestigial attempt at saving the program itself.

Data Storage Model

All database records are stored in the single string variable A$, initialised at line 10 to CHR$ 111 (the letter “o”). Each record consists of four fields separated by specific delimiter characters:

CHR$ codeCharacterRole
111oRecord separator (start/end of record)
67CEnd of Subject field
68DEnd of Item 1 field
69EEnd of Item 2 field
70FEnd of Item 3 / Last Item field

This scheme is fragile: any user input containing the letters C, D, E, F, or lowercase “o” will corrupt the delimiter structure. This is a significant bug — the program does not sanitise or validate field input against these reserved characters.

Menu Dispatch Idiom

Line 230 gates valid input by checking CODE Y$<29 OR CODE Y$>34. On the ZX81, character codes 29–33 correspond to the digit characters 1–5. Line 260 uses GOTO VAL Y$*1000 to jump directly to the appropriate 1000-block, a compact and efficient dispatch mechanism that avoids a chain of IF statements.

Search and Navigation

The keyword search at line 4000 scans A$ with a FOR/NEXT loop comparing substrings of length LEN C$. When a match is found, the code walks backwards from position N to locate the preceding CHR$ 111 record boundary (variable A), then forwards to find the closing boundary (variable B), isolating the record into D$. The subroutine at line 4800 prints up to the next delimiter and then trims D$ in place using LET D$=D$(N TO LEN D$).

There is a bug at line 4360: the search for the second field delimiter uses CODE D$(N)=63 (character “?”) rather than the expected 68 (“D”). This means Item 1 will never be correctly located or printed during a search display.

Delete and Edit Logic

Deletion (line 2310) reconstructs A$ by concatenating the portion before the found record with the portion after it: LET A$=A$( TO A)+A$(B+1 TO LEN A$). This correctly excises the block including its trailing CHR$ 111 separator.

The edit routine at line 3710 uses a similar splice: LET A$=A$( TO A)+F$+A$(B TO LEN A$). Note that unlike the delete case, it preserves the trailing boundary by including A$(B TO ...) rather than A$(B+1 TO ...), which is correct since the rebuilt F$ does not include the closing CHR$ 111.

The edit flow contains dead code: after locating the record into D$ at line 3170, execution jumps to 3800 for confirmation, but a “not found” retry at line 3850 sends control to 3070 (the NEXT of the search loop), which may iterate incorrectly after the loop variable is exhausted. Line 3175 (GOTO 3800) causes lines 3180 onwards to be unreachable on the first pass; they are only reached from line 3840 (IF INKEY$="Y" THEN GOTO 3180), which is the intended confirmation path.

FAST/SLOW Usage

The program switches between FAST and SLOW modes frequently. SLOW is invoked before INPUT statements to enable the display (required for the user to see what they are typing on a ZX81), and FAST is restored for processing and printing loops. This is standard ZX81 practice to balance display visibility with execution speed.

Notable Techniques

  • The prompt at line 210 is printed twice: first as normal video text, then overprinted in inverse video using the % escape sequences, producing a highlighted instruction without needing separate PRINT AT coordinates.
  • PAUSE 40000 (lines 2290, 3830, 4705) is used as an indefinite wait for a keypress, exploiting the fact that on a ZX81 PAUSE 40000 is effectively infinite until interrupted.
  • The cassette SAVE at line 5040 saves only the A$ variable (the entire database), not the program itself, allowing the data to be reloaded independently.

Content

Appears On

Assembled by Tim Ward from many sources. Contains programs 10252 – 10293.

Related Products

Related Articles

Related Content

Image Gallery

Mini Data Base

Source Code

   5 REM "DBAS%E"
  10 LET A$=CHR$ 111
 100 FAST 
 110 CLS 
 120 PRINT AT 1,10;"MINI DATA BASE"
 130 PRINT AT 4,0;"TO ENTER DATA";TAB 30;1
 140 PRINT AT 6,0;"TO DELETE DATA";TAB 30;2
 150 PRINT AT 8,0;"TO EDIT DATA";TAB 30;3
 160 PRINT AT 10,0;"TO SEARCH FOR DATA";TAB 30;4
 170 PRINT AT  12,0;"TO SAVE DATA ON TAPE";TAB 30;5
 200 SLOW 
 210 PRINT AT 21,6;" ENTER ONE OF ABOVE";AT 21,6;"% %E%N%T%E%R% %O%N%E% %O%F% %A%B%O%V%E% "
 220 LET Y$=INKEY$
 230 IF CODE Y$<29 OR CODE Y$>34 THEN GOTO 210
 240 FAST 
 250 CLS 
 260 GOTO VAL Y$*1000
\n1000 REM %D%A%T%A% %E%N%T%R%Y
\n1010 CLS 
\n1020 PRINT 
\n1030 PRINT "SUBJECT?"
\n1035 SLOW 
\n1040 INPUT B$
\n1045 PRINT ,,B$
\n1050 IF B$="" THEN GOTO 100
\n1060 LET A$=A$+B$+CHR$ 67
\n1070 PRINT ,,"ITEM NO. 1?"
\n1080 INPUT B$
\n1085 PRINT ,,B$
\n1090 LET A$=A$+B$+CHR$ 68
\n1100 PRINT ,,"ITEM NO. 2?"
\n1110 INPUT B$
\n1115 PRINT ,,B$
\n1120 LET A$=A$+B$+CHR$ 69
\n1130 PRINT ,,"ITEM NO. 3?"
\n1140 INPUT B$
\n1145 PRINT ,,B$
\n1150 LET A$=A$+B$+CHR$ 70
\n1400 PRINT ,,"LAST ITEM?"
\n1410 INPUT B$
\n1415 PRINT ,,B$
\n1416 PAUSE 100
\n1420 LET A$=A$+B$+CHR$ 111
\n1430 GOTO 1000
\n2000 REM %D%E%L%E%T%E% %D%A%T%A% %B%L%O%C%K
\n2010 PRINT AT 10,0;"ENTER KEYWORD OF DATA TO BE     DELETED :::"
\n2020 SLOW 
\n2030 INPUT C$
\n2040 FAST 
\n2050 FOR N=1 TO LEN A$-LEN C$+1
\n2060 IF A$(N TO N+LEN C$-1)=C$ THEN GOTO 2200
\n2070 NEXT N
\n2080 CLS 
\n2090 PRINT AT 10,0;"DATA NOT IN FILE :::"
\n2100 PAUSE 500
\n2120 GOTO 100
\n2200 FOR A=N TO 1 STEP -1
\n2210 IF CODE A$(A)=111 THEN GOTO 2230
\n2220 NEXT A
\n2230 FOR B=N TO LEN A$
\n2240 IF CODE A$(B)=111 THEN GOTO 2260
\n2250 NEXT B
\n2260 CLS 
\n2270 PRINT ,,A$(A+1 TO B-1)
\n2280 PRINT ,,"IS THIS THE DATA BLOCK YOU WANT DELETED?"
\n2290 PAUSE 40000
\n2300 IF INKEY$="N" THEN GOTO 2070
\n2310 LET A$=A$(  TO A)+A$(B+1 TO LEN A$)
\n2320 GOTO 100
\n3000 REM %E%D%I%T% %D%A%T%A\: 
\n3010 PRINT ,,"ENTER KEYWORD?"
\n3020 SLOW 
\n3030 INPUT C$
\n3040 FAST 
\n3050 FOR N=1 TO LEN A$-LEN C$+1
\n3060 IF A$(N TO N+LEN C$-1)=C$ THEN GOTO 3100
\n3070 NEXT N
\n3080 GOTO 2080
\n3100 FOR A=N TO 1 STEP -1
\n3120 IF CODE A$(A)=111 THEN GOTO 3140
\n3130 NEXT A
\n3140 FOR B=N TO LEN A$
\n3150 IF CODE A$(B)=111 THEN GOTO 3170
\n3160 NEXT B
\n3170 LET D$=A$(A+1 TO B-1)
\n3175 GOTO 3800
\n3180 FOR I=1 TO LEN D$
\n3190 IF CODE D$(I)=67 THEN GOTO 3210
\n3200 NEXT I
\n3210 CLS 
\n3220 PRINT ,,"SUBJECT IS ";D$( TO I-1)
\n3230 PRINT ,,"ENTER NEW SUBJECT OR PRESS ENTERFOR NO CHANGE?"
\n3240 SLOW 
\n3250 INPUT E$
\n3260 IF E$="" THEN LET E$=D$( TO I-1)
\n3265 LET D$=E$+D$(I TO LEN D$)
\n3270 FAST 
\n3275 LET F$=E$+CHR$ 67
\n3280 CLS 
\n3290 LET C=I+1
\n3300 FOR I=C TO LEN D$
\n3310 IF CODE D$(I)=68 THEN GOTO 3330
\n3320 NEXT I
\n3330 PRINT ,,"ITEM 1 IS ";D$(C TO I-1)
\n3340 PRINT ,,"ENTER NEW ITEM OR PRESS ENTER   FOR NO CHANGE?"
\n3350 SLOW 
\n3360 INPUT E$
\n3370 IF E$="" THEN LET E$=D$(C TO I-1)
\n3380 LET F$=F$+E$+CHR$ 68
\n3390 FAST 
\n3400 CLS 
\n3410 LET C=I+1
\n3420 FOR I=C TO LEN D$
\n3430 IF CODE D$(I)=69 THEN GOTO 3450
\n3440 NEXT I
\n3450 PRINT ,,"ITEM 2 IS ";D$(C TO I-1)
\n3460 PRINT ,,"ENTER NEW ITEM OR PRESS ENTER   FOR NO CHANGE?"
\n3465 SLOW 
\n3470 INPUT E$
\n3480 IF E$="" THEN LET E$=D$(C TO I-1)
\n3490 LET F$=F$+E$+CHR$ 69
\n3500 FAST 
\n3510 CLS 
\n3520 LET C=I+1
\n3530 FOR I=C TO LEN D$
\n3540 IF CODE D$(I)=70 THEN GOTO 3560
\n3550 NEXT I
\n3560 PRINT ,,"ITEM 3 IS ";D$(C TO I-1)
\n3575 SLOW 
\n3580 INPUT E$
\n3590 IF E$="" THEN LET E$=D$(C TO I-1)
\n3600 LET F$=F$+E$+CHR$ 70
\n3610 FAST 
\n3620 CLS 
\n3630 LET C=I+1
\n3640 PRINT ,,"LAST ITEM IS ";D$(C TO LEN D$)
\n3650 PRINT ,,"ENTER NEW ITEM OR PRESS ENTER   FOR NO CHANGE?"
\n3655 SLOW 
\n3660 INPUT E$
\n3670 IF E$="" THEN LET E$=D$(C TO LEN D$)
\n3680 LET F$=F$+E$
\n3690 FAST 
\n3700 CLS 
\n3710 LET A$=A$( TO A)+F$+A$(B TO LEN A$)
\n3720 GOTO 100
\n3800 CLS 
\n3810 PRINT ,,D$
\n3820 PRINT ,,,,"IS THIS THE CORRECT DATA BLOCK?"
\n3830 PAUSE 40000
\n3840 IF INKEY$="Y" THEN GOTO 3180
\n3850 GOTO 3070
\n4000 REM %K%E%Y%W%O%R%D% %S%E%A%R%C%H% 
\n4010 CLS 
\n4020 PRINT AT 10,0;"ENTER KEYWORD OR PHRASE?"
\n4030 SLOW 
\n4040 INPUT C$
\n4050 FAST 
\n4060 CLS 
\n4070 FOR N=1 TO LEN A$-LEN C$+1
\n4080 IF A$(N TO N+LEN C$-1)=C$ THEN GOTO 4200
\n4090 NEXT N
\n4100 PRINT AT 10,0;"NOT IN FILE :::"
\n4120 PAUSE 500
\n4130 GOTO 100
\n4200 LET NN=N
\n4205 FOR A=N TO 1 STEP -1
\n4210 IF A$(A)=CHR$ 111 THEN GOTO 4230
\n4220 NEXT A
\n4230 FOR B=N TO LEN A$
\n4240 IF A$(B)=CHR$ 111 THEN GOTO 4300
\n4250 NEXT B
\n4300 LET D$=A$(A TO B)
\n4310 FOR N=1 TO LEN D$
\n4320 IF CODE D$(N)=67 THEN GOTO 4340
\n4330 NEXT N
\n4340 GOSUB 4800
\n4350 FOR N=1 TO LEN D$
\n4360 IF CODE D$(N)=63 THEN GOTO 4380
\n4370 NEXT N
\n4380 GOSUB 4800
\n4390 FOR N=1 TO LEN D$
\n4400 IF CODE D$(N)=69 THEN GOTO 4420
\n4410 NEXT N
\n4420 GOSUB 4800
\n4430 FOR N=1 TO LEN D$
\n4440 IF CODE D$(N)=70 THEN GOTO 4460
\n4450 NEXT N
\n4460 GOSUB 4800
\n4700 PRINT D$(2 TO LEN D$)
\n4705 PAUSE 40000
\n4710 IF INKEY$="Z" THEN COPY 
\n4720 CLS 
\n4730 FOR N=NN+1 TO LEN A$-LEN C$+1
\n4740 GOTO 100
\n4799 STOP 
\n4800 PRINT D$(2 TO N-1)
\n4810 PRINT 
\n4820 LET D$=D$(N TO LEN D$)
\n4830 RETURN 
\n5000 REM % %S%A%V%E% %D%A%T%A% %O%N% %C%A%S%S%E%T%T%E% 
\n5010 PRINT ,,"ENTER FILE NAME, PREPARE","RECORDER AND PRESS ENTER:::"
\n5020 SLOW 
\n5030 INPUT Z$
\n5040 SAVE Z$
\n5050 GOTO 100
\n5060 CLEAR 
\n5070 SAVE "1025%3"
\n5080 RUN 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top