Record Formatter

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

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.

  1. Lines 10–20: Machine code in REM; program identity label
  2. Lines 30–80: Array and variable initialization
  3. Lines 100–180: Field definition loop (up to 64 fields)
  4. Lines 190–300: Print record layout to printer
  5. Lines 310–550: Main menu and dispatch
  6. Lines 560–760: Enter new record subroutine
  7. Lines 770–1140: Change a record subroutine
  8. Lines 1150–1460: Display a record subroutine
  9. Lines 1470–1680: Print a record subroutine
  10. Lines 1690–2010: Print data tape directory subroutine
  11. Lines 2020–2110: Copy data tape subroutine
  12. Lines 2120–2200: Copy program subroutine
  13. Lines 2210–2270: End program subroutine
  14. Lines 2280–2400: Read record from tape subroutine
  15. Lines 2410–2540: Write record to tape subroutine
  16. Lines 2550–2590: Input checker subroutine (Y/N/M)
  17. 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:

OffsetAddressBytesMnemonicNotes
016514CD E7 02CALL 02E7hZX81 ROM: slow-speed display/sync entry
31651706 0ELD B,0EhLoop counter = 14
51651921 00 FFLD HL,FF00hStart of candidate address range
8165222BDEC HLStep HL down
9165237CLD A,H
1016524B5OR LCheck HL=0
111652520 FBJR NZ,-5Loop until zero
131652710 F6DJNZ -10Outer timing loop
15165292A 10 40LD HL,(4010h)Load A$ descriptor pointer
181653223INC HL
19165334ELD C,(HL)Low byte of length
201653423INC HL
211653546LD B,(HL)High byte of length
221653623INC HL
2316537C5PUSH BCSave byte count
24165385ELD E,(HL)Data address low
2516539CD 1F 03CALL 031FhROM: output byte to tape
2816542C1POP BC
29165430BDEC BC
301654478LD A,B
3116545B1OR CCheck BC=0
321654620 F4JR NZ,-12Write loop
3416548C9RETEnd of write routine
3516549CD E7 02CALL 02E7hRead routine starts here
38165522A 10 40LD 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 loopDIM 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 checkIF 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 2610GOTO 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Record Formatter

Source Code

  10 REM \CD\E7



Record Formatter

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

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.

  1. Lines 10–20: Machine code in REM; program identity label
  2. Lines 30–80: Array and variable initialization
  3. Lines 100–180: Field definition loop (up to 64 fields)
  4. Lines 190–300: Print record layout to printer
  5. Lines 310–550: Main menu and dispatch
  6. Lines 560–760: Enter new record subroutine
  7. Lines 770–1140: Change a record subroutine
  8. Lines 1150–1460: Display a record subroutine
  9. Lines 1470–1680: Print a record subroutine
  10. Lines 1690–2010: Print data tape directory subroutine
  11. Lines 2020–2110: Copy data tape subroutine
  12. Lines 2120–2200: Copy program subroutine
  13. Lines 2210–2270: End program subroutine
  14. Lines 2280–2400: Read record from tape subroutine
  15. Lines 2410–2540: Write record to tape subroutine
  16. Lines 2550–2590: Input checker subroutine (Y/N/M)
  17. 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:

OffsetAddressBytesMnemonicNotes
016514CD E7 02CALL 02E7hZX81 ROM: slow-speed display/sync entry
31651706 0ELD B,0EhLoop counter = 14
51651921 00 FFLD HL,FF00hStart of candidate address range
8165222BDEC HLStep HL down
9165237CLD A,H
1016524B5OR LCheck HL=0
111652520 FBJR NZ,-5Loop until zero
131652710 F6DJNZ -10Outer timing loop
15165292A 10 40LD HL,(4010h)Load A$ descriptor pointer
181653223INC HL
19165334ELD C,(HL)Low byte of length
201653423INC HL
211653546LD B,(HL)High byte of length
221653623INC HL
2316537C5PUSH BCSave byte count
24165385ELD E,(HL)Data address low
2516539CD 1F 03CALL 031FhROM: output byte to tape
2816542C1POP BC
29165430BDEC BC
301654478LD A,B
3116545B1OR CCheck BC=0
321654620 F4JR NZ,-12Write loop
3416548C9RETEnd of write routine
3516549CD E7 02CALL 02E7hRead routine starts here
38165522A 10 40LD 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 loopDIM 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 checkIF 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 2610GOTO 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Record Formatter

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.

Scroll to Top

