--- title: "ZX Linotype" id: 56749 type: "computer_media" slug: "zx-linotype" url: "http://localhost/computer_media/zx-linotype/" markdown_url: "http://localhost/computer_media/zx-linotype.md" published_at: "2024-09-22T23:31:59+00:00" modified_at: "2026-04-03T07:58:54+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/ZXLin.jpeg" excerpt: "A BASIC word processor with eight editing modes, tape save, text justification, and a machine-code helper packed into a REM statement — all inside 2,250 characters of storage." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" indiv: - name: "James Hill" slug: "james-hill" taxonomy: "indiv" url: "http://localhost/indiv/james-hill/" genre: - name: "Word Processor" slug: "word-processor" taxonomy: "genre" url: "http://localhost/type/word-processor/" media_type: "Program" programmers: - name: "James Hill" slug: "james-hill" taxonomy: "indiv" url: "http://localhost/indiv/james-hill/" download_url: "https://archive.org/download/timex-sinclair-software-archive/ZX%20Linotype%20%281985%29%28Hill%2C%20James%20L.%29%28TS1000%29%28US%29%28Program%29.zip" mediadate: "1985" images: - url: "http://localhost/wp-content/uploads/2024/09/ZXLin.jpeg" - url: "http://localhost/wp-content/uploads/2024/09/SCR-20241102-mbmn.png" - url: "http://localhost/wp-content/uploads/2024/09/Tape-21.jpg" media_type_tags: "Word Processor" --- # ZX Linotype 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 `\21\22\23\24\25\1C` 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**: `FAST` is engaged for computationally intensive operations (input processing, printing loops) and `SLOW` for 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 n` followed 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 by `GOTO 810` from line 740, but the listing shows this line numbered 820 with line 810 absent — the `GOTO 810` at 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 and `DIM P$(C)` at line 147 are re-dimensioned each run but `I$` is used as an INPUT buffer and `P$` as a working line copy — both correctly sized to `C` characters. - 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=1` on a new search term but does not reset it when continuing with `£`, allowing incremental forward search — this is intentional design, not a bug. ## Source Code ``` 1 REM 1C602AC409545D1E702AC40918C1EDB0C917322AC409545D15222AC40918C1EDB8C921222324251C 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=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 ```