The first program is a DXCC (DX Century Club) countries log for amateur radio operators, storing up to 340 country records in a single large string array D$(340,32), where each 32-character row holds country number, callsign prefix, country name, and QSL card data. It provides search by number, prefix, or name; a paged review mode; and a totals screen showing worked, credited, and QSL-sent/received counts. The second program is a full-screen typewriter utility that tracks cursor position column-by-column across a 32-column display, uses SCROLL to handle page overflow, and supports backspace, newline, and direct cursor positioning by line and column number. Both programs use the SLOW/FAST idiom around PAUSE and POKE 16437,255 to debounce keyboard input reliably on the ZX81.
Program Analysis
Program 1: DXCC Countries List
This amateur radio utility, written by R. J. Lees (W3ZQN) in September 1982, maintains a database of up to 340 DXCC (DX Century Club) country entities. The entire database is stored in a single two-dimensional string array D$(340,32), where each row is exactly 32 characters wide and encodes structured fields at fixed byte offsets.
Record Layout
| Columns | Field | Length |
|---|---|---|
| 1–3 | Country number | 3 |
| 4 | Separator (space) | 1 |
| 5–15 | Callsign prefix | 11 |
| 16 | Separator | 1 |
| 17–26 | Country name | 10 |
| 27 | Separator | 1 |
| 28–32 | QSL data (MMYY + S/R/C) | 5 |
Searching by prefix uses D$(C,5 TO 15)=P$ and by name uses D$(C,17 TO 26)=N$. The final character at position 32 encodes QSL status: S = sent/no return, R = sent and returned, C = DXCC credited. The TOTALS routine (lines 4000–4240) iterates all 340 records, testing individual character positions to accumulate five counters.
Program Structure
- Lines 11–15: Array declarations (
C$,P$,N$,I$,D$) - Lines 100–200: Main menu loop
- Lines 1000–1050: Search sub-menu
- Lines 1100–1260: Search by country number
- Lines 1500–1710: Search by prefix
- Lines 2000–2210: Search by name
- Lines 3000–3120: Paged review mode
- Lines 4000–4240: Totals computation and display
- Lines 5000–5210: Data input routine
- Lines 6000–6520: Shared display/change/another subroutines
- Lines 7000–7020: Exit with warning message
- Lines 8000–8120: Keypress wait and “not found” subroutines
- Lines 9000–9010: SAVE and restart
Key BASIC Idioms and Techniques
The keypress-wait subroutine at line 8000 uses SLOW, PAUSE 20, POKE 16437,255, and a busy-wait loop on INKEY$. The POKE to address 16437 resets the ZX81’s internal frame counter, preventing a system BREAK. After returning, the calling code checks INKEY$ directly for the expected key — this is safe because SLOW mode retains the keyboard state long enough for the test.
The input routine at lines 5000–5190 stores the country number as a string in C$, then uses VAL C$ at line 5012 to obtain the numeric index C. The country number string is also written directly into the first three columns of the record via D$(C, TO 3)=C$.
The review routine (line 3030) steps by 21 with FOR B=PS TO 340 STEP 21 and prints a page of 22 records with an inner loop, using a guard at line 3050 to stop at record 341. The “B” key advances pages; any other key returns to the main menu — though the logic at lines 3090–3100 has a minor anomaly: line 3100 tests INKEY$<>"B" which is always true right after a non-B key exits line 3090, but the intent is simply to branch to 130 on any non-B input.
Notable Anomalies
- Line 4050 is missing from the listing (skips from 4040 to 4060), suggesting a deleted line.
- Lines 4100 and 4120–4130 are also absent, indicating further deletions in the totals section.
- Line 1120 tests
D$(C,1)=" "to detect an empty record, then calls subroutine 8100; however, execution falls through to line 1130 regardless, because there is no explicit RETURN path after the GOSUB — the program then checksINKEY$for Y/N navigation, which works correctly in practice. - The SAVE line (9000) saves the file with an inverse-video character embedded in the name.
Program 2: TYPE — Full-Screen Typewriter
Written by R. J. Lees (revision 1, May 1983), this utility turns the display into a typewriter, printing characters at a tracked cursor position (N,C) and displaying a block-graphic cursor character (\##, inverse hash) at the current position. It supports 22 lines of 32 columns.
Program Structure
- Lines 1–5: REMs and initialization (
L=0line count) - Lines 10–210: Main character-input loop; cursor display and movement
- Lines 300–320: Space (character 118 = newline/enter on ZX81 — actually this handles ENTER as space+advance)
- Lines 400–450: Newline/carriage return handling with SCROLL at row 21
- Lines 500–530: Backspace (character 119)
- Lines 600–630: Cursor jump by line and column (triggered by character 117 at column 0)
- Lines 700–800: End-of-screen (22 lines filled) — waits for keypress, optionally prints/copies
- Lines 900–930: Cursor repositioning after end-of-screen
- Line 9000–9010: SAVE and restart
Cursor and Column Tracking
The variable C tracks the current column (0–31) and N tracks the current row. After each character is printed, C is incremented. When C reaches 27–31, the code at lines 160–200 places inverse digit characters (%5 through %1) as a visual countdown to the end of the line, alerting the typist that the margin is near. At C=32, a newline is forced.
Control Key Mapping
| CHR$ code | Action |
|---|---|
| 118 | Print space and advance (treated as spacebar or ENTER) |
| 114 | Carriage return / newline |
| 119 | Backspace (move cursor left) |
| 117 at C=0 | Jump to specific line and column |
| 117 (end-of-screen) | Jump to specific line and column after full page |
| 14 (end-of-screen) | COPY screen to printer, then scroll and continue |
Notable Techniques
The main input loop uses the classic double-wait idiom: lines 50–60 first flush any held key (INKEY$<>"" busy-wait), then wait for a new keypress (INKEY$="" busy-wait), bracketed by SLOW/FAST for display stability. The cursor is a block-graphic inverse character printed with PRINT AT N,C;"\##".
The line counter L is reset to 0 at line 5 (not line 10), and L=L-1 appears in the cursor-jump routines to compensate for the increment that will occur when execution resumes normally — this prevents double-counting of lines when repositioning.
The revision note in line 2 documents that lines 630 and 930 were changed from GOTO 20 to GOTO 30, which skips the LET N=21 reset, allowing the cursor jump to land at an arbitrary row rather than always resetting to row 21.
Content
Source Code
11 DIM C$(3)
12 DIM P$(11)
13 DIM N$(10)
14 DIM I$(5)
15 DIM D$(340,32)
100 PRINT TAB 5;"DXCC COUNTRIES LIST"
101 PRINT "PROG. BY W3ZQN, R J LEES, 09/82"
105 PRINT "%T%O% %R%U%N% %U%S%E% %"%G%O%T%O% %1%0%0%"% % % % % % % % % % % %T%O% %S%A%V%E% %U%S%E% %"%G%O%T%O% %9%0%0%0%"% % % % % % % % % %I%F% %"%R%U%N%"% %U%S%E%D%,% %A%L%L% %D%A%T%A% %I%S% %L%O%S%T% "
110 PRINT ,,"EACH DATA LINE HAS:",TAB 2;"COUNTRY NUMBER- 3 SPACES",TAB 10;"PREFIX-11",TAB 10;"NAME -10",TAB 10;"DATA - 5"
120 PRINT ,," DATA IS MO, YR, AND DXCC CODE: (S)ENT/(R)ECEIVED/(C)REDITED"
130 PRINT ,,,,"%E%N%T%E%R% %R%O%U%T%I%N%E% %D%E%S%I%R%E%D%:"," S-SEARCH (LOCATE/CHANGE DATA)"," R-REVIEW (BY PAGES)"," T-TOTALS (WORKED,CREDITED,ETC) I-INPUT (CHANGE DATA BASE)"," E-EXIT (STOP THE PROGRAM)"
140 GOSUB 8000
150 IF INKEY$="S" THEN GOTO 1000
160 IF INKEY$="R" THEN GOTO 3000
170 IF INKEY$="T" THEN GOTO 4000
180 IF INKEY$="I" THEN GOTO 5000
190 IF INKEY$="E" THEN GOTO 7000
200 GOTO 130
\n1000 PRINT "%S%E%L%E%C%T% %S%E%A%R%C%H% %R%O%U%T%I%N%E%:",TAB 3;"C-BY NUMBER",,TAB 3;"P-BY PREFIX",,TAB 3;"N-BY NAME"
\n1010 GOSUB 8000
\n1020 IF INKEY$="C" THEN GOTO 1100
\n1030 IF INKEY$="P" THEN GOTO 1500
\n1040 IF INKEY$="N" THEN GOTO 2000
\n1050 GOTO 1000
\n1100 PRINT "%E%N%T%E%R% %C%O%U%N%T%R%Y% %N%O%.%:"
\n1110 INPUT C
\n1120 IF D$(C,1)=" " THEN GOSUB 8100
\n1130 IF INKEY$="Y" THEN GOTO 1100
\n1140 IF INKEY$="N" THEN GOTO 130
\n1150 CLS
\n1160 PRINT D$(C)
\n1170 GOSUB 6000
\n1180 IF INKEY$="N" THEN GOTO 1250
\n1190 IF INKEY$="Y" THEN GOSUB 6100
\n1195 IF INKEY$="Y" THEN GOTO 1100
\n1200 GOTO 130
\n1250 GOSUB 6500
\n1260 GOTO 1195
\n1500 PRINT "%E%N%T%E%R% %P%R%E%F%I%X"
\n1510 INPUT P$
\n1520 FOR C=1 TO 340
\n1530 IF D$(C,5 TO 15)=P$ THEN GOTO 1600
\n1540 NEXT C
\n1550 GOSUB 8100
\n1560 IF INKEY$="Y" THEN GOTO 1500
\n1570 IF INKEY$="N" THEN GOTO 130
\n1580 GOTO 1550
\n1600 CLS
\n1610 PRINT D$(C)
\n1620 GOSUB 6000
\n1630 IF INKEY$="N" THEN GOTO 1700
\n1640 IF INKEY$="Y" THEN GOSUB 6100
\n1650 IF INKEY$="Y" THEN GOTO 1500
\n1660 GOTO 130
\n1700 GOSUB 6500
\n1710 GOTO 1650
\n2000 PRINT "%E%N%T%E%R% %C%O%U%N%T%R%Y% %N%A%M%E"
\n2010 INPUT N$
\n2020 FOR C=1 TO 340
\n2030 IF D$(C,17 TO 26)=N$ THEN GOTO 2100
\n2040 NEXT C
\n2050 GOSUB 8100
\n2060 IF INKEY$="Y" THEN GOTO 2000
\n2070 IF INKEY$="N" THEN GOTO 130
\n2080 GOTO 2050
\n2100 CLS
\n2110 PRINT D$(C)
\n2120 GOSUB 6000
\n2130 IF INKEY$="N" THEN GOTO 2200
\n2140 IF INKEY$="Y" THEN GOSUB 6100
\n2150 IF INKEY$="Y" THEN GOTO 2000
\n2160 GOTO 130
\n2200 GOSUB 6500
\n2210 GOTO 2150
\n3000 PRINT "USE ""B"" (SCROLL) TO PAGE FORWARDHIT ANY KEY TO EXIT ROUTINE"
\n3010 PRINT ,,"%S%T%A%R%T% %P%A%G%E% %A%T% %W%H%A%T% %C%O%U%N%T%R%Y% %N%O%.%?"
\n3020 INPUT PS
\n3025 CLS
\n3030 FOR B=PS TO 340 STEP 21
\n3040 FOR C=B TO B+21
\n3050 IF C=341 THEN GOTO 3080
\n3060 PRINT D$(C)
\n3070 NEXT C
\n3080 GOSUB 8000
\n3090 IF INKEY$="B" THEN GOTO 3110
\n3100 IF INKEY$<>"B" THEN GOTO 130
\n3110 NEXT B
\n3120 GOTO 130
\n4000 LET CL=0
\n4010 LET CW=0
\n4020 LET CS=0
\n4030 LET CR=0
\n4040 LET CC=0
\n4060 FOR C=1 TO 340
\n4070 IF D$(C,5)<>" " THEN LET CL=CL+1
\n4080 IF D$(C,28)<>" " THEN LET CW=CW+1
\n4090 IF D$(C,32)="S" THEN LET CS=CS+1
\n4110 IF D$(C,32)="R" THEN LET CR=CR+1
\n4140 IF D$(C,32)="C" THEN LET CC=CC+1
\n4150 NEXT C
\n4160 PRINT CL,"COUNTRIES LISTED"
\n4170 PRINT ,,CW,"WORKED"
\n4180 PRINT ,,CL-CW,"NOT WORKED"
\n4190 PRINT ,,CS,"QSL SENT,NO RET"
\n4200 PRINT ,,CR,"QSL SENT AND RET"
\n4210 PRINT ,,CC,"DXCC CREDITED"
\n4220 PRINT ,,,,"%H%I%T% %A%N%Y% %K%E%Y% %T%O% %R%E%T%U%R%N"
\n4230 GOSUB 8000
\n4240 GOTO 130
\n5000 PRINT "%C%O%U%N%T%R%Y% %N%O%.%?% %(%0% %T%O% %E%X%I%T%)"
\n5010 INPUT C$
\n5012 LET C=VAL C$
\n5015 IF C<1 OR C>340 THEN GOTO 5200
\n5020 CLS
\n5025 LET D$(C, TO 3)=C$
\n5030 PRINT "COUNTRY NUMBER: ";C;" "
\n5040 PRINT AT 2,0;"%P%R%E%F%I%X%?% %(%1%1% %M%A%X%)"
\n5050 INPUT P$
\n5060 LET D$(C,5 TO 15)=P$
\n5070 PRINT AT 2,0;" PREFIX: ";P$
\n5080 PRINT AT 4,0;"%N%A%M%E%?% %(%1%0% %M%A%X%)"
\n5090 INPUT N$
\n5100 LET D$(C,17 TO 26)=N$
\n5110 PRINT AT 4,0;" NAME: ";N$
\n5120 PRINT AT 6,0;"%D%A%T%A%?% %(%M%M%Y%Y%S%/%R%/%C%)"
\n5130 INPUT I$
\n5140 LET D$(C,28 TO 32)=I$
\n5150 PRINT AT 6,0;" DATA: ";I$
\n5160 PRINT AT 9,0;D$(C)
\n5170 PRINT AT 13,0;"%H%I%T% %A%N%Y% %K%E%Y% %T%O% %C%O%N%T%I%N%U%E"
\n5180 GOSUB 8000
\n5190 GOTO 5000
\n5200 CLS
\n5210 GOTO 130
\n6000 PRINT ,,"CHANGE DATA? %Y%/%N"
\n6010 GOSUB 8000
\n6020 RETURN
\n6100 PRINT AT 20,0;D$(C)
\n6110 PRINT AT 21,1;D$(C,28 TO )
\n6120 INPUT I$
\n6130 LET D$(C,28 TO )=I$
\n6140 CLS
\n6150 PRINT D$(C)
\n6160 GOSUB 6500
\n6170 RETURN
\n6500 PRINT ,,"ANOTHER? %Y%/%N"
\n6519 GOSUB 8000
\n6520 RETURN
\n7000 CLS
\n7010 PRINT "YOU HAVE STOPPED THE PROGRAM",,,"REMEMBER: TO START IT AGAIN USE",TAB 10;"""GOTO 100""; TO SAVE IT";TAB 10;"USE ""GOTO 9000""",TAB 10;"NEVER USE ""RUN"" OR ",TAB 10;"DATA WILL BE LOST"
\n7020 STOP
\n8000 SLOW
\n8005 PAUSE 20
\n8006 POKE 16437,255
\n8010 IF INKEY$="" THEN GOTO 8010
\n8020 FAST
\n8030 CLS
\n8040 RETURN
\n8100 CLS
\n8105 PRINT "NOT FOUND. TRY AGAIN? %Y%/%N"
\n8110 GOSUB 8000
\n8120 RETURN
\n9000 SAVE "DXC%C"
\n9010 GOTO 100
1 REM PROGRAM "TYPE" BY W3ZQN- R. J. LEES, 705 JONATHAN RD., KING OF PRUSSIA, PA. 19406, JAN,1983
2 REM REV. 1, 5/83: ADDED LINES 625 AND 925; REVISED LINES 630 AND 930 FROM "GOTO 20" TO "GOTO 30" - THIS ALLOWS EDITING BY LINE NO. AND COLUMN NO.
5 LET L=0
10 LET N=21
20 LET C=0
30 PRINT AT N,C;"\##"
40 SLOW
50 IF INKEY$<>"" THEN GOTO 50
60 IF INKEY$="" THEN GOTO 60
70 FAST
80 PRINT AT N,C;INKEY$;
90 IF INKEY$=CHR$ 118 THEN GOTO 300
100 IF INKEY$=CHR$ 114 THEN GOTO 400
110 IF INKEY$=CHR$ 119 THEN GOTO 500
120 IF INKEY$=CHR$ 117 AND C=0 THEN GOTO 600
130 LET C=C+1
140 IF C=32 THEN GOTO 410
150 IF C<27 THEN PRINT AT N,C;"\##"
160 IF C=27 THEN PRINT AT N,C;"%5"
170 IF C=28 THEN PRINT AT N,C;"%4"
180 IF C=29 THEN PRINT AT N,C;"%3"
190 IF C=30 THEN PRINT AT N,C;"%2"
200 IF C=31 THEN PRINT AT N,C;"%1"
210 GOTO 40
300 PRINT AT N,C;" "
320 GOTO 130
400 PRINT AT N,C;" "
410 LET L=L+1
420 IF L=22 THEN GOTO 700
430 IF N<>21 THEN GOTO 10
440 SCROLL
450 GOTO 20
500 PRINT AT N,C;" "
510 IF C=0 THEN GOTO 530
520 LET C=C-1
530 GOTO 30
600 INPUT EL
610 LET N=21-EL
620 LET L=L-1
625 INPUT C
630 GOTO 30
700 SLOW
710 IF INKEY$<>"" THEN GOTO 710
720 IF INKEY$="" THEN GOTO 720
730 FAST
740 IF INKEY$=CHR$ 117 THEN GOTO 900
750 IF INKEY$=CHR$ 14 THEN GOTO 770
760 GOTO 700
770 COPY
780 PRINT AT 21,0;"-----"
790 SCROLL
800 GOTO 5
900 INPUT EM
910 LET N=22-EM
920 LET L=L-1
925 INPUT C
930 GOTO 30
\n9000 SAVE "TYP%E"
\n9010 GOTO 5
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.


