ZX Linotype is a full-screen word processor that stores up to 2,250 characters in a single string array, organized into fixed-width lines whose column width (1–32 characters) is chosen at startup. The program offers eight editing modes — Over, Insert, Delete, Scroll, Find, Print, Save, and Erase — cycled with the arrow keys through a status bar. Text justification is implemented in BASIC at lines 1170–1265, inserting spaces into lines to pad them flush with the right margin. Printer output is handled via LPRINT with a screen-preview alternative, and documents are saved to tape using the standard SAVE command with a user-supplied filename. A short machine-code routine is embedded in the REM at line 1, and the program calls USR 16514 and USR 16536 to compute print positions, suggesting the REM code provides utility functions for the display engine.
Program Analysis
Program Structure
The program is organized into clearly delimited subroutine blocks, each introduced by a REM line with inverse-video labels. Control flow is managed by a status variable S (1–8) and a computed GOTO at line 530 that dispatches to the appropriate mode handler.
| Lines | Function |
|---|---|
| 1 | Machine code in REM |
| 4–50 | Initialisation, dimension T$, set column width C |
| 147–180 | Screen setup, display current line |
| 300–410 | Input routine (Over / Insert modes) |
| 500–570 | Status menu and dispatcher |
| 600–670 | Delete mode |
| 700–860 | Scroll mode |
| 900–975 | Find / search mode |
| 1000–1350 | Print mode (LPRINT or screen) |
| 1400–1480 | Save mode |
| 1500–1550 | Erase / reset |
| 2000–2040 | Line number display |
| 3000–3040 | Locate (jump to line number) |
| 9000–9060 | Title screen and column-width input; SAVE program |
Text Storage Model
All document text lives in the single string T$, dimensioned to 2,250 characters at line 10. The program treats T$ as a flat array of fixed-width lines, each C characters long (where C is chosen by the user, 1–32). The current line pointer X is always a multiple of C plus 1, and T tracks the last used character position. Slicing such as T$(X TO X+C-1) extracts one display line, while T$(TO X-1)+I$+T$(X+C TO ) performs over-type insertion.
Machine Code in REM
Line 1 contains a raw machine-code payload embedded in the REM statement. The byte sequence includes Z80 instructions recognisable as: LD BC,nnnn, LD HL,(nnnn), ADD HL,DE, LD D,H / LD E,L, LDIR, RET, and CPIR. The program calls into this code indirectly via USR 16514 (at lines 390, 760, 1320) and USR 16536 (line 840), which return values used as column arguments to PRINT AT. The trailing bytes itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-56749 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.7 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.5"C are ASCII/character data likely used as a parameter table.
Status Dispatching
Eight editing modes are encoded in S (1 = Over, 2 = Insert, 3 = Delete, 4 = Scroll, 5 = Find, 6 = Print, 7 = Save, 8 = Erase). The arrow keys 8 (up) and 5 (down) cycle S with wrap-around arithmetic at lines 506–507. The dispatch at line 530 uses a single computed expression:
GOTO 300*(S<3)+600*(S=3)+700*(S=4)+900*(S=5)+1000*(S=6)+1400*(S=7)+1500*(S=8)
This is a classic Sinclair BASIC idiom: only one term is non-zero, producing exactly the desired destination. CHR$ 118 is the ENTER key code used throughout as the confirmation keystroke.
Text Justification Algorithm
When the rightmost character of a line is not a sentence-ending punctuation mark and justification mode J=1 is active (toggled by </> sentinel characters stored in the last column), the print routine (lines 1170–1265) walks the line backwards from position C, finds spaces, and duplicates them (P$=P$(TO Q)+P$(Q TO )) until the line fills to width C. Centering is applied to lines whose last character is * (lines 1270–1300), padding with leading spaces equal to half the whitespace deficit.
Key Idioms and Techniques
- FAST/SLOW switching:
FASTis engaged for computationally intensive operations (input processing, printing loops) andSLOWfor interactive display to maintain readable output. - Sentinel characters:
<and>in the last column of a stored line act as justification on/off flags, and*triggers centering — a compact in-band signalling scheme. - Empty-string variable E$: Used pervasively as a blank-line filler (
PRINT AT n,0;E$) to clear rows without CLS;E$is never explicitly assigned, so it defaults to"". - £ as command character: The pound sign (currency symbol) is repurposed as a mode-switch trigger (line 320) and as a search-continuation command (line 930), exploiting its non-alphabetic status.
- Keyboard polling loop: Patterns like
IF INKEY$<>"" THEN GOTO nfollowed immediately by a main poll loop flush any held key before entering a new mode, preventing accidental double-triggers.
Notable Bugs and Anomalies
- Line 810 (
LET X=X-C) is reached byGOTO 810from line 740, but the listing shows this line numbered 820 with line 810 absent — theGOTO 810at line 740 targets a non-existent line; on a real system this would cause a NEXT WITHOUT FOR or similar error when scrolling backward unless line 810 exists in the actual tokenised file and was omitted from this listing. - The
DIM I$(C)at line 40 andDIM P$(C)at line 147 are re-dimensioned each run butI$is used as an INPUT buffer andP$as a working line copy — both correctly sized toCcharacters. - Line 9050 (
SAVE "ZX %L") and line 9060 (GOTO 1) are unreachable during normal execution; they exist as a developer convenience for re-saving the program. - The search routine (lines 941–950) resets
X=1on a new search term but does not reset it when continuing with£, allowing incremental forward search — this is intentional design, not a bug.
Content
Source Code
1 REM 1C6 02A C40 9545D 1E7 02A C40 9 18C 1EDB0C9 173 22A C40 9545D 152 22A C40 9 18C 1EDB8C921222324251C
4 REM ZX LINOTYPE (C) 1985 BY JAMES L. HILL
5 GOSUB 9000
10 DIM T$(2250)
30 LET H$="BEGIN NEW DOCUMENT"
40 DIM I$(C)
50 LET T=0
147 DIM P$(C)
148 PRINT AT 6,15-LEN H$/2;H$
150 LET X=1
160 PRINT AT 2,0;"''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''";AT 5,0;"................................................................";AT 19,0;"<><><><><><><><><><><><><><><><>"
165 PRINT AT 20,0;T$(X TO X+C-1)
170 LET S=1
180 PRINT AT 0,0;S$(S)
299 REM %I%N%P%U%T% %R%O%U%T%I%N%E
300 FAST
301 PRINT AT 3,0;"ENTER TEXT - ENTER ""£"" TO CHANGESTATUS OR ""££"" FOR LINE NUMBERS "
302 IF S=1 THEN PRINT AT 19,0;"<<<<<<%T%Y%P%E% %O%V%E%R% %N%E%X%T% %L%I%N%E>>>>>>>"
303 IF S=2 THEN PRINT AT 19,0;"<<<<<<<<%I%N%S%E%R%T% %T%E%X%T% %H%E%R%E>>>>>>>>"
309 PRINT AT 21,0;"..%1%2%3%4%5%6%7%8%9%0%1%2%3%4%5%6%7%8%9%0%1%2%3%4%5%6%7%8%9%0.."
310 INPUT I$
320 IF I$(1)="£" THEN GOTO 500
330 IF S=1 AND X>=2250-C+1 THEN GOTO 310
340 IF S=2 AND T>=2250-C THEN GOTO 310
350 IF S=1 THEN LET T$=T$( TO X-1)+I$+T$(X+C TO )
360 IF S=2 THEN LET T$=T$( TO X-1)+I$+T$(X TO )
370 LET X=X+C
375 IF S=1 AND X>T THEN LET T=T+C
380 IF S=2 THEN LET T=T+C
390 PRINT AT 18,USR 16514;I$
400 PRINT AT 20,0;T$(X TO X+C-1)
410 GOTO 309
499 REM %S%T%A%T%U%S
500 SLOW
501 IF I$(2)="£" THEN GOTO 2000
502 IF INKEY$<>"" THEN GOTO 502
503 PRINT AT 3,0;" USE ARROWS TO CHANGE STATUS THEN TOUCH ""ENTER"" ";AT 19,0;"<><><><><><><><><><><><><><><><>"
504 LET D$=INKEY$
506 IF D$="8" THEN LET S=S+(S<=7)-7*(S=8)
507 IF D$="5" THEN LET S=S-(S>=2)+7*(S=1)
508 PRINT AT 0,0;S$(S)
530 IF D$=CHR$ 118 THEN GOTO 300*(S<3)+600*(S=3)+700*(S=4)+900*(S=5)+1000*(S=6)+1400*(S=7)+1500*(S=8)
560 PRINT AT 0,0;"0VER INSERT DELETE SCROLL FIND PRINT SAVE ERASE "
570 GOTO 504
600 REM %D%E%L%E%T%E
601 IF INKEY$<>"" THEN GOTO 615
605 PRINT AT 3,0;" SHIFT ""0"" TO DELETE OR TOUCH ""ENTER"" TO CHANGE STATUS ";AT 19,0;"<<<<<<<<%D%E%L%E%T%E% %N%E%X%T% %L%I%N%E>>>>>>>>"
615 IF INKEY$<>"" THEN GOTO 615
620 LET D$=INKEY$
640 IF D$=CHR$ 118 THEN GOTO 500
645 IF X>T OR X>=2250-C+1 THEN GOTO 620
650 IF D$=CHR$ 119 THEN LET T$=T$( TO X-1)+T$(X+C TO )
655 IF D$=CHR$ 119 THEN LET T=T-C
660 PRINT AT 20,0;T$(X TO X+C-1)
670 GOTO 620
700 REM %S%C%R%O%L%L
701 IF INKEY$<>"" THEN GOTO 701
702 PRINT AT 3,0;" USE ARROWS TO SCROLL OR TOUCH ""ENTER"" TO CHANGE STATUS "
710 LET D$=INKEY$
730 IF D$="7" AND X<T AND X<2250-C+1 THEN GOTO 760
740 IF D$="6" AND X>=C+1 THEN GOTO 810
750 IF D$=CHR$ 118 THEN GOTO 500
755 GOTO 710
760 PRINT AT 18,USR 16514;T$(X TO X+C-1)
770 LET X=X+C
790 PRINT AT 20,0;T$(X TO X+C-1)
800 GOTO 710
820 LET X=X-C
830 PRINT AT 20,0;T$(X TO X+C-1)
840 IF X>=13*C+1 THEN PRINT AT 6,USR 16536;T$(X-13*C TO X-13*C+C-1)
850 IF X<13*C+1 THEN PRINT AT 6,USR 16536;E$
860 GOTO 710
900 REM %F%I%N%D
901 IF INKEY$<>"" THEN GOTO 901
905 PRINT AT 3,0;"ENTER WORD OR PHRASE TO FIND OR TOUCH ""ENTER"" TO CHANGE STATUS "
910 SLOW
911 INPUT D$
912 PRINT AT 20,0;E$
915 IF D$="" THEN GOTO 500
920 FAST
921 FOR N=6 TO 18
922 PRINT AT N,0;E$
923 NEXT N
930 IF D$<>"£" THEN LET F$=D$
940 IF D$<>"£" THEN LET X=1
941 FOR N=X TO T-LEN F$+1
945 IF T$(N TO N+LEN F$-1)=F$ THEN GOTO 965
950 NEXT N
955 PRINT AT 20,0;"*******SEARCH IS COMPLETE*******"
960 GOTO 905
965 LET X=INT (N/C)*C+1
970 PRINT AT 20,0;T$(X TO X+C-1);AT 3,0;"ENTER ""£"" TO CONTINUE SEARCH OR"
973 LET X=X+C
975 GOTO 910
1000 REM %P%R%I%N%T
1010 IF INKEY$<>"" THEN GOTO 1010
1020 PRINT AT 3,0;"ENTER ""P""(PRINTER) - ""S""(SCREEN)TOUCH ""ENTER"" TO CHANGE STATUS "
1030 INPUT D$
1035 IF D$="" THEN GOTO 500
1040 LET PS=(D$="P")
1050 PRINT AT 3,0;"ENTER NO. OF FIRST LINE TO PRINT";E$
1060 INPUT L1
1070 PRINT AT 4,0;"ENTER NO. OF LAST LINE TO PRINT "
1080 INPUT L2
1082 FOR N=6 TO 18
1084 PRINT AT N,0;E$
1086 NEXT N
1087 PRINT AT 20,0;E$
1090 IF PS=1 THEN FAST
1092 LET J=0
1100 IF L2*C>T THEN LET L2=T/C
1110 FOR N=L1 TO L2
1115 LET CJ=0
1120 LET P$=T$(N*C-C+1 TO N*C)
1130 IF P$(C)="<" THEN LET J=1
1140 IF P$(C)=">" THEN LET J=0
1150 IF P$(C)=">" OR P$(C)="<" THEN LET P$(C)=" "
1160 IF P$(C)="*" THEN GOTO 1270
1165 IF J=0 THEN GOTO 1310
1170 FOR M=C TO 1 STEP -1
1180 IF P$(M)="." OR P$(M)=":" OR P$(M)="?" THEN GOTO 1310
1190 IF P$(M)<>" " THEN GOTO 1220
1200 NEXT M
1210 GOTO 1310
1220 FOR Q=M TO 1 STEP -1
1225 IF P$(Q)=" " THEN LET CJ=1
1230 IF P$(Q)=" " THEN LET P$=P$( TO Q)+P$(Q TO )
1240 IF P$(C)<>" " THEN GOTO 1310
1250 NEXT Q
1260 IF CJ=1 THEN GOTO 1170
1265 GOTO 1310
1270 FOR M=C-1 TO 1 STEP -1
1280 IF P$(M)<>" " THEN GOTO 1300
1290 NEXT M
1300 LET P$=E$( TO (C-M)/2)+P$
1310 IF PS=1 THEN LPRINT P$
1320 IF PS=0 THEN PRINT AT 18,USR 16514;P$
1330 NEXT N
1340 SLOW
1350 GOTO 1020
1400 REM %S%A%V%E
1410 IF INKEY$<>"" THEN GOTO 1410
1420 PRINT AT 3,0;" ENTER NAME OF DOCUMENT OR TOUCH ""ENTER"" TO CHANGE STATUS "
1430 INPUT H$
1440 IF H$="" THEN GOTO 500
1450 PRINT AT 3,0;"ENTER ""S"" WHEN RECORDER IS READY";E$
1460 INPUT D$
1470 SAVE H$
1480 GOTO 148
1500 REM %E%R%A%S%E
1510 IF INKEY$<>"" THEN GOTO 1510
1520 PRINT AT 3,0;" ENTER ""E"" TO ERASE DOCUMENT OR TOUCH ""ENTER"" TO CHANGE STATUS "
1530 INPUT D$
1540 IF D$<>"E" THEN GOTO 500
1545 CLS
1546 FAST
1550 GOTO 1
2000 REM %L%I%N%E% %N%U%M%B%E%R%S
2001 PRINT AT 19,0;E$;AT 19,0;"%L%I%N%E% %B%E%L%O%W%= ";(X+C-1)/C,"%L%I%N%E%S% %U%S%E%D%= ";T/C
2010 SLOW
2020 FOR N=1 TO 40
2030 NEXT N
2040 GOTO 300
3000 REM %L%O%C%A%T%E
3001 PRINT "ENTER LINE NUMBER"
3010 INPUT D$
3015 FAST
3020 LET X=(VAL D$)*C-C+1
3030 IF X>T THEN LET X=T-C+1
3040 GOTO 160
9000 REM %T%I%T%L%E
9001 SLOW
9002 PRINT AT 6,10;"ZX LINOTYPE";AT 10,3;"(C) 1985 - JAMES L. HILL";AT 19,4;"TOUCH ""ENTER"" TO BEGIN"
9010 INPUT D$
9021 PRINT AT 19,0;" COLUMN WIDTH? (ENTER A NUMBER 1 THROUGH 32)"
9022 INPUT C
9023 FAST
9024 CLS
9030 RETURN
9050 SAVE "ZX %L"
9060 GOTO 1
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.


