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
1000 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"
1010 GOSUB 8000
1020 IF INKEY$="C" THEN GOTO 1100
1030 IF INKEY$="P" THEN GOTO 1500
1040 IF INKEY$="N" THEN GOTO 2000
1050 GOTO 1000
1100 PRINT "%E%N%T%E%R% %C%O%U%N%T%R%Y% %N%O%.%:"
1110 INPUT C
1120 IF D$(C,1)=" " THEN GOSUB 8100
1130 IF INKEY$="Y" THEN GOTO 1100
1140 IF INKEY$="N" THEN GOTO 130
1150 CLS
1160 PRINT D$(C)
1170 GOSUB 6000
1180 IF INKEY$="N" THEN GOTO 1250
1190 IF INKEY$="Y" THEN GOSUB 6100
1195 IF INKEY$="Y" THEN GOTO 1100
1200 GOTO 130
1250 GOSUB 6500
1260 GOTO 1195
1500 PRINT "%E%N%T%E%R% %P%R%E%F%I%X"
1510 INPUT P$
1520 FOR C=1 TO 340
1530 IF D$(C,5 TO 15)=P$ THEN GOTO 1600
1540 NEXT C
1550 GOSUB 8100
1560 IF INKEY$="Y" THEN GOTO 1500
1570 IF INKEY$="N" THEN GOTO 130
1580 GOTO 1550
1600 CLS
1610 PRINT D$(C)
1620 GOSUB 6000
1630 IF INKEY$="N" THEN GOTO 1700
1640 IF INKEY$="Y" THEN GOSUB 6100
1650 IF INKEY$="Y" THEN GOTO 1500
1660 GOTO 130
1700 GOSUB 6500
1710 GOTO 1650
2000 PRINT "%E%N%T%E%R% %C%O%U%N%T%R%Y% %N%A%M%E"
2010 INPUT N$
2020 FOR C=1 TO 340
2030 IF D$(C,17 TO 26)=N$ THEN GOTO 2100
2040 NEXT C
2050 GOSUB 8100
2060 IF INKEY$="Y" THEN GOTO 2000
2070 IF INKEY$="N" THEN GOTO 130
2080 GOTO 2050
2100 CLS
2110 PRINT D$(C)
2120 GOSUB 6000
2130 IF INKEY$="N" THEN GOTO 2200
2140 IF INKEY$="Y" THEN GOSUB 6100
2150 IF INKEY$="Y" THEN GOTO 2000
2160 GOTO 130
2200 GOSUB 6500
2210 GOTO 2150
3000 PRINT "USE ""B"" (SCROLL) TO PAGE FORWARDHIT ANY KEY TO EXIT ROUTINE"
3010 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%.%?"
3020 INPUT PS
3025 CLS
3030 FOR B=PS TO 340 STEP 21
3040 FOR C=B TO B+21
3050 IF C=341 THEN GOTO 3080
3060 PRINT D$(C)
3070 NEXT C
3080 GOSUB 8000
3090 IF INKEY$="B" THEN GOTO 3110
3100 IF INKEY$<>"B" THEN GOTO 130
3110 NEXT B
3120 GOTO 130
4000 LET CL=0
4010 LET CW=0
4020 LET CS=0
4030 LET CR=0
4040 LET CC=0
4060 FOR C=1 TO 340
4070 IF D$(C,5)<>" " THEN LET CL=CL+1
4080 IF D$(C,28)<>" " THEN LET CW=CW+1
4090 IF D$(C,32)="S" THEN LET CS=CS+1
4110 IF D$(C,32)="R" THEN LET CR=CR+1
4140 IF D$(C,32)="C" THEN LET CC=CC+1
4150 NEXT C
4160 PRINT CL,"COUNTRIES LISTED"
4170 PRINT ,,CW,"WORKED"
4180 PRINT ,,CL-CW,"NOT WORKED"
4190 PRINT ,,CS,"QSL SENT,NO RET"
4200 PRINT ,,CR,"QSL SENT AND RET"
4210 PRINT ,,CC,"DXCC CREDITED"
4220 PRINT ,,,,"%H%I%T% %A%N%Y% %K%E%Y% %T%O% %R%E%T%U%R%N"
4230 GOSUB 8000
4240 GOTO 130
5000 PRINT "%C%O%U%N%T%R%Y% %N%O%.%?% %(%0% %T%O% %E%X%I%T%)"
5010 INPUT C$
5012 LET C=VAL C$
5015 IF C<1 OR C>340 THEN GOTO 5200
5020 CLS
5025 LET D$(C, TO 3)=C$
5030 PRINT "COUNTRY NUMBER: ";C;" "
5040 PRINT AT 2,0;"%P%R%E%F%I%X%?% %(%1%1% %M%A%X%)"
5050 INPUT P$
5060 LET D$(C,5 TO 15)=P$
5070 PRINT AT 2,0;" PREFIX: ";P$
5080 PRINT AT 4,0;"%N%A%M%E%?% %(%1%0% %M%A%X%)"
5090 INPUT N$
5100 LET D$(C,17 TO 26)=N$
5110 PRINT AT 4,0;" NAME: ";N$
5120 PRINT AT 6,0;"%D%A%T%A%?% %(%M%M%Y%Y%S%/%R%/%C%)"
5130 INPUT I$
5140 LET D$(C,28 TO 32)=I$
5150 PRINT AT 6,0;" DATA: ";I$
5160 PRINT AT 9,0;D$(C)
5170 PRINT AT 13,0;"%H%I%T% %A%N%Y% %K%E%Y% %T%O% %C%O%N%T%I%N%U%E"
5180 GOSUB 8000
5190 GOTO 5000
5200 CLS
5210 GOTO 130
6000 PRINT ,,"CHANGE DATA? %Y%/%N"
6010 GOSUB 8000
6020 RETURN
6100 PRINT AT 20,0;D$(C)
6110 PRINT AT 21,1;D$(C,28 TO )
6120 INPUT I$
6130 LET D$(C,28 TO )=I$
6140 CLS
6150 PRINT D$(C)
6160 GOSUB 6500
6170 RETURN
6500 PRINT ,,"ANOTHER? %Y%/%N"
6519 GOSUB 8000
6520 RETURN
7000 CLS
7010 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"
7020 STOP
8000 SLOW
8005 PAUSE 20
8006 POKE 16437,255
8010 IF INKEY$="" THEN GOTO 8010
8020 FAST
8030 CLS
8040 RETURN
8100 CLS
8105 PRINT "NOT FOUND. TRY AGAIN? %Y%/%N"
8110 GOSUB 8000
8120 RETURN
9000 SAVE "DXC%C"
9010 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
9000 SAVE "TYP%E"
9010 GOTO 5
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.


