--- title: "Word Processor" id: 56937 type: "computer_media" slug: "word-processor" url: "http://localhost/computer_media/word-processor/" markdown_url: "http://localhost/computer_media/word-processor.md" published_at: "2024-10-02T00:50:31+00:00" modified_at: "2026-04-03T07:58:46+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/5WrdPrc.png" excerpt: "A surprisingly capable word processor that stores over 5,000 characters, offers paged navigation, search, inline editing, and printer output — all in pure BASIC." 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/" genre: - name: "Word Processor" slug: "word-processor" taxonomy: "genre" url: "http://localhost/type/word-processor/" media_contents: - id: 56732 title: "Timex Sinclair Public Domain Library Tape 1001" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1001/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/09/5WrdPrc.png" media_type_tags: "Word Processor" --- # Word Processor This program is a full-featured word processor, storing up to 5,120 characters of text in a single large string array A$(5120). It supports paged display (640 characters per page), a cursor-based edit mode with character insert, delete, and replace operations, as well as text-flow utilities that remove double spaces and re-join split words across line boundaries. The program uses inverse-video characters (CHR$ 128–255 range) via the cursor routines at lines 1000–1070 to highlight the current edit position within the text. Output can be directed to the screen (“LOOK”), printer (LPRINT), or saved to tape. *** ## Program Analysis ### Program Structure The program is organized as a collection of numbered routines, with a dispatcher at lines 15–70 forming the main entry/edit loop and line 5000 as the title-screen menu. Control flow is entirely via `GOTO` and `GOSUB` rather than structured loops, which is typical for BASIC word-processor programs of this era. | Line Range | Function | | --- | --- | | 3 | Bootstrap jump to start-up menu (line 5000) | | 15–70 | Main entry loop: display page, accept command string, dispatch | | 100–140 | Tape SAVE routine | | 999–1070 | Cursor highlight/restore subroutine (inverse video) | | 2000–2520 | “LINE” command — re-join words split across line boundaries | | 3000–3194 | “SPACE” command — collapse runs of more than one space | | 4000–4067 | Search routine | | 4500–4610 | Edit menu display | | 5000–5075 | Title/main menu screen | | 5490–5599 | Command reference screen | | 6000–6010 | LPRINT (print to paper) | | 6200–6270 | “LOOK” — scroll text to screen with optional copy/pause | | 7000–7999 | Full edit mode (cursor movement, delete, insert, replace) | | 8000–8100 | Page selection subroutine | | 9000–9090 | New-file initialisation (clears and dimensions A$) | ### Text Storage Model All document text is held in the single string array `A$(5120)`, treated as a flat byte buffer. The variable `BOT` acts as a “next free” pointer into this buffer, and `PAGE` is always a multiple of 640, giving the end address of the currently displayed page (each page holds 640 characters, matching 20 lines × 32 columns). The display window is always `A$(PAGE-639 TO PAGE)`. A sentinel character `%*` (inverse asterisk) is written at `BOT` after each entry to mark the end of text. The variable `C$` (initialised at line 9050 to 31 spaces) serves as a “blank filler” string used to erase vacated regions of `A$` after deletions and space-removal operations, avoiding stale characters. ### Cursor Highlight Technique The edit cursor is implemented without any machine code by exploiting the inverse-video character encoding. Subroutine at line 1000 reads the character at `INDEX`, saves it to `B$`, adds 128 to its code (converting it to its inverse-video counterpart), and writes it back. The companion restore at line 1060 writes `B$(1)` back, undoing the inversion. This gives a visible blinking-style cursor using only standard BASIC string operations. ### Paging and Navigation Page navigation in edit mode (lines 7059–7065) simply adds or subtracts 640 from `PAGE`, clamped between 640 and 5120. The numeric keys 5–8 move the cursor by ±1 character or ±32 characters (one screen row), mirroring the conventional arrow-key layout. Keys 1, 2, and 9 jump the cursor to the page end, middle line, and page start respectively. ### Key BASIC Idioms - **String-array as byte buffer:**`A$(X TO Y)=A$(Y TO Z)` style slice assignments perform bulk moves for insert and delete without any machine code. - **FAST/SLOW switching:**`FAST` is used during intensive string scanning (search, space removal) and `SLOW` for display-intensive sections, controlling the display driver’s CPU time. - **Computed boolean movement:** Line 7050 uses `INDEX=INDEX+(Z$="8")-(Z$="5")` — a classic idiom where boolean results (0 or 1) directly adjust a variable without an `IF` branch. - **INKEY$ polling loop:** Lines 5060–5075 poll `INKEY$` in a tight loop without `PAUSE`, a common idiom for menu key selection. ### Word-Wrap / Line Reformatting (LINE Command) The LINE routine (lines 2000–2520) scans forward from variable `B` in 32-character steps (`IP=IP+32`). At each position, if the character is not a natural word boundary (space, period, comma, semicolon, colon, question mark), it searches backward for the nearest space and shifts text to insert a space, effectively re-joining a word that was split across a display line. This is a rudimentary word-wrap correction pass rather than a full reflow engine. ### Notable Bugs and Anomalies - **Line 310 (missing):** Line 3110 contains `GOTO 310` when a chain of spaces is found during the double-space removal pass. Line 310 does not exist in the listing; this would cause a runtime error during space compression of long runs. - **Line 6250 logic error:** The condition `IF INKEY$<>"P" OR INKEY$<>"S"` is always true (no key can simultaneously equal both “P” and “S”), so the intended guard against non-P/S keys never works correctly. The LOOK mode cannot properly branch on key identity as intended. - **Uninitialised variable B:** The LINE command at line 2010 uses `LET IP=B`, but `B` is never explicitly set anywhere visible in the listing. It appears to be a forward reference to something set elsewhere (possibly the cursor position), but its value at invocation is undefined from a cold start. - **Line 7500 gap:** The INSERT routine jumps to line 7501 but there is no line 7500 in the listing, so `IF INKEY$="I" THEN GOTO 7500` (line 7210) would cause a “line does not exist” error on some interpreters. - **LPRINT with bare slice:** Line 6001 uses `LPRINT A$( TO BOT-1)` with an empty lower bound, implying `A$(1 TO BOT-1)` — printing the entire document buffer. This is syntactically valid but relies on the interpreter accepting an omitted lower slice bound. - **Lines 9070–9090 unreachable:** Lines `9070 CLEAR`, `9080 SAVE "1000\05"`, and `9090 RUN` appear after `9060 GOTO 15` and are never reachable during normal execution; they appear to be remnants of a bootstrap/auto-run loader. ## Source Code ``` 3 GOTO 5000 15 FAST 16 PRINT AT 1,0;A$(PAGE-639 TO PAGE) 18 PRINT AT 0,0;"SPACE LEFT=";5120-BOT 19 PRINT AT 0,25;"PAGE ";INT (PAGE/640) 20 PRINT AT 21,6;"% %E%N%T%R%Y% %M%O%D%E% " 21 INPUT Z$ 22 IF Z$="LOOK" THEN GOTO 6200 23 IF Z$=" LPRINT " THEN GOTO 6000 24 IF Z$="SPACE" THEN GOTO 3000 25 IF Z$="LINE" THEN GOTO 2000 26 IF Z$=" STOP " THEN GOTO 5000 27 IF Z$="SAVE" THEN GOTO 100 28 IF Z$="PAGE" THEN GOSUB 8000 29 IF Z$="EDIT" THEN GOTO 7000 39 LET ZZ=LEN Z$ 40 LET TOP=BOT+ZZ 50 LET A$(BOT TO TOP)=Z$ 51 LET A$(TOP+1)=" " 52 LET BOT=TOP+1 53 LET A$(BOT)="%*" 55 CLS 70 GOTO 15 100 CLS 110 PRINT "TO SAVE PROGRAM AND DATA ",,,"START TAPE AND PRESS ENTER" 120 INPUT Z$ 130 SAVE "WORD PROCESSO%R" 140 GOTO 5000 999 REM %C%U%R%S%O%R% %R%O%U%T%I%N%E%S FOR EDIT 1000 LET XX=CODE A$(INDEX) 1010 LET B$=A$(INDEX) 1020 IF XX<0 OR XX>127 THEN RETURN 1030 LET XX=XX+128 1040 LET A$(INDEX)=CHR$ XX 1050 RETURN 1060 LET A$(INDEX)=B$(1) 1070 RETURN 2000 REM %S%P%A%C%E% %L%I%N%E%S 2001 SLOW 2002 LET PAGE=640 2010 LET IP=B 2020 IF A$(IP)=" " OR A$(IP+1)=" " OR A$(IP)="." OR A$(IP)="," OR A$(IP)=";" OR A$(IP)=":" OR A$(IP)="?" THEN GOTO 2500 2030 LET PO=IP-1 2040 IF A$(PO)=" " THEN GOTO 2060 2045 LET PO=PO-1 2050 GOTO 2040 2060 LET DIF=IP-PO 2062 LET BOT=BOT+DIF 2065 LET A$(IP TO IP+((BOT-DIF)-PO))=A$(PO TO BOT-DIF) 2070 LET A$(PO TO IP)=C$(1 TO DIF+1) 2100 RETURN 2500 LET IP=IP+32 2501 IF PAGE=BOT THEN GOTO 15 2520 GOTO 2020 3000 REM %R%E%M%O%V%E% %S%P%A%C%E%S% %(%O%V%E%R% %2%) 3001 LET Z$="" 3002 SLOW 3003 LET PAGE=640 3010 FOR A=1 TO BOT 3020 IF A$(A)=" " AND A$(A+1)=" " THEN GOSUB 3100 3030 NEXT A 3040 GOTO 15 3100 LET BA=A+1 3105 LET BA=BA+1 3106 IF BA>=BOT THEN GOTO 15 3110 IF A$(BA)=" " THEN GOTO 310 3140 LET BA=BA-1 3150 LET DIF=BA-A 3160 LET A$(A TO A+(BOT-BA))=A$(BA TO BOT) 3190 LET BOT=BOT-DIF 3191 LET A$(BOT TO BOT+DIF)=C$(1 TO DIF+1) 3192 IF PAGE"" THEN GOTO 6250 6240 NEXT C 6244 PAUSE 200 6245 FAST 6246 CLS 6247 GOTO 15 6250 IF INKEY$<>"P" OR INKEY$<>"S" THEN GOTO 6245 6255 IF INKEY$="P" THEN COPY 6260 IF INKEY$="S" THEN GOTO 6260 6270 GOTO 6240 7000 REM %E%D%I%T 7001 SLOW 7010 LET INDEX=PAGE-639 7015 PRINT AT 21,0;" % %E%D%I%T% %M%O%D%E% ";" " 7016 PRINT AT 0,0;"SPACE LEFT=";5120-BOT;" " 7020 GOSUB 1000 7030 PRINT AT 1,0;A$(PAGE-639 TO PAGE) 7045 GOSUB 1060 7049 LET Z$=INKEY$ 7050 LET INDEX=INDEX+(Z$="8")-(Z$="5") 7051 IF Z$="6" THEN LET INDEX=INDEX+32 7052 IF Z$="7" THEN LET INDEX=INDEX-32 7053 IF Z$="5" OR Z$="6" OR Z$="7" OR Z$="8" THEN GOTO 7020 7054 IF Z$="0" THEN GOTO 7200 7055 IF Z$="R" THEN GOTO 7900 7056 IF Z$="S" THEN GOTO 4000 7057 IF Z$="1" THEN LET INDEX=PAGE 7058 IF Z$="2" THEN LET INDEX=PAGE-319 7059 IF Z$="4" THEN LET PAGE=PAGE+640 7060 IF PAGE>5000 THEN LET PAGE=5120 7061 IF Z$="4" THEN LET INDEX =PAGE-639 7063 IF Z$="3" THEN LET PAGE=PAGE-640 7064 IF PAGE<640 THEN LET PAGE=640 7065 IF Z$="3" THEN LET INDEX=PAGE-639 7066 IF Z$="M" THEN GOTO 4500 7067 IF Z$="9" THEN LET INDEX=PAGE-639 7068 PRINT AT 0,25;"PAGE ";INT (PAGE/640) 7070 GOTO 7020 7200 PRINT AT 21,7;"%C%H%A%N%G%E% % % % % " 7209 IF INKEY$="D" THEN GOTO 7300 7210 IF INKEY$="I" THEN GOTO 7500 7220 IF INKEY$="C" THEN GOTO 7700 7230 IF INKEY$="R" THEN GOTO 7900 7299 GOTO 7209 7300 REM %D%E%L%E%T%E 7310 LET B$=A$(INDEX+1 TO BOT) 7320 LET A$(INDEX TO BOT-1)=B$ 7340 LET BOT=BOT-1 7341 LET A$(BOT+1)=" " 7350 LET B$="" 7399 GOTO 7015 7501 PRINT AT 21,6;"%I%N%S%E%R%T% %C%H%A%R%A%C%T%E%R%S" 7502 INPUT Z$ 7503 GOSUB 1060 7505 LET ZZ=LEN Z$ 7510 LET NBOT=BOT+ZZ 7525 LET B$=A$(INDEX TO BOT) 7540 LET B$=Z$+B$ 7570 LET A$(INDEX TO NBOT)=B$ 7580 LET BOT=NBOT 7590 LET B$="" 7599 GOTO 7015 7700 REM %C%H%A%N%G%E 7701 PRINT AT 21,6;"% %R%E%P%L%A%C%E% " 7710 INPUT Z$ 7720 LET A$(INDEX TO INDEX+LEN Z$-1)=Z$ 7799 GOTO 7015 7900 REM %R%E%T%U%R%N 7901 FAST 7910 GOSUB 1060 7999 GOTO 15 8000 REM %P%A%G%E% %R%O%U%T%I%N%E 8020 SLOW 8030 PRINT AT 21,6;"% %W%H%I%C%H% %P%A%G%E% %N%U%M%B%E%R%?% " 8036 INPUT PAGE 8040 LET PAGE=PAGE*640 8050 IF PAGE<640 THEN LET PAGE=640 8051 IF PAGE>5120 THEN LET PAGE=4976 8060 PRINT AT 21,6;" " 8099 LET Z$="" 8100 RETURN 9000 CLS 9001 PRINT AT 6,4;"TYPE ""YES"" IF YOU WISH TO CLEAR FILE" 9002 INPUT Z$ 9003 IF Z$<>"YES" THEN GOTO 5000 9005 DIM A$(5120) 9020 LET B=32 9030 LET BOT=1 9040 LET PAGE=640 9050 LET C$=" " 9060 GOTO 15 9070 CLEAR 9080 SAVE "1000%5" 9090 RUN ```