Record Formatter

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

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.

  1. Lines 10–20: Machine code in REM; program identity label
  2. Lines 30–80: Array and variable initialization
  3. Lines 100–180: Field definition loop (up to 64 fields)
  4. Lines 190–300: Print record layout to printer
  5. Lines 310–550: Main menu and dispatch
  6. Lines 560–760: Enter new record subroutine
  7. Lines 770–1140: Change a record subroutine
  8. Lines 1150–1460: Display a record subroutine
  9. Lines 1470–1680: Print a record subroutine
  10. Lines 1690–2010: Print data tape directory subroutine
  11. Lines 2020–2110: Copy data tape subroutine
  12. Lines 2120–2200: Copy program subroutine
  13. Lines 2210–2270: End program subroutine
  14. Lines 2280–2400: Read record from tape subroutine
  15. Lines 2410–2540: Write record to tape subroutine
  16. Lines 2550–2590: Input checker subroutine (Y/N/M)
  17. 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:

OffsetAddressBytesMnemonicNotes
016514CD E7 02CALL 02E7hZX81 ROM: slow-speed display/sync entry
31651706 0ELD B,0EhLoop counter = 14
51651921 00 FFLD HL,FF00hStart of candidate address range
8165222BDEC HLStep HL down
9165237CLD A,H
1016524B5OR LCheck HL=0
111652520 FBJR NZ,-5Loop until zero
131652710 F6DJNZ -10Outer timing loop
15165292A 10 40LD HL,(4010h)Load A$ descriptor pointer
181653223INC HL
19165334ELD C,(HL)Low byte of length
201653423INC HL
211653546LD B,(HL)High byte of length
221653623INC HL
2316537C5PUSH BCSave byte count
24165385ELD E,(HL)Data address low
2516539CD 1F 03CALL 031FhROM: output byte to tape
2816542C1POP BC
29165430BDEC BC
301654478LD A,B
3116545B1OR CCheck BC=0
321654620 F4JR NZ,-12Write loop
3416548C9RETEnd of write routine
3516549CD E7 02CALL 02E7hRead routine starts here
38165522A 10 40LD 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 loopDIM 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 checkIF 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 2610GOTO 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Record Formatter

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.

Scroll to Top
E

Record Formatter

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

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.

  1. Lines 10–20: Machine code in REM; program identity label
  2. Lines 30–80: Array and variable initialization
  3. Lines 100–180: Field definition loop (up to 64 fields)
  4. Lines 190–300: Print record layout to printer
  5. Lines 310–550: Main menu and dispatch
  6. Lines 560–760: Enter new record subroutine
  7. Lines 770–1140: Change a record subroutine
  8. Lines 1150–1460: Display a record subroutine
  9. Lines 1470–1680: Print a record subroutine
  10. Lines 1690–2010: Print data tape directory subroutine
  11. Lines 2020–2110: Copy data tape subroutine
  12. Lines 2120–2200: Copy program subroutine
  13. Lines 2210–2270: End program subroutine
  14. Lines 2280–2400: Read record from tape subroutine
  15. Lines 2410–2540: Write record to tape subroutine
  16. Lines 2550–2590: Input checker subroutine (Y/N/M)
  17. 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:

OffsetAddressBytesMnemonicNotes
016514CD E7 02CALL 02E7hZX81 ROM: slow-speed display/sync entry
31651706 0ELD B,0EhLoop counter = 14
51651921 00 FFLD HL,FF00hStart of candidate address range
8165222BDEC HLStep HL down
9165237CLD A,H
1016524B5OR LCheck HL=0
111652520 FBJR NZ,-5Loop until zero
131652710 F6DJNZ -10Outer timing loop
15165292A 10 40LD HL,(4010h)Load A$ descriptor pointer
181653223INC HL
19165334ELD C,(HL)Low byte of length
201653423INC HL
211653546LD B,(HL)High byte of length
221653623INC HL
2316537C5PUSH BCSave byte count
24165385ELD E,(HL)Data address low
2516539CD 1F 03CALL 031FhROM: output byte to tape
2816542C1POP BC
29165430BDEC BC
301654478LD A,B
3116545B1OR CCheck BC=0
321654620 F4JR NZ,-12Write loop
3416548C9RETEnd of write routine
3516549CD E7 02CALL 02E7hRead routine starts here
38165522A 10 40LD 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 loopDIM 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 checkIF 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 2610GOTO 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Record Formatter

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.

Scroll to Top
\FF

