Record Formatter Ver. 1 is a ZX81/TS1000 database management program that allows users to define up to 64 custom fields, then enter, display, edit, and print records stored in a 1,459-character string array. Tape I/O is handled by two machine-code routines embedded in the line-10 REM statement: one at USR 16514 writes records to tape and one at USR 16549 reads them back, called via RAND USR. The program uses a packed record layout where each field’s start and end positions are tracked in parallel numeric arrays A() and B(), allowing substring slicing of the master string A$(1). A directory-printing routine compresses data by stripping redundant spaces before sending output to the printer via LPRINT.
Program Analysis
Program Structure
The program is organized into clearly labeled sections using inverse-text REM statements as headers. Execution begins at line 10 (which contains machine code) and proceeds through initialization before entering the main menu loop.
- Lines 10–20: Machine code in REM; program identity label
- Lines 30–80: Array and variable initialization
- Lines 100–180: Field definition loop (up to 64 fields)
- Lines 190–300: Print record layout to printer
- Lines 310–550: Main menu and dispatch
- Lines 560–760: Enter new record subroutine
- Lines 770–1140: Change a record subroutine
- Lines 1150–1460: Display a record subroutine
- Lines 1470–1680: Print a record subroutine
- Lines 1690–2010: Print data tape directory subroutine
- Lines 2020–2110: Copy data tape subroutine
- Lines 2120–2200: Copy program subroutine
- Lines 2210–2270: End program subroutine
- Lines 2280–2400: Read record from tape subroutine
- Lines 2410–2540: Write record to tape subroutine
- Lines 2550–2590: Input checker subroutine (Y/N/M)
- Lines 2600–2610: SAVE and restart
Machine Code Routines
Two machine-code routines are embedded in the REM statement at line 10. They are invoked via RAND USR 16514 (write record) and RAND USR 16549 (read record). The ZX81 system variables place the start of the BASIC program at address 16509 (407Fh); the REM data begins at offset 5 (after the line number, length, and REM token), so the routines land at 16514 and 16549 respectively.
Disassembly of the REM bytes reveals two distinct routines:
| Offset | Address | Bytes | Mnemonic | Notes |
|---|---|---|---|---|
| 0 | 16514 | CD E7 02 | CALL 02E7h | ZX81 ROM: slow-speed display/sync entry |
| 3 | 16517 | 06 0E | LD B,0Eh | Loop counter = 14 |
| 5 | 16519 | 21 00 FF | LD HL,FF00h | Start of candidate address range |
| 8 | 16522 | 2B | DEC HL | Step HL down |
| 9 | 16523 | 7C | LD A,H | |
| 10 | 16524 | B5 | OR L | Check HL=0 |
| 11 | 16525 | 20 FB | JR NZ,-5 | Loop until zero |
| 13 | 16527 | 10 F6 | DJNZ -10 | Outer timing loop |
| 15 | 16529 | 2A 10 40 | LD HL,(4010h) | Load A$ descriptor pointer |
| 18 | 16532 | 23 | INC HL | |
| 19 | 16533 | 4E | LD C,(HL) | Low byte of length |
| 20 | 16534 | 23 | INC HL | |
| 21 | 16535 | 46 | LD B,(HL) | High byte of length |
| 22 | 16536 | 23 | INC HL | |
| 23 | 16537 | C5 | PUSH BC | Save byte count |
| 24 | 16538 | 5E | LD E,(HL) | Data address low |
| 25 | 16539 | CD 1F 03 | CALL 031Fh | ROM: output byte to tape |
| 28 | 16542 | C1 | POP BC | |
| 29 | 16543 | 0B | DEC BC | |
| 30 | 16544 | 78 | LD A,B | |
| 31 | 16545 | B1 | OR C | Check BC=0 |
| 32 | 16546 | 20 F4 | JR NZ,-12 | Write loop |
| 34 | 16548 | C9 | RET | End of write routine |
| 35 | 16549 | CD E7 02 | CALL 02E7h | Read routine starts here |
| 38 | 16552 | 2A 10 40 | LD HL,(4010h) | Load A$ descriptor |
| … | … | 1E 08 DB FE D3 FF… | (tape read loop) | Reads bytes from EAR port, reconstructs A$ |
The read routine polls the EAR port (DB FE = IN A,(FEh)) and outputs to FFh (D3 FF = OUT (FFh),A), using rotate and bit-test instructions to decode the Manchester-like tape signal. The length of data transferred is derived from the A$ array descriptor at address 4010h, so the routines always read/write exactly 1,459 bytes — the full record.
Data Layout
The master record is held in A$(1), a single 1,459-character string (the first and only row of the 1×1459 DIM). Field positions are pre-computed during setup:
A(X)— start position of field X within A$(1)B(X)— end position of field X within A$(1)C(X)— declared length of field XB$(X)— 32-character field title (DIM B$(64,32))
Field data is read and written using ZX81 substring slicing: A$(1,A(X) TO B(X)). A temporary single-row string C$(1,C(X)) is re-DIMmed for each field during entry and editing to enforce the correct field width.
Menu and Navigation
The main menu at line 310 uses a single-keypress idiom: INKEY$ is tested in a tight loop at line 450, then captured at line 460 and dispatched via a cascade of IF … THEN GOSUB / GOTO statements. The reusable input checker subroutine at line 2550 accepts only Y, N, or M (Menu return), providing consistent three-way navigation throughout.
Key BASIC Idioms
- RAND USR — used to call machine-code routines without storing a return value, discarding the USR result safely.
- Re-DIM inside loop —
DIM C$(1,C(X))at lines 630 and 1010 re-allocates C$ each iteration to match the current field’s length, ensuring INPUT fills exactly the right number of characters. - VAL-style line targets — line numbers in
GOTO/GOSUBare written with leading zeros (e.g.,GOTO 0450,GOSUB 0560), a common ZX81 style that has no runtime effect but aids readability. - FAST/SLOW bracketing — printer output blocks (lines 190–300 and 1610–1670) are wrapped in
FAST/SLOWto disable the display interrupt and speed up LPRINT operations.
Directory Space-Compression Routine
The tape directory printer (lines 1930–1970) implements a simple run-length space compressor: it builds D$ by copying non-space characters from C$(1) and inserting a single space only when the next character is a space, collapsing multiple spaces into one. This produces compact, human-readable directory entries from fixed-width fields.
Notable Bugs and Anomalies
- Line 1000 unreachable check —
IF I$="N" AND X=65 THEN GOTO 1130followsIF I$="N" THEN NEXT Xat line 990. IfI$="N", control jumps to NEXT X and never reaches line 1000; the X=65 boundary check is therefore dead code. The loop termination after all 64 fields are processed falls through to line 1130 naturally via the FOR/NEXT mechanism. - Field count vs. tape block size — The program defines up to 64 fields but the directory loop at line 1880 is hard-coded to
FOR X=1 TO 35, implying the data tape is expected to hold exactly 35 records. There is no run-time check that the total declared field lengths do not exceed 1,459. - Line 1430 double-read of INKEY$ — After the wait loop at line 1420 confirms a key is pressed, line 1430 calls
INKEY$again. On a fast machine this could return an empty string if the key was released between the two polls, potentially failing to detect the M keypress. - Line 2610 —
GOTO 300targets line 300 (SLOW), not the menu at line 310, meaning after a SAVE the machine briefly executes SLOW before falling into the menu — harmless but slightly inconsistent with the directGOTO 0310used elsewhere.
Content
Source Code
10 REM \CD\E7
Skip to content
Record Formatter
This file is part of Timex Sinclair Public Domain Library Tape 1003
. Download the collection to get this file.
Record Formatter Ver. 1 is a ZX81/TS1000 database management program that allows users to define up to 64 custom fields, then enter, display, edit, and print records stored in a 1,459-character string array. Tape I/O is handled by two machine-code routines embedded in the line-10 REM statement: one at USR 16514 writes records to tape and one at USR 16549 reads them back, called via RAND USR. The program uses a packed record layout where each field’s start and end positions are tracked in parallel numeric arrays A() and B(), allowing substring slicing of the master string A$(1). A directory-printing routine compresses data by stripping redundant spaces before sending output to the printer via LPRINT.
Program Analysis
Program Structure
The program is organized into clearly labeled sections using inverse-text REM statements as headers. Execution begins at line 10 (which contains machine code) and proceeds through initialization before entering the main menu loop.
- Lines 10–20: Machine code in REM; program identity label
- Lines 30–80: Array and variable initialization
- Lines 100–180: Field definition loop (up to 64 fields)
- Lines 190–300: Print record layout to printer
- Lines 310–550: Main menu and dispatch
- Lines 560–760: Enter new record subroutine
- Lines 770–1140: Change a record subroutine
- Lines 1150–1460: Display a record subroutine
- Lines 1470–1680: Print a record subroutine
- Lines 1690–2010: Print data tape directory subroutine
- Lines 2020–2110: Copy data tape subroutine
- Lines 2120–2200: Copy program subroutine
- Lines 2210–2270: End program subroutine
- Lines 2280–2400: Read record from tape subroutine
- Lines 2410–2540: Write record to tape subroutine
- Lines 2550–2590: Input checker subroutine (Y/N/M)
- Lines 2600–2610: SAVE and restart
Machine Code Routines
Two machine-code routines are embedded in the REM statement at line 10. They are invoked via RAND USR 16514 (write record) and RAND USR 16549 (read record). The ZX81 system variables place the start of the BASIC program at address 16509 (407Fh); the REM data begins at offset 5 (after the line number, length, and REM token), so the routines land at 16514 and 16549 respectively.
Disassembly of the REM bytes reveals two distinct routines:
Offset Address Bytes Mnemonic Notes 0 16514 CD E7 02 CALL 02E7h ZX81 ROM: slow-speed display/sync entry 3 16517 06 0E LD B,0Eh Loop counter = 14 5 16519 21 00 FF LD HL,FF00h Start of candidate address range 8 16522 2B DEC HL Step HL down 9 16523 7C LD A,H 10 16524 B5 OR L Check HL=0 11 16525 20 FB JR NZ,-5 Loop until zero 13 16527 10 F6 DJNZ -10 Outer timing loop 15 16529 2A 10 40 LD HL,(4010h) Load A$ descriptor pointer 18 16532 23 INC HL 19 16533 4E LD C,(HL) Low byte of length 20 16534 23 INC HL 21 16535 46 LD B,(HL) High byte of length 22 16536 23 INC HL 23 16537 C5 PUSH BC Save byte count 24 16538 5E LD E,(HL) Data address low 25 16539 CD 1F 03 CALL 031Fh ROM: output byte to tape 28 16542 C1 POP BC 29 16543 0B DEC BC 30 16544 78 LD A,B 31 16545 B1 OR C Check BC=0 32 16546 20 F4 JR NZ,-12 Write loop 34 16548 C9 RET End of write routine 35 16549 CD E7 02 CALL 02E7h Read routine starts here 38 16552 2A 10 40 LD HL,(4010h) Load A$ descriptor … … 1E 08 DB FE D3 FF… (tape read loop) Reads bytes from EAR port, reconstructs A$
The read routine polls the EAR port (DB FE = IN A,(FEh)) and outputs to FFh (D3 FF = OUT (FFh),A), using rotate and bit-test instructions to decode the Manchester-like tape signal. The length of data transferred is derived from the A$ array descriptor at address 4010h, so the routines always read/write exactly 1,459 bytes — the full record.
Data Layout
The master record is held in A$(1), a single 1,459-character string (the first and only row of the 1×1459 DIM). Field positions are pre-computed during setup:
A(X) — start position of field X within A$(1)
B(X) — end position of field X within A$(1)
C(X) — declared length of field X
B$(X) — 32-character field title (DIM B$(64,32))
Field data is read and written using ZX81 substring slicing: A$(1,A(X) TO B(X)). A temporary single-row string C$(1,C(X)) is re-DIMmed for each field during entry and editing to enforce the correct field width.
Menu and Navigation
The main menu at line 310 uses a single-keypress idiom: INKEY$ is tested in a tight loop at line 450, then captured at line 460 and dispatched via a cascade of IF … THEN GOSUB / GOTO statements. The reusable input checker subroutine at line 2550 accepts only Y, N, or M (Menu return), providing consistent three-way navigation throughout.
Key BASIC Idioms
- RAND USR — used to call machine-code routines without storing a return value, discarding the USR result safely.
- Re-DIM inside loop —
DIM C$(1,C(X)) at lines 630 and 1010 re-allocates C$ each iteration to match the current field’s length, ensuring INPUT fills exactly the right number of characters.
- VAL-style line targets — line numbers in
GOTO/GOSUB are written with leading zeros (e.g., GOTO 0450, GOSUB 0560), a common ZX81 style that has no runtime effect but aids readability.
- FAST/SLOW bracketing — printer output blocks (lines 190–300 and 1610–1670) are wrapped in
FAST/SLOW to disable the display interrupt and speed up LPRINT operations.
Directory Space-Compression Routine
The tape directory printer (lines 1930–1970) implements a simple run-length space compressor: it builds D$ by copying non-space characters from C$(1) and inserting a single space only when the next character is a space, collapsing multiple spaces into one. This produces compact, human-readable directory entries from fixed-width fields.
Notable Bugs and Anomalies
- Line 1000 unreachable check —
IF I$="N" AND X=65 THEN GOTO 1130 follows IF I$="N" THEN NEXT X at line 990. If I$="N", control jumps to NEXT X and never reaches line 1000; the X=65 boundary check is therefore dead code. The loop termination after all 64 fields are processed falls through to line 1130 naturally via the FOR/NEXT mechanism.
- Field count vs. tape block size — The program defines up to 64 fields but the directory loop at line 1880 is hard-coded to
FOR X=1 TO 35, implying the data tape is expected to hold exactly 35 records. There is no run-time check that the total declared field lengths do not exceed 1,459.
- Line 1430 double-read of INKEY$ — After the wait loop at line 1420 confirms a key is pressed, line 1430 calls
INKEY$ again. On a fast machine this could return an empty string if the key was released between the two polls, potentially failing to detect the M keypress.
- Line 2610 —
GOTO 300 targets line 300 (SLOW), not the menu at line 310, meaning after a SAVE the machine briefly executes SLOW before falling into the menu — harmless but slightly inconsistent with the direct GOTO 0310 used elsewhere.
Content
Source Code
10 REM \CD\E7\02\06\0E\21\00\FF\2B\7C\B5\20\FB\10\F6\2A\10\40\23\4E\23\46\23\C5\5E\CD\1F\03\C1\0B\78\B1\20\F4\C9\CD\E7\02\2A\10\40\23\4E\23\46\23\C5\1E\08\DB\FE\D3\FF\17\30\F9\0E\94\06\1A\0D\DB\FE\17\CB\79\79\38\F5\10\F5\20\04\FE\56\30\E4\3F\CB\16\1D\20\DE\C1\0B\78\B1\C8\18\D3
20 REM %P%R%O%G%R%A%M% %S%E%T% %U%P% % % % % % % % %
30 DIM A$(1,1459)
40 DIM B$(64,32)
50 DIM A(64)
60 DIM B(64)
70 DIM C(64)
80 LET M=310
90 LET W=1
100 FOR X=1 TO 64
110 PRINT AT 12,0;"ENTER FIELD TITLE (32 POS)"
120 INPUT B$(X)
130 PRINT AT 12,0;"ENTER LENGTH OF FIELD "
140 INPUT C(X)
150 LET A(X)=W
160 LET B(X)=W+C(X)-1
170 LET W=W+C(X)
180 NEXT X
190 FAST
200 LPRINT "RECORD LAYOUT"
210 LPRINT
220 LPRINT "FIELD NAME"
230 LPRINT "ST POS END POS LENGTH FLD NBR."
240 LPRINT "--------------------------------"
250 FOR X=1 TO 64
260 LPRINT B$(X)
270 LPRINT A(X);TAB 8;B(X);TAB 17;C(X);TAB 25;X
280 LPRINT
290 NEXT X
300 SLOW
310 REM %M%E%N%U% % % % % % % % % % % % % % % % % % %
320 CLS
330 PRINT TAB 5;"RECORD FORMATTER VER.1"
340 PRINT TAB 3;"COPYRIGHT 1985 TIM L. WARD",,,
350 PRINT "DO YOU WISH TO..",,,
360 PRINT "1)...ENTER A NEW RECORD?",,,
370 PRINT "2)...CHANGE A RECORD?",,,
380 PRINT "3)...DISPLAY A RECORD?",,,
390 PRINT "4)...PRINT A RECORD?",,,
400 PRINT "5)...PRINT DATA TAPE DIRECTORY?",,,
410 PRINT "6)...COPY DATA TAPE?",,,
420 PRINT "7)...COPY PROGRAM?",,,
430 PRINT "8)...END PROGRAM?",,,
440 PRINT "ENTER NBR. OF SELECTION"
450 IF INKEY$="" THEN GOTO 0450
460 LET I$=INKEY$
470 IF I$="1" THEN GOSUB 0560
480 IF I$="2" THEN GOSUB 0770
490 IF I$="3" THEN GOSUB 1150
500 IF I$="4" THEN GOSUB 1470
510 IF I$="5" THEN GOSUB 1690
520 IF I$="6" THEN GOSUB 2020
530 IF I$="7" THEN GOTO 2120
540 IF I$="8" THEN GOSUB 2210
550 GOTO 0310
560 REM %E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D% % % % %
570 CLS
580 PRINT ,,,,,,"DO YOU WISH TO ADD A NEW RCD?"
590 PRINT TAB 11;"(Y, N, OR M)"
600 GOSUB 2550
610 IF I$<>"Y" THEN RETURN
620 FOR X=1 TO 64
630 DIM C$(1,C(X))
640 CLS
650 PRINT AT 0,6;"%E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D"
660 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
670 PRINT AT 4,0;B$(X)
680 INPUT C$(1)
690 PRINT AT 6,0;C$(1)
700 PRINT "IS THIS CORRECT? (Y OR N)"
710 GOSUB 2550
720 IF I$<>"Y" THEN GOTO 0640
730 LET A$(1,A(X) TO B(X))=C$(1)
740 NEXT X
750 GOSUB 2410
760 RETURN
770 REM %C%H%A%N%G%E% %A% %R%E%C%O%R%D% % % % % % % %
780 CLS
790 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
800 PRINT AT 2,0;"DO YOU WISH TO CHANGE THIS RCD?"
810 PRINT AT 4,11;"(Y, N, OR M)",,,
820 FOR X=1 TO 5
830 PRINT B$(X)
840 PRINT A$(1,A(X) TO B(X))
850 NEXT X
860 GOSUB 2550
870 IF I$="M" THEN RETURN
880 IF I$="Y" THEN GOTO 0920
890 GOSUB 2410
900 GOSUB 2280
910 GOTO 0770
920 FOR X=1 TO 64
930 CLS
940 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
950 PRINT AT 2,0;"CHANGE THIS FIELD? (Y OR N)"
960 PRINT AT 4,0;B$(X)
970 PRINT A$(1,A(X) TO B(X))
980 GOSUB 2550
990 IF I$="N" THEN NEXT X
1000 IF I$="N" AND X=65 THEN GOTO 1130
1010 DIM C$(1,C(X))
1020 CLS
1030 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
1040 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
1050 PRINT AT 4,0;B$(X)
1060 INPUT C$(1)
1070 PRINT AT 6,0;C$(1)
1080 PRINT "IS THIS CORRECT? (Y OR N)"
1090 GOSUB 2550
1100 IF I$<>"Y" THEN GOTO 1020
1110 LET A$(1,A(X) TO B(X))=C$(1)
1120 NEXT X
1130 GOSUB 2410
1140 RETURN
1150 REM %D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D% % % % % % %
1160 CLS
1170 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1180 PRINT AT 2,0;"DO YOU WISH TO DISPLAY THIS RCD?"
1190 PRINT AT 4,11;"(Y, N, OR M)"
1200 FOR X=1 TO 5
1210 PRINT B$(X)
1220 PRINT A$(1,A(X) TO B(X))
1230 NEXT X
1240 GOSUB 2550
1250 IF I$="M" THEN RETURN
1260 IF I$="Y" THEN GOTO 1290
1270 GOSUB 2280
1280 GOTO 1150
1290 CLS
1300 FOR X=1 TO 64
1310 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1320 PRINT AT 2,0;"RECORD DISPLAYED IS FOR..."
1330 PRINT AT 4,0;"GEN/CODE NBR. ";A$(1, TO 5)
1340 PRINT AT 5,0;A$(1,6 TO 20)
1350 PRINT AT 6,0;A$(1,21 TO 35)
1360 PRINT AT 7,0;A$(1,36 TO 50)
1370 PRINT AT 8,0;A$(1,51 TO 65)
1380 PRINT AT 15,0;"%P%R%E%S%S% %E%N%T%E%R% %F%O%R% %N%E%X%T% %F%I%E%L%D% % % % % % "
1390 PRINT AT 16,0;"%P%R%E%S%S% %"%M%"% %T%O% %R%E%T%U%R%N% %T%O% % %M%E%N%U% % % % "
1400 PRINT AT 10,0;B$(X)
1410 PRINT AT 12,0;A$(1,A(X) TO B(X))
1420 IF INKEY$="" THEN GOTO 1420
1430 IF INKEY$="M" THEN RETURN
1440 PRINT AT 12,0;" "
1450 NEXT X
1460 RETURN
1470 REM %P%R%I%N%T% %A% %R%E%C%O%R%D% % % % % % % % %
1480 CLS
1490 PRINT AT 0,8;"%P%R%I%N%T% %A% %R%E%C%O%R%D"
1500 PRINT AT 2,0;"DO YOU WISH TO PRINT THIS RCD?"
1510 PRINT AT 4,11;"(Y, N, OR M)",,,
1520 FOR X=1 TO 5
1530 PRINT B$(X)
1540 PRINT A$(1,A(X) TO B(X))
1550 NEXT X
1560 GOSUB 2550
1570 IF I$="Y" THEN GOTO 1610
1580 IF I$="M" THEN RETURN
1590 GOSUB 2280
1600 GOTO 1470
1610 FAST
1620 FOR X=1 TO 64
1630 LPRINT B$(X)
1640 LPRINT A$(1,A(X) TO B(X))
1650 LPRINT
1660 NEXT X
1670 SLOW
1680 RETURN
1690 REM %P%R%I%N%T% %D%/%T% %D%I%R%E%C%T%O%R%Y% % % %
1700 CLS
1710 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1720 PRINT AT 4,0;"IS THE PRINTER ON ? (Y, N, OR M)"
1730 GOSUB 2550
1740 IF I$="M" THEN RETURN
1750 IF I$="Y" THEN GOTO 1790
1760 PRINT AT 12,0;"PLEASE TURN THE PRINTER ON"
1770 PRINT AT 14,0;"PRESS ENTER WHEN PRINTER IS ON"
1780 INPUT I$
1790 CLS
1800 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1810 PRINT AT 4,0;"PLACE OLD DATA TAPE IN TAPE DECK"
1820 PRINT AT 6,0;"PRESS ""PLAY"" ON TAPE DECK"
1830 PRINT AT 8,0;"PRESS ""ENTER"" ON COMPUTER"
1840 INPUT I$
1850 LPRINT "% % % % % % % DATA TAPE DIRECTORY% % % % % % ",,
1860 LPRINT "GEN/"
1870 LPRINT "CODE FIRST/LAST NAME",,,
1880 FOR X=1 TO 35
1890 RAND USR 16549
1900 DIM C$(1,36)
1910 LET C$(1)=A$(1,1 TO 5)+" "+A$(1,6 TO 20)+A$(1,51 TO 65)
1920 LET D$=""
1930 FOR Y=1 TO 36
1940 IF C$(1,Y)=" " THEN GOTO 1970
1950 LET D$=D$+C$(1,Y)
1960 IF C$(1,Y+1)=" " THEN LET D$=D$+" "
1970 NEXT Y
1980 LPRINT D$
1990 LPRINT
2000 NEXT X
2010 RETURN
2020 REM %C%O%P%Y% %D%A%T%A% %T%A%P%E% % % % % % % % %
2030 CLS
2040 PRINT ,,,,,,"HOW MANY RECORDS DO YOU WISH TO",,,"COPY? (1 TO 35)"
2050 INPUT Z
2060 IF Z>35 THEN GOTO 2020
2070 FOR X=1 TO Z
2080 GOSUB 2280
2090 GOSUB 2410
2100 NEXT X
2110 RETURN
2120 REM %C%O%P%Y% %P%R%O%G%R%A%M% % % % % % % % % % %
2130 CLS
2140 PRINT ,,,,,,"PLACE BLANK PROGRAM TAPE IN TAPE",,"DECK, PRESS ""PLAY/RECORD"" ON",,,"TAPE DECK, PRESS ""ENTER"" ON",,,"COMPUTER."
2150 INPUT I$
2160 CLS
2170 SAVE "FORMATTE%R"
2180 PRINT ,,,,,,"PRESS ""STOP"" ON TAPE DECK",,,"PRESS ""ENTER"" ON COMPUTER."
2190 INPUT I$
2200 GOTO 0310
2210 REM %E%N%D% %P%R%O%G%R%A%M% % % % % % % % % % % %
2220 CLS
2230 PRINT ,,,,,,"ARE YOU SURE YOU WANT TO QUIT?"
2240 PRINT TAB 11;"(Y, N, OR M)"
2250 GOSUB 2550
2260 IF I$="Y" THEN NEW
2270 RETURN
2280 REM %R%E%A%D% %R%E%C%O%R%D% %O%N% %T%A%P%E% % % %
2290 CLS
2300 PRINT AT 2,0;"PLACE OLD DATA TAPE IN TAPE DECK"
2310 PRINT AT 4,0;"PRESS ""PLAY"" ON TAPE DECK"
2320 PRINT AT 6,0;"PRESS ""ENTER"" ON COMPUTER"
2330 INPUT Z$
2340 RAND USR 16549
2350 CLS
2360 SLOW
2370 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2380 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2390 INPUT Z$
2400 RETURN
2410 REM %W%R%I%T%E% %R%E%C%O%R%D% %O%N% %T%A%P%E% % %
2420 CLS
2430 PRINT AT 2,0;"PLACE NEW DATA TAPE IN TAPE DECK"
2440 PRINT AT 4,0;"PRESS ""PLAY/RECORD"" ON TAPE"
2450 PRINT "DECK"
2460 PRINT AT 7,0;"PRESS ""ENTER"" ON COMPUTER"
2470 INPUT Z$
2480 RAND USR 16514
2490 CLS
2500 SLOW
2510 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2520 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2530 INPUT Z$
2540 RETURN
2550 REM %I%N%P%U%T% %C%H%E%C%K%E%R% %(%Y% %O%R% %N%)%
2560 IF INKEY$="" THEN GOTO 2550
2570 LET I$=INKEY$
2580 IF I$<>"Y" AND I$<>"N" AND I$<>"M" THEN GOTO 2550
2590 RETURN
2600 SAVE "1016%0"
2610 GOTO 300
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
Skip to content
Record Formatter
This file is part of Timex Sinclair Public Domain Library Tape 1003
. Download the collection to get this file.
Record Formatter Ver. 1 is a ZX81/TS1000 database management program that allows users to define up to 64 custom fields, then enter, display, edit, and print records stored in a 1,459-character string array. Tape I/O is handled by two machine-code routines embedded in the line-10 REM statement: one at USR 16514 writes records to tape and one at USR 16549 reads them back, called via RAND USR. The program uses a packed record layout where each field’s start and end positions are tracked in parallel numeric arrays A() and B(), allowing substring slicing of the master string A$(1). A directory-printing routine compresses data by stripping redundant spaces before sending output to the printer via LPRINT.
Program Analysis
Program Structure
The program is organized into clearly labeled sections using inverse-text REM statements as headers. Execution begins at line 10 (which contains machine code) and proceeds through initialization before entering the main menu loop.
- Lines 10–20: Machine code in REM; program identity label
- Lines 30–80: Array and variable initialization
- Lines 100–180: Field definition loop (up to 64 fields)
- Lines 190–300: Print record layout to printer
- Lines 310–550: Main menu and dispatch
- Lines 560–760: Enter new record subroutine
- Lines 770–1140: Change a record subroutine
- Lines 1150–1460: Display a record subroutine
- Lines 1470–1680: Print a record subroutine
- Lines 1690–2010: Print data tape directory subroutine
- Lines 2020–2110: Copy data tape subroutine
- Lines 2120–2200: Copy program subroutine
- Lines 2210–2270: End program subroutine
- Lines 2280–2400: Read record from tape subroutine
- Lines 2410–2540: Write record to tape subroutine
- Lines 2550–2590: Input checker subroutine (Y/N/M)
- Lines 2600–2610: SAVE and restart
Machine Code Routines
Two machine-code routines are embedded in the REM statement at line 10. They are invoked via RAND USR 16514 (write record) and RAND USR 16549 (read record). The ZX81 system variables place the start of the BASIC program at address 16509 (407Fh); the REM data begins at offset 5 (after the line number, length, and REM token), so the routines land at 16514 and 16549 respectively.
Disassembly of the REM bytes reveals two distinct routines:
Offset Address Bytes Mnemonic Notes 0 16514 CD E7 02 CALL 02E7h ZX81 ROM: slow-speed display/sync entry 3 16517 06 0E LD B,0Eh Loop counter = 14 5 16519 21 00 FF LD HL,FF00h Start of candidate address range 8 16522 2B DEC HL Step HL down 9 16523 7C LD A,H 10 16524 B5 OR L Check HL=0 11 16525 20 FB JR NZ,-5 Loop until zero 13 16527 10 F6 DJNZ -10 Outer timing loop 15 16529 2A 10 40 LD HL,(4010h) Load A$ descriptor pointer 18 16532 23 INC HL 19 16533 4E LD C,(HL) Low byte of length 20 16534 23 INC HL 21 16535 46 LD B,(HL) High byte of length 22 16536 23 INC HL 23 16537 C5 PUSH BC Save byte count 24 16538 5E LD E,(HL) Data address low 25 16539 CD 1F 03 CALL 031Fh ROM: output byte to tape 28 16542 C1 POP BC 29 16543 0B DEC BC 30 16544 78 LD A,B 31 16545 B1 OR C Check BC=0 32 16546 20 F4 JR NZ,-12 Write loop 34 16548 C9 RET End of write routine 35 16549 CD E7 02 CALL 02E7h Read routine starts here 38 16552 2A 10 40 LD HL,(4010h) Load A$ descriptor … … 1E 08 DB FE D3 FF… (tape read loop) Reads bytes from EAR port, reconstructs A$
The read routine polls the EAR port (DB FE = IN A,(FEh)) and outputs to FFh (D3 FF = OUT (FFh),A), using rotate and bit-test instructions to decode the Manchester-like tape signal. The length of data transferred is derived from the A$ array descriptor at address 4010h, so the routines always read/write exactly 1,459 bytes — the full record.
Data Layout
The master record is held in A$(1), a single 1,459-character string (the first and only row of the 1×1459 DIM). Field positions are pre-computed during setup:
A(X) — start position of field X within A$(1)
B(X) — end position of field X within A$(1)
C(X) — declared length of field X
B$(X) — 32-character field title (DIM B$(64,32))
Field data is read and written using ZX81 substring slicing: A$(1,A(X) TO B(X)). A temporary single-row string C$(1,C(X)) is re-DIMmed for each field during entry and editing to enforce the correct field width.
Menu and Navigation
The main menu at line 310 uses a single-keypress idiom: INKEY$ is tested in a tight loop at line 450, then captured at line 460 and dispatched via a cascade of IF … THEN GOSUB / GOTO statements. The reusable input checker subroutine at line 2550 accepts only Y, N, or M (Menu return), providing consistent three-way navigation throughout.
Key BASIC Idioms
- RAND USR — used to call machine-code routines without storing a return value, discarding the USR result safely.
- Re-DIM inside loop —
DIM C$(1,C(X)) at lines 630 and 1010 re-allocates C$ each iteration to match the current field’s length, ensuring INPUT fills exactly the right number of characters.
- VAL-style line targets — line numbers in
GOTO/GOSUB are written with leading zeros (e.g., GOTO 0450, GOSUB 0560), a common ZX81 style that has no runtime effect but aids readability.
- FAST/SLOW bracketing — printer output blocks (lines 190–300 and 1610–1670) are wrapped in
FAST/SLOW to disable the display interrupt and speed up LPRINT operations.
Directory Space-Compression Routine
The tape directory printer (lines 1930–1970) implements a simple run-length space compressor: it builds D$ by copying non-space characters from C$(1) and inserting a single space only when the next character is a space, collapsing multiple spaces into one. This produces compact, human-readable directory entries from fixed-width fields.
Notable Bugs and Anomalies
- Line 1000 unreachable check —
IF I$="N" AND X=65 THEN GOTO 1130 follows IF I$="N" THEN NEXT X at line 990. If I$="N", control jumps to NEXT X and never reaches line 1000; the X=65 boundary check is therefore dead code. The loop termination after all 64 fields are processed falls through to line 1130 naturally via the FOR/NEXT mechanism.
- Field count vs. tape block size — The program defines up to 64 fields but the directory loop at line 1880 is hard-coded to
FOR X=1 TO 35, implying the data tape is expected to hold exactly 35 records. There is no run-time check that the total declared field lengths do not exceed 1,459.
- Line 1430 double-read of INKEY$ — After the wait loop at line 1420 confirms a key is pressed, line 1430 calls
INKEY$ again. On a fast machine this could return an empty string if the key was released between the two polls, potentially failing to detect the M keypress.
- Line 2610 —
GOTO 300 targets line 300 (SLOW), not the menu at line 310, meaning after a SAVE the machine briefly executes SLOW before falling into the menu — harmless but slightly inconsistent with the direct GOTO 0310 used elsewhere.
Content
Source Code
10 REM \CD\E7\02\06\0E\21\00\FF\2B\7C\B5\20\FB\10\F6\2A\10\40\23\4E\23\46\23\C5\5E\CD\1F\03\C1\0B\78\B1\20\F4\C9\CD\E7\02\2A\10\40\23\4E\23\46\23\C5\1E\08\DB\FE\D3\FF\17\30\F9\0E\94\06\1A\0D\DB\FE\17\CB\79\79\38\F5\10\F5\20\04\FE\56\30\E4\3F\CB\16\1D\20\DE\C1\0B\78\B1\C8\18\D3
20 REM %P%R%O%G%R%A%M% %S%E%T% %U%P% % % % % % % % %
30 DIM A$(1,1459)
40 DIM B$(64,32)
50 DIM A(64)
60 DIM B(64)
70 DIM C(64)
80 LET M=310
90 LET W=1
100 FOR X=1 TO 64
110 PRINT AT 12,0;"ENTER FIELD TITLE (32 POS)"
120 INPUT B$(X)
130 PRINT AT 12,0;"ENTER LENGTH OF FIELD "
140 INPUT C(X)
150 LET A(X)=W
160 LET B(X)=W+C(X)-1
170 LET W=W+C(X)
180 NEXT X
190 FAST
200 LPRINT "RECORD LAYOUT"
210 LPRINT
220 LPRINT "FIELD NAME"
230 LPRINT "ST POS END POS LENGTH FLD NBR."
240 LPRINT "--------------------------------"
250 FOR X=1 TO 64
260 LPRINT B$(X)
270 LPRINT A(X);TAB 8;B(X);TAB 17;C(X);TAB 25;X
280 LPRINT
290 NEXT X
300 SLOW
310 REM %M%E%N%U% % % % % % % % % % % % % % % % % % %
320 CLS
330 PRINT TAB 5;"RECORD FORMATTER VER.1"
340 PRINT TAB 3;"COPYRIGHT 1985 TIM L. WARD",,,
350 PRINT "DO YOU WISH TO..",,,
360 PRINT "1)...ENTER A NEW RECORD?",,,
370 PRINT "2)...CHANGE A RECORD?",,,
380 PRINT "3)...DISPLAY A RECORD?",,,
390 PRINT "4)...PRINT A RECORD?",,,
400 PRINT "5)...PRINT DATA TAPE DIRECTORY?",,,
410 PRINT "6)...COPY DATA TAPE?",,,
420 PRINT "7)...COPY PROGRAM?",,,
430 PRINT "8)...END PROGRAM?",,,
440 PRINT "ENTER NBR. OF SELECTION"
450 IF INKEY$="" THEN GOTO 0450
460 LET I$=INKEY$
470 IF I$="1" THEN GOSUB 0560
480 IF I$="2" THEN GOSUB 0770
490 IF I$="3" THEN GOSUB 1150
500 IF I$="4" THEN GOSUB 1470
510 IF I$="5" THEN GOSUB 1690
520 IF I$="6" THEN GOSUB 2020
530 IF I$="7" THEN GOTO 2120
540 IF I$="8" THEN GOSUB 2210
550 GOTO 0310
560 REM %E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D% % % % %
570 CLS
580 PRINT ,,,,,,"DO YOU WISH TO ADD A NEW RCD?"
590 PRINT TAB 11;"(Y, N, OR M)"
600 GOSUB 2550
610 IF I$<>"Y" THEN RETURN
620 FOR X=1 TO 64
630 DIM C$(1,C(X))
640 CLS
650 PRINT AT 0,6;"%E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D"
660 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
670 PRINT AT 4,0;B$(X)
680 INPUT C$(1)
690 PRINT AT 6,0;C$(1)
700 PRINT "IS THIS CORRECT? (Y OR N)"
710 GOSUB 2550
720 IF I$<>"Y" THEN GOTO 0640
730 LET A$(1,A(X) TO B(X))=C$(1)
740 NEXT X
750 GOSUB 2410
760 RETURN
770 REM %C%H%A%N%G%E% %A% %R%E%C%O%R%D% % % % % % % %
780 CLS
790 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
800 PRINT AT 2,0;"DO YOU WISH TO CHANGE THIS RCD?"
810 PRINT AT 4,11;"(Y, N, OR M)",,,
820 FOR X=1 TO 5
830 PRINT B$(X)
840 PRINT A$(1,A(X) TO B(X))
850 NEXT X
860 GOSUB 2550
870 IF I$="M" THEN RETURN
880 IF I$="Y" THEN GOTO 0920
890 GOSUB 2410
900 GOSUB 2280
910 GOTO 0770
920 FOR X=1 TO 64
930 CLS
940 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
950 PRINT AT 2,0;"CHANGE THIS FIELD? (Y OR N)"
960 PRINT AT 4,0;B$(X)
970 PRINT A$(1,A(X) TO B(X))
980 GOSUB 2550
990 IF I$="N" THEN NEXT X
1000 IF I$="N" AND X=65 THEN GOTO 1130
1010 DIM C$(1,C(X))
1020 CLS
1030 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
1040 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
1050 PRINT AT 4,0;B$(X)
1060 INPUT C$(1)
1070 PRINT AT 6,0;C$(1)
1080 PRINT "IS THIS CORRECT? (Y OR N)"
1090 GOSUB 2550
1100 IF I$<>"Y" THEN GOTO 1020
1110 LET A$(1,A(X) TO B(X))=C$(1)
1120 NEXT X
1130 GOSUB 2410
1140 RETURN
1150 REM %D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D% % % % % % %
1160 CLS
1170 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1180 PRINT AT 2,0;"DO YOU WISH TO DISPLAY THIS RCD?"
1190 PRINT AT 4,11;"(Y, N, OR M)"
1200 FOR X=1 TO 5
1210 PRINT B$(X)
1220 PRINT A$(1,A(X) TO B(X))
1230 NEXT X
1240 GOSUB 2550
1250 IF I$="M" THEN RETURN
1260 IF I$="Y" THEN GOTO 1290
1270 GOSUB 2280
1280 GOTO 1150
1290 CLS
1300 FOR X=1 TO 64
1310 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1320 PRINT AT 2,0;"RECORD DISPLAYED IS FOR..."
1330 PRINT AT 4,0;"GEN/CODE NBR. ";A$(1, TO 5)
1340 PRINT AT 5,0;A$(1,6 TO 20)
1350 PRINT AT 6,0;A$(1,21 TO 35)
1360 PRINT AT 7,0;A$(1,36 TO 50)
1370 PRINT AT 8,0;A$(1,51 TO 65)
1380 PRINT AT 15,0;"%P%R%E%S%S% %E%N%T%E%R% %F%O%R% %N%E%X%T% %F%I%E%L%D% % % % % % "
1390 PRINT AT 16,0;"%P%R%E%S%S% %"%M%"% %T%O% %R%E%T%U%R%N% %T%O% % %M%E%N%U% % % % "
1400 PRINT AT 10,0;B$(X)
1410 PRINT AT 12,0;A$(1,A(X) TO B(X))
1420 IF INKEY$="" THEN GOTO 1420
1430 IF INKEY$="M" THEN RETURN
1440 PRINT AT 12,0;" "
1450 NEXT X
1460 RETURN
1470 REM %P%R%I%N%T% %A% %R%E%C%O%R%D% % % % % % % % %
1480 CLS
1490 PRINT AT 0,8;"%P%R%I%N%T% %A% %R%E%C%O%R%D"
1500 PRINT AT 2,0;"DO YOU WISH TO PRINT THIS RCD?"
1510 PRINT AT 4,11;"(Y, N, OR M)",,,
1520 FOR X=1 TO 5
1530 PRINT B$(X)
1540 PRINT A$(1,A(X) TO B(X))
1550 NEXT X
1560 GOSUB 2550
1570 IF I$="Y" THEN GOTO 1610
1580 IF I$="M" THEN RETURN
1590 GOSUB 2280
1600 GOTO 1470
1610 FAST
1620 FOR X=1 TO 64
1630 LPRINT B$(X)
1640 LPRINT A$(1,A(X) TO B(X))
1650 LPRINT
1660 NEXT X
1670 SLOW
1680 RETURN
1690 REM %P%R%I%N%T% %D%/%T% %D%I%R%E%C%T%O%R%Y% % % %
1700 CLS
1710 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1720 PRINT AT 4,0;"IS THE PRINTER ON ? (Y, N, OR M)"
1730 GOSUB 2550
1740 IF I$="M" THEN RETURN
1750 IF I$="Y" THEN GOTO 1790
1760 PRINT AT 12,0;"PLEASE TURN THE PRINTER ON"
1770 PRINT AT 14,0;"PRESS ENTER WHEN PRINTER IS ON"
1780 INPUT I$
1790 CLS
1800 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1810 PRINT AT 4,0;"PLACE OLD DATA TAPE IN TAPE DECK"
1820 PRINT AT 6,0;"PRESS ""PLAY"" ON TAPE DECK"
1830 PRINT AT 8,0;"PRESS ""ENTER"" ON COMPUTER"
1840 INPUT I$
1850 LPRINT "% % % % % % % DATA TAPE DIRECTORY% % % % % % ",,
1860 LPRINT "GEN/"
1870 LPRINT "CODE FIRST/LAST NAME",,,
1880 FOR X=1 TO 35
1890 RAND USR 16549
1900 DIM C$(1,36)
1910 LET C$(1)=A$(1,1 TO 5)+" "+A$(1,6 TO 20)+A$(1,51 TO 65)
1920 LET D$=""
1930 FOR Y=1 TO 36
1940 IF C$(1,Y)=" " THEN GOTO 1970
1950 LET D$=D$+C$(1,Y)
1960 IF C$(1,Y+1)=" " THEN LET D$=D$+" "
1970 NEXT Y
1980 LPRINT D$
1990 LPRINT
2000 NEXT X
2010 RETURN
2020 REM %C%O%P%Y% %D%A%T%A% %T%A%P%E% % % % % % % % %
2030 CLS
2040 PRINT ,,,,,,"HOW MANY RECORDS DO YOU WISH TO",,,"COPY? (1 TO 35)"
2050 INPUT Z
2060 IF Z>35 THEN GOTO 2020
2070 FOR X=1 TO Z
2080 GOSUB 2280
2090 GOSUB 2410
2100 NEXT X
2110 RETURN
2120 REM %C%O%P%Y% %P%R%O%G%R%A%M% % % % % % % % % % %
2130 CLS
2140 PRINT ,,,,,,"PLACE BLANK PROGRAM TAPE IN TAPE",,"DECK, PRESS ""PLAY/RECORD"" ON",,,"TAPE DECK, PRESS ""ENTER"" ON",,,"COMPUTER."
2150 INPUT I$
2160 CLS
2170 SAVE "FORMATTE%R"
2180 PRINT ,,,,,,"PRESS ""STOP"" ON TAPE DECK",,,"PRESS ""ENTER"" ON COMPUTER."
2190 INPUT I$
2200 GOTO 0310
2210 REM %E%N%D% %P%R%O%G%R%A%M% % % % % % % % % % % %
2220 CLS
2230 PRINT ,,,,,,"ARE YOU SURE YOU WANT TO QUIT?"
2240 PRINT TAB 11;"(Y, N, OR M)"
2250 GOSUB 2550
2260 IF I$="Y" THEN NEW
2270 RETURN
2280 REM %R%E%A%D% %R%E%C%O%R%D% %O%N% %T%A%P%E% % % %
2290 CLS
2300 PRINT AT 2,0;"PLACE OLD DATA TAPE IN TAPE DECK"
2310 PRINT AT 4,0;"PRESS ""PLAY"" ON TAPE DECK"
2320 PRINT AT 6,0;"PRESS ""ENTER"" ON COMPUTER"
2330 INPUT Z$
2340 RAND USR 16549
2350 CLS
2360 SLOW
2370 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2380 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2390 INPUT Z$
2400 RETURN
2410 REM %W%R%I%T%E% %R%E%C%O%R%D% %O%N% %T%A%P%E% % %
2420 CLS
2430 PRINT AT 2,0;"PLACE NEW DATA TAPE IN TAPE DECK"
2440 PRINT AT 4,0;"PRESS ""PLAY/RECORD"" ON TAPE"
2450 PRINT "DECK"
2460 PRINT AT 7,0;"PRESS ""ENTER"" ON COMPUTER"
2470 INPUT Z$
2480 RAND USR 16514
2490 CLS
2500 SLOW
2510 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2520 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2530 INPUT Z$
2540 RETURN
2550 REM %I%N%P%U%T% %C%H%E%C%K%E%R% %(%Y% %O%R% %N%)%
2560 IF INKEY$="" THEN GOTO 2550
2570 LET I$=INKEY$
2580 IF I$<>"Y" AND I$<>"N" AND I$<>"M" THEN GOTO 2550
2590 RETURN
2600 SAVE "1016%0"
2610 GOTO 300
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
E
Skip to content
Record Formatter
This file is part of Timex Sinclair Public Domain Library Tape 1003
. Download the collection to get this file.
Record Formatter Ver. 1 is a ZX81/TS1000 database management program that allows users to define up to 64 custom fields, then enter, display, edit, and print records stored in a 1,459-character string array. Tape I/O is handled by two machine-code routines embedded in the line-10 REM statement: one at USR 16514 writes records to tape and one at USR 16549 reads them back, called via RAND USR. The program uses a packed record layout where each field’s start and end positions are tracked in parallel numeric arrays A() and B(), allowing substring slicing of the master string A$(1). A directory-printing routine compresses data by stripping redundant spaces before sending output to the printer via LPRINT.
Program Analysis
Program Structure
The program is organized into clearly labeled sections using inverse-text REM statements as headers. Execution begins at line 10 (which contains machine code) and proceeds through initialization before entering the main menu loop.
- Lines 10–20: Machine code in REM; program identity label
- Lines 30–80: Array and variable initialization
- Lines 100–180: Field definition loop (up to 64 fields)
- Lines 190–300: Print record layout to printer
- Lines 310–550: Main menu and dispatch
- Lines 560–760: Enter new record subroutine
- Lines 770–1140: Change a record subroutine
- Lines 1150–1460: Display a record subroutine
- Lines 1470–1680: Print a record subroutine
- Lines 1690–2010: Print data tape directory subroutine
- Lines 2020–2110: Copy data tape subroutine
- Lines 2120–2200: Copy program subroutine
- Lines 2210–2270: End program subroutine
- Lines 2280–2400: Read record from tape subroutine
- Lines 2410–2540: Write record to tape subroutine
- Lines 2550–2590: Input checker subroutine (Y/N/M)
- Lines 2600–2610: SAVE and restart
Machine Code Routines
Two machine-code routines are embedded in the REM statement at line 10. They are invoked via RAND USR 16514 (write record) and RAND USR 16549 (read record). The ZX81 system variables place the start of the BASIC program at address 16509 (407Fh); the REM data begins at offset 5 (after the line number, length, and REM token), so the routines land at 16514 and 16549 respectively.
Disassembly of the REM bytes reveals two distinct routines:
Offset Address Bytes Mnemonic Notes 0 16514 CD E7 02 CALL 02E7h ZX81 ROM: slow-speed display/sync entry 3 16517 06 0E LD B,0Eh Loop counter = 14 5 16519 21 00 FF LD HL,FF00h Start of candidate address range 8 16522 2B DEC HL Step HL down 9 16523 7C LD A,H 10 16524 B5 OR L Check HL=0 11 16525 20 FB JR NZ,-5 Loop until zero 13 16527 10 F6 DJNZ -10 Outer timing loop 15 16529 2A 10 40 LD HL,(4010h) Load A$ descriptor pointer 18 16532 23 INC HL 19 16533 4E LD C,(HL) Low byte of length 20 16534 23 INC HL 21 16535 46 LD B,(HL) High byte of length 22 16536 23 INC HL 23 16537 C5 PUSH BC Save byte count 24 16538 5E LD E,(HL) Data address low 25 16539 CD 1F 03 CALL 031Fh ROM: output byte to tape 28 16542 C1 POP BC 29 16543 0B DEC BC 30 16544 78 LD A,B 31 16545 B1 OR C Check BC=0 32 16546 20 F4 JR NZ,-12 Write loop 34 16548 C9 RET End of write routine 35 16549 CD E7 02 CALL 02E7h Read routine starts here 38 16552 2A 10 40 LD HL,(4010h) Load A$ descriptor … … 1E 08 DB FE D3 FF… (tape read loop) Reads bytes from EAR port, reconstructs A$
The read routine polls the EAR port (DB FE = IN A,(FEh)) and outputs to FFh (D3 FF = OUT (FFh),A), using rotate and bit-test instructions to decode the Manchester-like tape signal. The length of data transferred is derived from the A$ array descriptor at address 4010h, so the routines always read/write exactly 1,459 bytes — the full record.
Data Layout
The master record is held in A$(1), a single 1,459-character string (the first and only row of the 1×1459 DIM). Field positions are pre-computed during setup:
A(X) — start position of field X within A$(1)
B(X) — end position of field X within A$(1)
C(X) — declared length of field X
B$(X) — 32-character field title (DIM B$(64,32))
Field data is read and written using ZX81 substring slicing: A$(1,A(X) TO B(X)). A temporary single-row string C$(1,C(X)) is re-DIMmed for each field during entry and editing to enforce the correct field width.
Menu and Navigation
The main menu at line 310 uses a single-keypress idiom: INKEY$ is tested in a tight loop at line 450, then captured at line 460 and dispatched via a cascade of IF … THEN GOSUB / GOTO statements. The reusable input checker subroutine at line 2550 accepts only Y, N, or M (Menu return), providing consistent three-way navigation throughout.
Key BASIC Idioms
- RAND USR — used to call machine-code routines without storing a return value, discarding the USR result safely.
- Re-DIM inside loop —
DIM C$(1,C(X)) at lines 630 and 1010 re-allocates C$ each iteration to match the current field’s length, ensuring INPUT fills exactly the right number of characters.
- VAL-style line targets — line numbers in
GOTO/GOSUB are written with leading zeros (e.g., GOTO 0450, GOSUB 0560), a common ZX81 style that has no runtime effect but aids readability.
- FAST/SLOW bracketing — printer output blocks (lines 190–300 and 1610–1670) are wrapped in
FAST/SLOW to disable the display interrupt and speed up LPRINT operations.
Directory Space-Compression Routine
The tape directory printer (lines 1930–1970) implements a simple run-length space compressor: it builds D$ by copying non-space characters from C$(1) and inserting a single space only when the next character is a space, collapsing multiple spaces into one. This produces compact, human-readable directory entries from fixed-width fields.
Notable Bugs and Anomalies
- Line 1000 unreachable check —
IF I$="N" AND X=65 THEN GOTO 1130 follows IF I$="N" THEN NEXT X at line 990. If I$="N", control jumps to NEXT X and never reaches line 1000; the X=65 boundary check is therefore dead code. The loop termination after all 64 fields are processed falls through to line 1130 naturally via the FOR/NEXT mechanism.
- Field count vs. tape block size — The program defines up to 64 fields but the directory loop at line 1880 is hard-coded to
FOR X=1 TO 35, implying the data tape is expected to hold exactly 35 records. There is no run-time check that the total declared field lengths do not exceed 1,459.
- Line 1430 double-read of INKEY$ — After the wait loop at line 1420 confirms a key is pressed, line 1430 calls
INKEY$ again. On a fast machine this could return an empty string if the key was released between the two polls, potentially failing to detect the M keypress.
- Line 2610 —
GOTO 300 targets line 300 (SLOW), not the menu at line 310, meaning after a SAVE the machine briefly executes SLOW before falling into the menu — harmless but slightly inconsistent with the direct GOTO 0310 used elsewhere.
Content
Source Code
10 REM \CD\E7\02\06\0E\21\00\FF\2B\7C\B5\20\FB\10\F6\2A\10\40\23\4E\23\46\23\C5\5E\CD\1F\03\C1\0B\78\B1\20\F4\C9\CD\E7\02\2A\10\40\23\4E\23\46\23\C5\1E\08\DB\FE\D3\FF\17\30\F9\0E\94\06\1A\0D\DB\FE\17\CB\79\79\38\F5\10\F5\20\04\FE\56\30\E4\3F\CB\16\1D\20\DE\C1\0B\78\B1\C8\18\D3
20 REM %P%R%O%G%R%A%M% %S%E%T% %U%P% % % % % % % % %
30 DIM A$(1,1459)
40 DIM B$(64,32)
50 DIM A(64)
60 DIM B(64)
70 DIM C(64)
80 LET M=310
90 LET W=1
100 FOR X=1 TO 64
110 PRINT AT 12,0;"ENTER FIELD TITLE (32 POS)"
120 INPUT B$(X)
130 PRINT AT 12,0;"ENTER LENGTH OF FIELD "
140 INPUT C(X)
150 LET A(X)=W
160 LET B(X)=W+C(X)-1
170 LET W=W+C(X)
180 NEXT X
190 FAST
200 LPRINT "RECORD LAYOUT"
210 LPRINT
220 LPRINT "FIELD NAME"
230 LPRINT "ST POS END POS LENGTH FLD NBR."
240 LPRINT "--------------------------------"
250 FOR X=1 TO 64
260 LPRINT B$(X)
270 LPRINT A(X);TAB 8;B(X);TAB 17;C(X);TAB 25;X
280 LPRINT
290 NEXT X
300 SLOW
310 REM %M%E%N%U% % % % % % % % % % % % % % % % % % %
320 CLS
330 PRINT TAB 5;"RECORD FORMATTER VER.1"
340 PRINT TAB 3;"COPYRIGHT 1985 TIM L. WARD",,,
350 PRINT "DO YOU WISH TO..",,,
360 PRINT "1)...ENTER A NEW RECORD?",,,
370 PRINT "2)...CHANGE A RECORD?",,,
380 PRINT "3)...DISPLAY A RECORD?",,,
390 PRINT "4)...PRINT A RECORD?",,,
400 PRINT "5)...PRINT DATA TAPE DIRECTORY?",,,
410 PRINT "6)...COPY DATA TAPE?",,,
420 PRINT "7)...COPY PROGRAM?",,,
430 PRINT "8)...END PROGRAM?",,,
440 PRINT "ENTER NBR. OF SELECTION"
450 IF INKEY$="" THEN GOTO 0450
460 LET I$=INKEY$
470 IF I$="1" THEN GOSUB 0560
480 IF I$="2" THEN GOSUB 0770
490 IF I$="3" THEN GOSUB 1150
500 IF I$="4" THEN GOSUB 1470
510 IF I$="5" THEN GOSUB 1690
520 IF I$="6" THEN GOSUB 2020
530 IF I$="7" THEN GOTO 2120
540 IF I$="8" THEN GOSUB 2210
550 GOTO 0310
560 REM %E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D% % % % %
570 CLS
580 PRINT ,,,,,,"DO YOU WISH TO ADD A NEW RCD?"
590 PRINT TAB 11;"(Y, N, OR M)"
600 GOSUB 2550
610 IF I$<>"Y" THEN RETURN
620 FOR X=1 TO 64
630 DIM C$(1,C(X))
640 CLS
650 PRINT AT 0,6;"%E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D"
660 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
670 PRINT AT 4,0;B$(X)
680 INPUT C$(1)
690 PRINT AT 6,0;C$(1)
700 PRINT "IS THIS CORRECT? (Y OR N)"
710 GOSUB 2550
720 IF I$<>"Y" THEN GOTO 0640
730 LET A$(1,A(X) TO B(X))=C$(1)
740 NEXT X
750 GOSUB 2410
760 RETURN
770 REM %C%H%A%N%G%E% %A% %R%E%C%O%R%D% % % % % % % %
780 CLS
790 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
800 PRINT AT 2,0;"DO YOU WISH TO CHANGE THIS RCD?"
810 PRINT AT 4,11;"(Y, N, OR M)",,,
820 FOR X=1 TO 5
830 PRINT B$(X)
840 PRINT A$(1,A(X) TO B(X))
850 NEXT X
860 GOSUB 2550
870 IF I$="M" THEN RETURN
880 IF I$="Y" THEN GOTO 0920
890 GOSUB 2410
900 GOSUB 2280
910 GOTO 0770
920 FOR X=1 TO 64
930 CLS
940 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
950 PRINT AT 2,0;"CHANGE THIS FIELD? (Y OR N)"
960 PRINT AT 4,0;B$(X)
970 PRINT A$(1,A(X) TO B(X))
980 GOSUB 2550
990 IF I$="N" THEN NEXT X
1000 IF I$="N" AND X=65 THEN GOTO 1130
1010 DIM C$(1,C(X))
1020 CLS
1030 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
1040 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
1050 PRINT AT 4,0;B$(X)
1060 INPUT C$(1)
1070 PRINT AT 6,0;C$(1)
1080 PRINT "IS THIS CORRECT? (Y OR N)"
1090 GOSUB 2550
1100 IF I$<>"Y" THEN GOTO 1020
1110 LET A$(1,A(X) TO B(X))=C$(1)
1120 NEXT X
1130 GOSUB 2410
1140 RETURN
1150 REM %D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D% % % % % % %
1160 CLS
1170 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1180 PRINT AT 2,0;"DO YOU WISH TO DISPLAY THIS RCD?"
1190 PRINT AT 4,11;"(Y, N, OR M)"
1200 FOR X=1 TO 5
1210 PRINT B$(X)
1220 PRINT A$(1,A(X) TO B(X))
1230 NEXT X
1240 GOSUB 2550
1250 IF I$="M" THEN RETURN
1260 IF I$="Y" THEN GOTO 1290
1270 GOSUB 2280
1280 GOTO 1150
1290 CLS
1300 FOR X=1 TO 64
1310 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1320 PRINT AT 2,0;"RECORD DISPLAYED IS FOR..."
1330 PRINT AT 4,0;"GEN/CODE NBR. ";A$(1, TO 5)
1340 PRINT AT 5,0;A$(1,6 TO 20)
1350 PRINT AT 6,0;A$(1,21 TO 35)
1360 PRINT AT 7,0;A$(1,36 TO 50)
1370 PRINT AT 8,0;A$(1,51 TO 65)
1380 PRINT AT 15,0;"%P%R%E%S%S% %E%N%T%E%R% %F%O%R% %N%E%X%T% %F%I%E%L%D% % % % % % "
1390 PRINT AT 16,0;"%P%R%E%S%S% %"%M%"% %T%O% %R%E%T%U%R%N% %T%O% % %M%E%N%U% % % % "
1400 PRINT AT 10,0;B$(X)
1410 PRINT AT 12,0;A$(1,A(X) TO B(X))
1420 IF INKEY$="" THEN GOTO 1420
1430 IF INKEY$="M" THEN RETURN
1440 PRINT AT 12,0;" "
1450 NEXT X
1460 RETURN
1470 REM %P%R%I%N%T% %A% %R%E%C%O%R%D% % % % % % % % %
1480 CLS
1490 PRINT AT 0,8;"%P%R%I%N%T% %A% %R%E%C%O%R%D"
1500 PRINT AT 2,0;"DO YOU WISH TO PRINT THIS RCD?"
1510 PRINT AT 4,11;"(Y, N, OR M)",,,
1520 FOR X=1 TO 5
1530 PRINT B$(X)
1540 PRINT A$(1,A(X) TO B(X))
1550 NEXT X
1560 GOSUB 2550
1570 IF I$="Y" THEN GOTO 1610
1580 IF I$="M" THEN RETURN
1590 GOSUB 2280
1600 GOTO 1470
1610 FAST
1620 FOR X=1 TO 64
1630 LPRINT B$(X)
1640 LPRINT A$(1,A(X) TO B(X))
1650 LPRINT
1660 NEXT X
1670 SLOW
1680 RETURN
1690 REM %P%R%I%N%T% %D%/%T% %D%I%R%E%C%T%O%R%Y% % % %
1700 CLS
1710 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1720 PRINT AT 4,0;"IS THE PRINTER ON ? (Y, N, OR M)"
1730 GOSUB 2550
1740 IF I$="M" THEN RETURN
1750 IF I$="Y" THEN GOTO 1790
1760 PRINT AT 12,0;"PLEASE TURN THE PRINTER ON"
1770 PRINT AT 14,0;"PRESS ENTER WHEN PRINTER IS ON"
1780 INPUT I$
1790 CLS
1800 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1810 PRINT AT 4,0;"PLACE OLD DATA TAPE IN TAPE DECK"
1820 PRINT AT 6,0;"PRESS ""PLAY"" ON TAPE DECK"
1830 PRINT AT 8,0;"PRESS ""ENTER"" ON COMPUTER"
1840 INPUT I$
1850 LPRINT "% % % % % % % DATA TAPE DIRECTORY% % % % % % ",,
1860 LPRINT "GEN/"
1870 LPRINT "CODE FIRST/LAST NAME",,,
1880 FOR X=1 TO 35
1890 RAND USR 16549
1900 DIM C$(1,36)
1910 LET C$(1)=A$(1,1 TO 5)+" "+A$(1,6 TO 20)+A$(1,51 TO 65)
1920 LET D$=""
1930 FOR Y=1 TO 36
1940 IF C$(1,Y)=" " THEN GOTO 1970
1950 LET D$=D$+C$(1,Y)
1960 IF C$(1,Y+1)=" " THEN LET D$=D$+" "
1970 NEXT Y
1980 LPRINT D$
1990 LPRINT
2000 NEXT X
2010 RETURN
2020 REM %C%O%P%Y% %D%A%T%A% %T%A%P%E% % % % % % % % %
2030 CLS
2040 PRINT ,,,,,,"HOW MANY RECORDS DO YOU WISH TO",,,"COPY? (1 TO 35)"
2050 INPUT Z
2060 IF Z>35 THEN GOTO 2020
2070 FOR X=1 TO Z
2080 GOSUB 2280
2090 GOSUB 2410
2100 NEXT X
2110 RETURN
2120 REM %C%O%P%Y% %P%R%O%G%R%A%M% % % % % % % % % % %
2130 CLS
2140 PRINT ,,,,,,"PLACE BLANK PROGRAM TAPE IN TAPE",,"DECK, PRESS ""PLAY/RECORD"" ON",,,"TAPE DECK, PRESS ""ENTER"" ON",,,"COMPUTER."
2150 INPUT I$
2160 CLS
2170 SAVE "FORMATTE%R"
2180 PRINT ,,,,,,"PRESS ""STOP"" ON TAPE DECK",,,"PRESS ""ENTER"" ON COMPUTER."
2190 INPUT I$
2200 GOTO 0310
2210 REM %E%N%D% %P%R%O%G%R%A%M% % % % % % % % % % % %
2220 CLS
2230 PRINT ,,,,,,"ARE YOU SURE YOU WANT TO QUIT?"
2240 PRINT TAB 11;"(Y, N, OR M)"
2250 GOSUB 2550
2260 IF I$="Y" THEN NEW
2270 RETURN
2280 REM %R%E%A%D% %R%E%C%O%R%D% %O%N% %T%A%P%E% % % %
2290 CLS
2300 PRINT AT 2,0;"PLACE OLD DATA TAPE IN TAPE DECK"
2310 PRINT AT 4,0;"PRESS ""PLAY"" ON TAPE DECK"
2320 PRINT AT 6,0;"PRESS ""ENTER"" ON COMPUTER"
2330 INPUT Z$
2340 RAND USR 16549
2350 CLS
2360 SLOW
2370 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2380 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2390 INPUT Z$
2400 RETURN
2410 REM %W%R%I%T%E% %R%E%C%O%R%D% %O%N% %T%A%P%E% % %
2420 CLS
2430 PRINT AT 2,0;"PLACE NEW DATA TAPE IN TAPE DECK"
2440 PRINT AT 4,0;"PRESS ""PLAY/RECORD"" ON TAPE"
2450 PRINT "DECK"
2460 PRINT AT 7,0;"PRESS ""ENTER"" ON COMPUTER"
2470 INPUT Z$
2480 RAND USR 16514
2490 CLS
2500 SLOW
2510 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2520 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2530 INPUT Z$
2540 RETURN
2550 REM %I%N%P%U%T% %C%H%E%C%K%E%R% %(%Y% %O%R% %N%)%
2560 IF INKEY$="" THEN GOTO 2550
2570 LET I$=INKEY$
2580 IF I$<>"Y" AND I$<>"N" AND I$<>"M" THEN GOTO 2550
2590 RETURN
2600 SAVE "1016%0"
2610 GOTO 300
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
\FF
Skip to content
Record Formatter
This file is part of Timex Sinclair Public Domain Library Tape 1003
. Download the collection to get this file.
Record Formatter Ver. 1 is a ZX81/TS1000 database management program that allows users to define up to 64 custom fields, then enter, display, edit, and print records stored in a 1,459-character string array. Tape I/O is handled by two machine-code routines embedded in the line-10 REM statement: one at USR 16514 writes records to tape and one at USR 16549 reads them back, called via RAND USR. The program uses a packed record layout where each field’s start and end positions are tracked in parallel numeric arrays A() and B(), allowing substring slicing of the master string A$(1). A directory-printing routine compresses data by stripping redundant spaces before sending output to the printer via LPRINT.
Program Analysis
Program Structure
The program is organized into clearly labeled sections using inverse-text REM statements as headers. Execution begins at line 10 (which contains machine code) and proceeds through initialization before entering the main menu loop.
- Lines 10–20: Machine code in REM; program identity label
- Lines 30–80: Array and variable initialization
- Lines 100–180: Field definition loop (up to 64 fields)
- Lines 190–300: Print record layout to printer
- Lines 310–550: Main menu and dispatch
- Lines 560–760: Enter new record subroutine
- Lines 770–1140: Change a record subroutine
- Lines 1150–1460: Display a record subroutine
- Lines 1470–1680: Print a record subroutine
- Lines 1690–2010: Print data tape directory subroutine
- Lines 2020–2110: Copy data tape subroutine
- Lines 2120–2200: Copy program subroutine
- Lines 2210–2270: End program subroutine
- Lines 2280–2400: Read record from tape subroutine
- Lines 2410–2540: Write record to tape subroutine
- Lines 2550–2590: Input checker subroutine (Y/N/M)
- Lines 2600–2610: SAVE and restart
Machine Code Routines
Two machine-code routines are embedded in the REM statement at line 10. They are invoked via RAND USR 16514 (write record) and RAND USR 16549 (read record). The ZX81 system variables place the start of the BASIC program at address 16509 (407Fh); the REM data begins at offset 5 (after the line number, length, and REM token), so the routines land at 16514 and 16549 respectively.
Disassembly of the REM bytes reveals two distinct routines:
Offset Address Bytes Mnemonic Notes 0 16514 CD E7 02 CALL 02E7h ZX81 ROM: slow-speed display/sync entry 3 16517 06 0E LD B,0Eh Loop counter = 14 5 16519 21 00 FF LD HL,FF00h Start of candidate address range 8 16522 2B DEC HL Step HL down 9 16523 7C LD A,H 10 16524 B5 OR L Check HL=0 11 16525 20 FB JR NZ,-5 Loop until zero 13 16527 10 F6 DJNZ -10 Outer timing loop 15 16529 2A 10 40 LD HL,(4010h) Load A$ descriptor pointer 18 16532 23 INC HL 19 16533 4E LD C,(HL) Low byte of length 20 16534 23 INC HL 21 16535 46 LD B,(HL) High byte of length 22 16536 23 INC HL 23 16537 C5 PUSH BC Save byte count 24 16538 5E LD E,(HL) Data address low 25 16539 CD 1F 03 CALL 031Fh ROM: output byte to tape 28 16542 C1 POP BC 29 16543 0B DEC BC 30 16544 78 LD A,B 31 16545 B1 OR C Check BC=0 32 16546 20 F4 JR NZ,-12 Write loop 34 16548 C9 RET End of write routine 35 16549 CD E7 02 CALL 02E7h Read routine starts here 38 16552 2A 10 40 LD HL,(4010h) Load A$ descriptor … … 1E 08 DB FE D3 FF… (tape read loop) Reads bytes from EAR port, reconstructs A$
The read routine polls the EAR port (DB FE = IN A,(FEh)) and outputs to FFh (D3 FF = OUT (FFh),A), using rotate and bit-test instructions to decode the Manchester-like tape signal. The length of data transferred is derived from the A$ array descriptor at address 4010h, so the routines always read/write exactly 1,459 bytes — the full record.
Data Layout
The master record is held in A$(1), a single 1,459-character string (the first and only row of the 1×1459 DIM). Field positions are pre-computed during setup:
A(X) — start position of field X within A$(1)
B(X) — end position of field X within A$(1)
C(X) — declared length of field X
B$(X) — 32-character field title (DIM B$(64,32))
Field data is read and written using ZX81 substring slicing: A$(1,A(X) TO B(X)). A temporary single-row string C$(1,C(X)) is re-DIMmed for each field during entry and editing to enforce the correct field width.
Menu and Navigation
The main menu at line 310 uses a single-keypress idiom: INKEY$ is tested in a tight loop at line 450, then captured at line 460 and dispatched via a cascade of IF … THEN GOSUB / GOTO statements. The reusable input checker subroutine at line 2550 accepts only Y, N, or M (Menu return), providing consistent three-way navigation throughout.
Key BASIC Idioms
- RAND USR — used to call machine-code routines without storing a return value, discarding the USR result safely.
- Re-DIM inside loop —
DIM C$(1,C(X)) at lines 630 and 1010 re-allocates C$ each iteration to match the current field’s length, ensuring INPUT fills exactly the right number of characters.
- VAL-style line targets — line numbers in
GOTO/GOSUB are written with leading zeros (e.g., GOTO 0450, GOSUB 0560), a common ZX81 style that has no runtime effect but aids readability.
- FAST/SLOW bracketing — printer output blocks (lines 190–300 and 1610–1670) are wrapped in
FAST/SLOW to disable the display interrupt and speed up LPRINT operations.
Directory Space-Compression Routine
The tape directory printer (lines 1930–1970) implements a simple run-length space compressor: it builds D$ by copying non-space characters from C$(1) and inserting a single space only when the next character is a space, collapsing multiple spaces into one. This produces compact, human-readable directory entries from fixed-width fields.
Notable Bugs and Anomalies
- Line 1000 unreachable check —
IF I$="N" AND X=65 THEN GOTO 1130 follows IF I$="N" THEN NEXT X at line 990. If I$="N", control jumps to NEXT X and never reaches line 1000; the X=65 boundary check is therefore dead code. The loop termination after all 64 fields are processed falls through to line 1130 naturally via the FOR/NEXT mechanism.
- Field count vs. tape block size — The program defines up to 64 fields but the directory loop at line 1880 is hard-coded to
FOR X=1 TO 35, implying the data tape is expected to hold exactly 35 records. There is no run-time check that the total declared field lengths do not exceed 1,459.
- Line 1430 double-read of INKEY$ — After the wait loop at line 1420 confirms a key is pressed, line 1430 calls
INKEY$ again. On a fast machine this could return an empty string if the key was released between the two polls, potentially failing to detect the M keypress.
- Line 2610 —
GOTO 300 targets line 300 (SLOW), not the menu at line 310, meaning after a SAVE the machine briefly executes SLOW before falling into the menu — harmless but slightly inconsistent with the direct GOTO 0310 used elsewhere.
Content
Source Code
10 REM \CD\E7\02\06\0E\21\00\FF\2B\7C\B5\20\FB\10\F6\2A\10\40\23\4E\23\46\23\C5\5E\CD\1F\03\C1\0B\78\B1\20\F4\C9\CD\E7\02\2A\10\40\23\4E\23\46\23\C5\1E\08\DB\FE\D3\FF\17\30\F9\0E\94\06\1A\0D\DB\FE\17\CB\79\79\38\F5\10\F5\20\04\FE\56\30\E4\3F\CB\16\1D\20\DE\C1\0B\78\B1\C8\18\D3
20 REM %P%R%O%G%R%A%M% %S%E%T% %U%P% % % % % % % % %
30 DIM A$(1,1459)
40 DIM B$(64,32)
50 DIM A(64)
60 DIM B(64)
70 DIM C(64)
80 LET M=310
90 LET W=1
100 FOR X=1 TO 64
110 PRINT AT 12,0;"ENTER FIELD TITLE (32 POS)"
120 INPUT B$(X)
130 PRINT AT 12,0;"ENTER LENGTH OF FIELD "
140 INPUT C(X)
150 LET A(X)=W
160 LET B(X)=W+C(X)-1
170 LET W=W+C(X)
180 NEXT X
190 FAST
200 LPRINT "RECORD LAYOUT"
210 LPRINT
220 LPRINT "FIELD NAME"
230 LPRINT "ST POS END POS LENGTH FLD NBR."
240 LPRINT "--------------------------------"
250 FOR X=1 TO 64
260 LPRINT B$(X)
270 LPRINT A(X);TAB 8;B(X);TAB 17;C(X);TAB 25;X
280 LPRINT
290 NEXT X
300 SLOW
310 REM %M%E%N%U% % % % % % % % % % % % % % % % % % %
320 CLS
330 PRINT TAB 5;"RECORD FORMATTER VER.1"
340 PRINT TAB 3;"COPYRIGHT 1985 TIM L. WARD",,,
350 PRINT "DO YOU WISH TO..",,,
360 PRINT "1)...ENTER A NEW RECORD?",,,
370 PRINT "2)...CHANGE A RECORD?",,,
380 PRINT "3)...DISPLAY A RECORD?",,,
390 PRINT "4)...PRINT A RECORD?",,,
400 PRINT "5)...PRINT DATA TAPE DIRECTORY?",,,
410 PRINT "6)...COPY DATA TAPE?",,,
420 PRINT "7)...COPY PROGRAM?",,,
430 PRINT "8)...END PROGRAM?",,,
440 PRINT "ENTER NBR. OF SELECTION"
450 IF INKEY$="" THEN GOTO 0450
460 LET I$=INKEY$
470 IF I$="1" THEN GOSUB 0560
480 IF I$="2" THEN GOSUB 0770
490 IF I$="3" THEN GOSUB 1150
500 IF I$="4" THEN GOSUB 1470
510 IF I$="5" THEN GOSUB 1690
520 IF I$="6" THEN GOSUB 2020
530 IF I$="7" THEN GOTO 2120
540 IF I$="8" THEN GOSUB 2210
550 GOTO 0310
560 REM %E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D% % % % %
570 CLS
580 PRINT ,,,,,,"DO YOU WISH TO ADD A NEW RCD?"
590 PRINT TAB 11;"(Y, N, OR M)"
600 GOSUB 2550
610 IF I$<>"Y" THEN RETURN
620 FOR X=1 TO 64
630 DIM C$(1,C(X))
640 CLS
650 PRINT AT 0,6;"%E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D"
660 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
670 PRINT AT 4,0;B$(X)
680 INPUT C$(1)
690 PRINT AT 6,0;C$(1)
700 PRINT "IS THIS CORRECT? (Y OR N)"
710 GOSUB 2550
720 IF I$<>"Y" THEN GOTO 0640
730 LET A$(1,A(X) TO B(X))=C$(1)
740 NEXT X
750 GOSUB 2410
760 RETURN
770 REM %C%H%A%N%G%E% %A% %R%E%C%O%R%D% % % % % % % %
780 CLS
790 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
800 PRINT AT 2,0;"DO YOU WISH TO CHANGE THIS RCD?"
810 PRINT AT 4,11;"(Y, N, OR M)",,,
820 FOR X=1 TO 5
830 PRINT B$(X)
840 PRINT A$(1,A(X) TO B(X))
850 NEXT X
860 GOSUB 2550
870 IF I$="M" THEN RETURN
880 IF I$="Y" THEN GOTO 0920
890 GOSUB 2410
900 GOSUB 2280
910 GOTO 0770
920 FOR X=1 TO 64
930 CLS
940 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
950 PRINT AT 2,0;"CHANGE THIS FIELD? (Y OR N)"
960 PRINT AT 4,0;B$(X)
970 PRINT A$(1,A(X) TO B(X))
980 GOSUB 2550
990 IF I$="N" THEN NEXT X
1000 IF I$="N" AND X=65 THEN GOTO 1130
1010 DIM C$(1,C(X))
1020 CLS
1030 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
1040 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
1050 PRINT AT 4,0;B$(X)
1060 INPUT C$(1)
1070 PRINT AT 6,0;C$(1)
1080 PRINT "IS THIS CORRECT? (Y OR N)"
1090 GOSUB 2550
1100 IF I$<>"Y" THEN GOTO 1020
1110 LET A$(1,A(X) TO B(X))=C$(1)
1120 NEXT X
1130 GOSUB 2410
1140 RETURN
1150 REM %D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D% % % % % % %
1160 CLS
1170 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1180 PRINT AT 2,0;"DO YOU WISH TO DISPLAY THIS RCD?"
1190 PRINT AT 4,11;"(Y, N, OR M)"
1200 FOR X=1 TO 5
1210 PRINT B$(X)
1220 PRINT A$(1,A(X) TO B(X))
1230 NEXT X
1240 GOSUB 2550
1250 IF I$="M" THEN RETURN
1260 IF I$="Y" THEN GOTO 1290
1270 GOSUB 2280
1280 GOTO 1150
1290 CLS
1300 FOR X=1 TO 64
1310 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1320 PRINT AT 2,0;"RECORD DISPLAYED IS FOR..."
1330 PRINT AT 4,0;"GEN/CODE NBR. ";A$(1, TO 5)
1340 PRINT AT 5,0;A$(1,6 TO 20)
1350 PRINT AT 6,0;A$(1,21 TO 35)
1360 PRINT AT 7,0;A$(1,36 TO 50)
1370 PRINT AT 8,0;A$(1,51 TO 65)
1380 PRINT AT 15,0;"%P%R%E%S%S% %E%N%T%E%R% %F%O%R% %N%E%X%T% %F%I%E%L%D% % % % % % "
1390 PRINT AT 16,0;"%P%R%E%S%S% %"%M%"% %T%O% %R%E%T%U%R%N% %T%O% % %M%E%N%U% % % % "
1400 PRINT AT 10,0;B$(X)
1410 PRINT AT 12,0;A$(1,A(X) TO B(X))
1420 IF INKEY$="" THEN GOTO 1420
1430 IF INKEY$="M" THEN RETURN
1440 PRINT AT 12,0;" "
1450 NEXT X
1460 RETURN
1470 REM %P%R%I%N%T% %A% %R%E%C%O%R%D% % % % % % % % %
1480 CLS
1490 PRINT AT 0,8;"%P%R%I%N%T% %A% %R%E%C%O%R%D"
1500 PRINT AT 2,0;"DO YOU WISH TO PRINT THIS RCD?"
1510 PRINT AT 4,11;"(Y, N, OR M)",,,
1520 FOR X=1 TO 5
1530 PRINT B$(X)
1540 PRINT A$(1,A(X) TO B(X))
1550 NEXT X
1560 GOSUB 2550
1570 IF I$="Y" THEN GOTO 1610
1580 IF I$="M" THEN RETURN
1590 GOSUB 2280
1600 GOTO 1470
1610 FAST
1620 FOR X=1 TO 64
1630 LPRINT B$(X)
1640 LPRINT A$(1,A(X) TO B(X))
1650 LPRINT
1660 NEXT X
1670 SLOW
1680 RETURN
1690 REM %P%R%I%N%T% %D%/%T% %D%I%R%E%C%T%O%R%Y% % % %
1700 CLS
1710 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1720 PRINT AT 4,0;"IS THE PRINTER ON ? (Y, N, OR M)"
1730 GOSUB 2550
1740 IF I$="M" THEN RETURN
1750 IF I$="Y" THEN GOTO 1790
1760 PRINT AT 12,0;"PLEASE TURN THE PRINTER ON"
1770 PRINT AT 14,0;"PRESS ENTER WHEN PRINTER IS ON"
1780 INPUT I$
1790 CLS
1800 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1810 PRINT AT 4,0;"PLACE OLD DATA TAPE IN TAPE DECK"
1820 PRINT AT 6,0;"PRESS ""PLAY"" ON TAPE DECK"
1830 PRINT AT 8,0;"PRESS ""ENTER"" ON COMPUTER"
1840 INPUT I$
1850 LPRINT "% % % % % % % DATA TAPE DIRECTORY% % % % % % ",,
1860 LPRINT "GEN/"
1870 LPRINT "CODE FIRST/LAST NAME",,,
1880 FOR X=1 TO 35
1890 RAND USR 16549
1900 DIM C$(1,36)
1910 LET C$(1)=A$(1,1 TO 5)+" "+A$(1,6 TO 20)+A$(1,51 TO 65)
1920 LET D$=""
1930 FOR Y=1 TO 36
1940 IF C$(1,Y)=" " THEN GOTO 1970
1950 LET D$=D$+C$(1,Y)
1960 IF C$(1,Y+1)=" " THEN LET D$=D$+" "
1970 NEXT Y
1980 LPRINT D$
1990 LPRINT
2000 NEXT X
2010 RETURN
2020 REM %C%O%P%Y% %D%A%T%A% %T%A%P%E% % % % % % % % %
2030 CLS
2040 PRINT ,,,,,,"HOW MANY RECORDS DO YOU WISH TO",,,"COPY? (1 TO 35)"
2050 INPUT Z
2060 IF Z>35 THEN GOTO 2020
2070 FOR X=1 TO Z
2080 GOSUB 2280
2090 GOSUB 2410
2100 NEXT X
2110 RETURN
2120 REM %C%O%P%Y% %P%R%O%G%R%A%M% % % % % % % % % % %
2130 CLS
2140 PRINT ,,,,,,"PLACE BLANK PROGRAM TAPE IN TAPE",,"DECK, PRESS ""PLAY/RECORD"" ON",,,"TAPE DECK, PRESS ""ENTER"" ON",,,"COMPUTER."
2150 INPUT I$
2160 CLS
2170 SAVE "FORMATTE%R"
2180 PRINT ,,,,,,"PRESS ""STOP"" ON TAPE DECK",,,"PRESS ""ENTER"" ON COMPUTER."
2190 INPUT I$
2200 GOTO 0310
2210 REM %E%N%D% %P%R%O%G%R%A%M% % % % % % % % % % % %
2220 CLS
2230 PRINT ,,,,,,"ARE YOU SURE YOU WANT TO QUIT?"
2240 PRINT TAB 11;"(Y, N, OR M)"
2250 GOSUB 2550
2260 IF I$="Y" THEN NEW
2270 RETURN
2280 REM %R%E%A%D% %R%E%C%O%R%D% %O%N% %T%A%P%E% % % %
2290 CLS
2300 PRINT AT 2,0;"PLACE OLD DATA TAPE IN TAPE DECK"
2310 PRINT AT 4,0;"PRESS ""PLAY"" ON TAPE DECK"
2320 PRINT AT 6,0;"PRESS ""ENTER"" ON COMPUTER"
2330 INPUT Z$
2340 RAND USR 16549
2350 CLS
2360 SLOW
2370 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2380 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2390 INPUT Z$
2400 RETURN
2410 REM %W%R%I%T%E% %R%E%C%O%R%D% %O%N% %T%A%P%E% % %
2420 CLS
2430 PRINT AT 2,0;"PLACE NEW DATA TAPE IN TAPE DECK"
2440 PRINT AT 4,0;"PRESS ""PLAY/RECORD"" ON TAPE"
2450 PRINT "DECK"
2460 PRINT AT 7,0;"PRESS ""ENTER"" ON COMPUTER"
2470 INPUT Z$
2480 RAND USR 16514
2490 CLS
2500 SLOW
2510 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2520 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2530 INPUT Z$
2540 RETURN
2550 REM %I%N%P%U%T% %C%H%E%C%K%E%R% %(%Y% %O%R% %N%)%
2560 IF INKEY$="" THEN GOTO 2550
2570 LET I$=INKEY$
2580 IF I$<>"Y" AND I$<>"N" AND I$<>"M" THEN GOTO 2550
2590 RETURN
2600 SAVE "1016%0"
2610 GOTO 300
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
BC\B5\FB\F6
Skip to content
Record Formatter
This file is part of Timex Sinclair Public Domain Library Tape 1003
. Download the collection to get this file.
Record Formatter Ver. 1 is a ZX81/TS1000 database management program that allows users to define up to 64 custom fields, then enter, display, edit, and print records stored in a 1,459-character string array. Tape I/O is handled by two machine-code routines embedded in the line-10 REM statement: one at USR 16514 writes records to tape and one at USR 16549 reads them back, called via RAND USR. The program uses a packed record layout where each field’s start and end positions are tracked in parallel numeric arrays A() and B(), allowing substring slicing of the master string A$(1). A directory-printing routine compresses data by stripping redundant spaces before sending output to the printer via LPRINT.
Program Analysis
Program Structure
The program is organized into clearly labeled sections using inverse-text REM statements as headers. Execution begins at line 10 (which contains machine code) and proceeds through initialization before entering the main menu loop.
- Lines 10–20: Machine code in REM; program identity label
- Lines 30–80: Array and variable initialization
- Lines 100–180: Field definition loop (up to 64 fields)
- Lines 190–300: Print record layout to printer
- Lines 310–550: Main menu and dispatch
- Lines 560–760: Enter new record subroutine
- Lines 770–1140: Change a record subroutine
- Lines 1150–1460: Display a record subroutine
- Lines 1470–1680: Print a record subroutine
- Lines 1690–2010: Print data tape directory subroutine
- Lines 2020–2110: Copy data tape subroutine
- Lines 2120–2200: Copy program subroutine
- Lines 2210–2270: End program subroutine
- Lines 2280–2400: Read record from tape subroutine
- Lines 2410–2540: Write record to tape subroutine
- Lines 2550–2590: Input checker subroutine (Y/N/M)
- Lines 2600–2610: SAVE and restart
Machine Code Routines
Two machine-code routines are embedded in the REM statement at line 10. They are invoked via RAND USR 16514 (write record) and RAND USR 16549 (read record). The ZX81 system variables place the start of the BASIC program at address 16509 (407Fh); the REM data begins at offset 5 (after the line number, length, and REM token), so the routines land at 16514 and 16549 respectively.
Disassembly of the REM bytes reveals two distinct routines:
Offset Address Bytes Mnemonic Notes 0 16514 CD E7 02 CALL 02E7h ZX81 ROM: slow-speed display/sync entry 3 16517 06 0E LD B,0Eh Loop counter = 14 5 16519 21 00 FF LD HL,FF00h Start of candidate address range 8 16522 2B DEC HL Step HL down 9 16523 7C LD A,H 10 16524 B5 OR L Check HL=0 11 16525 20 FB JR NZ,-5 Loop until zero 13 16527 10 F6 DJNZ -10 Outer timing loop 15 16529 2A 10 40 LD HL,(4010h) Load A$ descriptor pointer 18 16532 23 INC HL 19 16533 4E LD C,(HL) Low byte of length 20 16534 23 INC HL 21 16535 46 LD B,(HL) High byte of length 22 16536 23 INC HL 23 16537 C5 PUSH BC Save byte count 24 16538 5E LD E,(HL) Data address low 25 16539 CD 1F 03 CALL 031Fh ROM: output byte to tape 28 16542 C1 POP BC 29 16543 0B DEC BC 30 16544 78 LD A,B 31 16545 B1 OR C Check BC=0 32 16546 20 F4 JR NZ,-12 Write loop 34 16548 C9 RET End of write routine 35 16549 CD E7 02 CALL 02E7h Read routine starts here 38 16552 2A 10 40 LD HL,(4010h) Load A$ descriptor … … 1E 08 DB FE D3 FF… (tape read loop) Reads bytes from EAR port, reconstructs A$
The read routine polls the EAR port (DB FE = IN A,(FEh)) and outputs to FFh (D3 FF = OUT (FFh),A), using rotate and bit-test instructions to decode the Manchester-like tape signal. The length of data transferred is derived from the A$ array descriptor at address 4010h, so the routines always read/write exactly 1,459 bytes — the full record.
Data Layout
The master record is held in A$(1), a single 1,459-character string (the first and only row of the 1×1459 DIM). Field positions are pre-computed during setup:
A(X) — start position of field X within A$(1)
B(X) — end position of field X within A$(1)
C(X) — declared length of field X
B$(X) — 32-character field title (DIM B$(64,32))
Field data is read and written using ZX81 substring slicing: A$(1,A(X) TO B(X)). A temporary single-row string C$(1,C(X)) is re-DIMmed for each field during entry and editing to enforce the correct field width.
Menu and Navigation
The main menu at line 310 uses a single-keypress idiom: INKEY$ is tested in a tight loop at line 450, then captured at line 460 and dispatched via a cascade of IF … THEN GOSUB / GOTO statements. The reusable input checker subroutine at line 2550 accepts only Y, N, or M (Menu return), providing consistent three-way navigation throughout.
Key BASIC Idioms
- RAND USR — used to call machine-code routines without storing a return value, discarding the USR result safely.
- Re-DIM inside loop —
DIM C$(1,C(X)) at lines 630 and 1010 re-allocates C$ each iteration to match the current field’s length, ensuring INPUT fills exactly the right number of characters.
- VAL-style line targets — line numbers in
GOTO/GOSUB are written with leading zeros (e.g., GOTO 0450, GOSUB 0560), a common ZX81 style that has no runtime effect but aids readability.
- FAST/SLOW bracketing — printer output blocks (lines 190–300 and 1610–1670) are wrapped in
FAST/SLOW to disable the display interrupt and speed up LPRINT operations.
Directory Space-Compression Routine
The tape directory printer (lines 1930–1970) implements a simple run-length space compressor: it builds D$ by copying non-space characters from C$(1) and inserting a single space only when the next character is a space, collapsing multiple spaces into one. This produces compact, human-readable directory entries from fixed-width fields.
Notable Bugs and Anomalies
- Line 1000 unreachable check —
IF I$="N" AND X=65 THEN GOTO 1130 follows IF I$="N" THEN NEXT X at line 990. If I$="N", control jumps to NEXT X and never reaches line 1000; the X=65 boundary check is therefore dead code. The loop termination after all 64 fields are processed falls through to line 1130 naturally via the FOR/NEXT mechanism.
- Field count vs. tape block size — The program defines up to 64 fields but the directory loop at line 1880 is hard-coded to
FOR X=1 TO 35, implying the data tape is expected to hold exactly 35 records. There is no run-time check that the total declared field lengths do not exceed 1,459.
- Line 1430 double-read of INKEY$ — After the wait loop at line 1420 confirms a key is pressed, line 1430 calls
INKEY$ again. On a fast machine this could return an empty string if the key was released between the two polls, potentially failing to detect the M keypress.
- Line 2610 —
GOTO 300 targets line 300 (SLOW), not the menu at line 310, meaning after a SAVE the machine briefly executes SLOW before falling into the menu — harmless but slightly inconsistent with the direct GOTO 0310 used elsewhere.
Content
Source Code
10 REM \CD\E7\02\06\0E\21\00\FF\2B\7C\B5\20\FB\10\F6\2A\10\40\23\4E\23\46\23\C5\5E\CD\1F\03\C1\0B\78\B1\20\F4\C9\CD\E7\02\2A\10\40\23\4E\23\46\23\C5\1E\08\DB\FE\D3\FF\17\30\F9\0E\94\06\1A\0D\DB\FE\17\CB\79\79\38\F5\10\F5\20\04\FE\56\30\E4\3F\CB\16\1D\20\DE\C1\0B\78\B1\C8\18\D3
20 REM %P%R%O%G%R%A%M% %S%E%T% %U%P% % % % % % % % %
30 DIM A$(1,1459)
40 DIM B$(64,32)
50 DIM A(64)
60 DIM B(64)
70 DIM C(64)
80 LET M=310
90 LET W=1
100 FOR X=1 TO 64
110 PRINT AT 12,0;"ENTER FIELD TITLE (32 POS)"
120 INPUT B$(X)
130 PRINT AT 12,0;"ENTER LENGTH OF FIELD "
140 INPUT C(X)
150 LET A(X)=W
160 LET B(X)=W+C(X)-1
170 LET W=W+C(X)
180 NEXT X
190 FAST
200 LPRINT "RECORD LAYOUT"
210 LPRINT
220 LPRINT "FIELD NAME"
230 LPRINT "ST POS END POS LENGTH FLD NBR."
240 LPRINT "--------------------------------"
250 FOR X=1 TO 64
260 LPRINT B$(X)
270 LPRINT A(X);TAB 8;B(X);TAB 17;C(X);TAB 25;X
280 LPRINT
290 NEXT X
300 SLOW
310 REM %M%E%N%U% % % % % % % % % % % % % % % % % % %
320 CLS
330 PRINT TAB 5;"RECORD FORMATTER VER.1"
340 PRINT TAB 3;"COPYRIGHT 1985 TIM L. WARD",,,
350 PRINT "DO YOU WISH TO..",,,
360 PRINT "1)...ENTER A NEW RECORD?",,,
370 PRINT "2)...CHANGE A RECORD?",,,
380 PRINT "3)...DISPLAY A RECORD?",,,
390 PRINT "4)...PRINT A RECORD?",,,
400 PRINT "5)...PRINT DATA TAPE DIRECTORY?",,,
410 PRINT "6)...COPY DATA TAPE?",,,
420 PRINT "7)...COPY PROGRAM?",,,
430 PRINT "8)...END PROGRAM?",,,
440 PRINT "ENTER NBR. OF SELECTION"
450 IF INKEY$="" THEN GOTO 0450
460 LET I$=INKEY$
470 IF I$="1" THEN GOSUB 0560
480 IF I$="2" THEN GOSUB 0770
490 IF I$="3" THEN GOSUB 1150
500 IF I$="4" THEN GOSUB 1470
510 IF I$="5" THEN GOSUB 1690
520 IF I$="6" THEN GOSUB 2020
530 IF I$="7" THEN GOTO 2120
540 IF I$="8" THEN GOSUB 2210
550 GOTO 0310
560 REM %E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D% % % % %
570 CLS
580 PRINT ,,,,,,"DO YOU WISH TO ADD A NEW RCD?"
590 PRINT TAB 11;"(Y, N, OR M)"
600 GOSUB 2550
610 IF I$<>"Y" THEN RETURN
620 FOR X=1 TO 64
630 DIM C$(1,C(X))
640 CLS
650 PRINT AT 0,6;"%E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D"
660 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
670 PRINT AT 4,0;B$(X)
680 INPUT C$(1)
690 PRINT AT 6,0;C$(1)
700 PRINT "IS THIS CORRECT? (Y OR N)"
710 GOSUB 2550
720 IF I$<>"Y" THEN GOTO 0640
730 LET A$(1,A(X) TO B(X))=C$(1)
740 NEXT X
750 GOSUB 2410
760 RETURN
770 REM %C%H%A%N%G%E% %A% %R%E%C%O%R%D% % % % % % % %
780 CLS
790 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
800 PRINT AT 2,0;"DO YOU WISH TO CHANGE THIS RCD?"
810 PRINT AT 4,11;"(Y, N, OR M)",,,
820 FOR X=1 TO 5
830 PRINT B$(X)
840 PRINT A$(1,A(X) TO B(X))
850 NEXT X
860 GOSUB 2550
870 IF I$="M" THEN RETURN
880 IF I$="Y" THEN GOTO 0920
890 GOSUB 2410
900 GOSUB 2280
910 GOTO 0770
920 FOR X=1 TO 64
930 CLS
940 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
950 PRINT AT 2,0;"CHANGE THIS FIELD? (Y OR N)"
960 PRINT AT 4,0;B$(X)
970 PRINT A$(1,A(X) TO B(X))
980 GOSUB 2550
990 IF I$="N" THEN NEXT X
1000 IF I$="N" AND X=65 THEN GOTO 1130
1010 DIM C$(1,C(X))
1020 CLS
1030 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
1040 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
1050 PRINT AT 4,0;B$(X)
1060 INPUT C$(1)
1070 PRINT AT 6,0;C$(1)
1080 PRINT "IS THIS CORRECT? (Y OR N)"
1090 GOSUB 2550
1100 IF I$<>"Y" THEN GOTO 1020
1110 LET A$(1,A(X) TO B(X))=C$(1)
1120 NEXT X
1130 GOSUB 2410
1140 RETURN
1150 REM %D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D% % % % % % %
1160 CLS
1170 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1180 PRINT AT 2,0;"DO YOU WISH TO DISPLAY THIS RCD?"
1190 PRINT AT 4,11;"(Y, N, OR M)"
1200 FOR X=1 TO 5
1210 PRINT B$(X)
1220 PRINT A$(1,A(X) TO B(X))
1230 NEXT X
1240 GOSUB 2550
1250 IF I$="M" THEN RETURN
1260 IF I$="Y" THEN GOTO 1290
1270 GOSUB 2280
1280 GOTO 1150
1290 CLS
1300 FOR X=1 TO 64
1310 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1320 PRINT AT 2,0;"RECORD DISPLAYED IS FOR..."
1330 PRINT AT 4,0;"GEN/CODE NBR. ";A$(1, TO 5)
1340 PRINT AT 5,0;A$(1,6 TO 20)
1350 PRINT AT 6,0;A$(1,21 TO 35)
1360 PRINT AT 7,0;A$(1,36 TO 50)
1370 PRINT AT 8,0;A$(1,51 TO 65)
1380 PRINT AT 15,0;"%P%R%E%S%S% %E%N%T%E%R% %F%O%R% %N%E%X%T% %F%I%E%L%D% % % % % % "
1390 PRINT AT 16,0;"%P%R%E%S%S% %"%M%"% %T%O% %R%E%T%U%R%N% %T%O% % %M%E%N%U% % % % "
1400 PRINT AT 10,0;B$(X)
1410 PRINT AT 12,0;A$(1,A(X) TO B(X))
1420 IF INKEY$="" THEN GOTO 1420
1430 IF INKEY$="M" THEN RETURN
1440 PRINT AT 12,0;" "
1450 NEXT X
1460 RETURN
1470 REM %P%R%I%N%T% %A% %R%E%C%O%R%D% % % % % % % % %
1480 CLS
1490 PRINT AT 0,8;"%P%R%I%N%T% %A% %R%E%C%O%R%D"
1500 PRINT AT 2,0;"DO YOU WISH TO PRINT THIS RCD?"
1510 PRINT AT 4,11;"(Y, N, OR M)",,,
1520 FOR X=1 TO 5
1530 PRINT B$(X)
1540 PRINT A$(1,A(X) TO B(X))
1550 NEXT X
1560 GOSUB 2550
1570 IF I$="Y" THEN GOTO 1610
1580 IF I$="M" THEN RETURN
1590 GOSUB 2280
1600 GOTO 1470
1610 FAST
1620 FOR X=1 TO 64
1630 LPRINT B$(X)
1640 LPRINT A$(1,A(X) TO B(X))
1650 LPRINT
1660 NEXT X
1670 SLOW
1680 RETURN
1690 REM %P%R%I%N%T% %D%/%T% %D%I%R%E%C%T%O%R%Y% % % %
1700 CLS
1710 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1720 PRINT AT 4,0;"IS THE PRINTER ON ? (Y, N, OR M)"
1730 GOSUB 2550
1740 IF I$="M" THEN RETURN
1750 IF I$="Y" THEN GOTO 1790
1760 PRINT AT 12,0;"PLEASE TURN THE PRINTER ON"
1770 PRINT AT 14,0;"PRESS ENTER WHEN PRINTER IS ON"
1780 INPUT I$
1790 CLS
1800 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1810 PRINT AT 4,0;"PLACE OLD DATA TAPE IN TAPE DECK"
1820 PRINT AT 6,0;"PRESS ""PLAY"" ON TAPE DECK"
1830 PRINT AT 8,0;"PRESS ""ENTER"" ON COMPUTER"
1840 INPUT I$
1850 LPRINT "% % % % % % % DATA TAPE DIRECTORY% % % % % % ",,
1860 LPRINT "GEN/"
1870 LPRINT "CODE FIRST/LAST NAME",,,
1880 FOR X=1 TO 35
1890 RAND USR 16549
1900 DIM C$(1,36)
1910 LET C$(1)=A$(1,1 TO 5)+" "+A$(1,6 TO 20)+A$(1,51 TO 65)
1920 LET D$=""
1930 FOR Y=1 TO 36
1940 IF C$(1,Y)=" " THEN GOTO 1970
1950 LET D$=D$+C$(1,Y)
1960 IF C$(1,Y+1)=" " THEN LET D$=D$+" "
1970 NEXT Y
1980 LPRINT D$
1990 LPRINT
2000 NEXT X
2010 RETURN
2020 REM %C%O%P%Y% %D%A%T%A% %T%A%P%E% % % % % % % % %
2030 CLS
2040 PRINT ,,,,,,"HOW MANY RECORDS DO YOU WISH TO",,,"COPY? (1 TO 35)"
2050 INPUT Z
2060 IF Z>35 THEN GOTO 2020
2070 FOR X=1 TO Z
2080 GOSUB 2280
2090 GOSUB 2410
2100 NEXT X
2110 RETURN
2120 REM %C%O%P%Y% %P%R%O%G%R%A%M% % % % % % % % % % %
2130 CLS
2140 PRINT ,,,,,,"PLACE BLANK PROGRAM TAPE IN TAPE",,"DECK, PRESS ""PLAY/RECORD"" ON",,,"TAPE DECK, PRESS ""ENTER"" ON",,,"COMPUTER."
2150 INPUT I$
2160 CLS
2170 SAVE "FORMATTE%R"
2180 PRINT ,,,,,,"PRESS ""STOP"" ON TAPE DECK",,,"PRESS ""ENTER"" ON COMPUTER."
2190 INPUT I$
2200 GOTO 0310
2210 REM %E%N%D% %P%R%O%G%R%A%M% % % % % % % % % % % %
2220 CLS
2230 PRINT ,,,,,,"ARE YOU SURE YOU WANT TO QUIT?"
2240 PRINT TAB 11;"(Y, N, OR M)"
2250 GOSUB 2550
2260 IF I$="Y" THEN NEW
2270 RETURN
2280 REM %R%E%A%D% %R%E%C%O%R%D% %O%N% %T%A%P%E% % % %
2290 CLS
2300 PRINT AT 2,0;"PLACE OLD DATA TAPE IN TAPE DECK"
2310 PRINT AT 4,0;"PRESS ""PLAY"" ON TAPE DECK"
2320 PRINT AT 6,0;"PRESS ""ENTER"" ON COMPUTER"
2330 INPUT Z$
2340 RAND USR 16549
2350 CLS
2360 SLOW
2370 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2380 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2390 INPUT Z$
2400 RETURN
2410 REM %W%R%I%T%E% %R%E%C%O%R%D% %O%N% %T%A%P%E% % %
2420 CLS
2430 PRINT AT 2,0;"PLACE NEW DATA TAPE IN TAPE DECK"
2440 PRINT AT 4,0;"PRESS ""PLAY/RECORD"" ON TAPE"
2450 PRINT "DECK"
2460 PRINT AT 7,0;"PRESS ""ENTER"" ON COMPUTER"
2470 INPUT Z$
2480 RAND USR 16514
2490 CLS
2500 SLOW
2510 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2520 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2530 INPUT Z$
2540 RETURN
2550 REM %I%N%P%U%T% %C%H%E%C%K%E%R% %(%Y% %O%R% %N%)%
2560 IF INKEY$="" THEN GOTO 2550
2570 LET I$=INKEY$
2580 IF I$<>"Y" AND I$<>"N" AND I$<>"M" THEN GOTO 2550
2590 RETURN
2600 SAVE "1016%0"
2610 GOTO 300
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
AE\C5E\CD itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-57272 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.5 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.4"F\C1
Skip to content
Record Formatter
This file is part of Timex Sinclair Public Domain Library Tape 1003
. Download the collection to get this file.
Record Formatter Ver. 1 is a ZX81/TS1000 database management program that allows users to define up to 64 custom fields, then enter, display, edit, and print records stored in a 1,459-character string array. Tape I/O is handled by two machine-code routines embedded in the line-10 REM statement: one at USR 16514 writes records to tape and one at USR 16549 reads them back, called via RAND USR. The program uses a packed record layout where each field’s start and end positions are tracked in parallel numeric arrays A() and B(), allowing substring slicing of the master string A$(1). A directory-printing routine compresses data by stripping redundant spaces before sending output to the printer via LPRINT.
Program Analysis
Program Structure
The program is organized into clearly labeled sections using inverse-text REM statements as headers. Execution begins at line 10 (which contains machine code) and proceeds through initialization before entering the main menu loop.
- Lines 10–20: Machine code in REM; program identity label
- Lines 30–80: Array and variable initialization
- Lines 100–180: Field definition loop (up to 64 fields)
- Lines 190–300: Print record layout to printer
- Lines 310–550: Main menu and dispatch
- Lines 560–760: Enter new record subroutine
- Lines 770–1140: Change a record subroutine
- Lines 1150–1460: Display a record subroutine
- Lines 1470–1680: Print a record subroutine
- Lines 1690–2010: Print data tape directory subroutine
- Lines 2020–2110: Copy data tape subroutine
- Lines 2120–2200: Copy program subroutine
- Lines 2210–2270: End program subroutine
- Lines 2280–2400: Read record from tape subroutine
- Lines 2410–2540: Write record to tape subroutine
- Lines 2550–2590: Input checker subroutine (Y/N/M)
- Lines 2600–2610: SAVE and restart
Machine Code Routines
Two machine-code routines are embedded in the REM statement at line 10. They are invoked via RAND USR 16514 (write record) and RAND USR 16549 (read record). The ZX81 system variables place the start of the BASIC program at address 16509 (407Fh); the REM data begins at offset 5 (after the line number, length, and REM token), so the routines land at 16514 and 16549 respectively.
Disassembly of the REM bytes reveals two distinct routines:
Offset Address Bytes Mnemonic Notes 0 16514 CD E7 02 CALL 02E7h ZX81 ROM: slow-speed display/sync entry 3 16517 06 0E LD B,0Eh Loop counter = 14 5 16519 21 00 FF LD HL,FF00h Start of candidate address range 8 16522 2B DEC HL Step HL down 9 16523 7C LD A,H 10 16524 B5 OR L Check HL=0 11 16525 20 FB JR NZ,-5 Loop until zero 13 16527 10 F6 DJNZ -10 Outer timing loop 15 16529 2A 10 40 LD HL,(4010h) Load A$ descriptor pointer 18 16532 23 INC HL 19 16533 4E LD C,(HL) Low byte of length 20 16534 23 INC HL 21 16535 46 LD B,(HL) High byte of length 22 16536 23 INC HL 23 16537 C5 PUSH BC Save byte count 24 16538 5E LD E,(HL) Data address low 25 16539 CD 1F 03 CALL 031Fh ROM: output byte to tape 28 16542 C1 POP BC 29 16543 0B DEC BC 30 16544 78 LD A,B 31 16545 B1 OR C Check BC=0 32 16546 20 F4 JR NZ,-12 Write loop 34 16548 C9 RET End of write routine 35 16549 CD E7 02 CALL 02E7h Read routine starts here 38 16552 2A 10 40 LD HL,(4010h) Load A$ descriptor … … 1E 08 DB FE D3 FF… (tape read loop) Reads bytes from EAR port, reconstructs A$
The read routine polls the EAR port (DB FE = IN A,(FEh)) and outputs to FFh (D3 FF = OUT (FFh),A), using rotate and bit-test instructions to decode the Manchester-like tape signal. The length of data transferred is derived from the A$ array descriptor at address 4010h, so the routines always read/write exactly 1,459 bytes — the full record.
Data Layout
The master record is held in A$(1), a single 1,459-character string (the first and only row of the 1×1459 DIM). Field positions are pre-computed during setup:
A(X) — start position of field X within A$(1)
B(X) — end position of field X within A$(1)
C(X) — declared length of field X
B$(X) — 32-character field title (DIM B$(64,32))
Field data is read and written using ZX81 substring slicing: A$(1,A(X) TO B(X)). A temporary single-row string C$(1,C(X)) is re-DIMmed for each field during entry and editing to enforce the correct field width.
Menu and Navigation
The main menu at line 310 uses a single-keypress idiom: INKEY$ is tested in a tight loop at line 450, then captured at line 460 and dispatched via a cascade of IF … THEN GOSUB / GOTO statements. The reusable input checker subroutine at line 2550 accepts only Y, N, or M (Menu return), providing consistent three-way navigation throughout.
Key BASIC Idioms
- RAND USR — used to call machine-code routines without storing a return value, discarding the USR result safely.
- Re-DIM inside loop —
DIM C$(1,C(X)) at lines 630 and 1010 re-allocates C$ each iteration to match the current field’s length, ensuring INPUT fills exactly the right number of characters.
- VAL-style line targets — line numbers in
GOTO/GOSUB are written with leading zeros (e.g., GOTO 0450, GOSUB 0560), a common ZX81 style that has no runtime effect but aids readability.
- FAST/SLOW bracketing — printer output blocks (lines 190–300 and 1610–1670) are wrapped in
FAST/SLOW to disable the display interrupt and speed up LPRINT operations.
Directory Space-Compression Routine
The tape directory printer (lines 1930–1970) implements a simple run-length space compressor: it builds D$ by copying non-space characters from C$(1) and inserting a single space only when the next character is a space, collapsing multiple spaces into one. This produces compact, human-readable directory entries from fixed-width fields.
Notable Bugs and Anomalies
- Line 1000 unreachable check —
IF I$="N" AND X=65 THEN GOTO 1130 follows IF I$="N" THEN NEXT X at line 990. If I$="N", control jumps to NEXT X and never reaches line 1000; the X=65 boundary check is therefore dead code. The loop termination after all 64 fields are processed falls through to line 1130 naturally via the FOR/NEXT mechanism.
- Field count vs. tape block size — The program defines up to 64 fields but the directory loop at line 1880 is hard-coded to
FOR X=1 TO 35, implying the data tape is expected to hold exactly 35 records. There is no run-time check that the total declared field lengths do not exceed 1,459.
- Line 1430 double-read of INKEY$ — After the wait loop at line 1420 confirms a key is pressed, line 1430 calls
INKEY$ again. On a fast machine this could return an empty string if the key was released between the two polls, potentially failing to detect the M keypress.
- Line 2610 —
GOTO 300 targets line 300 (SLOW), not the menu at line 310, meaning after a SAVE the machine briefly executes SLOW before falling into the menu — harmless but slightly inconsistent with the direct GOTO 0310 used elsewhere.
Content
Source Code
10 REM \CD\E7\02\06\0E\21\00\FF\2B\7C\B5\20\FB\10\F6\2A\10\40\23\4E\23\46\23\C5\5E\CD\1F\03\C1\0B\78\B1\20\F4\C9\CD\E7\02\2A\10\40\23\4E\23\46\23\C5\1E\08\DB\FE\D3\FF\17\30\F9\0E\94\06\1A\0D\DB\FE\17\CB\79\79\38\F5\10\F5\20\04\FE\56\30\E4\3F\CB\16\1D\20\DE\C1\0B\78\B1\C8\18\D3
20 REM %P%R%O%G%R%A%M% %S%E%T% %U%P% % % % % % % % %
30 DIM A$(1,1459)
40 DIM B$(64,32)
50 DIM A(64)
60 DIM B(64)
70 DIM C(64)
80 LET M=310
90 LET W=1
100 FOR X=1 TO 64
110 PRINT AT 12,0;"ENTER FIELD TITLE (32 POS)"
120 INPUT B$(X)
130 PRINT AT 12,0;"ENTER LENGTH OF FIELD "
140 INPUT C(X)
150 LET A(X)=W
160 LET B(X)=W+C(X)-1
170 LET W=W+C(X)
180 NEXT X
190 FAST
200 LPRINT "RECORD LAYOUT"
210 LPRINT
220 LPRINT "FIELD NAME"
230 LPRINT "ST POS END POS LENGTH FLD NBR."
240 LPRINT "--------------------------------"
250 FOR X=1 TO 64
260 LPRINT B$(X)
270 LPRINT A(X);TAB 8;B(X);TAB 17;C(X);TAB 25;X
280 LPRINT
290 NEXT X
300 SLOW
310 REM %M%E%N%U% % % % % % % % % % % % % % % % % % %
320 CLS
330 PRINT TAB 5;"RECORD FORMATTER VER.1"
340 PRINT TAB 3;"COPYRIGHT 1985 TIM L. WARD",,,
350 PRINT "DO YOU WISH TO..",,,
360 PRINT "1)...ENTER A NEW RECORD?",,,
370 PRINT "2)...CHANGE A RECORD?",,,
380 PRINT "3)...DISPLAY A RECORD?",,,
390 PRINT "4)...PRINT A RECORD?",,,
400 PRINT "5)...PRINT DATA TAPE DIRECTORY?",,,
410 PRINT "6)...COPY DATA TAPE?",,,
420 PRINT "7)...COPY PROGRAM?",,,
430 PRINT "8)...END PROGRAM?",,,
440 PRINT "ENTER NBR. OF SELECTION"
450 IF INKEY$="" THEN GOTO 0450
460 LET I$=INKEY$
470 IF I$="1" THEN GOSUB 0560
480 IF I$="2" THEN GOSUB 0770
490 IF I$="3" THEN GOSUB 1150
500 IF I$="4" THEN GOSUB 1470
510 IF I$="5" THEN GOSUB 1690
520 IF I$="6" THEN GOSUB 2020
530 IF I$="7" THEN GOTO 2120
540 IF I$="8" THEN GOSUB 2210
550 GOTO 0310
560 REM %E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D% % % % %
570 CLS
580 PRINT ,,,,,,"DO YOU WISH TO ADD A NEW RCD?"
590 PRINT TAB 11;"(Y, N, OR M)"
600 GOSUB 2550
610 IF I$<>"Y" THEN RETURN
620 FOR X=1 TO 64
630 DIM C$(1,C(X))
640 CLS
650 PRINT AT 0,6;"%E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D"
660 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
670 PRINT AT 4,0;B$(X)
680 INPUT C$(1)
690 PRINT AT 6,0;C$(1)
700 PRINT "IS THIS CORRECT? (Y OR N)"
710 GOSUB 2550
720 IF I$<>"Y" THEN GOTO 0640
730 LET A$(1,A(X) TO B(X))=C$(1)
740 NEXT X
750 GOSUB 2410
760 RETURN
770 REM %C%H%A%N%G%E% %A% %R%E%C%O%R%D% % % % % % % %
780 CLS
790 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
800 PRINT AT 2,0;"DO YOU WISH TO CHANGE THIS RCD?"
810 PRINT AT 4,11;"(Y, N, OR M)",,,
820 FOR X=1 TO 5
830 PRINT B$(X)
840 PRINT A$(1,A(X) TO B(X))
850 NEXT X
860 GOSUB 2550
870 IF I$="M" THEN RETURN
880 IF I$="Y" THEN GOTO 0920
890 GOSUB 2410
900 GOSUB 2280
910 GOTO 0770
920 FOR X=1 TO 64
930 CLS
940 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
950 PRINT AT 2,0;"CHANGE THIS FIELD? (Y OR N)"
960 PRINT AT 4,0;B$(X)
970 PRINT A$(1,A(X) TO B(X))
980 GOSUB 2550
990 IF I$="N" THEN NEXT X
1000 IF I$="N" AND X=65 THEN GOTO 1130
1010 DIM C$(1,C(X))
1020 CLS
1030 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
1040 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
1050 PRINT AT 4,0;B$(X)
1060 INPUT C$(1)
1070 PRINT AT 6,0;C$(1)
1080 PRINT "IS THIS CORRECT? (Y OR N)"
1090 GOSUB 2550
1100 IF I$<>"Y" THEN GOTO 1020
1110 LET A$(1,A(X) TO B(X))=C$(1)
1120 NEXT X
1130 GOSUB 2410
1140 RETURN
1150 REM %D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D% % % % % % %
1160 CLS
1170 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1180 PRINT AT 2,0;"DO YOU WISH TO DISPLAY THIS RCD?"
1190 PRINT AT 4,11;"(Y, N, OR M)"
1200 FOR X=1 TO 5
1210 PRINT B$(X)
1220 PRINT A$(1,A(X) TO B(X))
1230 NEXT X
1240 GOSUB 2550
1250 IF I$="M" THEN RETURN
1260 IF I$="Y" THEN GOTO 1290
1270 GOSUB 2280
1280 GOTO 1150
1290 CLS
1300 FOR X=1 TO 64
1310 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1320 PRINT AT 2,0;"RECORD DISPLAYED IS FOR..."
1330 PRINT AT 4,0;"GEN/CODE NBR. ";A$(1, TO 5)
1340 PRINT AT 5,0;A$(1,6 TO 20)
1350 PRINT AT 6,0;A$(1,21 TO 35)
1360 PRINT AT 7,0;A$(1,36 TO 50)
1370 PRINT AT 8,0;A$(1,51 TO 65)
1380 PRINT AT 15,0;"%P%R%E%S%S% %E%N%T%E%R% %F%O%R% %N%E%X%T% %F%I%E%L%D% % % % % % "
1390 PRINT AT 16,0;"%P%R%E%S%S% %"%M%"% %T%O% %R%E%T%U%R%N% %T%O% % %M%E%N%U% % % % "
1400 PRINT AT 10,0;B$(X)
1410 PRINT AT 12,0;A$(1,A(X) TO B(X))
1420 IF INKEY$="" THEN GOTO 1420
1430 IF INKEY$="M" THEN RETURN
1440 PRINT AT 12,0;" "
1450 NEXT X
1460 RETURN
1470 REM %P%R%I%N%T% %A% %R%E%C%O%R%D% % % % % % % % %
1480 CLS
1490 PRINT AT 0,8;"%P%R%I%N%T% %A% %R%E%C%O%R%D"
1500 PRINT AT 2,0;"DO YOU WISH TO PRINT THIS RCD?"
1510 PRINT AT 4,11;"(Y, N, OR M)",,,
1520 FOR X=1 TO 5
1530 PRINT B$(X)
1540 PRINT A$(1,A(X) TO B(X))
1550 NEXT X
1560 GOSUB 2550
1570 IF I$="Y" THEN GOTO 1610
1580 IF I$="M" THEN RETURN
1590 GOSUB 2280
1600 GOTO 1470
1610 FAST
1620 FOR X=1 TO 64
1630 LPRINT B$(X)
1640 LPRINT A$(1,A(X) TO B(X))
1650 LPRINT
1660 NEXT X
1670 SLOW
1680 RETURN
1690 REM %P%R%I%N%T% %D%/%T% %D%I%R%E%C%T%O%R%Y% % % %
1700 CLS
1710 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1720 PRINT AT 4,0;"IS THE PRINTER ON ? (Y, N, OR M)"
1730 GOSUB 2550
1740 IF I$="M" THEN RETURN
1750 IF I$="Y" THEN GOTO 1790
1760 PRINT AT 12,0;"PLEASE TURN THE PRINTER ON"
1770 PRINT AT 14,0;"PRESS ENTER WHEN PRINTER IS ON"
1780 INPUT I$
1790 CLS
1800 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1810 PRINT AT 4,0;"PLACE OLD DATA TAPE IN TAPE DECK"
1820 PRINT AT 6,0;"PRESS ""PLAY"" ON TAPE DECK"
1830 PRINT AT 8,0;"PRESS ""ENTER"" ON COMPUTER"
1840 INPUT I$
1850 LPRINT "% % % % % % % DATA TAPE DIRECTORY% % % % % % ",,
1860 LPRINT "GEN/"
1870 LPRINT "CODE FIRST/LAST NAME",,,
1880 FOR X=1 TO 35
1890 RAND USR 16549
1900 DIM C$(1,36)
1910 LET C$(1)=A$(1,1 TO 5)+" "+A$(1,6 TO 20)+A$(1,51 TO 65)
1920 LET D$=""
1930 FOR Y=1 TO 36
1940 IF C$(1,Y)=" " THEN GOTO 1970
1950 LET D$=D$+C$(1,Y)
1960 IF C$(1,Y+1)=" " THEN LET D$=D$+" "
1970 NEXT Y
1980 LPRINT D$
1990 LPRINT
2000 NEXT X
2010 RETURN
2020 REM %C%O%P%Y% %D%A%T%A% %T%A%P%E% % % % % % % % %
2030 CLS
2040 PRINT ,,,,,,"HOW MANY RECORDS DO YOU WISH TO",,,"COPY? (1 TO 35)"
2050 INPUT Z
2060 IF Z>35 THEN GOTO 2020
2070 FOR X=1 TO Z
2080 GOSUB 2280
2090 GOSUB 2410
2100 NEXT X
2110 RETURN
2120 REM %C%O%P%Y% %P%R%O%G%R%A%M% % % % % % % % % % %
2130 CLS
2140 PRINT ,,,,,,"PLACE BLANK PROGRAM TAPE IN TAPE",,"DECK, PRESS ""PLAY/RECORD"" ON",,,"TAPE DECK, PRESS ""ENTER"" ON",,,"COMPUTER."
2150 INPUT I$
2160 CLS
2170 SAVE "FORMATTE%R"
2180 PRINT ,,,,,,"PRESS ""STOP"" ON TAPE DECK",,,"PRESS ""ENTER"" ON COMPUTER."
2190 INPUT I$
2200 GOTO 0310
2210 REM %E%N%D% %P%R%O%G%R%A%M% % % % % % % % % % % %
2220 CLS
2230 PRINT ,,,,,,"ARE YOU SURE YOU WANT TO QUIT?"
2240 PRINT TAB 11;"(Y, N, OR M)"
2250 GOSUB 2550
2260 IF I$="Y" THEN NEW
2270 RETURN
2280 REM %R%E%A%D% %R%E%C%O%R%D% %O%N% %T%A%P%E% % % %
2290 CLS
2300 PRINT AT 2,0;"PLACE OLD DATA TAPE IN TAPE DECK"
2310 PRINT AT 4,0;"PRESS ""PLAY"" ON TAPE DECK"
2320 PRINT AT 6,0;"PRESS ""ENTER"" ON COMPUTER"
2330 INPUT Z$
2340 RAND USR 16549
2350 CLS
2360 SLOW
2370 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2380 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2390 INPUT Z$
2400 RETURN
2410 REM %W%R%I%T%E% %R%E%C%O%R%D% %O%N% %T%A%P%E% % %
2420 CLS
2430 PRINT AT 2,0;"PLACE NEW DATA TAPE IN TAPE DECK"
2440 PRINT AT 4,0;"PRESS ""PLAY/RECORD"" ON TAPE"
2450 PRINT "DECK"
2460 PRINT AT 7,0;"PRESS ""ENTER"" ON COMPUTER"
2470 INPUT Z$
2480 RAND USR 16514
2490 CLS
2500 SLOW
2510 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2520 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2530 INPUT Z$
2540 RETURN
2550 REM %I%N%P%U%T% %C%H%E%C%K%E%R% %(%Y% %O%R% %N%)%
2560 IF INKEY$="" THEN GOTO 2550
2570 LET I$=INKEY$
2580 IF I$<>"Y" AND I$<>"N" AND I$<>"M" THEN GOTO 2550
2590 RETURN
2600 SAVE "1016%0"
2610 GOTO 300
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
B\B1\F4\C9\CD\E7
Skip to content
Record Formatter
This file is part of Timex Sinclair Public Domain Library Tape 1003
. Download the collection to get this file.
Record Formatter Ver. 1 is a ZX81/TS1000 database management program that allows users to define up to 64 custom fields, then enter, display, edit, and print records stored in a 1,459-character string array. Tape I/O is handled by two machine-code routines embedded in the line-10 REM statement: one at USR 16514 writes records to tape and one at USR 16549 reads them back, called via RAND USR. The program uses a packed record layout where each field’s start and end positions are tracked in parallel numeric arrays A() and B(), allowing substring slicing of the master string A$(1). A directory-printing routine compresses data by stripping redundant spaces before sending output to the printer via LPRINT.
Program Analysis
Program Structure
The program is organized into clearly labeled sections using inverse-text REM statements as headers. Execution begins at line 10 (which contains machine code) and proceeds through initialization before entering the main menu loop.
- Lines 10–20: Machine code in REM; program identity label
- Lines 30–80: Array and variable initialization
- Lines 100–180: Field definition loop (up to 64 fields)
- Lines 190–300: Print record layout to printer
- Lines 310–550: Main menu and dispatch
- Lines 560–760: Enter new record subroutine
- Lines 770–1140: Change a record subroutine
- Lines 1150–1460: Display a record subroutine
- Lines 1470–1680: Print a record subroutine
- Lines 1690–2010: Print data tape directory subroutine
- Lines 2020–2110: Copy data tape subroutine
- Lines 2120–2200: Copy program subroutine
- Lines 2210–2270: End program subroutine
- Lines 2280–2400: Read record from tape subroutine
- Lines 2410–2540: Write record to tape subroutine
- Lines 2550–2590: Input checker subroutine (Y/N/M)
- Lines 2600–2610: SAVE and restart
Machine Code Routines
Two machine-code routines are embedded in the REM statement at line 10. They are invoked via RAND USR 16514 (write record) and RAND USR 16549 (read record). The ZX81 system variables place the start of the BASIC program at address 16509 (407Fh); the REM data begins at offset 5 (after the line number, length, and REM token), so the routines land at 16514 and 16549 respectively.
Disassembly of the REM bytes reveals two distinct routines:
Offset Address Bytes Mnemonic Notes 0 16514 CD E7 02 CALL 02E7h ZX81 ROM: slow-speed display/sync entry 3 16517 06 0E LD B,0Eh Loop counter = 14 5 16519 21 00 FF LD HL,FF00h Start of candidate address range 8 16522 2B DEC HL Step HL down 9 16523 7C LD A,H 10 16524 B5 OR L Check HL=0 11 16525 20 FB JR NZ,-5 Loop until zero 13 16527 10 F6 DJNZ -10 Outer timing loop 15 16529 2A 10 40 LD HL,(4010h) Load A$ descriptor pointer 18 16532 23 INC HL 19 16533 4E LD C,(HL) Low byte of length 20 16534 23 INC HL 21 16535 46 LD B,(HL) High byte of length 22 16536 23 INC HL 23 16537 C5 PUSH BC Save byte count 24 16538 5E LD E,(HL) Data address low 25 16539 CD 1F 03 CALL 031Fh ROM: output byte to tape 28 16542 C1 POP BC 29 16543 0B DEC BC 30 16544 78 LD A,B 31 16545 B1 OR C Check BC=0 32 16546 20 F4 JR NZ,-12 Write loop 34 16548 C9 RET End of write routine 35 16549 CD E7 02 CALL 02E7h Read routine starts here 38 16552 2A 10 40 LD HL,(4010h) Load A$ descriptor … … 1E 08 DB FE D3 FF… (tape read loop) Reads bytes from EAR port, reconstructs A$
The read routine polls the EAR port (DB FE = IN A,(FEh)) and outputs to FFh (D3 FF = OUT (FFh),A), using rotate and bit-test instructions to decode the Manchester-like tape signal. The length of data transferred is derived from the A$ array descriptor at address 4010h, so the routines always read/write exactly 1,459 bytes — the full record.
Data Layout
The master record is held in A$(1), a single 1,459-character string (the first and only row of the 1×1459 DIM). Field positions are pre-computed during setup:
A(X) — start position of field X within A$(1)
B(X) — end position of field X within A$(1)
C(X) — declared length of field X
B$(X) — 32-character field title (DIM B$(64,32))
Field data is read and written using ZX81 substring slicing: A$(1,A(X) TO B(X)). A temporary single-row string C$(1,C(X)) is re-DIMmed for each field during entry and editing to enforce the correct field width.
Menu and Navigation
The main menu at line 310 uses a single-keypress idiom: INKEY$ is tested in a tight loop at line 450, then captured at line 460 and dispatched via a cascade of IF … THEN GOSUB / GOTO statements. The reusable input checker subroutine at line 2550 accepts only Y, N, or M (Menu return), providing consistent three-way navigation throughout.
Key BASIC Idioms
- RAND USR — used to call machine-code routines without storing a return value, discarding the USR result safely.
- Re-DIM inside loop —
DIM C$(1,C(X)) at lines 630 and 1010 re-allocates C$ each iteration to match the current field’s length, ensuring INPUT fills exactly the right number of characters.
- VAL-style line targets — line numbers in
GOTO/GOSUB are written with leading zeros (e.g., GOTO 0450, GOSUB 0560), a common ZX81 style that has no runtime effect but aids readability.
- FAST/SLOW bracketing — printer output blocks (lines 190–300 and 1610–1670) are wrapped in
FAST/SLOW to disable the display interrupt and speed up LPRINT operations.
Directory Space-Compression Routine
The tape directory printer (lines 1930–1970) implements a simple run-length space compressor: it builds D$ by copying non-space characters from C$(1) and inserting a single space only when the next character is a space, collapsing multiple spaces into one. This produces compact, human-readable directory entries from fixed-width fields.
Notable Bugs and Anomalies
- Line 1000 unreachable check —
IF I$="N" AND X=65 THEN GOTO 1130 follows IF I$="N" THEN NEXT X at line 990. If I$="N", control jumps to NEXT X and never reaches line 1000; the X=65 boundary check is therefore dead code. The loop termination after all 64 fields are processed falls through to line 1130 naturally via the FOR/NEXT mechanism.
- Field count vs. tape block size — The program defines up to 64 fields but the directory loop at line 1880 is hard-coded to
FOR X=1 TO 35, implying the data tape is expected to hold exactly 35 records. There is no run-time check that the total declared field lengths do not exceed 1,459.
- Line 1430 double-read of INKEY$ — After the wait loop at line 1420 confirms a key is pressed, line 1430 calls
INKEY$ again. On a fast machine this could return an empty string if the key was released between the two polls, potentially failing to detect the M keypress.
- Line 2610 —
GOTO 300 targets line 300 (SLOW), not the menu at line 310, meaning after a SAVE the machine briefly executes SLOW before falling into the menu — harmless but slightly inconsistent with the direct GOTO 0310 used elsewhere.
Content
Source Code
10 REM \CD\E7\02\06\0E\21\00\FF\2B\7C\B5\20\FB\10\F6\2A\10\40\23\4E\23\46\23\C5\5E\CD\1F\03\C1\0B\78\B1\20\F4\C9\CD\E7\02\2A\10\40\23\4E\23\46\23\C5\1E\08\DB\FE\D3\FF\17\30\F9\0E\94\06\1A\0D\DB\FE\17\CB\79\79\38\F5\10\F5\20\04\FE\56\30\E4\3F\CB\16\1D\20\DE\C1\0B\78\B1\C8\18\D3
20 REM %P%R%O%G%R%A%M% %S%E%T% %U%P% % % % % % % % %
30 DIM A$(1,1459)
40 DIM B$(64,32)
50 DIM A(64)
60 DIM B(64)
70 DIM C(64)
80 LET M=310
90 LET W=1
100 FOR X=1 TO 64
110 PRINT AT 12,0;"ENTER FIELD TITLE (32 POS)"
120 INPUT B$(X)
130 PRINT AT 12,0;"ENTER LENGTH OF FIELD "
140 INPUT C(X)
150 LET A(X)=W
160 LET B(X)=W+C(X)-1
170 LET W=W+C(X)
180 NEXT X
190 FAST
200 LPRINT "RECORD LAYOUT"
210 LPRINT
220 LPRINT "FIELD NAME"
230 LPRINT "ST POS END POS LENGTH FLD NBR."
240 LPRINT "--------------------------------"
250 FOR X=1 TO 64
260 LPRINT B$(X)
270 LPRINT A(X);TAB 8;B(X);TAB 17;C(X);TAB 25;X
280 LPRINT
290 NEXT X
300 SLOW
310 REM %M%E%N%U% % % % % % % % % % % % % % % % % % %
320 CLS
330 PRINT TAB 5;"RECORD FORMATTER VER.1"
340 PRINT TAB 3;"COPYRIGHT 1985 TIM L. WARD",,,
350 PRINT "DO YOU WISH TO..",,,
360 PRINT "1)...ENTER A NEW RECORD?",,,
370 PRINT "2)...CHANGE A RECORD?",,,
380 PRINT "3)...DISPLAY A RECORD?",,,
390 PRINT "4)...PRINT A RECORD?",,,
400 PRINT "5)...PRINT DATA TAPE DIRECTORY?",,,
410 PRINT "6)...COPY DATA TAPE?",,,
420 PRINT "7)...COPY PROGRAM?",,,
430 PRINT "8)...END PROGRAM?",,,
440 PRINT "ENTER NBR. OF SELECTION"
450 IF INKEY$="" THEN GOTO 0450
460 LET I$=INKEY$
470 IF I$="1" THEN GOSUB 0560
480 IF I$="2" THEN GOSUB 0770
490 IF I$="3" THEN GOSUB 1150
500 IF I$="4" THEN GOSUB 1470
510 IF I$="5" THEN GOSUB 1690
520 IF I$="6" THEN GOSUB 2020
530 IF I$="7" THEN GOTO 2120
540 IF I$="8" THEN GOSUB 2210
550 GOTO 0310
560 REM %E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D% % % % %
570 CLS
580 PRINT ,,,,,,"DO YOU WISH TO ADD A NEW RCD?"
590 PRINT TAB 11;"(Y, N, OR M)"
600 GOSUB 2550
610 IF I$<>"Y" THEN RETURN
620 FOR X=1 TO 64
630 DIM C$(1,C(X))
640 CLS
650 PRINT AT 0,6;"%E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D"
660 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
670 PRINT AT 4,0;B$(X)
680 INPUT C$(1)
690 PRINT AT 6,0;C$(1)
700 PRINT "IS THIS CORRECT? (Y OR N)"
710 GOSUB 2550
720 IF I$<>"Y" THEN GOTO 0640
730 LET A$(1,A(X) TO B(X))=C$(1)
740 NEXT X
750 GOSUB 2410
760 RETURN
770 REM %C%H%A%N%G%E% %A% %R%E%C%O%R%D% % % % % % % %
780 CLS
790 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
800 PRINT AT 2,0;"DO YOU WISH TO CHANGE THIS RCD?"
810 PRINT AT 4,11;"(Y, N, OR M)",,,
820 FOR X=1 TO 5
830 PRINT B$(X)
840 PRINT A$(1,A(X) TO B(X))
850 NEXT X
860 GOSUB 2550
870 IF I$="M" THEN RETURN
880 IF I$="Y" THEN GOTO 0920
890 GOSUB 2410
900 GOSUB 2280
910 GOTO 0770
920 FOR X=1 TO 64
930 CLS
940 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
950 PRINT AT 2,0;"CHANGE THIS FIELD? (Y OR N)"
960 PRINT AT 4,0;B$(X)
970 PRINT A$(1,A(X) TO B(X))
980 GOSUB 2550
990 IF I$="N" THEN NEXT X
1000 IF I$="N" AND X=65 THEN GOTO 1130
1010 DIM C$(1,C(X))
1020 CLS
1030 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
1040 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
1050 PRINT AT 4,0;B$(X)
1060 INPUT C$(1)
1070 PRINT AT 6,0;C$(1)
1080 PRINT "IS THIS CORRECT? (Y OR N)"
1090 GOSUB 2550
1100 IF I$<>"Y" THEN GOTO 1020
1110 LET A$(1,A(X) TO B(X))=C$(1)
1120 NEXT X
1130 GOSUB 2410
1140 RETURN
1150 REM %D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D% % % % % % %
1160 CLS
1170 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1180 PRINT AT 2,0;"DO YOU WISH TO DISPLAY THIS RCD?"
1190 PRINT AT 4,11;"(Y, N, OR M)"
1200 FOR X=1 TO 5
1210 PRINT B$(X)
1220 PRINT A$(1,A(X) TO B(X))
1230 NEXT X
1240 GOSUB 2550
1250 IF I$="M" THEN RETURN
1260 IF I$="Y" THEN GOTO 1290
1270 GOSUB 2280
1280 GOTO 1150
1290 CLS
1300 FOR X=1 TO 64
1310 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1320 PRINT AT 2,0;"RECORD DISPLAYED IS FOR..."
1330 PRINT AT 4,0;"GEN/CODE NBR. ";A$(1, TO 5)
1340 PRINT AT 5,0;A$(1,6 TO 20)
1350 PRINT AT 6,0;A$(1,21 TO 35)
1360 PRINT AT 7,0;A$(1,36 TO 50)
1370 PRINT AT 8,0;A$(1,51 TO 65)
1380 PRINT AT 15,0;"%P%R%E%S%S% %E%N%T%E%R% %F%O%R% %N%E%X%T% %F%I%E%L%D% % % % % % "
1390 PRINT AT 16,0;"%P%R%E%S%S% %"%M%"% %T%O% %R%E%T%U%R%N% %T%O% % %M%E%N%U% % % % "
1400 PRINT AT 10,0;B$(X)
1410 PRINT AT 12,0;A$(1,A(X) TO B(X))
1420 IF INKEY$="" THEN GOTO 1420
1430 IF INKEY$="M" THEN RETURN
1440 PRINT AT 12,0;" "
1450 NEXT X
1460 RETURN
1470 REM %P%R%I%N%T% %A% %R%E%C%O%R%D% % % % % % % % %
1480 CLS
1490 PRINT AT 0,8;"%P%R%I%N%T% %A% %R%E%C%O%R%D"
1500 PRINT AT 2,0;"DO YOU WISH TO PRINT THIS RCD?"
1510 PRINT AT 4,11;"(Y, N, OR M)",,,
1520 FOR X=1 TO 5
1530 PRINT B$(X)
1540 PRINT A$(1,A(X) TO B(X))
1550 NEXT X
1560 GOSUB 2550
1570 IF I$="Y" THEN GOTO 1610
1580 IF I$="M" THEN RETURN
1590 GOSUB 2280
1600 GOTO 1470
1610 FAST
1620 FOR X=1 TO 64
1630 LPRINT B$(X)
1640 LPRINT A$(1,A(X) TO B(X))
1650 LPRINT
1660 NEXT X
1670 SLOW
1680 RETURN
1690 REM %P%R%I%N%T% %D%/%T% %D%I%R%E%C%T%O%R%Y% % % %
1700 CLS
1710 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1720 PRINT AT 4,0;"IS THE PRINTER ON ? (Y, N, OR M)"
1730 GOSUB 2550
1740 IF I$="M" THEN RETURN
1750 IF I$="Y" THEN GOTO 1790
1760 PRINT AT 12,0;"PLEASE TURN THE PRINTER ON"
1770 PRINT AT 14,0;"PRESS ENTER WHEN PRINTER IS ON"
1780 INPUT I$
1790 CLS
1800 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1810 PRINT AT 4,0;"PLACE OLD DATA TAPE IN TAPE DECK"
1820 PRINT AT 6,0;"PRESS ""PLAY"" ON TAPE DECK"
1830 PRINT AT 8,0;"PRESS ""ENTER"" ON COMPUTER"
1840 INPUT I$
1850 LPRINT "% % % % % % % DATA TAPE DIRECTORY% % % % % % ",,
1860 LPRINT "GEN/"
1870 LPRINT "CODE FIRST/LAST NAME",,,
1880 FOR X=1 TO 35
1890 RAND USR 16549
1900 DIM C$(1,36)
1910 LET C$(1)=A$(1,1 TO 5)+" "+A$(1,6 TO 20)+A$(1,51 TO 65)
1920 LET D$=""
1930 FOR Y=1 TO 36
1940 IF C$(1,Y)=" " THEN GOTO 1970
1950 LET D$=D$+C$(1,Y)
1960 IF C$(1,Y+1)=" " THEN LET D$=D$+" "
1970 NEXT Y
1980 LPRINT D$
1990 LPRINT
2000 NEXT X
2010 RETURN
2020 REM %C%O%P%Y% %D%A%T%A% %T%A%P%E% % % % % % % % %
2030 CLS
2040 PRINT ,,,,,,"HOW MANY RECORDS DO YOU WISH TO",,,"COPY? (1 TO 35)"
2050 INPUT Z
2060 IF Z>35 THEN GOTO 2020
2070 FOR X=1 TO Z
2080 GOSUB 2280
2090 GOSUB 2410
2100 NEXT X
2110 RETURN
2120 REM %C%O%P%Y% %P%R%O%G%R%A%M% % % % % % % % % % %
2130 CLS
2140 PRINT ,,,,,,"PLACE BLANK PROGRAM TAPE IN TAPE",,"DECK, PRESS ""PLAY/RECORD"" ON",,,"TAPE DECK, PRESS ""ENTER"" ON",,,"COMPUTER."
2150 INPUT I$
2160 CLS
2170 SAVE "FORMATTE%R"
2180 PRINT ,,,,,,"PRESS ""STOP"" ON TAPE DECK",,,"PRESS ""ENTER"" ON COMPUTER."
2190 INPUT I$
2200 GOTO 0310
2210 REM %E%N%D% %P%R%O%G%R%A%M% % % % % % % % % % % %
2220 CLS
2230 PRINT ,,,,,,"ARE YOU SURE YOU WANT TO QUIT?"
2240 PRINT TAB 11;"(Y, N, OR M)"
2250 GOSUB 2550
2260 IF I$="Y" THEN NEW
2270 RETURN
2280 REM %R%E%A%D% %R%E%C%O%R%D% %O%N% %T%A%P%E% % % %
2290 CLS
2300 PRINT AT 2,0;"PLACE OLD DATA TAPE IN TAPE DECK"
2310 PRINT AT 4,0;"PRESS ""PLAY"" ON TAPE DECK"
2320 PRINT AT 6,0;"PRESS ""ENTER"" ON COMPUTER"
2330 INPUT Z$
2340 RAND USR 16549
2350 CLS
2360 SLOW
2370 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2380 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2390 INPUT Z$
2400 RETURN
2410 REM %W%R%I%T%E% %R%E%C%O%R%D% %O%N% %T%A%P%E% % %
2420 CLS
2430 PRINT AT 2,0;"PLACE NEW DATA TAPE IN TAPE DECK"
2440 PRINT AT 4,0;"PRESS ""PLAY/RECORD"" ON TAPE"
2450 PRINT "DECK"
2460 PRINT AT 7,0;"PRESS ""ENTER"" ON COMPUTER"
2470 INPUT Z$
2480 RAND USR 16514
2490 CLS
2500 SLOW
2510 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2520 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2530 INPUT Z$
2540 RETURN
2550 REM %I%N%P%U%T% %C%H%E%C%K%E%R% %(%Y% %O%R% %N%)%
2560 IF INKEY$="" THEN GOTO 2550
2570 LET I$=INKEY$
2580 IF I$<>"Y" AND I$<>"N" AND I$<>"M" THEN GOTO 2550
2590 RETURN
2600 SAVE "1016%0"
2610 GOTO 300
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
Skip to content
Record Formatter
This file is part of Timex Sinclair Public Domain Library Tape 1003
. Download the collection to get this file.
Record Formatter Ver. 1 is a ZX81/TS1000 database management program that allows users to define up to 64 custom fields, then enter, display, edit, and print records stored in a 1,459-character string array. Tape I/O is handled by two machine-code routines embedded in the line-10 REM statement: one at USR 16514 writes records to tape and one at USR 16549 reads them back, called via RAND USR. The program uses a packed record layout where each field’s start and end positions are tracked in parallel numeric arrays A() and B(), allowing substring slicing of the master string A$(1). A directory-printing routine compresses data by stripping redundant spaces before sending output to the printer via LPRINT.
Program Analysis
Program Structure
The program is organized into clearly labeled sections using inverse-text REM statements as headers. Execution begins at line 10 (which contains machine code) and proceeds through initialization before entering the main menu loop.
- Lines 10–20: Machine code in REM; program identity label
- Lines 30–80: Array and variable initialization
- Lines 100–180: Field definition loop (up to 64 fields)
- Lines 190–300: Print record layout to printer
- Lines 310–550: Main menu and dispatch
- Lines 560–760: Enter new record subroutine
- Lines 770–1140: Change a record subroutine
- Lines 1150–1460: Display a record subroutine
- Lines 1470–1680: Print a record subroutine
- Lines 1690–2010: Print data tape directory subroutine
- Lines 2020–2110: Copy data tape subroutine
- Lines 2120–2200: Copy program subroutine
- Lines 2210–2270: End program subroutine
- Lines 2280–2400: Read record from tape subroutine
- Lines 2410–2540: Write record to tape subroutine
- Lines 2550–2590: Input checker subroutine (Y/N/M)
- Lines 2600–2610: SAVE and restart
Machine Code Routines
Two machine-code routines are embedded in the REM statement at line 10. They are invoked via RAND USR 16514 (write record) and RAND USR 16549 (read record). The ZX81 system variables place the start of the BASIC program at address 16509 (407Fh); the REM data begins at offset 5 (after the line number, length, and REM token), so the routines land at 16514 and 16549 respectively.
Disassembly of the REM bytes reveals two distinct routines:
Offset Address Bytes Mnemonic Notes 0 16514 CD E7 02 CALL 02E7h ZX81 ROM: slow-speed display/sync entry 3 16517 06 0E LD B,0Eh Loop counter = 14 5 16519 21 00 FF LD HL,FF00h Start of candidate address range 8 16522 2B DEC HL Step HL down 9 16523 7C LD A,H 10 16524 B5 OR L Check HL=0 11 16525 20 FB JR NZ,-5 Loop until zero 13 16527 10 F6 DJNZ -10 Outer timing loop 15 16529 2A 10 40 LD HL,(4010h) Load A$ descriptor pointer 18 16532 23 INC HL 19 16533 4E LD C,(HL) Low byte of length 20 16534 23 INC HL 21 16535 46 LD B,(HL) High byte of length 22 16536 23 INC HL 23 16537 C5 PUSH BC Save byte count 24 16538 5E LD E,(HL) Data address low 25 16539 CD 1F 03 CALL 031Fh ROM: output byte to tape 28 16542 C1 POP BC 29 16543 0B DEC BC 30 16544 78 LD A,B 31 16545 B1 OR C Check BC=0 32 16546 20 F4 JR NZ,-12 Write loop 34 16548 C9 RET End of write routine 35 16549 CD E7 02 CALL 02E7h Read routine starts here 38 16552 2A 10 40 LD HL,(4010h) Load A$ descriptor … … 1E 08 DB FE D3 FF… (tape read loop) Reads bytes from EAR port, reconstructs A$
The read routine polls the EAR port (DB FE = IN A,(FEh)) and outputs to FFh (D3 FF = OUT (FFh),A), using rotate and bit-test instructions to decode the Manchester-like tape signal. The length of data transferred is derived from the A$ array descriptor at address 4010h, so the routines always read/write exactly 1,459 bytes — the full record.
Data Layout
The master record is held in A$(1), a single 1,459-character string (the first and only row of the 1×1459 DIM). Field positions are pre-computed during setup:
A(X) — start position of field X within A$(1)
B(X) — end position of field X within A$(1)
C(X) — declared length of field X
B$(X) — 32-character field title (DIM B$(64,32))
Field data is read and written using ZX81 substring slicing: A$(1,A(X) TO B(X)). A temporary single-row string C$(1,C(X)) is re-DIMmed for each field during entry and editing to enforce the correct field width.
Menu and Navigation
The main menu at line 310 uses a single-keypress idiom: INKEY$ is tested in a tight loop at line 450, then captured at line 460 and dispatched via a cascade of IF … THEN GOSUB / GOTO statements. The reusable input checker subroutine at line 2550 accepts only Y, N, or M (Menu return), providing consistent three-way navigation throughout.
Key BASIC Idioms
- RAND USR — used to call machine-code routines without storing a return value, discarding the USR result safely.
- Re-DIM inside loop —
DIM C$(1,C(X)) at lines 630 and 1010 re-allocates C$ each iteration to match the current field’s length, ensuring INPUT fills exactly the right number of characters.
- VAL-style line targets — line numbers in
GOTO/GOSUB are written with leading zeros (e.g., GOTO 0450, GOSUB 0560), a common ZX81 style that has no runtime effect but aids readability.
- FAST/SLOW bracketing — printer output blocks (lines 190–300 and 1610–1670) are wrapped in
FAST/SLOW to disable the display interrupt and speed up LPRINT operations.
Directory Space-Compression Routine
The tape directory printer (lines 1930–1970) implements a simple run-length space compressor: it builds D$ by copying non-space characters from C$(1) and inserting a single space only when the next character is a space, collapsing multiple spaces into one. This produces compact, human-readable directory entries from fixed-width fields.
Notable Bugs and Anomalies
- Line 1000 unreachable check —
IF I$="N" AND X=65 THEN GOTO 1130 follows IF I$="N" THEN NEXT X at line 990. If I$="N", control jumps to NEXT X and never reaches line 1000; the X=65 boundary check is therefore dead code. The loop termination after all 64 fields are processed falls through to line 1130 naturally via the FOR/NEXT mechanism.
- Field count vs. tape block size — The program defines up to 64 fields but the directory loop at line 1880 is hard-coded to
FOR X=1 TO 35, implying the data tape is expected to hold exactly 35 records. There is no run-time check that the total declared field lengths do not exceed 1,459.
- Line 1430 double-read of INKEY$ — After the wait loop at line 1420 confirms a key is pressed, line 1430 calls
INKEY$ again. On a fast machine this could return an empty string if the key was released between the two polls, potentially failing to detect the M keypress.
- Line 2610 —
GOTO 300 targets line 300 (SLOW), not the menu at line 310, meaning after a SAVE the machine briefly executes SLOW before falling into the menu — harmless but slightly inconsistent with the direct GOTO 0310 used elsewhere.
Content
Source Code
10 REM \CD\E7\02\06\0E\21\00\FF\2B\7C\B5\20\FB\10\F6\2A\10\40\23\4E\23\46\23\C5\5E\CD\1F\03\C1\0B\78\B1\20\F4\C9\CD\E7\02\2A\10\40\23\4E\23\46\23\C5\1E\08\DB\FE\D3\FF\17\30\F9\0E\94\06\1A\0D\DB\FE\17\CB\79\79\38\F5\10\F5\20\04\FE\56\30\E4\3F\CB\16\1D\20\DE\C1\0B\78\B1\C8\18\D3
20 REM %P%R%O%G%R%A%M% %S%E%T% %U%P% % % % % % % % %
30 DIM A$(1,1459)
40 DIM B$(64,32)
50 DIM A(64)
60 DIM B(64)
70 DIM C(64)
80 LET M=310
90 LET W=1
100 FOR X=1 TO 64
110 PRINT AT 12,0;"ENTER FIELD TITLE (32 POS)"
120 INPUT B$(X)
130 PRINT AT 12,0;"ENTER LENGTH OF FIELD "
140 INPUT C(X)
150 LET A(X)=W
160 LET B(X)=W+C(X)-1
170 LET W=W+C(X)
180 NEXT X
190 FAST
200 LPRINT "RECORD LAYOUT"
210 LPRINT
220 LPRINT "FIELD NAME"
230 LPRINT "ST POS END POS LENGTH FLD NBR."
240 LPRINT "--------------------------------"
250 FOR X=1 TO 64
260 LPRINT B$(X)
270 LPRINT A(X);TAB 8;B(X);TAB 17;C(X);TAB 25;X
280 LPRINT
290 NEXT X
300 SLOW
310 REM %M%E%N%U% % % % % % % % % % % % % % % % % % %
320 CLS
330 PRINT TAB 5;"RECORD FORMATTER VER.1"
340 PRINT TAB 3;"COPYRIGHT 1985 TIM L. WARD",,,
350 PRINT "DO YOU WISH TO..",,,
360 PRINT "1)...ENTER A NEW RECORD?",,,
370 PRINT "2)...CHANGE A RECORD?",,,
380 PRINT "3)...DISPLAY A RECORD?",,,
390 PRINT "4)...PRINT A RECORD?",,,
400 PRINT "5)...PRINT DATA TAPE DIRECTORY?",,,
410 PRINT "6)...COPY DATA TAPE?",,,
420 PRINT "7)...COPY PROGRAM?",,,
430 PRINT "8)...END PROGRAM?",,,
440 PRINT "ENTER NBR. OF SELECTION"
450 IF INKEY$="" THEN GOTO 0450
460 LET I$=INKEY$
470 IF I$="1" THEN GOSUB 0560
480 IF I$="2" THEN GOSUB 0770
490 IF I$="3" THEN GOSUB 1150
500 IF I$="4" THEN GOSUB 1470
510 IF I$="5" THEN GOSUB 1690
520 IF I$="6" THEN GOSUB 2020
530 IF I$="7" THEN GOTO 2120
540 IF I$="8" THEN GOSUB 2210
550 GOTO 0310
560 REM %E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D% % % % %
570 CLS
580 PRINT ,,,,,,"DO YOU WISH TO ADD A NEW RCD?"
590 PRINT TAB 11;"(Y, N, OR M)"
600 GOSUB 2550
610 IF I$<>"Y" THEN RETURN
620 FOR X=1 TO 64
630 DIM C$(1,C(X))
640 CLS
650 PRINT AT 0,6;"%E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D"
660 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
670 PRINT AT 4,0;B$(X)
680 INPUT C$(1)
690 PRINT AT 6,0;C$(1)
700 PRINT "IS THIS CORRECT? (Y OR N)"
710 GOSUB 2550
720 IF I$<>"Y" THEN GOTO 0640
730 LET A$(1,A(X) TO B(X))=C$(1)
740 NEXT X
750 GOSUB 2410
760 RETURN
770 REM %C%H%A%N%G%E% %A% %R%E%C%O%R%D% % % % % % % %
780 CLS
790 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
800 PRINT AT 2,0;"DO YOU WISH TO CHANGE THIS RCD?"
810 PRINT AT 4,11;"(Y, N, OR M)",,,
820 FOR X=1 TO 5
830 PRINT B$(X)
840 PRINT A$(1,A(X) TO B(X))
850 NEXT X
860 GOSUB 2550
870 IF I$="M" THEN RETURN
880 IF I$="Y" THEN GOTO 0920
890 GOSUB 2410
900 GOSUB 2280
910 GOTO 0770
920 FOR X=1 TO 64
930 CLS
940 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
950 PRINT AT 2,0;"CHANGE THIS FIELD? (Y OR N)"
960 PRINT AT 4,0;B$(X)
970 PRINT A$(1,A(X) TO B(X))
980 GOSUB 2550
990 IF I$="N" THEN NEXT X
1000 IF I$="N" AND X=65 THEN GOTO 1130
1010 DIM C$(1,C(X))
1020 CLS
1030 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
1040 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
1050 PRINT AT 4,0;B$(X)
1060 INPUT C$(1)
1070 PRINT AT 6,0;C$(1)
1080 PRINT "IS THIS CORRECT? (Y OR N)"
1090 GOSUB 2550
1100 IF I$<>"Y" THEN GOTO 1020
1110 LET A$(1,A(X) TO B(X))=C$(1)
1120 NEXT X
1130 GOSUB 2410
1140 RETURN
1150 REM %D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D% % % % % % %
1160 CLS
1170 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1180 PRINT AT 2,0;"DO YOU WISH TO DISPLAY THIS RCD?"
1190 PRINT AT 4,11;"(Y, N, OR M)"
1200 FOR X=1 TO 5
1210 PRINT B$(X)
1220 PRINT A$(1,A(X) TO B(X))
1230 NEXT X
1240 GOSUB 2550
1250 IF I$="M" THEN RETURN
1260 IF I$="Y" THEN GOTO 1290
1270 GOSUB 2280
1280 GOTO 1150
1290 CLS
1300 FOR X=1 TO 64
1310 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1320 PRINT AT 2,0;"RECORD DISPLAYED IS FOR..."
1330 PRINT AT 4,0;"GEN/CODE NBR. ";A$(1, TO 5)
1340 PRINT AT 5,0;A$(1,6 TO 20)
1350 PRINT AT 6,0;A$(1,21 TO 35)
1360 PRINT AT 7,0;A$(1,36 TO 50)
1370 PRINT AT 8,0;A$(1,51 TO 65)
1380 PRINT AT 15,0;"%P%R%E%S%S% %E%N%T%E%R% %F%O%R% %N%E%X%T% %F%I%E%L%D% % % % % % "
1390 PRINT AT 16,0;"%P%R%E%S%S% %"%M%"% %T%O% %R%E%T%U%R%N% %T%O% % %M%E%N%U% % % % "
1400 PRINT AT 10,0;B$(X)
1410 PRINT AT 12,0;A$(1,A(X) TO B(X))
1420 IF INKEY$="" THEN GOTO 1420
1430 IF INKEY$="M" THEN RETURN
1440 PRINT AT 12,0;" "
1450 NEXT X
1460 RETURN
1470 REM %P%R%I%N%T% %A% %R%E%C%O%R%D% % % % % % % % %
1480 CLS
1490 PRINT AT 0,8;"%P%R%I%N%T% %A% %R%E%C%O%R%D"
1500 PRINT AT 2,0;"DO YOU WISH TO PRINT THIS RCD?"
1510 PRINT AT 4,11;"(Y, N, OR M)",,,
1520 FOR X=1 TO 5
1530 PRINT B$(X)
1540 PRINT A$(1,A(X) TO B(X))
1550 NEXT X
1560 GOSUB 2550
1570 IF I$="Y" THEN GOTO 1610
1580 IF I$="M" THEN RETURN
1590 GOSUB 2280
1600 GOTO 1470
1610 FAST
1620 FOR X=1 TO 64
1630 LPRINT B$(X)
1640 LPRINT A$(1,A(X) TO B(X))
1650 LPRINT
1660 NEXT X
1670 SLOW
1680 RETURN
1690 REM %P%R%I%N%T% %D%/%T% %D%I%R%E%C%T%O%R%Y% % % %
1700 CLS
1710 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1720 PRINT AT 4,0;"IS THE PRINTER ON ? (Y, N, OR M)"
1730 GOSUB 2550
1740 IF I$="M" THEN RETURN
1750 IF I$="Y" THEN GOTO 1790
1760 PRINT AT 12,0;"PLEASE TURN THE PRINTER ON"
1770 PRINT AT 14,0;"PRESS ENTER WHEN PRINTER IS ON"
1780 INPUT I$
1790 CLS
1800 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1810 PRINT AT 4,0;"PLACE OLD DATA TAPE IN TAPE DECK"
1820 PRINT AT 6,0;"PRESS ""PLAY"" ON TAPE DECK"
1830 PRINT AT 8,0;"PRESS ""ENTER"" ON COMPUTER"
1840 INPUT I$
1850 LPRINT "% % % % % % % DATA TAPE DIRECTORY% % % % % % ",,
1860 LPRINT "GEN/"
1870 LPRINT "CODE FIRST/LAST NAME",,,
1880 FOR X=1 TO 35
1890 RAND USR 16549
1900 DIM C$(1,36)
1910 LET C$(1)=A$(1,1 TO 5)+" "+A$(1,6 TO 20)+A$(1,51 TO 65)
1920 LET D$=""
1930 FOR Y=1 TO 36
1940 IF C$(1,Y)=" " THEN GOTO 1970
1950 LET D$=D$+C$(1,Y)
1960 IF C$(1,Y+1)=" " THEN LET D$=D$+" "
1970 NEXT Y
1980 LPRINT D$
1990 LPRINT
2000 NEXT X
2010 RETURN
2020 REM %C%O%P%Y% %D%A%T%A% %T%A%P%E% % % % % % % % %
2030 CLS
2040 PRINT ,,,,,,"HOW MANY RECORDS DO YOU WISH TO",,,"COPY? (1 TO 35)"
2050 INPUT Z
2060 IF Z>35 THEN GOTO 2020
2070 FOR X=1 TO Z
2080 GOSUB 2280
2090 GOSUB 2410
2100 NEXT X
2110 RETURN
2120 REM %C%O%P%Y% %P%R%O%G%R%A%M% % % % % % % % % % %
2130 CLS
2140 PRINT ,,,,,,"PLACE BLANK PROGRAM TAPE IN TAPE",,"DECK, PRESS ""PLAY/RECORD"" ON",,,"TAPE DECK, PRESS ""ENTER"" ON",,,"COMPUTER."
2150 INPUT I$
2160 CLS
2170 SAVE "FORMATTE%R"
2180 PRINT ,,,,,,"PRESS ""STOP"" ON TAPE DECK",,,"PRESS ""ENTER"" ON COMPUTER."
2190 INPUT I$
2200 GOTO 0310
2210 REM %E%N%D% %P%R%O%G%R%A%M% % % % % % % % % % % %
2220 CLS
2230 PRINT ,,,,,,"ARE YOU SURE YOU WANT TO QUIT?"
2240 PRINT TAB 11;"(Y, N, OR M)"
2250 GOSUB 2550
2260 IF I$="Y" THEN NEW
2270 RETURN
2280 REM %R%E%A%D% %R%E%C%O%R%D% %O%N% %T%A%P%E% % % %
2290 CLS
2300 PRINT AT 2,0;"PLACE OLD DATA TAPE IN TAPE DECK"
2310 PRINT AT 4,0;"PRESS ""PLAY"" ON TAPE DECK"
2320 PRINT AT 6,0;"PRESS ""ENTER"" ON COMPUTER"
2330 INPUT Z$
2340 RAND USR 16549
2350 CLS
2360 SLOW
2370 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2380 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2390 INPUT Z$
2400 RETURN
2410 REM %W%R%I%T%E% %R%E%C%O%R%D% %O%N% %T%A%P%E% % %
2420 CLS
2430 PRINT AT 2,0;"PLACE NEW DATA TAPE IN TAPE DECK"
2440 PRINT AT 4,0;"PRESS ""PLAY/RECORD"" ON TAPE"
2450 PRINT "DECK"
2460 PRINT AT 7,0;"PRESS ""ENTER"" ON COMPUTER"
2470 INPUT Z$
2480 RAND USR 16514
2490 CLS
2500 SLOW
2510 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2520 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2530 INPUT Z$
2540 RETURN
2550 REM %I%N%P%U%T% %C%H%E%C%K%E%R% %(%Y% %O%R% %N%)%
2560 IF INKEY$="" THEN GOTO 2550
2570 LET I$=INKEY$
2580 IF I$<>"Y" AND I$<>"N" AND I$<>"M" THEN GOTO 2550
2590 RETURN
2600 SAVE "1016%0"
2610 GOTO 300
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
AE\C5 itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-57272 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.5 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.4"E\DB\FE\D3\FF\F9
Skip to content
Record Formatter
This file is part of Timex Sinclair Public Domain Library Tape 1003
. Download the collection to get this file.
Record Formatter Ver. 1 is a ZX81/TS1000 database management program that allows users to define up to 64 custom fields, then enter, display, edit, and print records stored in a 1,459-character string array. Tape I/O is handled by two machine-code routines embedded in the line-10 REM statement: one at USR 16514 writes records to tape and one at USR 16549 reads them back, called via RAND USR. The program uses a packed record layout where each field’s start and end positions are tracked in parallel numeric arrays A() and B(), allowing substring slicing of the master string A$(1). A directory-printing routine compresses data by stripping redundant spaces before sending output to the printer via LPRINT.
Program Analysis
Program Structure
The program is organized into clearly labeled sections using inverse-text REM statements as headers. Execution begins at line 10 (which contains machine code) and proceeds through initialization before entering the main menu loop.
- Lines 10–20: Machine code in REM; program identity label
- Lines 30–80: Array and variable initialization
- Lines 100–180: Field definition loop (up to 64 fields)
- Lines 190–300: Print record layout to printer
- Lines 310–550: Main menu and dispatch
- Lines 560–760: Enter new record subroutine
- Lines 770–1140: Change a record subroutine
- Lines 1150–1460: Display a record subroutine
- Lines 1470–1680: Print a record subroutine
- Lines 1690–2010: Print data tape directory subroutine
- Lines 2020–2110: Copy data tape subroutine
- Lines 2120–2200: Copy program subroutine
- Lines 2210–2270: End program subroutine
- Lines 2280–2400: Read record from tape subroutine
- Lines 2410–2540: Write record to tape subroutine
- Lines 2550–2590: Input checker subroutine (Y/N/M)
- Lines 2600–2610: SAVE and restart
Machine Code Routines
Two machine-code routines are embedded in the REM statement at line 10. They are invoked via RAND USR 16514 (write record) and RAND USR 16549 (read record). The ZX81 system variables place the start of the BASIC program at address 16509 (407Fh); the REM data begins at offset 5 (after the line number, length, and REM token), so the routines land at 16514 and 16549 respectively.
Disassembly of the REM bytes reveals two distinct routines:
Offset Address Bytes Mnemonic Notes 0 16514 CD E7 02 CALL 02E7h ZX81 ROM: slow-speed display/sync entry 3 16517 06 0E LD B,0Eh Loop counter = 14 5 16519 21 00 FF LD HL,FF00h Start of candidate address range 8 16522 2B DEC HL Step HL down 9 16523 7C LD A,H 10 16524 B5 OR L Check HL=0 11 16525 20 FB JR NZ,-5 Loop until zero 13 16527 10 F6 DJNZ -10 Outer timing loop 15 16529 2A 10 40 LD HL,(4010h) Load A$ descriptor pointer 18 16532 23 INC HL 19 16533 4E LD C,(HL) Low byte of length 20 16534 23 INC HL 21 16535 46 LD B,(HL) High byte of length 22 16536 23 INC HL 23 16537 C5 PUSH BC Save byte count 24 16538 5E LD E,(HL) Data address low 25 16539 CD 1F 03 CALL 031Fh ROM: output byte to tape 28 16542 C1 POP BC 29 16543 0B DEC BC 30 16544 78 LD A,B 31 16545 B1 OR C Check BC=0 32 16546 20 F4 JR NZ,-12 Write loop 34 16548 C9 RET End of write routine 35 16549 CD E7 02 CALL 02E7h Read routine starts here 38 16552 2A 10 40 LD HL,(4010h) Load A$ descriptor … … 1E 08 DB FE D3 FF… (tape read loop) Reads bytes from EAR port, reconstructs A$
The read routine polls the EAR port (DB FE = IN A,(FEh)) and outputs to FFh (D3 FF = OUT (FFh),A), using rotate and bit-test instructions to decode the Manchester-like tape signal. The length of data transferred is derived from the A$ array descriptor at address 4010h, so the routines always read/write exactly 1,459 bytes — the full record.
Data Layout
The master record is held in A$(1), a single 1,459-character string (the first and only row of the 1×1459 DIM). Field positions are pre-computed during setup:
A(X) — start position of field X within A$(1)
B(X) — end position of field X within A$(1)
C(X) — declared length of field X
B$(X) — 32-character field title (DIM B$(64,32))
Field data is read and written using ZX81 substring slicing: A$(1,A(X) TO B(X)). A temporary single-row string C$(1,C(X)) is re-DIMmed for each field during entry and editing to enforce the correct field width.
Menu and Navigation
The main menu at line 310 uses a single-keypress idiom: INKEY$ is tested in a tight loop at line 450, then captured at line 460 and dispatched via a cascade of IF … THEN GOSUB / GOTO statements. The reusable input checker subroutine at line 2550 accepts only Y, N, or M (Menu return), providing consistent three-way navigation throughout.
Key BASIC Idioms
- RAND USR — used to call machine-code routines without storing a return value, discarding the USR result safely.
- Re-DIM inside loop —
DIM C$(1,C(X)) at lines 630 and 1010 re-allocates C$ each iteration to match the current field’s length, ensuring INPUT fills exactly the right number of characters.
- VAL-style line targets — line numbers in
GOTO/GOSUB are written with leading zeros (e.g., GOTO 0450, GOSUB 0560), a common ZX81 style that has no runtime effect but aids readability.
- FAST/SLOW bracketing — printer output blocks (lines 190–300 and 1610–1670) are wrapped in
FAST/SLOW to disable the display interrupt and speed up LPRINT operations.
Directory Space-Compression Routine
The tape directory printer (lines 1930–1970) implements a simple run-length space compressor: it builds D$ by copying non-space characters from C$(1) and inserting a single space only when the next character is a space, collapsing multiple spaces into one. This produces compact, human-readable directory entries from fixed-width fields.
Notable Bugs and Anomalies
- Line 1000 unreachable check —
IF I$="N" AND X=65 THEN GOTO 1130 follows IF I$="N" THEN NEXT X at line 990. If I$="N", control jumps to NEXT X and never reaches line 1000; the X=65 boundary check is therefore dead code. The loop termination after all 64 fields are processed falls through to line 1130 naturally via the FOR/NEXT mechanism.
- Field count vs. tape block size — The program defines up to 64 fields but the directory loop at line 1880 is hard-coded to
FOR X=1 TO 35, implying the data tape is expected to hold exactly 35 records. There is no run-time check that the total declared field lengths do not exceed 1,459.
- Line 1430 double-read of INKEY$ — After the wait loop at line 1420 confirms a key is pressed, line 1430 calls
INKEY$ again. On a fast machine this could return an empty string if the key was released between the two polls, potentially failing to detect the M keypress.
- Line 2610 —
GOTO 300 targets line 300 (SLOW), not the menu at line 310, meaning after a SAVE the machine briefly executes SLOW before falling into the menu — harmless but slightly inconsistent with the direct GOTO 0310 used elsewhere.
Content
Source Code
10 REM \CD\E7\02\06\0E\21\00\FF\2B\7C\B5\20\FB\10\F6\2A\10\40\23\4E\23\46\23\C5\5E\CD\1F\03\C1\0B\78\B1\20\F4\C9\CD\E7\02\2A\10\40\23\4E\23\46\23\C5\1E\08\DB\FE\D3\FF\17\30\F9\0E\94\06\1A\0D\DB\FE\17\CB\79\79\38\F5\10\F5\20\04\FE\56\30\E4\3F\CB\16\1D\20\DE\C1\0B\78\B1\C8\18\D3
20 REM %P%R%O%G%R%A%M% %S%E%T% %U%P% % % % % % % % %
30 DIM A$(1,1459)
40 DIM B$(64,32)
50 DIM A(64)
60 DIM B(64)
70 DIM C(64)
80 LET M=310
90 LET W=1
100 FOR X=1 TO 64
110 PRINT AT 12,0;"ENTER FIELD TITLE (32 POS)"
120 INPUT B$(X)
130 PRINT AT 12,0;"ENTER LENGTH OF FIELD "
140 INPUT C(X)
150 LET A(X)=W
160 LET B(X)=W+C(X)-1
170 LET W=W+C(X)
180 NEXT X
190 FAST
200 LPRINT "RECORD LAYOUT"
210 LPRINT
220 LPRINT "FIELD NAME"
230 LPRINT "ST POS END POS LENGTH FLD NBR."
240 LPRINT "--------------------------------"
250 FOR X=1 TO 64
260 LPRINT B$(X)
270 LPRINT A(X);TAB 8;B(X);TAB 17;C(X);TAB 25;X
280 LPRINT
290 NEXT X
300 SLOW
310 REM %M%E%N%U% % % % % % % % % % % % % % % % % % %
320 CLS
330 PRINT TAB 5;"RECORD FORMATTER VER.1"
340 PRINT TAB 3;"COPYRIGHT 1985 TIM L. WARD",,,
350 PRINT "DO YOU WISH TO..",,,
360 PRINT "1)...ENTER A NEW RECORD?",,,
370 PRINT "2)...CHANGE A RECORD?",,,
380 PRINT "3)...DISPLAY A RECORD?",,,
390 PRINT "4)...PRINT A RECORD?",,,
400 PRINT "5)...PRINT DATA TAPE DIRECTORY?",,,
410 PRINT "6)...COPY DATA TAPE?",,,
420 PRINT "7)...COPY PROGRAM?",,,
430 PRINT "8)...END PROGRAM?",,,
440 PRINT "ENTER NBR. OF SELECTION"
450 IF INKEY$="" THEN GOTO 0450
460 LET I$=INKEY$
470 IF I$="1" THEN GOSUB 0560
480 IF I$="2" THEN GOSUB 0770
490 IF I$="3" THEN GOSUB 1150
500 IF I$="4" THEN GOSUB 1470
510 IF I$="5" THEN GOSUB 1690
520 IF I$="6" THEN GOSUB 2020
530 IF I$="7" THEN GOTO 2120
540 IF I$="8" THEN GOSUB 2210
550 GOTO 0310
560 REM %E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D% % % % %
570 CLS
580 PRINT ,,,,,,"DO YOU WISH TO ADD A NEW RCD?"
590 PRINT TAB 11;"(Y, N, OR M)"
600 GOSUB 2550
610 IF I$<>"Y" THEN RETURN
620 FOR X=1 TO 64
630 DIM C$(1,C(X))
640 CLS
650 PRINT AT 0,6;"%E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D"
660 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
670 PRINT AT 4,0;B$(X)
680 INPUT C$(1)
690 PRINT AT 6,0;C$(1)
700 PRINT "IS THIS CORRECT? (Y OR N)"
710 GOSUB 2550
720 IF I$<>"Y" THEN GOTO 0640
730 LET A$(1,A(X) TO B(X))=C$(1)
740 NEXT X
750 GOSUB 2410
760 RETURN
770 REM %C%H%A%N%G%E% %A% %R%E%C%O%R%D% % % % % % % %
780 CLS
790 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
800 PRINT AT 2,0;"DO YOU WISH TO CHANGE THIS RCD?"
810 PRINT AT 4,11;"(Y, N, OR M)",,,
820 FOR X=1 TO 5
830 PRINT B$(X)
840 PRINT A$(1,A(X) TO B(X))
850 NEXT X
860 GOSUB 2550
870 IF I$="M" THEN RETURN
880 IF I$="Y" THEN GOTO 0920
890 GOSUB 2410
900 GOSUB 2280
910 GOTO 0770
920 FOR X=1 TO 64
930 CLS
940 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
950 PRINT AT 2,0;"CHANGE THIS FIELD? (Y OR N)"
960 PRINT AT 4,0;B$(X)
970 PRINT A$(1,A(X) TO B(X))
980 GOSUB 2550
990 IF I$="N" THEN NEXT X
1000 IF I$="N" AND X=65 THEN GOTO 1130
1010 DIM C$(1,C(X))
1020 CLS
1030 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
1040 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
1050 PRINT AT 4,0;B$(X)
1060 INPUT C$(1)
1070 PRINT AT 6,0;C$(1)
1080 PRINT "IS THIS CORRECT? (Y OR N)"
1090 GOSUB 2550
1100 IF I$<>"Y" THEN GOTO 1020
1110 LET A$(1,A(X) TO B(X))=C$(1)
1120 NEXT X
1130 GOSUB 2410
1140 RETURN
1150 REM %D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D% % % % % % %
1160 CLS
1170 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1180 PRINT AT 2,0;"DO YOU WISH TO DISPLAY THIS RCD?"
1190 PRINT AT 4,11;"(Y, N, OR M)"
1200 FOR X=1 TO 5
1210 PRINT B$(X)
1220 PRINT A$(1,A(X) TO B(X))
1230 NEXT X
1240 GOSUB 2550
1250 IF I$="M" THEN RETURN
1260 IF I$="Y" THEN GOTO 1290
1270 GOSUB 2280
1280 GOTO 1150
1290 CLS
1300 FOR X=1 TO 64
1310 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1320 PRINT AT 2,0;"RECORD DISPLAYED IS FOR..."
1330 PRINT AT 4,0;"GEN/CODE NBR. ";A$(1, TO 5)
1340 PRINT AT 5,0;A$(1,6 TO 20)
1350 PRINT AT 6,0;A$(1,21 TO 35)
1360 PRINT AT 7,0;A$(1,36 TO 50)
1370 PRINT AT 8,0;A$(1,51 TO 65)
1380 PRINT AT 15,0;"%P%R%E%S%S% %E%N%T%E%R% %F%O%R% %N%E%X%T% %F%I%E%L%D% % % % % % "
1390 PRINT AT 16,0;"%P%R%E%S%S% %"%M%"% %T%O% %R%E%T%U%R%N% %T%O% % %M%E%N%U% % % % "
1400 PRINT AT 10,0;B$(X)
1410 PRINT AT 12,0;A$(1,A(X) TO B(X))
1420 IF INKEY$="" THEN GOTO 1420
1430 IF INKEY$="M" THEN RETURN
1440 PRINT AT 12,0;" "
1450 NEXT X
1460 RETURN
1470 REM %P%R%I%N%T% %A% %R%E%C%O%R%D% % % % % % % % %
1480 CLS
1490 PRINT AT 0,8;"%P%R%I%N%T% %A% %R%E%C%O%R%D"
1500 PRINT AT 2,0;"DO YOU WISH TO PRINT THIS RCD?"
1510 PRINT AT 4,11;"(Y, N, OR M)",,,
1520 FOR X=1 TO 5
1530 PRINT B$(X)
1540 PRINT A$(1,A(X) TO B(X))
1550 NEXT X
1560 GOSUB 2550
1570 IF I$="Y" THEN GOTO 1610
1580 IF I$="M" THEN RETURN
1590 GOSUB 2280
1600 GOTO 1470
1610 FAST
1620 FOR X=1 TO 64
1630 LPRINT B$(X)
1640 LPRINT A$(1,A(X) TO B(X))
1650 LPRINT
1660 NEXT X
1670 SLOW
1680 RETURN
1690 REM %P%R%I%N%T% %D%/%T% %D%I%R%E%C%T%O%R%Y% % % %
1700 CLS
1710 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1720 PRINT AT 4,0;"IS THE PRINTER ON ? (Y, N, OR M)"
1730 GOSUB 2550
1740 IF I$="M" THEN RETURN
1750 IF I$="Y" THEN GOTO 1790
1760 PRINT AT 12,0;"PLEASE TURN THE PRINTER ON"
1770 PRINT AT 14,0;"PRESS ENTER WHEN PRINTER IS ON"
1780 INPUT I$
1790 CLS
1800 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1810 PRINT AT 4,0;"PLACE OLD DATA TAPE IN TAPE DECK"
1820 PRINT AT 6,0;"PRESS ""PLAY"" ON TAPE DECK"
1830 PRINT AT 8,0;"PRESS ""ENTER"" ON COMPUTER"
1840 INPUT I$
1850 LPRINT "% % % % % % % DATA TAPE DIRECTORY% % % % % % ",,
1860 LPRINT "GEN/"
1870 LPRINT "CODE FIRST/LAST NAME",,,
1880 FOR X=1 TO 35
1890 RAND USR 16549
1900 DIM C$(1,36)
1910 LET C$(1)=A$(1,1 TO 5)+" "+A$(1,6 TO 20)+A$(1,51 TO 65)
1920 LET D$=""
1930 FOR Y=1 TO 36
1940 IF C$(1,Y)=" " THEN GOTO 1970
1950 LET D$=D$+C$(1,Y)
1960 IF C$(1,Y+1)=" " THEN LET D$=D$+" "
1970 NEXT Y
1980 LPRINT D$
1990 LPRINT
2000 NEXT X
2010 RETURN
2020 REM %C%O%P%Y% %D%A%T%A% %T%A%P%E% % % % % % % % %
2030 CLS
2040 PRINT ,,,,,,"HOW MANY RECORDS DO YOU WISH TO",,,"COPY? (1 TO 35)"
2050 INPUT Z
2060 IF Z>35 THEN GOTO 2020
2070 FOR X=1 TO Z
2080 GOSUB 2280
2090 GOSUB 2410
2100 NEXT X
2110 RETURN
2120 REM %C%O%P%Y% %P%R%O%G%R%A%M% % % % % % % % % % %
2130 CLS
2140 PRINT ,,,,,,"PLACE BLANK PROGRAM TAPE IN TAPE",,"DECK, PRESS ""PLAY/RECORD"" ON",,,"TAPE DECK, PRESS ""ENTER"" ON",,,"COMPUTER."
2150 INPUT I$
2160 CLS
2170 SAVE "FORMATTE%R"
2180 PRINT ,,,,,,"PRESS ""STOP"" ON TAPE DECK",,,"PRESS ""ENTER"" ON COMPUTER."
2190 INPUT I$
2200 GOTO 0310
2210 REM %E%N%D% %P%R%O%G%R%A%M% % % % % % % % % % % %
2220 CLS
2230 PRINT ,,,,,,"ARE YOU SURE YOU WANT TO QUIT?"
2240 PRINT TAB 11;"(Y, N, OR M)"
2250 GOSUB 2550
2260 IF I$="Y" THEN NEW
2270 RETURN
2280 REM %R%E%A%D% %R%E%C%O%R%D% %O%N% %T%A%P%E% % % %
2290 CLS
2300 PRINT AT 2,0;"PLACE OLD DATA TAPE IN TAPE DECK"
2310 PRINT AT 4,0;"PRESS ""PLAY"" ON TAPE DECK"
2320 PRINT AT 6,0;"PRESS ""ENTER"" ON COMPUTER"
2330 INPUT Z$
2340 RAND USR 16549
2350 CLS
2360 SLOW
2370 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2380 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2390 INPUT Z$
2400 RETURN
2410 REM %W%R%I%T%E% %R%E%C%O%R%D% %O%N% %T%A%P%E% % %
2420 CLS
2430 PRINT AT 2,0;"PLACE NEW DATA TAPE IN TAPE DECK"
2440 PRINT AT 4,0;"PRESS ""PLAY/RECORD"" ON TAPE"
2450 PRINT "DECK"
2460 PRINT AT 7,0;"PRESS ""ENTER"" ON COMPUTER"
2470 INPUT Z$
2480 RAND USR 16514
2490 CLS
2500 SLOW
2510 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2520 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2530 INPUT Z$
2540 RETURN
2550 REM %I%N%P%U%T% %C%H%E%C%K%E%R% %(%Y% %O%R% %N%)%
2560 IF INKEY$="" THEN GOTO 2550
2570 LET I$=INKEY$
2580 IF I$<>"Y" AND I$<>"N" AND I$<>"M" THEN GOTO 2550
2590 RETURN
2600 SAVE "1016%0"
2610 GOTO 300
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
E itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-57272 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.5 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.4"A
Skip to content
Record Formatter
This file is part of Timex Sinclair Public Domain Library Tape 1003
. Download the collection to get this file.
Record Formatter Ver. 1 is a ZX81/TS1000 database management program that allows users to define up to 64 custom fields, then enter, display, edit, and print records stored in a 1,459-character string array. Tape I/O is handled by two machine-code routines embedded in the line-10 REM statement: one at USR 16514 writes records to tape and one at USR 16549 reads them back, called via RAND USR. The program uses a packed record layout where each field’s start and end positions are tracked in parallel numeric arrays A() and B(), allowing substring slicing of the master string A$(1). A directory-printing routine compresses data by stripping redundant spaces before sending output to the printer via LPRINT.
Program Analysis
Program Structure
The program is organized into clearly labeled sections using inverse-text REM statements as headers. Execution begins at line 10 (which contains machine code) and proceeds through initialization before entering the main menu loop.
- Lines 10–20: Machine code in REM; program identity label
- Lines 30–80: Array and variable initialization
- Lines 100–180: Field definition loop (up to 64 fields)
- Lines 190–300: Print record layout to printer
- Lines 310–550: Main menu and dispatch
- Lines 560–760: Enter new record subroutine
- Lines 770–1140: Change a record subroutine
- Lines 1150–1460: Display a record subroutine
- Lines 1470–1680: Print a record subroutine
- Lines 1690–2010: Print data tape directory subroutine
- Lines 2020–2110: Copy data tape subroutine
- Lines 2120–2200: Copy program subroutine
- Lines 2210–2270: End program subroutine
- Lines 2280–2400: Read record from tape subroutine
- Lines 2410–2540: Write record to tape subroutine
- Lines 2550–2590: Input checker subroutine (Y/N/M)
- Lines 2600–2610: SAVE and restart
Machine Code Routines
Two machine-code routines are embedded in the REM statement at line 10. They are invoked via RAND USR 16514 (write record) and RAND USR 16549 (read record). The ZX81 system variables place the start of the BASIC program at address 16509 (407Fh); the REM data begins at offset 5 (after the line number, length, and REM token), so the routines land at 16514 and 16549 respectively.
Disassembly of the REM bytes reveals two distinct routines:
Offset Address Bytes Mnemonic Notes 0 16514 CD E7 02 CALL 02E7h ZX81 ROM: slow-speed display/sync entry 3 16517 06 0E LD B,0Eh Loop counter = 14 5 16519 21 00 FF LD HL,FF00h Start of candidate address range 8 16522 2B DEC HL Step HL down 9 16523 7C LD A,H 10 16524 B5 OR L Check HL=0 11 16525 20 FB JR NZ,-5 Loop until zero 13 16527 10 F6 DJNZ -10 Outer timing loop 15 16529 2A 10 40 LD HL,(4010h) Load A$ descriptor pointer 18 16532 23 INC HL 19 16533 4E LD C,(HL) Low byte of length 20 16534 23 INC HL 21 16535 46 LD B,(HL) High byte of length 22 16536 23 INC HL 23 16537 C5 PUSH BC Save byte count 24 16538 5E LD E,(HL) Data address low 25 16539 CD 1F 03 CALL 031Fh ROM: output byte to tape 28 16542 C1 POP BC 29 16543 0B DEC BC 30 16544 78 LD A,B 31 16545 B1 OR C Check BC=0 32 16546 20 F4 JR NZ,-12 Write loop 34 16548 C9 RET End of write routine 35 16549 CD E7 02 CALL 02E7h Read routine starts here 38 16552 2A 10 40 LD HL,(4010h) Load A$ descriptor … … 1E 08 DB FE D3 FF… (tape read loop) Reads bytes from EAR port, reconstructs A$
The read routine polls the EAR port (DB FE = IN A,(FEh)) and outputs to FFh (D3 FF = OUT (FFh),A), using rotate and bit-test instructions to decode the Manchester-like tape signal. The length of data transferred is derived from the A$ array descriptor at address 4010h, so the routines always read/write exactly 1,459 bytes — the full record.
Data Layout
The master record is held in A$(1), a single 1,459-character string (the first and only row of the 1×1459 DIM). Field positions are pre-computed during setup:
A(X) — start position of field X within A$(1)
B(X) — end position of field X within A$(1)
C(X) — declared length of field X
B$(X) — 32-character field title (DIM B$(64,32))
Field data is read and written using ZX81 substring slicing: A$(1,A(X) TO B(X)). A temporary single-row string C$(1,C(X)) is re-DIMmed for each field during entry and editing to enforce the correct field width.
Menu and Navigation
The main menu at line 310 uses a single-keypress idiom: INKEY$ is tested in a tight loop at line 450, then captured at line 460 and dispatched via a cascade of IF … THEN GOSUB / GOTO statements. The reusable input checker subroutine at line 2550 accepts only Y, N, or M (Menu return), providing consistent three-way navigation throughout.
Key BASIC Idioms
- RAND USR — used to call machine-code routines without storing a return value, discarding the USR result safely.
- Re-DIM inside loop —
DIM C$(1,C(X)) at lines 630 and 1010 re-allocates C$ each iteration to match the current field’s length, ensuring INPUT fills exactly the right number of characters.
- VAL-style line targets — line numbers in
GOTO/GOSUB are written with leading zeros (e.g., GOTO 0450, GOSUB 0560), a common ZX81 style that has no runtime effect but aids readability.
- FAST/SLOW bracketing — printer output blocks (lines 190–300 and 1610–1670) are wrapped in
FAST/SLOW to disable the display interrupt and speed up LPRINT operations.
Directory Space-Compression Routine
The tape directory printer (lines 1930–1970) implements a simple run-length space compressor: it builds D$ by copying non-space characters from C$(1) and inserting a single space only when the next character is a space, collapsing multiple spaces into one. This produces compact, human-readable directory entries from fixed-width fields.
Notable Bugs and Anomalies
- Line 1000 unreachable check —
IF I$="N" AND X=65 THEN GOTO 1130 follows IF I$="N" THEN NEXT X at line 990. If I$="N", control jumps to NEXT X and never reaches line 1000; the X=65 boundary check is therefore dead code. The loop termination after all 64 fields are processed falls through to line 1130 naturally via the FOR/NEXT mechanism.
- Field count vs. tape block size — The program defines up to 64 fields but the directory loop at line 1880 is hard-coded to
FOR X=1 TO 35, implying the data tape is expected to hold exactly 35 records. There is no run-time check that the total declared field lengths do not exceed 1,459.
- Line 1430 double-read of INKEY$ — After the wait loop at line 1420 confirms a key is pressed, line 1430 calls
INKEY$ again. On a fast machine this could return an empty string if the key was released between the two polls, potentially failing to detect the M keypress.
- Line 2610 —
GOTO 300 targets line 300 (SLOW), not the menu at line 310, meaning after a SAVE the machine briefly executes SLOW before falling into the menu — harmless but slightly inconsistent with the direct GOTO 0310 used elsewhere.
Content
Source Code
10 REM \CD\E7\02\06\0E\21\00\FF\2B\7C\B5\20\FB\10\F6\2A\10\40\23\4E\23\46\23\C5\5E\CD\1F\03\C1\0B\78\B1\20\F4\C9\CD\E7\02\2A\10\40\23\4E\23\46\23\C5\1E\08\DB\FE\D3\FF\17\30\F9\0E\94\06\1A\0D\DB\FE\17\CB\79\79\38\F5\10\F5\20\04\FE\56\30\E4\3F\CB\16\1D\20\DE\C1\0B\78\B1\C8\18\D3
20 REM %P%R%O%G%R%A%M% %S%E%T% %U%P% % % % % % % % %
30 DIM A$(1,1459)
40 DIM B$(64,32)
50 DIM A(64)
60 DIM B(64)
70 DIM C(64)
80 LET M=310
90 LET W=1
100 FOR X=1 TO 64
110 PRINT AT 12,0;"ENTER FIELD TITLE (32 POS)"
120 INPUT B$(X)
130 PRINT AT 12,0;"ENTER LENGTH OF FIELD "
140 INPUT C(X)
150 LET A(X)=W
160 LET B(X)=W+C(X)-1
170 LET W=W+C(X)
180 NEXT X
190 FAST
200 LPRINT "RECORD LAYOUT"
210 LPRINT
220 LPRINT "FIELD NAME"
230 LPRINT "ST POS END POS LENGTH FLD NBR."
240 LPRINT "--------------------------------"
250 FOR X=1 TO 64
260 LPRINT B$(X)
270 LPRINT A(X);TAB 8;B(X);TAB 17;C(X);TAB 25;X
280 LPRINT
290 NEXT X
300 SLOW
310 REM %M%E%N%U% % % % % % % % % % % % % % % % % % %
320 CLS
330 PRINT TAB 5;"RECORD FORMATTER VER.1"
340 PRINT TAB 3;"COPYRIGHT 1985 TIM L. WARD",,,
350 PRINT "DO YOU WISH TO..",,,
360 PRINT "1)...ENTER A NEW RECORD?",,,
370 PRINT "2)...CHANGE A RECORD?",,,
380 PRINT "3)...DISPLAY A RECORD?",,,
390 PRINT "4)...PRINT A RECORD?",,,
400 PRINT "5)...PRINT DATA TAPE DIRECTORY?",,,
410 PRINT "6)...COPY DATA TAPE?",,,
420 PRINT "7)...COPY PROGRAM?",,,
430 PRINT "8)...END PROGRAM?",,,
440 PRINT "ENTER NBR. OF SELECTION"
450 IF INKEY$="" THEN GOTO 0450
460 LET I$=INKEY$
470 IF I$="1" THEN GOSUB 0560
480 IF I$="2" THEN GOSUB 0770
490 IF I$="3" THEN GOSUB 1150
500 IF I$="4" THEN GOSUB 1470
510 IF I$="5" THEN GOSUB 1690
520 IF I$="6" THEN GOSUB 2020
530 IF I$="7" THEN GOTO 2120
540 IF I$="8" THEN GOSUB 2210
550 GOTO 0310
560 REM %E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D% % % % %
570 CLS
580 PRINT ,,,,,,"DO YOU WISH TO ADD A NEW RCD?"
590 PRINT TAB 11;"(Y, N, OR M)"
600 GOSUB 2550
610 IF I$<>"Y" THEN RETURN
620 FOR X=1 TO 64
630 DIM C$(1,C(X))
640 CLS
650 PRINT AT 0,6;"%E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D"
660 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
670 PRINT AT 4,0;B$(X)
680 INPUT C$(1)
690 PRINT AT 6,0;C$(1)
700 PRINT "IS THIS CORRECT? (Y OR N)"
710 GOSUB 2550
720 IF I$<>"Y" THEN GOTO 0640
730 LET A$(1,A(X) TO B(X))=C$(1)
740 NEXT X
750 GOSUB 2410
760 RETURN
770 REM %C%H%A%N%G%E% %A% %R%E%C%O%R%D% % % % % % % %
780 CLS
790 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
800 PRINT AT 2,0;"DO YOU WISH TO CHANGE THIS RCD?"
810 PRINT AT 4,11;"(Y, N, OR M)",,,
820 FOR X=1 TO 5
830 PRINT B$(X)
840 PRINT A$(1,A(X) TO B(X))
850 NEXT X
860 GOSUB 2550
870 IF I$="M" THEN RETURN
880 IF I$="Y" THEN GOTO 0920
890 GOSUB 2410
900 GOSUB 2280
910 GOTO 0770
920 FOR X=1 TO 64
930 CLS
940 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
950 PRINT AT 2,0;"CHANGE THIS FIELD? (Y OR N)"
960 PRINT AT 4,0;B$(X)
970 PRINT A$(1,A(X) TO B(X))
980 GOSUB 2550
990 IF I$="N" THEN NEXT X
1000 IF I$="N" AND X=65 THEN GOTO 1130
1010 DIM C$(1,C(X))
1020 CLS
1030 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
1040 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
1050 PRINT AT 4,0;B$(X)
1060 INPUT C$(1)
1070 PRINT AT 6,0;C$(1)
1080 PRINT "IS THIS CORRECT? (Y OR N)"
1090 GOSUB 2550
1100 IF I$<>"Y" THEN GOTO 1020
1110 LET A$(1,A(X) TO B(X))=C$(1)
1120 NEXT X
1130 GOSUB 2410
1140 RETURN
1150 REM %D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D% % % % % % %
1160 CLS
1170 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1180 PRINT AT 2,0;"DO YOU WISH TO DISPLAY THIS RCD?"
1190 PRINT AT 4,11;"(Y, N, OR M)"
1200 FOR X=1 TO 5
1210 PRINT B$(X)
1220 PRINT A$(1,A(X) TO B(X))
1230 NEXT X
1240 GOSUB 2550
1250 IF I$="M" THEN RETURN
1260 IF I$="Y" THEN GOTO 1290
1270 GOSUB 2280
1280 GOTO 1150
1290 CLS
1300 FOR X=1 TO 64
1310 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1320 PRINT AT 2,0;"RECORD DISPLAYED IS FOR..."
1330 PRINT AT 4,0;"GEN/CODE NBR. ";A$(1, TO 5)
1340 PRINT AT 5,0;A$(1,6 TO 20)
1350 PRINT AT 6,0;A$(1,21 TO 35)
1360 PRINT AT 7,0;A$(1,36 TO 50)
1370 PRINT AT 8,0;A$(1,51 TO 65)
1380 PRINT AT 15,0;"%P%R%E%S%S% %E%N%T%E%R% %F%O%R% %N%E%X%T% %F%I%E%L%D% % % % % % "
1390 PRINT AT 16,0;"%P%R%E%S%S% %"%M%"% %T%O% %R%E%T%U%R%N% %T%O% % %M%E%N%U% % % % "
1400 PRINT AT 10,0;B$(X)
1410 PRINT AT 12,0;A$(1,A(X) TO B(X))
1420 IF INKEY$="" THEN GOTO 1420
1430 IF INKEY$="M" THEN RETURN
1440 PRINT AT 12,0;" "
1450 NEXT X
1460 RETURN
1470 REM %P%R%I%N%T% %A% %R%E%C%O%R%D% % % % % % % % %
1480 CLS
1490 PRINT AT 0,8;"%P%R%I%N%T% %A% %R%E%C%O%R%D"
1500 PRINT AT 2,0;"DO YOU WISH TO PRINT THIS RCD?"
1510 PRINT AT 4,11;"(Y, N, OR M)",,,
1520 FOR X=1 TO 5
1530 PRINT B$(X)
1540 PRINT A$(1,A(X) TO B(X))
1550 NEXT X
1560 GOSUB 2550
1570 IF I$="Y" THEN GOTO 1610
1580 IF I$="M" THEN RETURN
1590 GOSUB 2280
1600 GOTO 1470
1610 FAST
1620 FOR X=1 TO 64
1630 LPRINT B$(X)
1640 LPRINT A$(1,A(X) TO B(X))
1650 LPRINT
1660 NEXT X
1670 SLOW
1680 RETURN
1690 REM %P%R%I%N%T% %D%/%T% %D%I%R%E%C%T%O%R%Y% % % %
1700 CLS
1710 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1720 PRINT AT 4,0;"IS THE PRINTER ON ? (Y, N, OR M)"
1730 GOSUB 2550
1740 IF I$="M" THEN RETURN
1750 IF I$="Y" THEN GOTO 1790
1760 PRINT AT 12,0;"PLEASE TURN THE PRINTER ON"
1770 PRINT AT 14,0;"PRESS ENTER WHEN PRINTER IS ON"
1780 INPUT I$
1790 CLS
1800 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1810 PRINT AT 4,0;"PLACE OLD DATA TAPE IN TAPE DECK"
1820 PRINT AT 6,0;"PRESS ""PLAY"" ON TAPE DECK"
1830 PRINT AT 8,0;"PRESS ""ENTER"" ON COMPUTER"
1840 INPUT I$
1850 LPRINT "% % % % % % % DATA TAPE DIRECTORY% % % % % % ",,
1860 LPRINT "GEN/"
1870 LPRINT "CODE FIRST/LAST NAME",,,
1880 FOR X=1 TO 35
1890 RAND USR 16549
1900 DIM C$(1,36)
1910 LET C$(1)=A$(1,1 TO 5)+" "+A$(1,6 TO 20)+A$(1,51 TO 65)
1920 LET D$=""
1930 FOR Y=1 TO 36
1940 IF C$(1,Y)=" " THEN GOTO 1970
1950 LET D$=D$+C$(1,Y)
1960 IF C$(1,Y+1)=" " THEN LET D$=D$+" "
1970 NEXT Y
1980 LPRINT D$
1990 LPRINT
2000 NEXT X
2010 RETURN
2020 REM %C%O%P%Y% %D%A%T%A% %T%A%P%E% % % % % % % % %
2030 CLS
2040 PRINT ,,,,,,"HOW MANY RECORDS DO YOU WISH TO",,,"COPY? (1 TO 35)"
2050 INPUT Z
2060 IF Z>35 THEN GOTO 2020
2070 FOR X=1 TO Z
2080 GOSUB 2280
2090 GOSUB 2410
2100 NEXT X
2110 RETURN
2120 REM %C%O%P%Y% %P%R%O%G%R%A%M% % % % % % % % % % %
2130 CLS
2140 PRINT ,,,,,,"PLACE BLANK PROGRAM TAPE IN TAPE",,"DECK, PRESS ""PLAY/RECORD"" ON",,,"TAPE DECK, PRESS ""ENTER"" ON",,,"COMPUTER."
2150 INPUT I$
2160 CLS
2170 SAVE "FORMATTE%R"
2180 PRINT ,,,,,,"PRESS ""STOP"" ON TAPE DECK",,,"PRESS ""ENTER"" ON COMPUTER."
2190 INPUT I$
2200 GOTO 0310
2210 REM %E%N%D% %P%R%O%G%R%A%M% % % % % % % % % % % %
2220 CLS
2230 PRINT ,,,,,,"ARE YOU SURE YOU WANT TO QUIT?"
2240 PRINT TAB 11;"(Y, N, OR M)"
2250 GOSUB 2550
2260 IF I$="Y" THEN NEW
2270 RETURN
2280 REM %R%E%A%D% %R%E%C%O%R%D% %O%N% %T%A%P%E% % % %
2290 CLS
2300 PRINT AT 2,0;"PLACE OLD DATA TAPE IN TAPE DECK"
2310 PRINT AT 4,0;"PRESS ""PLAY"" ON TAPE DECK"
2320 PRINT AT 6,0;"PRESS ""ENTER"" ON COMPUTER"
2330 INPUT Z$
2340 RAND USR 16549
2350 CLS
2360 SLOW
2370 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2380 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2390 INPUT Z$
2400 RETURN
2410 REM %W%R%I%T%E% %R%E%C%O%R%D% %O%N% %T%A%P%E% % %
2420 CLS
2430 PRINT AT 2,0;"PLACE NEW DATA TAPE IN TAPE DECK"
2440 PRINT AT 4,0;"PRESS ""PLAY/RECORD"" ON TAPE"
2450 PRINT "DECK"
2460 PRINT AT 7,0;"PRESS ""ENTER"" ON COMPUTER"
2470 INPUT Z$
2480 RAND USR 16514
2490 CLS
2500 SLOW
2510 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2520 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2530 INPUT Z$
2540 RETURN
2550 REM %I%N%P%U%T% %C%H%E%C%K%E%R% %(%Y% %O%R% %N%)%
2560 IF INKEY$="" THEN GOTO 2550
2570 LET I$=INKEY$
2580 IF I$<>"Y" AND I$<>"N" AND I$<>"M" THEN GOTO 2550
2590 RETURN
2600 SAVE "1016%0"
2610 GOTO 300
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
D\DB\FE\CB\F5\F5\FE\E4F\CB itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-57272 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.5 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.4"D\DE\C1
Skip to content
Record Formatter
This file is part of Timex Sinclair Public Domain Library Tape 1003
. Download the collection to get this file.
Record Formatter Ver. 1 is a ZX81/TS1000 database management program that allows users to define up to 64 custom fields, then enter, display, edit, and print records stored in a 1,459-character string array. Tape I/O is handled by two machine-code routines embedded in the line-10 REM statement: one at USR 16514 writes records to tape and one at USR 16549 reads them back, called via RAND USR. The program uses a packed record layout where each field’s start and end positions are tracked in parallel numeric arrays A() and B(), allowing substring slicing of the master string A$(1). A directory-printing routine compresses data by stripping redundant spaces before sending output to the printer via LPRINT.
Program Analysis
Program Structure
The program is organized into clearly labeled sections using inverse-text REM statements as headers. Execution begins at line 10 (which contains machine code) and proceeds through initialization before entering the main menu loop.
- Lines 10–20: Machine code in REM; program identity label
- Lines 30–80: Array and variable initialization
- Lines 100–180: Field definition loop (up to 64 fields)
- Lines 190–300: Print record layout to printer
- Lines 310–550: Main menu and dispatch
- Lines 560–760: Enter new record subroutine
- Lines 770–1140: Change a record subroutine
- Lines 1150–1460: Display a record subroutine
- Lines 1470–1680: Print a record subroutine
- Lines 1690–2010: Print data tape directory subroutine
- Lines 2020–2110: Copy data tape subroutine
- Lines 2120–2200: Copy program subroutine
- Lines 2210–2270: End program subroutine
- Lines 2280–2400: Read record from tape subroutine
- Lines 2410–2540: Write record to tape subroutine
- Lines 2550–2590: Input checker subroutine (Y/N/M)
- Lines 2600–2610: SAVE and restart
Machine Code Routines
Two machine-code routines are embedded in the REM statement at line 10. They are invoked via RAND USR 16514 (write record) and RAND USR 16549 (read record). The ZX81 system variables place the start of the BASIC program at address 16509 (407Fh); the REM data begins at offset 5 (after the line number, length, and REM token), so the routines land at 16514 and 16549 respectively.
Disassembly of the REM bytes reveals two distinct routines:
Offset Address Bytes Mnemonic Notes 0 16514 CD E7 02 CALL 02E7h ZX81 ROM: slow-speed display/sync entry 3 16517 06 0E LD B,0Eh Loop counter = 14 5 16519 21 00 FF LD HL,FF00h Start of candidate address range 8 16522 2B DEC HL Step HL down 9 16523 7C LD A,H 10 16524 B5 OR L Check HL=0 11 16525 20 FB JR NZ,-5 Loop until zero 13 16527 10 F6 DJNZ -10 Outer timing loop 15 16529 2A 10 40 LD HL,(4010h) Load A$ descriptor pointer 18 16532 23 INC HL 19 16533 4E LD C,(HL) Low byte of length 20 16534 23 INC HL 21 16535 46 LD B,(HL) High byte of length 22 16536 23 INC HL 23 16537 C5 PUSH BC Save byte count 24 16538 5E LD E,(HL) Data address low 25 16539 CD 1F 03 CALL 031Fh ROM: output byte to tape 28 16542 C1 POP BC 29 16543 0B DEC BC 30 16544 78 LD A,B 31 16545 B1 OR C Check BC=0 32 16546 20 F4 JR NZ,-12 Write loop 34 16548 C9 RET End of write routine 35 16549 CD E7 02 CALL 02E7h Read routine starts here 38 16552 2A 10 40 LD HL,(4010h) Load A$ descriptor … … 1E 08 DB FE D3 FF… (tape read loop) Reads bytes from EAR port, reconstructs A$
The read routine polls the EAR port (DB FE = IN A,(FEh)) and outputs to FFh (D3 FF = OUT (FFh),A), using rotate and bit-test instructions to decode the Manchester-like tape signal. The length of data transferred is derived from the A$ array descriptor at address 4010h, so the routines always read/write exactly 1,459 bytes — the full record.
Data Layout
The master record is held in A$(1), a single 1,459-character string (the first and only row of the 1×1459 DIM). Field positions are pre-computed during setup:
A(X) — start position of field X within A$(1)
B(X) — end position of field X within A$(1)
C(X) — declared length of field X
B$(X) — 32-character field title (DIM B$(64,32))
Field data is read and written using ZX81 substring slicing: A$(1,A(X) TO B(X)). A temporary single-row string C$(1,C(X)) is re-DIMmed for each field during entry and editing to enforce the correct field width.
Menu and Navigation
The main menu at line 310 uses a single-keypress idiom: INKEY$ is tested in a tight loop at line 450, then captured at line 460 and dispatched via a cascade of IF … THEN GOSUB / GOTO statements. The reusable input checker subroutine at line 2550 accepts only Y, N, or M (Menu return), providing consistent three-way navigation throughout.
Key BASIC Idioms
- RAND USR — used to call machine-code routines without storing a return value, discarding the USR result safely.
- Re-DIM inside loop —
DIM C$(1,C(X)) at lines 630 and 1010 re-allocates C$ each iteration to match the current field’s length, ensuring INPUT fills exactly the right number of characters.
- VAL-style line targets — line numbers in
GOTO/GOSUB are written with leading zeros (e.g., GOTO 0450, GOSUB 0560), a common ZX81 style that has no runtime effect but aids readability.
- FAST/SLOW bracketing — printer output blocks (lines 190–300 and 1610–1670) are wrapped in
FAST/SLOW to disable the display interrupt and speed up LPRINT operations.
Directory Space-Compression Routine
The tape directory printer (lines 1930–1970) implements a simple run-length space compressor: it builds D$ by copying non-space characters from C$(1) and inserting a single space only when the next character is a space, collapsing multiple spaces into one. This produces compact, human-readable directory entries from fixed-width fields.
Notable Bugs and Anomalies
- Line 1000 unreachable check —
IF I$="N" AND X=65 THEN GOTO 1130 follows IF I$="N" THEN NEXT X at line 990. If I$="N", control jumps to NEXT X and never reaches line 1000; the X=65 boundary check is therefore dead code. The loop termination after all 64 fields are processed falls through to line 1130 naturally via the FOR/NEXT mechanism.
- Field count vs. tape block size — The program defines up to 64 fields but the directory loop at line 1880 is hard-coded to
FOR X=1 TO 35, implying the data tape is expected to hold exactly 35 records. There is no run-time check that the total declared field lengths do not exceed 1,459.
- Line 1430 double-read of INKEY$ — After the wait loop at line 1420 confirms a key is pressed, line 1430 calls
INKEY$ again. On a fast machine this could return an empty string if the key was released between the two polls, potentially failing to detect the M keypress.
- Line 2610 —
GOTO 300 targets line 300 (SLOW), not the menu at line 310, meaning after a SAVE the machine briefly executes SLOW before falling into the menu — harmless but slightly inconsistent with the direct GOTO 0310 used elsewhere.
Content
Source Code
10 REM \CD\E7\02\06\0E\21\00\FF\2B\7C\B5\20\FB\10\F6\2A\10\40\23\4E\23\46\23\C5\5E\CD\1F\03\C1\0B\78\B1\20\F4\C9\CD\E7\02\2A\10\40\23\4E\23\46\23\C5\1E\08\DB\FE\D3\FF\17\30\F9\0E\94\06\1A\0D\DB\FE\17\CB\79\79\38\F5\10\F5\20\04\FE\56\30\E4\3F\CB\16\1D\20\DE\C1\0B\78\B1\C8\18\D3
20 REM %P%R%O%G%R%A%M% %S%E%T% %U%P% % % % % % % % %
30 DIM A$(1,1459)
40 DIM B$(64,32)
50 DIM A(64)
60 DIM B(64)
70 DIM C(64)
80 LET M=310
90 LET W=1
100 FOR X=1 TO 64
110 PRINT AT 12,0;"ENTER FIELD TITLE (32 POS)"
120 INPUT B$(X)
130 PRINT AT 12,0;"ENTER LENGTH OF FIELD "
140 INPUT C(X)
150 LET A(X)=W
160 LET B(X)=W+C(X)-1
170 LET W=W+C(X)
180 NEXT X
190 FAST
200 LPRINT "RECORD LAYOUT"
210 LPRINT
220 LPRINT "FIELD NAME"
230 LPRINT "ST POS END POS LENGTH FLD NBR."
240 LPRINT "--------------------------------"
250 FOR X=1 TO 64
260 LPRINT B$(X)
270 LPRINT A(X);TAB 8;B(X);TAB 17;C(X);TAB 25;X
280 LPRINT
290 NEXT X
300 SLOW
310 REM %M%E%N%U% % % % % % % % % % % % % % % % % % %
320 CLS
330 PRINT TAB 5;"RECORD FORMATTER VER.1"
340 PRINT TAB 3;"COPYRIGHT 1985 TIM L. WARD",,,
350 PRINT "DO YOU WISH TO..",,,
360 PRINT "1)...ENTER A NEW RECORD?",,,
370 PRINT "2)...CHANGE A RECORD?",,,
380 PRINT "3)...DISPLAY A RECORD?",,,
390 PRINT "4)...PRINT A RECORD?",,,
400 PRINT "5)...PRINT DATA TAPE DIRECTORY?",,,
410 PRINT "6)...COPY DATA TAPE?",,,
420 PRINT "7)...COPY PROGRAM?",,,
430 PRINT "8)...END PROGRAM?",,,
440 PRINT "ENTER NBR. OF SELECTION"
450 IF INKEY$="" THEN GOTO 0450
460 LET I$=INKEY$
470 IF I$="1" THEN GOSUB 0560
480 IF I$="2" THEN GOSUB 0770
490 IF I$="3" THEN GOSUB 1150
500 IF I$="4" THEN GOSUB 1470
510 IF I$="5" THEN GOSUB 1690
520 IF I$="6" THEN GOSUB 2020
530 IF I$="7" THEN GOTO 2120
540 IF I$="8" THEN GOSUB 2210
550 GOTO 0310
560 REM %E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D% % % % %
570 CLS
580 PRINT ,,,,,,"DO YOU WISH TO ADD A NEW RCD?"
590 PRINT TAB 11;"(Y, N, OR M)"
600 GOSUB 2550
610 IF I$<>"Y" THEN RETURN
620 FOR X=1 TO 64
630 DIM C$(1,C(X))
640 CLS
650 PRINT AT 0,6;"%E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D"
660 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
670 PRINT AT 4,0;B$(X)
680 INPUT C$(1)
690 PRINT AT 6,0;C$(1)
700 PRINT "IS THIS CORRECT? (Y OR N)"
710 GOSUB 2550
720 IF I$<>"Y" THEN GOTO 0640
730 LET A$(1,A(X) TO B(X))=C$(1)
740 NEXT X
750 GOSUB 2410
760 RETURN
770 REM %C%H%A%N%G%E% %A% %R%E%C%O%R%D% % % % % % % %
780 CLS
790 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
800 PRINT AT 2,0;"DO YOU WISH TO CHANGE THIS RCD?"
810 PRINT AT 4,11;"(Y, N, OR M)",,,
820 FOR X=1 TO 5
830 PRINT B$(X)
840 PRINT A$(1,A(X) TO B(X))
850 NEXT X
860 GOSUB 2550
870 IF I$="M" THEN RETURN
880 IF I$="Y" THEN GOTO 0920
890 GOSUB 2410
900 GOSUB 2280
910 GOTO 0770
920 FOR X=1 TO 64
930 CLS
940 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
950 PRINT AT 2,0;"CHANGE THIS FIELD? (Y OR N)"
960 PRINT AT 4,0;B$(X)
970 PRINT A$(1,A(X) TO B(X))
980 GOSUB 2550
990 IF I$="N" THEN NEXT X
1000 IF I$="N" AND X=65 THEN GOTO 1130
1010 DIM C$(1,C(X))
1020 CLS
1030 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
1040 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
1050 PRINT AT 4,0;B$(X)
1060 INPUT C$(1)
1070 PRINT AT 6,0;C$(1)
1080 PRINT "IS THIS CORRECT? (Y OR N)"
1090 GOSUB 2550
1100 IF I$<>"Y" THEN GOTO 1020
1110 LET A$(1,A(X) TO B(X))=C$(1)
1120 NEXT X
1130 GOSUB 2410
1140 RETURN
1150 REM %D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D% % % % % % %
1160 CLS
1170 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1180 PRINT AT 2,0;"DO YOU WISH TO DISPLAY THIS RCD?"
1190 PRINT AT 4,11;"(Y, N, OR M)"
1200 FOR X=1 TO 5
1210 PRINT B$(X)
1220 PRINT A$(1,A(X) TO B(X))
1230 NEXT X
1240 GOSUB 2550
1250 IF I$="M" THEN RETURN
1260 IF I$="Y" THEN GOTO 1290
1270 GOSUB 2280
1280 GOTO 1150
1290 CLS
1300 FOR X=1 TO 64
1310 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
1320 PRINT AT 2,0;"RECORD DISPLAYED IS FOR..."
1330 PRINT AT 4,0;"GEN/CODE NBR. ";A$(1, TO 5)
1340 PRINT AT 5,0;A$(1,6 TO 20)
1350 PRINT AT 6,0;A$(1,21 TO 35)
1360 PRINT AT 7,0;A$(1,36 TO 50)
1370 PRINT AT 8,0;A$(1,51 TO 65)
1380 PRINT AT 15,0;"%P%R%E%S%S% %E%N%T%E%R% %F%O%R% %N%E%X%T% %F%I%E%L%D% % % % % % "
1390 PRINT AT 16,0;"%P%R%E%S%S% %"%M%"% %T%O% %R%E%T%U%R%N% %T%O% % %M%E%N%U% % % % "
1400 PRINT AT 10,0;B$(X)
1410 PRINT AT 12,0;A$(1,A(X) TO B(X))
1420 IF INKEY$="" THEN GOTO 1420
1430 IF INKEY$="M" THEN RETURN
1440 PRINT AT 12,0;" "
1450 NEXT X
1460 RETURN
1470 REM %P%R%I%N%T% %A% %R%E%C%O%R%D% % % % % % % % %
1480 CLS
1490 PRINT AT 0,8;"%P%R%I%N%T% %A% %R%E%C%O%R%D"
1500 PRINT AT 2,0;"DO YOU WISH TO PRINT THIS RCD?"
1510 PRINT AT 4,11;"(Y, N, OR M)",,,
1520 FOR X=1 TO 5
1530 PRINT B$(X)
1540 PRINT A$(1,A(X) TO B(X))
1550 NEXT X
1560 GOSUB 2550
1570 IF I$="Y" THEN GOTO 1610
1580 IF I$="M" THEN RETURN
1590 GOSUB 2280
1600 GOTO 1470
1610 FAST
1620 FOR X=1 TO 64
1630 LPRINT B$(X)
1640 LPRINT A$(1,A(X) TO B(X))
1650 LPRINT
1660 NEXT X
1670 SLOW
1680 RETURN
1690 REM %P%R%I%N%T% %D%/%T% %D%I%R%E%C%T%O%R%Y% % % %
1700 CLS
1710 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1720 PRINT AT 4,0;"IS THE PRINTER ON ? (Y, N, OR M)"
1730 GOSUB 2550
1740 IF I$="M" THEN RETURN
1750 IF I$="Y" THEN GOTO 1790
1760 PRINT AT 12,0;"PLEASE TURN THE PRINTER ON"
1770 PRINT AT 14,0;"PRESS ENTER WHEN PRINTER IS ON"
1780 INPUT I$
1790 CLS
1800 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
1810 PRINT AT 4,0;"PLACE OLD DATA TAPE IN TAPE DECK"
1820 PRINT AT 6,0;"PRESS ""PLAY"" ON TAPE DECK"
1830 PRINT AT 8,0;"PRESS ""ENTER"" ON COMPUTER"
1840 INPUT I$
1850 LPRINT "% % % % % % % DATA TAPE DIRECTORY% % % % % % ",,
1860 LPRINT "GEN/"
1870 LPRINT "CODE FIRST/LAST NAME",,,
1880 FOR X=1 TO 35
1890 RAND USR 16549
1900 DIM C$(1,36)
1910 LET C$(1)=A$(1,1 TO 5)+" "+A$(1,6 TO 20)+A$(1,51 TO 65)
1920 LET D$=""
1930 FOR Y=1 TO 36
1940 IF C$(1,Y)=" " THEN GOTO 1970
1950 LET D$=D$+C$(1,Y)
1960 IF C$(1,Y+1)=" " THEN LET D$=D$+" "
1970 NEXT Y
1980 LPRINT D$
1990 LPRINT
2000 NEXT X
2010 RETURN
2020 REM %C%O%P%Y% %D%A%T%A% %T%A%P%E% % % % % % % % %
2030 CLS
2040 PRINT ,,,,,,"HOW MANY RECORDS DO YOU WISH TO",,,"COPY? (1 TO 35)"
2050 INPUT Z
2060 IF Z>35 THEN GOTO 2020
2070 FOR X=1 TO Z
2080 GOSUB 2280
2090 GOSUB 2410
2100 NEXT X
2110 RETURN
2120 REM %C%O%P%Y% %P%R%O%G%R%A%M% % % % % % % % % % %
2130 CLS
2140 PRINT ,,,,,,"PLACE BLANK PROGRAM TAPE IN TAPE",,"DECK, PRESS ""PLAY/RECORD"" ON",,,"TAPE DECK, PRESS ""ENTER"" ON",,,"COMPUTER."
2150 INPUT I$
2160 CLS
2170 SAVE "FORMATTE%R"
2180 PRINT ,,,,,,"PRESS ""STOP"" ON TAPE DECK",,,"PRESS ""ENTER"" ON COMPUTER."
2190 INPUT I$
2200 GOTO 0310
2210 REM %E%N%D% %P%R%O%G%R%A%M% % % % % % % % % % % %
2220 CLS
2230 PRINT ,,,,,,"ARE YOU SURE YOU WANT TO QUIT?"
2240 PRINT TAB 11;"(Y, N, OR M)"
2250 GOSUB 2550
2260 IF I$="Y" THEN NEW
2270 RETURN
2280 REM %R%E%A%D% %R%E%C%O%R%D% %O%N% %T%A%P%E% % % %
2290 CLS
2300 PRINT AT 2,0;"PLACE OLD DATA TAPE IN TAPE DECK"
2310 PRINT AT 4,0;"PRESS ""PLAY"" ON TAPE DECK"
2320 PRINT AT 6,0;"PRESS ""ENTER"" ON COMPUTER"
2330 INPUT Z$
2340 RAND USR 16549
2350 CLS
2360 SLOW
2370 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2380 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2390 INPUT Z$
2400 RETURN
2410 REM %W%R%I%T%E% %R%E%C%O%R%D% %O%N% %T%A%P%E% % %
2420 CLS
2430 PRINT AT 2,0;"PLACE NEW DATA TAPE IN TAPE DECK"
2440 PRINT AT 4,0;"PRESS ""PLAY/RECORD"" ON TAPE"
2450 PRINT "DECK"
2460 PRINT AT 7,0;"PRESS ""ENTER"" ON COMPUTER"
2470 INPUT Z$
2480 RAND USR 16514
2490 CLS
2500 SLOW
2510 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
2520 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
2530 INPUT Z$
2540 RETURN
2550 REM %I%N%P%U%T% %C%H%E%C%K%E%R% %(%Y% %O%R% %N%)%
2560 IF INKEY$="" THEN GOTO 2550
2570 LET I$=INKEY$
2580 IF I$<>"Y" AND I$<>"N" AND I$<>"M" THEN GOTO 2550
2590 RETURN
2600 SAVE "1016%0"
2610 GOTO 300
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
B\B1\C8\D3
20 REM %P%R%O%G%R%A%M% %S%E%T% %U%P% % % % % % % % %
30 DIM A$(1,1459)
40 DIM B$(64,32)
50 DIM A(64)
60 DIM B(64)
70 DIM C(64)
80 LET M=310
90 LET W=1
100 FOR X=1 TO 64
110 PRINT AT 12,0;"ENTER FIELD TITLE (32 POS)"
120 INPUT B$(X)
130 PRINT AT 12,0;"ENTER LENGTH OF FIELD "
140 INPUT C(X)
150 LET A(X)=W
160 LET B(X)=W+C(X)-1
170 LET W=W+C(X)
180 NEXT X
190 FAST
200 LPRINT "RECORD LAYOUT"
210 LPRINT
220 LPRINT "FIELD NAME"
230 LPRINT "ST POS END POS LENGTH FLD NBR."
240 LPRINT "--------------------------------"
250 FOR X=1 TO 64
260 LPRINT B$(X)
270 LPRINT A(X);TAB 8;B(X);TAB 17;C(X);TAB 25;X
280 LPRINT
290 NEXT X
300 SLOW
310 REM %M%E%N%U% % % % % % % % % % % % % % % % % % %
320 CLS
330 PRINT TAB 5;"RECORD FORMATTER VER.1"
340 PRINT TAB 3;"COPYRIGHT 1985 TIM L. WARD",,,
350 PRINT "DO YOU WISH TO..",,,
360 PRINT "1)...ENTER A NEW RECORD?",,,
370 PRINT "2)...CHANGE A RECORD?",,,
380 PRINT "3)...DISPLAY A RECORD?",,,
390 PRINT "4)...PRINT A RECORD?",,,
400 PRINT "5)...PRINT DATA TAPE DIRECTORY?",,,
410 PRINT "6)...COPY DATA TAPE?",,,
420 PRINT "7)...COPY PROGRAM?",,,
430 PRINT "8)...END PROGRAM?",,,
440 PRINT "ENTER NBR. OF SELECTION"
450 IF INKEY$="" THEN GOTO 0450
460 LET I$=INKEY$
470 IF I$="1" THEN GOSUB 0560
480 IF I$="2" THEN GOSUB 0770
490 IF I$="3" THEN GOSUB 1150
500 IF I$="4" THEN GOSUB 1470
510 IF I$="5" THEN GOSUB 1690
520 IF I$="6" THEN GOSUB 2020
530 IF I$="7" THEN GOTO 2120
540 IF I$="8" THEN GOSUB 2210
550 GOTO 0310
560 REM %E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D% % % % %
570 CLS
580 PRINT ,,,,,,"DO YOU WISH TO ADD A NEW RCD?"
590 PRINT TAB 11;"(Y, N, OR M)"
600 GOSUB 2550
610 IF I$<>"Y" THEN RETURN
620 FOR X=1 TO 64
630 DIM C$(1,C(X))
640 CLS
650 PRINT AT 0,6;"%E%N%T%E%R% %A% %N%E%W% %R%E%C%O%R%D"
660 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
670 PRINT AT 4,0;B$(X)
680 INPUT C$(1)
690 PRINT AT 6,0;C$(1)
700 PRINT "IS THIS CORRECT? (Y OR N)"
710 GOSUB 2550
720 IF I$<>"Y" THEN GOTO 0640
730 LET A$(1,A(X) TO B(X))=C$(1)
740 NEXT X
750 GOSUB 2410
760 RETURN
770 REM %C%H%A%N%G%E% %A% %R%E%C%O%R%D% % % % % % % %
780 CLS
790 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
800 PRINT AT 2,0;"DO YOU WISH TO CHANGE THIS RCD?"
810 PRINT AT 4,11;"(Y, N, OR M)",,,
820 FOR X=1 TO 5
830 PRINT B$(X)
840 PRINT A$(1,A(X) TO B(X))
850 NEXT X
860 GOSUB 2550
870 IF I$="M" THEN RETURN
880 IF I$="Y" THEN GOTO 0920
890 GOSUB 2410
900 GOSUB 2280
910 GOTO 0770
920 FOR X=1 TO 64
930 CLS
940 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
950 PRINT AT 2,0;"CHANGE THIS FIELD? (Y OR N)"
960 PRINT AT 4,0;B$(X)
970 PRINT A$(1,A(X) TO B(X))
980 GOSUB 2550
990 IF I$="N" THEN NEXT X
\n1000 IF I$="N" AND X=65 THEN GOTO 1130
\n1010 DIM C$(1,C(X))
\n1020 CLS
\n1030 PRINT AT 0,8;"%C%H%A%N%G%E% %A% %R%E%C%O%R%D"
\n1040 PRINT AT 2,0;"PLEASE ENTER INDIVIDUALS:"
\n1050 PRINT AT 4,0;B$(X)
\n1060 INPUT C$(1)
\n1070 PRINT AT 6,0;C$(1)
\n1080 PRINT "IS THIS CORRECT? (Y OR N)"
\n1090 GOSUB 2550
\n1100 IF I$<>"Y" THEN GOTO 1020
\n1110 LET A$(1,A(X) TO B(X))=C$(1)
\n1120 NEXT X
\n1130 GOSUB 2410
\n1140 RETURN
\n1150 REM %D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D% % % % % % %
\n1160 CLS
\n1170 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
\n1180 PRINT AT 2,0;"DO YOU WISH TO DISPLAY THIS RCD?"
\n1190 PRINT AT 4,11;"(Y, N, OR M)"
\n1200 FOR X=1 TO 5
\n1210 PRINT B$(X)
\n1220 PRINT A$(1,A(X) TO B(X))
\n1230 NEXT X
\n1240 GOSUB 2550
\n1250 IF I$="M" THEN RETURN
\n1260 IF I$="Y" THEN GOTO 1290
\n1270 GOSUB 2280
\n1280 GOTO 1150
\n1290 CLS
\n1300 FOR X=1 TO 64
\n1310 PRINT AT 0,8;"%D%I%S%P%L%A%Y% %A% %R%E%C%O%R%D"
\n1320 PRINT AT 2,0;"RECORD DISPLAYED IS FOR..."
\n1330 PRINT AT 4,0;"GEN/CODE NBR. ";A$(1, TO 5)
\n1340 PRINT AT 5,0;A$(1,6 TO 20)
\n1350 PRINT AT 6,0;A$(1,21 TO 35)
\n1360 PRINT AT 7,0;A$(1,36 TO 50)
\n1370 PRINT AT 8,0;A$(1,51 TO 65)
\n1380 PRINT AT 15,0;"%P%R%E%S%S% %E%N%T%E%R% %F%O%R% %N%E%X%T% %F%I%E%L%D% % % % % % "
\n1390 PRINT AT 16,0;"%P%R%E%S%S% %"%M%"% %T%O% %R%E%T%U%R%N% %T%O% % %M%E%N%U% % % % "
\n1400 PRINT AT 10,0;B$(X)
\n1410 PRINT AT 12,0;A$(1,A(X) TO B(X))
\n1420 IF INKEY$="" THEN GOTO 1420
\n1430 IF INKEY$="M" THEN RETURN
\n1440 PRINT AT 12,0;" "
\n1450 NEXT X
\n1460 RETURN
\n1470 REM %P%R%I%N%T% %A% %R%E%C%O%R%D% % % % % % % % %
\n1480 CLS
\n1490 PRINT AT 0,8;"%P%R%I%N%T% %A% %R%E%C%O%R%D"
\n1500 PRINT AT 2,0;"DO YOU WISH TO PRINT THIS RCD?"
\n1510 PRINT AT 4,11;"(Y, N, OR M)",,,
\n1520 FOR X=1 TO 5
\n1530 PRINT B$(X)
\n1540 PRINT A$(1,A(X) TO B(X))
\n1550 NEXT X
\n1560 GOSUB 2550
\n1570 IF I$="Y" THEN GOTO 1610
\n1580 IF I$="M" THEN RETURN
\n1590 GOSUB 2280
\n1600 GOTO 1470
\n1610 FAST
\n1620 FOR X=1 TO 64
\n1630 LPRINT B$(X)
\n1640 LPRINT A$(1,A(X) TO B(X))
\n1650 LPRINT
\n1660 NEXT X
\n1670 SLOW
\n1680 RETURN
\n1690 REM %P%R%I%N%T% %D%/%T% %D%I%R%E%C%T%O%R%Y% % % %
\n1700 CLS
\n1710 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
\n1720 PRINT AT 4,0;"IS THE PRINTER ON ? (Y, N, OR M)"
\n1730 GOSUB 2550
\n1740 IF I$="M" THEN RETURN
\n1750 IF I$="Y" THEN GOTO 1790
\n1760 PRINT AT 12,0;"PLEASE TURN THE PRINTER ON"
\n1770 PRINT AT 14,0;"PRESS ENTER WHEN PRINTER IS ON"
\n1780 INPUT I$
\n1790 CLS
\n1800 PRINT AT 0,5;"%D%A%T%A% %T%A%P%E% %D%I%R%E%C%T%O%R%Y"
\n1810 PRINT AT 4,0;"PLACE OLD DATA TAPE IN TAPE DECK"
\n1820 PRINT AT 6,0;"PRESS ""PLAY"" ON TAPE DECK"
\n1830 PRINT AT 8,0;"PRESS ""ENTER"" ON COMPUTER"
\n1840 INPUT I$
\n1850 LPRINT "% % % % % % % DATA TAPE DIRECTORY% % % % % % ",,
\n1860 LPRINT "GEN/"
\n1870 LPRINT "CODE FIRST/LAST NAME",,,
\n1880 FOR X=1 TO 35
\n1890 RAND USR 16549
\n1900 DIM C$(1,36)
\n1910 LET C$(1)=A$(1,1 TO 5)+" "+A$(1,6 TO 20)+A$(1,51 TO 65)
\n1920 LET D$=""
\n1930 FOR Y=1 TO 36
\n1940 IF C$(1,Y)=" " THEN GOTO 1970
\n1950 LET D$=D$+C$(1,Y)
\n1960 IF C$(1,Y+1)=" " THEN LET D$=D$+" "
\n1970 NEXT Y
\n1980 LPRINT D$
\n1990 LPRINT
\n2000 NEXT X
\n2010 RETURN
\n2020 REM %C%O%P%Y% %D%A%T%A% %T%A%P%E% % % % % % % % %
\n2030 CLS
\n2040 PRINT ,,,,,,"HOW MANY RECORDS DO YOU WISH TO",,,"COPY? (1 TO 35)"
\n2050 INPUT Z
\n2060 IF Z>35 THEN GOTO 2020
\n2070 FOR X=1 TO Z
\n2080 GOSUB 2280
\n2090 GOSUB 2410
\n2100 NEXT X
\n2110 RETURN
\n2120 REM %C%O%P%Y% %P%R%O%G%R%A%M% % % % % % % % % % %
\n2130 CLS
\n2140 PRINT ,,,,,,"PLACE BLANK PROGRAM TAPE IN TAPE",,"DECK, PRESS ""PLAY/RECORD"" ON",,,"TAPE DECK, PRESS ""ENTER"" ON",,,"COMPUTER."
\n2150 INPUT I$
\n2160 CLS
\n2170 SAVE "FORMATTE%R"
\n2180 PRINT ,,,,,,"PRESS ""STOP"" ON TAPE DECK",,,"PRESS ""ENTER"" ON COMPUTER."
\n2190 INPUT I$
\n2200 GOTO 0310
\n2210 REM %E%N%D% %P%R%O%G%R%A%M% % % % % % % % % % % %
\n2220 CLS
\n2230 PRINT ,,,,,,"ARE YOU SURE YOU WANT TO QUIT?"
\n2240 PRINT TAB 11;"(Y, N, OR M)"
\n2250 GOSUB 2550
\n2260 IF I$="Y" THEN NEW
\n2270 RETURN
\n2280 REM %R%E%A%D% %R%E%C%O%R%D% %O%N% %T%A%P%E% % % %
\n2290 CLS
\n2300 PRINT AT 2,0;"PLACE OLD DATA TAPE IN TAPE DECK"
\n2310 PRINT AT 4,0;"PRESS ""PLAY"" ON TAPE DECK"
\n2320 PRINT AT 6,0;"PRESS ""ENTER"" ON COMPUTER"
\n2330 INPUT Z$
\n2340 RAND USR 16549
\n2350 CLS
\n2360 SLOW
\n2370 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
\n2380 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
\n2390 INPUT Z$
\n2400 RETURN
\n2410 REM %W%R%I%T%E% %R%E%C%O%R%D% %O%N% %T%A%P%E% % %
\n2420 CLS
\n2430 PRINT AT 2,0;"PLACE NEW DATA TAPE IN TAPE DECK"
\n2440 PRINT AT 4,0;"PRESS ""PLAY/RECORD"" ON TAPE"
\n2450 PRINT "DECK"
\n2460 PRINT AT 7,0;"PRESS ""ENTER"" ON COMPUTER"
\n2470 INPUT Z$
\n2480 RAND USR 16514
\n2490 CLS
\n2500 SLOW
\n2510 PRINT AT 12,0;"PRESS ""STOP"" ON TAPE DECK"
\n2520 PRINT AT 14,0;"PRESS ""ENTER"" ON COMPUTER"
\n2530 INPUT Z$
\n2540 RETURN
\n2550 REM %I%N%P%U%T% %C%H%E%C%K%E%R% %(%Y% %O%R% %N%)%
\n2560 IF INKEY$="" THEN GOTO 2550
\n2570 LET I$=INKEY$
\n2580 IF I$<>"Y" AND I$<>"N" AND I$<>"M" THEN GOTO 2550
\n2590 RETURN
\n2600 SAVE "1016%0"
\n2610 GOTO 300
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
