TEXTWRITER 1000 is a full-screen word processor that stores text in a two-dimensional string array B$(Z,32), where Z is the user-defined number of lines and each row holds up to 32 characters. The editor supports cursor movement, word-wrap at the right margin, a cut/copy/paste buffer using a second array M$, and tab stops stored in array E(5). Printing is handled via LPRINT with selectable single or double spacing, paginating automatically every 74 lines. An edit-command interpreter at line 1500 accepts two-letter codes (AL for insert lines, DL for delete lines, AC for append-compress, MP for paste, C for compact/reflow) entered at a prompt.
Program Analysis
Program Structure
The program is divided into clearly functional regions, navigated entirely by GOTO and GOSUB:
- Lines 10–113 — Initialisation and main menu (display, new file, save, print)
- Lines 115–140 — File dimension setup; allocates
B$(Z,32)andE(5) - Lines 145–660 — Main editing loop: keystroke dispatch, character entry, cursor movement, word-wrap, screen scrolling
- Lines 700–760 — Page-down (forward scroll by 21 lines)
- Lines 800–960 — Subroutines: restore character (800), header print (920), space/erase (940)
- Lines 1000–1050 — Page-up (backward scroll by 10 lines)
- Lines 1500–2930 — Edit-command interpreter and its operations (insert lines, delete lines, copy block, paste, compact/reflow)
- Lines 3000–3030 — Save routine
- Lines 4000–5010 — Tab-stop set and jump
- Lines 5500–5630 — LPRINT with single/double spacing and pagination
Data Structures
B$(Z,32)— Main text buffer; a 2-D string array with Z rows of 32 characters. Dimensioned at runtime after the user specifies the required number of lines.M$(C,32)— Cut/copy buffer; dimensioned on demand when a block-mark command is issued, holdingLL+1lines.E(5)— Numeric array storing up to 5 tab-stop column positions, set interactively.T$— File title, displayed centred in the menu header.Z$— Overflow accumulator for characters typed past column 32 (used during word-wrap).
Keystroke Dispatch
The editor reads keystrokes via PAUSE 50000 followed by INKEY$ at line 170. Character codes are checked numerically to distinguish printable from control characters. The dispatch table is:
| Code | Action |
|---|---|
| <64 | Printable character — stored in B$, cursor advances |
| 112 (p) | Move cursor up one line (with page-back if needed) |
| 114 (r) | Cursor left / delete (via subroutine 800 + 940) |
| 115 (s) | Re-print current cell (used as no-op / refresh) |
| 117 (u) | Enter edit-command mode (line 1500) |
| 118 (v) | Newline / ENTER — erase current cell and advance |
| 119 (w) | Delete character at cursor (space it out) |
| 121 (y) | Tab jump (if tab stops set) or newline |
| 224 | Set tab stop (line 4000) |
| 227 | Return to main menu (line 42) |
| 229 | Page down (line 700) |
Screen Editing and Cursor Representation
The current cursor position is shown by printing the character at (X, Y-1) in inverse video using CHR$ (CODE B$(W+X,Y)+128) at line 145. W is the window offset (which logical row is at the top of the screen), X is the screen row (1–21), and Y is the column (1–32). Restoring a cell to normal video is handled by subroutine 920/800 which re-prints B$(W+X,Y) without the +128 offset.
Word-Wrap at Column 33
When Y reaches 33 (line 175/500), the program switches to overflow-accumulation mode. Subsequent normal characters are appended to Z$. On a control keystroke, the current line is scanned right-to-left for the last space (line 550–560), the text from that point plus Z$ is moved to the next line (line 575), and the current line is truncated (line 580). This provides a basic word-wrap without requiring the user to manage line breaks manually.
Edit Command Language
Pressing the key with code 117 opens a two-letter command prompt. Commands are parsed at lines 1540–1590:
AL[n]— Insertnblank lines at cursor (default fromLL)DL[n]— Deletenlines at cursorAC— Append and compact: reflow text by joining short linesA[n]— Insertnspaces at cursor positionMP— Paste (mark-paste) the clipboard at cursorC— Compact: remove leading spaces and join continuation lines- Numeric string only — defines a block mark of that many lines into
M$
Cut/Copy Buffer
Marking a block (entering a number at the edit prompt) stores lines in M$(1..LL+1), dimensioned dynamically at line 2820. The variable LL holds the block size minus one; D and F record the first and last line numbers of the marked region, displayed in the header by subroutine 920 (line 925) when LL <> -1. LL is initialised to -1 at line 10 to signal “no buffer”.
Printing (LPRINT)
Lines 5500–5630 iterate from line LB to LE, calling LPRINT B$(I). Double-spacing adds a blank LPRINT after each line. A line counter LC triggers a form feed (five blank lines, line 5610) every 74 printed lines regardless of spacing mode. The page length of 74 is hardcoded.
Notable Techniques
- Dynamic DIM: Both
B$andM$are dimensioned at runtime with user-supplied or computed sizes, a practical approach to managing limited RAM. - Inverse cursor via +128: Adding 128 to a character code produces its inverse-video counterpart — a well-known ZX81/TS1000 display trick that avoids any machine code.
- Window scrolling with W offset: Logical line number is always
W+X; changingWby ±10 or ±21 and re-printing lines 1–21 provides smooth paging without moving data. - SLOW/FAST switching: The editor uses
SLOWfor display-intensive sections (printing the screen) andFASTduring computation-heavy operations like block moves, reducing flicker and improving speed respectively. - Tab stops in a numeric array: Storing up to 5 tab column positions in
E(5)and scanning them at line 4080 is a compact alternative to a string-based tab ruler.
Bugs and Anomalies
- Line 100 sets
W=LB-1unconditionally, but for the display option (menu choice 1) this is immediately overridden byGOTO 112beforeWis used, so the assignment is harmless but redundant. - At line 251, the check
IF W+X=Z THEN GOTO 145prevents moving past the last allocated line but does not display a warning to the user. - Line 4065 loops
J=1 TO 6butE(5)only has indices 1–5; accessingE(6)would cause an error, but the branch at line 4070 (IF J=6 THEN GOTO 230) fires before the subscript is evaluated, so it is safe in practice. - The compact/reflow routine at lines 2000–2190 uses
Yas both the starting column and a loop variable, which may leaveYin an unexpected state; line 2210 restores it from saved valueQ. - Line 595 checks
IF X=21 THEN GOTO 1020after a word-wrap to scroll down, but this scroll shiftsWby +10 and setsX=12rather than +1/X=21, which could misplace the cursor relative to the wrapped text.
Content
Source Code
10 LET LL=-1
20 DIM M$(1)
30 LET Z$=""
35 LET Y=1
40 LET W=0
42 SLOW
45 CLS
47 LET X=1
50 PRINT AT 3,8;"%T%E%X%T%W%R%I%T%E%R% %1%0%0%0";AT 5,15-LEN T$/2;T$
55 PRINT ,,"%M%E%N%U",,,,"1) DISPLAY CURRENT TEXT FILE","2) START NEW FILE","3) SAVE FILE",,,,"%P%R%I%N%T",,,,"4) SINGLE SPACE",,"5) DOUBLE SPACE"
60 INPUT LN
70 CLS
80 IF LN=2 THEN GOTO 115
85 IF LN=3 THEN GOTO 3000
95 PRINT AT 18,0;"ENTER START LINE","LAST TEXT ON ";M;"(";Z;")"
97 INPUT LB
100 LET W=LB-1
102 IF LN=1 THEN GOTO 112
104 PRINT AT 18,6;"FINAL"
106 INPUT LE
110 GOTO 5500
112 FAST
113 CLS
114 GOTO 610
115 PAUSE 120
117 LET M=0
118 PRINT AT 20,0;"ENTER LINES REQUIRED"
119 INPUT Z
120 DIM B$(Z,32)
122 CLS
125 FAST
130 GOSUB 920
135 DIM E(5)
137 LET ST=0
140 FAST
145 PRINT AT X,Y-1;CHR$ (CODE B$(W+X,Y)+128)
160 PAUSE 50000
170 LET A$=INKEY$
175 IF Y=33 THEN GOTO 500
180 IF CODE A$>63 THEN GOTO 310
185 IF W+X>M THEN LET M=W+X
190 LET B$(W+X,Y)=A$
200 PRINT AT X,Y-1;B$(W+X,Y)
210 LET Y=Y+1
211 IF Y=33 THEN GOTO 970
215 GOTO 145
230 IF CODE A$=121 THEN GOSUB 800
240 LET Y=1
250 IF CODE A$=112 THEN LET X=X-2
251 IF W+X=Z THEN GOTO 145
252 LET X=X+1
270 IF X>21 THEN GOTO 1020
280 IF X<1 AND W>0 THEN GOTO 1000
285 IF X>21 THEN LET X=21
287 IF X<1 THEN LET X=1
290 GOTO 145
310 LET A=CODE A$
315 IF A=117 THEN GOTO 1500
320 IF A<114 THEN GOTO 900
330 IF A=118 THEN GOTO 420
340 IF A=115 THEN GOTO 200
345 IF A=229 THEN GOTO 700
350 IF A=227 THEN GOTO 42
355 IF A=121 AND E(1)>1 THEN GOTO 4062
360 IF A=121 THEN GOTO 230
365 IF A=224 THEN GOTO 4000
370 GOSUB 800
375 IF A=119 THEN GOSUB 940
380 LET Y=Y-1
390 IF Y<1 THEN LET X=X-1
400 IF Y<1 THEN LET Y=32
410 GOTO 280
420 GOSUB 940
440 GOTO 210
500 IF CODE A$>63 THEN GOTO 525
510 LET Z$=Z$+A$
515 IF X<21 THEN PRINT AT X+1,0;Z$
520 GOTO 160
525 IF Z$="" THEN GOTO 240
528 LET T=W+X
530 LET D$=B$(T)
540 LET Y=Y-1
550 IF D$(Y)=" " THEN GOTO 565
560 GOTO 540
565 LET YY=LEN (D$(Y+1 TO )+Z$)+2
570 IF T=Z THEN GOTO 610
575 LET B$(T+1, TO YY)=D$(Y+1 TO )+Z$
580 LET B$(T,Y TO )=""
590 LET Y=YY
592 LET Z$=""
593 PRINT AT X,0;B$(T)
595 IF X=21 THEN GOTO 1020
600 PRINT B$(T+1)
605 GOTO 252
610 LET O=21
613 IF W+O>Z THEN GOSUB 760
617 LET R=1
618 IF A=117 AND W+O<>Z THEN LET R=X
619 GOSUB 920
620 PRINT AT R,0;
621 IF A<>118 AND A<>121 THEN SLOW
622 FOR J=R TO O
625 PRINT B$(W+J)
630 NEXT J
660 GOTO 140
700 IF W+22>Z THEN GOTO 160
710 LET W=W+21
720 LET X=1
730 GOTO 610
760 CLS
770 LET O=Z-W
780 RETURN
800 PRINT AT X,Y-1;B$(W+X,Y)
810 RETURN
900 GOSUB 800
910 GOTO 250
920 PRINT AT 0,29;" "
922 PRINT AT 0,0;"%T%Y%P%E% %M%O%D%E LINE ";W+1;" "
925 IF LL<>-1 THEN PRINT AT 0,19;"M:";D;"-";F
930 RETURN
940 PRINT AT X,Y-1;" "
950 LET B$(W+X,Y)=" "
960 RETURN
970 IF CODE A$=118 OR CODE A$=115 THEN GOTO 230
980 GOTO 160
\n1000 LET W=W-10
\n1006 IF W<0 THEN LET W=0
\n1008 LET X=10
\n1010 GOTO 610
\n1020 IF W>Z-21 THEN GOTO 140
\n1025 LET W=W+10
\n1030 LET X=12
\n1050 GOTO 610
\n1500 PRINT AT 0,0;"%E%D%I%T%:%E%N%T%E%R% %A%C%*%/%A%L%*%/%D%L%*%/%C%/%M%M%*%/%M%P% "
\n1520 LET Q=Y
\n1525 LET T=W+X
\n1530 INPUT C$
\n1540 IF C$="" THEN GOTO 610
\n1545 IF C$="MP" THEN GOTO 2890
\n1550 IF C$="C" THEN GOTO 2000
\n1555 LET C=1
\n1560 IF LEN C$>2 THEN LET C=VAL C$(3 TO )
\n1570 IF C$( TO 2)="AL" THEN GOTO 2300
\n1575 IF C$(1)="A" THEN GOTO 2520
\n1580 IF C$(1)="D" THEN GOTO 2450
\n1590 GOTO 2800
\n2000 FOR L=Y TO 32
\n2010 IF CODE B$(T,L)>0 THEN GOTO 2030
\n2020 NEXT L
\n2030 LET B$(T,Y TO )=B$(T,L TO )
\n2040 FOR N=L-Y TO 31
\n2050 IF CODE B$(T,32-N)>0 THEN GOTO 2070
\n2060 NEXT N
\n2065 GOTO 2080
\n2070 IF B$(T,32-N)="-" THEN LET N=N+2
\n2080 LET T=T+1
\n2085 IF T>Z THEN GOTO 2210
\n2090 IF B$(T,1)=" " THEN GOTO 2210
\n2100 FOR Y=N TO 1 STEP -1
\n2110 IF CODE B$(T,Y)=0 THEN GOTO 2150
\n2120 NEXT Y
\n2130 GOTO 2210
\n2150 IF N=32 THEN LET N=33
\n2160 LET B$(T-1,34-N TO )=B$(T, TO Y-1)
\n2170 LET L=Y+1
\n2180 LET Y=1
\n2190 GOTO 2030
\n2210 LET Y=Q
\n2220 IF C$(1)="A" THEN GOTO 2580
\n2230 GOTO 610
\n2250 LET C=LL+1
\n2300 IF Z-M<C THEN GOTO 1500
\n2305 FOR J=M TO T STEP -1
\n2310 LET B$(J+C)=B$(J)
\n2320 NEXT J
\n2330 FOR J=T TO T+C-1
\n2340 LET B$(J)=""
\n2345 NEXT J
\n2350 LET M=M+C
\n2355 IF C$(2)="L" THEN GOSUB 2400
\n2360 IF C$="MP" THEN GOTO 2898
\n2370 IF C$(2)<>"L" THEN GOTO 2610
\n2380 GOTO 610
\n2400 LET B$(T, TO Y-1)=B$(T+C, TO Y-1)
\n2410 LET B$(T+C, TO Y-1)=""
\n2420 RETURN
\n2450 IF T+C>M+1 THEN LET C=M+1-T
\n2455 FOR K=T TO M-C
\n2480 LET B$(K)=B$(K+C)
\n2490 NEXT K
\n2495 FOR K=K TO M
\n2500 LET B$(K)=""
\n2505 NEXT K
\n2508 LET M=M-C
\n2510 GOTO 610
\n2520 LET P=C
\n2525 LET B=0
\n2540 IF P>33-Y THEN LET P=33-Y
\n2550 FOR J=33-P TO 32
\n2560 IF B$(T,J)<>" " THEN GOTO 2700
\n2570 NEXT J
\n2580 LET T=W+X
\n2583 IF B>0 THEN LET B$(T,Y+P TO )=B$(T,Y TO B-1)
\n2584 IF B>0 THEN GOTO 2590
\n2585 LET B$(T,Y+P TO )=B$(T,Y TO 32-P)
\n2590 LET B$(T,Y TO Y+P-1)=""
\n2600 GOTO 610
\n2610 FOR B=33-P TO Y STEP -1
\n2620 IF B$(T-1,B)=" " THEN GOTO 2640
\n2630 NEXT B
\n2640 LET B$(T)=B$(T-1,B+1 TO )
\n2645 LET L=Y
\n2650 GOTO 2040
\n2700 LET T=T+1
\n2710 LET C=1
\n2720 GOTO 2305
\n2800 LET LL=C-1
\n2820 DIM M$(C,32)
\n2825 LET D=T
\n2827 IF LL<50 THEN SLOW
\n2828 IF T+LL>Z THEN LET LL=Z-T
\n2830 FOR J=0 TO LL
\n2840 LET M$(J+1)=B$(T+J)
\n2850 IF T+J-W<22 THEN PRINT AT T+J-W,0;CHR$ (CODE B$(T+J,1)+128)
\n2870 NEXT J
\n2872 LET F=T+LL
\n2875 FAST
\n2878 PRINT AT R,0;
\n2880 GOTO 610
\n2890 IF T+LL>Z THEN LET LL=Z-T
\n2895 IF T<=M THEN GOTO 2250
\n2898 FOR J=0 TO LL
\n2900 LET B$(T+J)=M$(J+1)
\n2920 NEXT J
\n2925 IF T+LL>M THEN LET M=T+LL
\n2930 GOTO 610
\n3000 CLS
\n3010 PRINT AT 10,5;"ENTER TITLE TO RECORD"
\n3015 INPUT T$
\n3018 CLS
\n3020 SAVE T$
\n3030 GOTO 30
\n4000 IF Y=1 THEN GOTO 135
\n4005 LET ST=ST+1
\n4010 IF ST>5 THEN GOTO 4040
\n4020 LET E(ST)=Y
\n4030 GOTO 145
\n4040 PRINT AT 0,19;"%5% %T%A%B%S% %M%A%X"
\n4045 PAUSE 60
\n4050 GOSUB 920
\n4055 GOTO 160
\n4062 GOSUB 800
\n4065 FOR J=1 TO 6
\n4070 IF J=6 THEN GOTO 230
\n4080 IF Y<E(J) THEN GOTO 5000
\n4090 NEXT J
\n5000 LET Y=E(J)
\n5010 GOTO 145
\n5500 FAST
\n5510 LET LF=1
\n5520 IF LN=5 THEN LET LF=2
\n5530 LET LC=0
\n5540 FOR I=LB TO LE
\n5550 LPRINT B$(I)
\n5560 IF LN=5 THEN LPRINT
\n5570 LET LC=LC+LF
\n5580 IF LC=74 THEN GOSUB 5610
\n5590 NEXT I
\n5600 GOTO 42
\n5610 LPRINT ,,,,
\n5620 LET LC=0
\n5630 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.