Record Formatter

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

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.

  1. Lines 10–20: Machine code in REM; program identity label
  2. Lines 30–80: Array and variable initialization
  3. Lines 100–180: Field definition loop (up to 64 fields)
  4. Lines 190–300: Print record layout to printer
  5. Lines 310–550: Main menu and dispatch
  6. Lines 560–760: Enter new record subroutine
  7. Lines 770–1140: Change a record subroutine
  8. Lines 1150–1460: Display a record subroutine
  9. Lines 1470–1680: Print a record subroutine
  10. Lines 1690–2010: Print data tape directory subroutine
  11. Lines 2020–2110: Copy data tape subroutine
  12. Lines 2120–2200: Copy program subroutine
  13. Lines 2210–2270: End program subroutine
  14. Lines 2280–2400: Read record from tape subroutine
  15. Lines 2410–2540: Write record to tape subroutine
  16. Lines 2550–2590: Input checker subroutine (Y/N/M)
  17. 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:

OffsetAddressBytesMnemonicNotes
016514CD E7 02CALL 02E7hZX81 ROM: slow-speed display/sync entry
31651706 0ELD B,0EhLoop counter = 14
51651921 00 FFLD HL,FF00hStart of candidate address range
8165222BDEC HLStep HL down
9165237CLD A,H
1016524B5OR LCheck HL=0
111652520 FBJR NZ,-5Loop until zero
131652710 F6DJNZ -10Outer timing loop
15165292A 10 40LD HL,(4010h)Load A$ descriptor pointer
181653223INC HL
19165334ELD C,(HL)Low byte of length
201653423INC HL
211653546LD B,(HL)High byte of length
221653623INC HL
2316537C5PUSH BCSave byte count
24165385ELD E,(HL)Data address low
2516539CD 1F 03CALL 031FhROM: output byte to tape
2816542C1POP BC
29165430BDEC BC
301654478LD A,B
3116545B1OR CCheck BC=0
321654620 F4JR NZ,-12Write loop
3416548C9RETEnd of write routine
3516549CD E7 02CALL 02E7hRead routine starts here
38165522A 10 40LD 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 loopDIM 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 checkIF 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 2610GOTO 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Record Formatter

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.

Scroll to Top
BC\B5\FB\F6

Record Formatter

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

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.

  1. Lines 10–20: Machine code in REM; program identity label
  2. Lines 30–80: Array and variable initialization
  3. Lines 100–180: Field definition loop (up to 64 fields)
  4. Lines 190–300: Print record layout to printer
  5. Lines 310–550: Main menu and dispatch
  6. Lines 560–760: Enter new record subroutine
  7. Lines 770–1140: Change a record subroutine
  8. Lines 1150–1460: Display a record subroutine
  9. Lines 1470–1680: Print a record subroutine
  10. Lines 1690–2010: Print data tape directory subroutine
  11. Lines 2020–2110: Copy data tape subroutine
  12. Lines 2120–2200: Copy program subroutine
  13. Lines 2210–2270: End program subroutine
  14. Lines 2280–2400: Read record from tape subroutine
  15. Lines 2410–2540: Write record to tape subroutine
  16. Lines 2550–2590: Input checker subroutine (Y/N/M)
  17. 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:

OffsetAddressBytesMnemonicNotes
016514CD E7 02CALL 02E7hZX81 ROM: slow-speed display/sync entry
31651706 0ELD B,0EhLoop counter = 14
51651921 00 FFLD HL,FF00hStart of candidate address range
8165222BDEC HLStep HL down
9165237CLD A,H
1016524B5OR LCheck HL=0
111652520 FBJR NZ,-5Loop until zero
131652710 F6DJNZ -10Outer timing loop
15165292A 10 40LD HL,(4010h)Load A$ descriptor pointer
181653223INC HL
19165334ELD C,(HL)Low byte of length
201653423INC HL
211653546LD B,(HL)High byte of length
221653623INC HL
2316537C5PUSH BCSave byte count
24165385ELD E,(HL)Data address low
2516539CD 1F 03CALL 031FhROM: output byte to tape
2816542C1POP BC
29165430BDEC BC
301654478LD A,B
3116545B1OR CCheck BC=0
321654620 F4JR NZ,-12Write loop
3416548C9RETEnd of write routine
3516549CD E7 02CALL 02E7hRead routine starts here
38165522A 10 40LD 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 loopDIM 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 checkIF 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 2610GOTO 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Record Formatter

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.

Scroll to Top
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

Record Formatter

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

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.

  1. Lines 10–20: Machine code in REM; program identity label
  2. Lines 30–80: Array and variable initialization
  3. Lines 100–180: Field definition loop (up to 64 fields)
  4. Lines 190–300: Print record layout to printer
  5. Lines 310–550: Main menu and dispatch
  6. Lines 560–760: Enter new record subroutine
  7. Lines 770–1140: Change a record subroutine
  8. Lines 1150–1460: Display a record subroutine
  9. Lines 1470–1680: Print a record subroutine
  10. Lines 1690–2010: Print data tape directory subroutine
  11. Lines 2020–2110: Copy data tape subroutine
  12. Lines 2120–2200: Copy program subroutine
  13. Lines 2210–2270: End program subroutine
  14. Lines 2280–2400: Read record from tape subroutine
  15. Lines 2410–2540: Write record to tape subroutine
  16. Lines 2550–2590: Input checker subroutine (Y/N/M)
  17. 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:

OffsetAddressBytesMnemonicNotes
016514CD E7 02CALL 02E7hZX81 ROM: slow-speed display/sync entry
31651706 0ELD B,0EhLoop counter = 14
51651921 00 FFLD HL,FF00hStart of candidate address range
8165222BDEC HLStep HL down
9165237CLD A,H
1016524B5OR LCheck HL=0
111652520 FBJR NZ,-5Loop until zero
131652710 F6DJNZ -10Outer timing loop
15165292A 10 40LD HL,(4010h)Load A$ descriptor pointer
181653223INC HL
19165334ELD C,(HL)Low byte of length
201653423INC HL
211653546LD B,(HL)High byte of length
221653623INC HL
2316537C5PUSH BCSave byte count
24165385ELD E,(HL)Data address low
2516539CD 1F 03CALL 031FhROM: output byte to tape
2816542C1POP BC
29165430BDEC BC
301654478LD A,B
3116545B1OR CCheck BC=0
321654620 F4JR NZ,-12Write loop
3416548C9RETEnd of write routine
3516549CD E7 02CALL 02E7hRead routine starts here
38165522A 10 40LD 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 loopDIM 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 checkIF 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 2610GOTO 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Record Formatter

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.

Scroll to Top
B\B1\F4\C9\CD\E7

Record Formatter

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

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.

  1. Lines 10–20: Machine code in REM; program identity label
  2. Lines 30–80: Array and variable initialization
  3. Lines 100–180: Field definition loop (up to 64 fields)
  4. Lines 190–300: Print record layout to printer
  5. Lines 310–550: Main menu and dispatch
  6. Lines 560–760: Enter new record subroutine
  7. Lines 770–1140: Change a record subroutine
  8. Lines 1150–1460: Display a record subroutine
  9. Lines 1470–1680: Print a record subroutine
  10. Lines 1690–2010: Print data tape directory subroutine
  11. Lines 2020–2110: Copy data tape subroutine
  12. Lines 2120–2200: Copy program subroutine
  13. Lines 2210–2270: End program subroutine
  14. Lines 2280–2400: Read record from tape subroutine
  15. Lines 2410–2540: Write record to tape subroutine
  16. Lines 2550–2590: Input checker subroutine (Y/N/M)
  17. 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:

OffsetAddressBytesMnemonicNotes
016514CD E7 02CALL 02E7hZX81 ROM: slow-speed display/sync entry
31651706 0ELD B,0EhLoop counter = 14
51651921 00 FFLD HL,FF00hStart of candidate address range
8165222BDEC HLStep HL down
9165237CLD A,H
1016524B5OR LCheck HL=0
111652520 FBJR NZ,-5Loop until zero
131652710 F6DJNZ -10Outer timing loop
15165292A 10 40LD HL,(4010h)Load A$ descriptor pointer
181653223INC HL
19165334ELD C,(HL)Low byte of length
201653423INC HL
211653546LD B,(HL)High byte of length
221653623INC HL
2316537C5PUSH BCSave byte count
24165385ELD E,(HL)Data address low
2516539CD 1F 03CALL 031FhROM: output byte to tape
2816542C1POP BC
29165430BDEC BC
301654478LD A,B
3116545B1OR CCheck BC=0
321654620 F4JR NZ,-12Write loop
3416548C9RETEnd of write routine
3516549CD E7 02CALL 02E7hRead routine starts here
38165522A 10 40LD 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 loopDIM 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 checkIF 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 2610GOTO 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Record Formatter

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.

Scroll to Top

Record Formatter

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

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.

  1. Lines 10–20: Machine code in REM; program identity label
  2. Lines 30–80: Array and variable initialization
  3. Lines 100–180: Field definition loop (up to 64 fields)
  4. Lines 190–300: Print record layout to printer
  5. Lines 310–550: Main menu and dispatch
  6. Lines 560–760: Enter new record subroutine
  7. Lines 770–1140: Change a record subroutine
  8. Lines 1150–1460: Display a record subroutine
  9. Lines 1470–1680: Print a record subroutine
  10. Lines 1690–2010: Print data tape directory subroutine
  11. Lines 2020–2110: Copy data tape subroutine
  12. Lines 2120–2200: Copy program subroutine
  13. Lines 2210–2270: End program subroutine
  14. Lines 2280–2400: Read record from tape subroutine
  15. Lines 2410–2540: Write record to tape subroutine
  16. Lines 2550–2590: Input checker subroutine (Y/N/M)
  17. 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:

OffsetAddressBytesMnemonicNotes
016514CD E7 02CALL 02E7hZX81 ROM: slow-speed display/sync entry
31651706 0ELD B,0EhLoop counter = 14
51651921 00 FFLD HL,FF00hStart of candidate address range
8165222BDEC HLStep HL down
9165237CLD A,H
1016524B5OR LCheck HL=0
111652520 FBJR NZ,-5Loop until zero
131652710 F6DJNZ -10Outer timing loop
15165292A 10 40LD HL,(4010h)Load A$ descriptor pointer
181653223INC HL
19165334ELD C,(HL)Low byte of length
201653423INC HL
211653546LD B,(HL)High byte of length
221653623INC HL
2316537C5PUSH BCSave byte count
24165385ELD E,(HL)Data address low
2516539CD 1F 03CALL 031FhROM: output byte to tape
2816542C1POP BC
29165430BDEC BC
301654478LD A,B
3116545B1OR CCheck BC=0
321654620 F4JR NZ,-12Write loop
3416548C9RETEnd of write routine
3516549CD E7 02CALL 02E7hRead routine starts here
38165522A 10 40LD 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 loopDIM 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 checkIF 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 2610GOTO 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Record Formatter

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.

Scroll to Top
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

Record Formatter

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

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.

  1. Lines 10–20: Machine code in REM; program identity label
  2. Lines 30–80: Array and variable initialization
  3. Lines 100–180: Field definition loop (up to 64 fields)
  4. Lines 190–300: Print record layout to printer
  5. Lines 310–550: Main menu and dispatch
  6. Lines 560–760: Enter new record subroutine
  7. Lines 770–1140: Change a record subroutine
  8. Lines 1150–1460: Display a record subroutine
  9. Lines 1470–1680: Print a record subroutine
  10. Lines 1690–2010: Print data tape directory subroutine
  11. Lines 2020–2110: Copy data tape subroutine
  12. Lines 2120–2200: Copy program subroutine
  13. Lines 2210–2270: End program subroutine
  14. Lines 2280–2400: Read record from tape subroutine
  15. Lines 2410–2540: Write record to tape subroutine
  16. Lines 2550–2590: Input checker subroutine (Y/N/M)
  17. 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:

OffsetAddressBytesMnemonicNotes
016514CD E7 02CALL 02E7hZX81 ROM: slow-speed display/sync entry
31651706 0ELD B,0EhLoop counter = 14
51651921 00 FFLD HL,FF00hStart of candidate address range
8165222BDEC HLStep HL down
9165237CLD A,H
1016524B5OR LCheck HL=0
111652520 FBJR NZ,-5Loop until zero
131652710 F6DJNZ -10Outer timing loop
15165292A 10 40LD HL,(4010h)Load A$ descriptor pointer
181653223INC HL
19165334ELD C,(HL)Low byte of length
201653423INC HL
211653546LD B,(HL)High byte of length
221653623INC HL
2316537C5PUSH BCSave byte count
24165385ELD E,(HL)Data address low
2516539CD 1F 03CALL 031FhROM: output byte to tape
2816542C1POP BC
29165430BDEC BC
301654478LD A,B
3116545B1OR CCheck BC=0
321654620 F4JR NZ,-12Write loop
3416548C9RETEnd of write routine
3516549CD E7 02CALL 02E7hRead routine starts here
38165522A 10 40LD 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 loopDIM 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 checkIF 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 2610GOTO 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Record Formatter

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.

Scroll to Top
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

Record Formatter

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

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.

  1. Lines 10–20: Machine code in REM; program identity label
  2. Lines 30–80: Array and variable initialization
  3. Lines 100–180: Field definition loop (up to 64 fields)
  4. Lines 190–300: Print record layout to printer
  5. Lines 310–550: Main menu and dispatch
  6. Lines 560–760: Enter new record subroutine
  7. Lines 770–1140: Change a record subroutine
  8. Lines 1150–1460: Display a record subroutine
  9. Lines 1470–1680: Print a record subroutine
  10. Lines 1690–2010: Print data tape directory subroutine
  11. Lines 2020–2110: Copy data tape subroutine
  12. Lines 2120–2200: Copy program subroutine
  13. Lines 2210–2270: End program subroutine
  14. Lines 2280–2400: Read record from tape subroutine
  15. Lines 2410–2540: Write record to tape subroutine
  16. Lines 2550–2590: Input checker subroutine (Y/N/M)
  17. 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:

OffsetAddressBytesMnemonicNotes
016514CD E7 02CALL 02E7hZX81 ROM: slow-speed display/sync entry
31651706 0ELD B,0EhLoop counter = 14
51651921 00 FFLD HL,FF00hStart of candidate address range
8165222BDEC HLStep HL down
9165237CLD A,H
1016524B5OR LCheck HL=0
111652520 FBJR NZ,-5Loop until zero
131652710 F6DJNZ -10Outer timing loop
15165292A 10 40LD HL,(4010h)Load A$ descriptor pointer
181653223INC HL
19165334ELD C,(HL)Low byte of length
201653423INC HL
211653546LD B,(HL)High byte of length
221653623INC HL
2316537C5PUSH BCSave byte count
24165385ELD E,(HL)Data address low
2516539CD 1F 03CALL 031FhROM: output byte to tape
2816542C1POP BC
29165430BDEC BC
301654478LD A,B
3116545B1OR CCheck BC=0
321654620 F4JR NZ,-12Write loop
3416548C9RETEnd of write routine
3516549CD E7 02CALL 02E7hRead routine starts here
38165522A 10 40LD 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 loopDIM 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 checkIF 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 2610GOTO 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Record Formatter

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.

Scroll to Top
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

Record Formatter

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

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.

  1. Lines 10–20: Machine code in REM; program identity label
  2. Lines 30–80: Array and variable initialization
  3. Lines 100–180: Field definition loop (up to 64 fields)
  4. Lines 190–300: Print record layout to printer
  5. Lines 310–550: Main menu and dispatch
  6. Lines 560–760: Enter new record subroutine
  7. Lines 770–1140: Change a record subroutine
  8. Lines 1150–1460: Display a record subroutine
  9. Lines 1470–1680: Print a record subroutine
  10. Lines 1690–2010: Print data tape directory subroutine
  11. Lines 2020–2110: Copy data tape subroutine
  12. Lines 2120–2200: Copy program subroutine
  13. Lines 2210–2270: End program subroutine
  14. Lines 2280–2400: Read record from tape subroutine
  15. Lines 2410–2540: Write record to tape subroutine
  16. Lines 2550–2590: Input checker subroutine (Y/N/M)
  17. 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:

OffsetAddressBytesMnemonicNotes
016514CD E7 02CALL 02E7hZX81 ROM: slow-speed display/sync entry
31651706 0ELD B,0EhLoop counter = 14
51651921 00 FFLD HL,FF00hStart of candidate address range
8165222BDEC HLStep HL down
9165237CLD A,H
1016524B5OR LCheck HL=0
111652520 FBJR NZ,-5Loop until zero
131652710 F6DJNZ -10Outer timing loop
15165292A 10 40LD HL,(4010h)Load A$ descriptor pointer
181653223INC HL
19165334ELD C,(HL)Low byte of length
201653423INC HL
211653546LD B,(HL)High byte of length
221653623INC HL
2316537C5PUSH BCSave byte count
24165385ELD E,(HL)Data address low
2516539CD 1F 03CALL 031FhROM: output byte to tape
2816542C1POP BC
29165430BDEC BC
301654478LD A,B
3116545B1OR CCheck BC=0
321654620 F4JR NZ,-12Write loop
3416548C9RETEnd of write routine
3516549CD E7 02CALL 02E7hRead routine starts here
38165522A 10 40LD 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 loopDIM 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 checkIF 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 2610GOTO 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Record Formatter

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.

Scroll to Top
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.

Scroll to Top