Text1 is a full-featured word processor program that supports text entry, tape-based load and save, screen editing, printing, and search-and-replace operations. It stores text in a raw memory buffer starting at address 38000, using POKE and PEEK extensively to manipulate bytes directly, and employs machine code routines loaded from tape (via `LOAD “text1 C” CODE`) for block-move and search operations triggered through `RANDOMIZE USR`. Special characters encoded as bytes 128–144 are used to represent formatting markers such as line breaks, paragraph breaks, and page breaks. The program detects a printer by polling port 251 via `IN` and adjusts its output mode accordingly, and it uses a cursor-navigation subroutine driven by keys 5–8 for screen editing in the scan/edit mode.
Program Structure
Text1 is organized as a menu-driven word processor with subroutines at low line numbers and major functional sections branched to via GO TO VAL b$*1000 from line 930. The six operational modes map to line ranges as follows:
| Menu Choice | Line Range | Function |
|---|---|---|
| 1 | 1000–1500 | Enter text |
| 2 | 2000–2050 | LOAD text from tape |
| 3 | 3000–3420 | PRINT text |
| 4 | 4000–4800 | Scan/edit text |
| 5 | 5000–5030 | SAVE text on tape |
| 6 | 6010–6030 | Set parameters |
| 7 | 7000 | STOP work |
Initialization runs through lines 5800–6030 on first load: a UDG is defined at line 5800 (a small bracket character for UDG-A), the machine code overlay is loaded from tape at line 5810, and workspace variables are set at line 6010. The main menu loop sits at lines 900–930.
Memory Layout
The program uses a fixed memory map for its text buffer and scratch areas:
te = 38000— base address of the text bufferli = 37000— line input scratch buffer (used by theGO SUB 60keyboard entry routine)37998–37999— two-byte little-endian word storing the current text lengthc1(written before SAVE, read after LOAD)37001–37002— stores a byte count used during the Move operation (line 4800)c2 = 15000— maximum number of characters the buffer can holdq = 23670,r = 23671— system variables SEED (low and high bytes), tapped after eachRANDOMIZEto extract a 16-bit value for machine code parameter passing
Machine Code Interface
All block-memory operations and search functions are handled by a machine code binary loaded separately from tape as "text1 C" CODE. Parameters are passed to the routines by a consistent idiom: RANDOMIZE is called with the desired value, then PEEK q and PEEK r (the SEED system variable, low and high bytes) are POKEd into argument slots within the machine code block, and finally RANDOMIZE USR address calls the routine. Two main entry points are used:
USR 60000(subroutine at line 30) — forward block move; takes three parameters: countv1, destinationv2, sourcev3USR 60014(subroutine at line 35) — reverse block move (for inserting/overlapping regions)USR 60028(subroutine at line 81) — string search; takes start addressli, text basete+c2, and end positionc3; returns result flag inPEEK 60143and found position viaPEEK 60135/60136USR 60151(subroutine at line 100) — adjusts scroll/display parameters for edge-of-buffer conditions
Subroutine 85 (lines 85–87) clamps the cursor position c to the valid range [1, c1] before any machine code call that uses c as an offset.
Key BASIC Idioms
The program makes heavy use of arithmetic on boolean-like expressions to avoid explicit numeric literals, following a common Sinclair BASIC space-saving convention:
SGN PIevaluates to1(since PI > 0)NOT PIevaluates to0PI + PIevaluates to approximately6.28, which truncates to6when used inPRINT ATVAL "number"inGO TO,GO SUB, andPOKEtargets is a well-known memory optimization that avoids storing the floating-point number in the BASIC line- The keypress-wait idiom at lines 10–11 (
PAUSE 0is not used here; instead line 10 waits for key-up then line 11 waits for key-down) is a clean debounce sequence
Text Entry (Lines 1000–1500)
Characters are POKEd directly into the buffer at 37999 + c where c is a one-based character index. The display position b tracks column (0–32); every 33rd character, POKE 23692, 9 suppresses the scroll prompt. The ENTER key opens a sub-menu (line 1100) offering line break (▀, code 131), paragraph break (▜, code 134), and page break (▞, code 139) markers — these special bytes drive the printer routine at lines 3000–3420. The quote character (code 34) is remapped to UDG-A (code 144) since bare quotes would interfere with string handling.
Print Routine (Lines 3000–3420)
The printer section walks the buffer byte by byte, assembling words into lines of up to 32 characters using a look-ahead to avoid splitting words. The variable x is the current buffer pointer; y is the tentative end of the next print segment. Special marker bytes branch to distinct handlers:
- Codes >127 (other than 144/UDG-A) signal a formatting marker; code 139 triggers a paragraph break (lines 3200–3230), code 134 triggers a page break (lines 3300–3320)
- Page formatting at lines 3400–3420 prints a five-line footer/header with a page number stored in
x2 - The printer-present flag
p(set at line 901 viaIN 251) controls whetherCOPYis issued (line 21) or INPUT is used to pause (line 22)
Scan/Edit Mode (Lines 4000–4800)
The scan/edit mode uses the machine code scroll routine (via GO SUB 95) to display a 320-character window centered on the cursor position c. Movement keys 5/6/7/8 (via GO SUB 40, lines 40–50) move a flashing cursor through the displayed text, updating both screen position (m, n) and buffer index c together. Additional single-letter commands from the sub-menu at line 4600 provide:
- Type (
z) — inserts from current position using the machine code block-move routines - Seek — calls the machine code search (line 4610)
- Alter (search-and-replace) — lines 4630–4670 search for one string and replace with another using block moves
- Move — relocates a previously cut block stored in the scratch buffer at address 37003 (lines 4800–4820)
- Delete — marks start with
g, moves cursor to end with repeateddkeypresses, then shifts the remainder of the buffer left (line 4230)
Save and Load (Lines 2000–2050, 5000–5030)
Before saving, the two-byte text length c1 is written to addresses 37998–37999 using the RANDOMIZE/PEEK q/PEEK r parameter idiom, so the entire block from 37998 is saved as a self-describing chunk. The SAVE covers c1 + 2 bytes. After loading, line 2040 reconstructs c1 from those same two bytes. A VERIFY step is offered after SAVE (line 5020–5030).
Notable Techniques and Anomalies
- Line 901 uses a compound
IN 251test (checking for both58and126) to detect printer presence; result is stored as0or1inpusing boolean arithmetic rather than IF/THEN. - Line 2 fills
a$with 320 spaces and returns immediately — this string is PRINTed in display mode to blank the screen efficiently before the machine code fills it. POKE 23692, 9at lines 1020 and 6030 resets the scroll counter, preventing the “scroll?” prompt from appearing during rapid text output.- Line 4160 has a subtle off-by-one guard: when
creaches 1 it clears the screen and goes to entry mode, preventing the reverse scroll machine code from being called with an invalid address. - The REM at line 3220 contains code that was commented out (alternative page-break formatting), which is an unusual but valid approach to preserving old code within the listing.
- Line 1500 checks
INKEY$ <> "z"to loop — this is a deliberate pause at buffer-full, requiring the user to press Z to force a tape save, after whichGO TO SGN PI(line 1510) jumps to line 1, which is a non-existent target — likely intended as a program termination or reset point.
Content
Source Code
1 GO TO 900
2 LET a$=" ":RETURN
10 IF INKEY$ <>"" THEN GO TO VAL "10"
11 LET b$= INKEY$:IF b$="" THEN GO TO VAL "11"
12 BEEP .02, NOT PI:RETURN
20 PRINT b$( TO y-x):LET x=y+1
21 IF x1=22 AND p= SGN PI THEN COPY :CLS :LET x1= NOT PI
22 IF x1=22 AND p= NOT PI THEN INPUT c$:CLS :LET x1= NOT PI
23 LET x1=x1+ SGN PI:LET x4=x4+ SGN PI:RETURN
25 PRINT AT PI+ PI, PI+ PI;" KEEP TAPE RUNNING "
30 GO SUB 85:RANDOMIZE v1:POKE VAL "60001", PEEK q:POKE VAL "60002", PEEK r:RANDOMIZE v2:POKE VAL "60004", PEEK q:POKE VAL "60005", PEEK r:RANDOMIZE v3:POKE VAL "60009", PEEK q:POKE VAL "60010", PEEK r:RANDOMIZE USR VAL "60000":RETURN
35 GO SUB 85:RANDOMIZE v1:POKE VAL "60015", PEEK q:POKE VAL "60016", PEEK r:RANDOMIZE v2:POKE VAL "60018", PEEK q:POKE VAL "60019", PEEK r:RANDOMIZE v3:POKE VAL "60023", PEEK q:POKE VAL "60024", PEEK r:RANDOMIZE USR VAL "60014":RETURN
40 LET c$= SCREEN$ (m,n):PRINT FLASH SGN PI; AT m,n;c$
41 GO SUB 11:PRINT AT m,n;c$
42 IF b$="5" THEN LET n=n- SGN PI:LET c=c- SGN PI
43 IF b$="6" THEN LET m=m+ SGN PI:LET c=c+32
44 IF b$="7" THEN LET m=m- SGN PI:LET c=c-32
45 IF b$="8" THEN LET n=n+ SGN PI:LET c=c+1
46 IF n<0 THEN LET n=n+32:LET m=m-1
47 IF n>31 THEN LET n=n-32:LET m=m+1
48 IF m<0 THEN LET c=c+32:LET m=m+ SGN PI:GO TO 48
49 IF m>19 THEN LET c=c-32:LET m=m- SGN PI:GO TO 49
50 RETURN
60 PRINT AT 20, NOT PI;" KEY TEXT "
61 PRINT ;:LET c3=li:LET b= NOT PI
62 GO SUB 10:LET a= CODE b$:IF a=13 THEN RETURN
63 IF CODE b$=34 THEN LET a=144:LET b$= CHR$ a
64 IF a=12 THEN GO TO 70
65 IF a<32 OR (a>127 AND a <>144) THEN GO TO 62
66 PRINT b$;:POKE c3,a:LET b=b+ SGN PI:LET c3=c3+ SGN PI:IF b=32 THEN LET b= NOT PI:POKE 23692,9
67 IF c3=37997 THEN RETURN
68 GO TO 62
70 LET c3=c3- SGN PI:IF c3<li THEN LET c3=li:GO TO 62
71 LET b=b- SGN PI:IF b<0 THEN LET b=31
72 PRINT AT 21,b;"_ "; AT 21,b;:GO TO 62
75 PRINT AT VAL "20", NOT PI;" FILE END ",,:RETURN
80 GO SUB 60
81 RANDOMIZE li:POKE VAL "60137", PEEK q:POKE VAL "60138", PEEK r:RANDOMIZE te+c2:POKE VAL "60139", PEEK q:POKE VAL "60140", PEEK r:RANDOMIZE c3:POKE VAL "60141", PEEK q:POKE VAL "60142", PEEK r:RANDOMIZE USR VAL "60028"
82 LET f= PEEK VAL "60143":LET b= VAL "PEEK 60135+256* PEEK 60136-te":RETURN
85 IF c<1 THEN LET c=1
86 IF c>c1 THEN LET c=c1
87 RETURN
90 INPUT "from cursor?";b$:RANDOMIZE te:IF b$="z" THEN RANDOMIZE te+c
91 POKE VAL "60135", PEEK q:POKE VAL "60136", PEEK r:RETURN
95 LET v1=640:LET v2=26734:LET v3=c+37680:IF c<321 OR c>c1-320 THEN GO SUB 97
96 GO SUB 30:CLS :GO SUB 2:PRINT a$:LET m=10:LET n= NOT PI:PRINT FLASH SGN PI; AT m,n; SCREEN$ (m,n):RETURN
97 GO SUB 100
98 IF c<321 THEN LET v1=c+319:LET v2=27055-c:LET v3=te:RETURN
99 LET v1=320+c1-c:LET v2=26734:LET v3=c+37680:RETURN
100 RANDOMIZE 26734:POKE VAL "60152", PEEK q:POKE VAL "60153", PEEK r:RANDOMIZE 27373:POKE VAL "60155", PEEK q:POKE VAL "60156", PEEK r:POKE VAL "60158", VAL "32":RANDOMIZE USR VAL "60151":RETURN
900 CLS :PRINT " TEXT 1 "'''"1 Enter text"'"2 LOAD text from tape"'"3 PRINT text"'"4 Scan/edit text"'"5 SAVE text on tape"'"6 Set parameters"'"7 STOP work"
901 LET p=(VAL "1" AND IN VAL "251"= VAL "58")+(VAL "0" AND IN VAL "251"= VAL "126")
904 PRINT ''" Status Board"
906 PRINT '" Printer is "; INK VAL "7"; PAPER VAL "4";"ON" AND p; PAPER VAL "2";"OFF" AND NOT p
907 PRINT '" Text entered is ";c1
910 GO SUB 10:IF LEN b$ <>1 OR b$<"1" OR b$>"7" THEN GO TO 900
920 CLS :IF b$="1" THEN PRINT AT 21, NOT PI;"_"; AT 21, NOT PI;
930 GO TO VAL b$*1000
1000 GO SUB 10:IF c>c2 THEN GO TO 1500
1010 IF CODE b$<32 OR CODE b$>127 THEN GO TO 1040
1015 IF CODE b$=34 THEN LET b$="[UDG-A]"
1020 POKE 37999+c, CODE b$:PRINT b$;:LET b=b+ SGN PI:LET c=c+ SGN PI:IF b=33 THEN LET b= SGN PI:POKE 23692,9
1025 IF c>c1 THEN LET c1=c
1030 GO TO 1000
1040 LET d=21
1050 IF CODE b$ <>12 THEN GO TO 1080
1060 LET b=b- SGN PI:POKE 37999+c, CODE " ":LET c=c- SGN PI:IF b= NOT PI THEN LET b=32:LET d=d- SGN PI:PRINT " "; AT 19, NOT PI;
1070 PRINT AT d,b-1;"_ "; AT d,b-1;:GO SUB 10:GO TO 1050
1080 IF CODE b$<128 AND CODE b$>31 THEN GO TO 1010
1090 IF CODE b$ <>13 THEN GO TO 1000
1100 INPUT "1line 2para 3page ZmenuENTERedit";b$:IF LEN b$ <>1 OR (b$ <>"z" AND (b$<"1" OR b$>"3")) THEN GO TO VAL "4000"
1110 IF b$="z" THEN GO TO SGN PI
1120 IF b$="1" THEN LET b$="▀"
1130 IF b$="2" THEN LET b$="▜"
1140 IF b$="3" THEN LET b$="▞"
1150 POKE VAL "37999+c", CODE b$:PRINT b$;:LET c=c+ SGN PI:LET b=b+ SGN PI:IF b>31 THEN LET b=1
1160 GO TO 1000
1500 BEEP VAL ".1", VAL "20":PRINT AT VAL "9", VAL "9";" BUFFER FULL "; TAB VAL "9";" FILE ON TAPE ":IF INKEY$ <>"z" THEN GO TO VAL "1500"
1510 GO TO SGN PI
2000 PRINT "Enter text name (max. 10 chars.":INPUT b$:PRINT 'b$
2010 PRINT '"OK? Press C":INPUT c$:IF c$ <>"c" THEN GO TO VAL "900"
2020 LET p= NOT PI:LET b= SGN PI:POKE VAL "23692", VAL "9"
2030 PRINT '"Play tape":LOAD b$ CODE
2040 LET c1= VAL "PEEK 37998+256* PEEK 37999"
2050 GO TO SGN PI
3000 LET x=te
3010 LET x1= SGN PI:LET x2=x1:LET x4=x1
3020 LET y=31
3030 LET f= PEEK x:IF f=144 THEN GO TO 3050
3040 IF f>127 THEN LET x=x+ SGN PI:IF f <>131 THEN GO TO 3200
3050 IF INKEY$="z" THEN GO TO 1
3055 IF x-te>c1 THEN PAUSE VAL "600":GO TO 1
3060 LET f= NOT PI:LET b$="":FOR j=x TO x+y:LET b$=b$+ CHR$ PEEK j:IF (PEEK j>127 AND PEEK j <>144) AND f= NOT PI THEN LET f=j
3070 NEXT j:LET y=j:IF f>0 THEN LET y=f
3080 LET f= NOT PI:FOR j=x TO y:IF PEEK j=32 THEN LET f= SGN PI:LET j=y
3090 NEXT j:IF f= NOT PI THEN GO TO 3110
3100 IF PEEK y <>32 AND PEEK y<128 THEN LET y=y- SGN PI:GO TO 3100
3110 GO SUB 20:IF PEEK y>127 THEN LET x=x-1
3120 GO SUB 3400:GO TO 3020
3200 IF f <>139 THEN GO TO 3300
3210 PRINT :GO SUB 21:GO SUB 3400:LET a=x3-x4:IF a<3 THEN FOR j=1 TO a:PRINT :GO SUB 21:GO SUB 3400:NEXT j:GO TO 3230
3220 REM PRINT :GO SUB 21:GO SUB 3400:PRINT :GO SUB 21:GO SUB 3400
3230 PRINT " ";:LET y=26:GO TO 3030
3300 IF f <>134 THEN LET x=x+ SGN PI:GO TO 3020
3310 LET a=x3-x4:PRINT :GO SUB 21:FOR j=1 TO a:PRINT :GO SUB 21:NEXT j:GO SUB 3410
3320 GO TO 3020
3400 IF x4<x3 OR p= NOT PI THEN RETURN
3410 FOR j=1 TO 5:PRINT :GO SUB 21:IF j=3 THEN PRINT TAB 15;x2:LET x2=x2+ SGN PI:GO SUB 21
3420 NEXT j:LET x4= SGN PI:RETURN
4000 IF c<1 THEN LET c=1
4010 IF c>c1 THEN LET c=c1
4020 GO SUB 95
4030 GO SUB 40
4050 IF b$="p" THEN LET c=c+608:GO TO 4000
4060 IF b$="q" THEN LET c=c-608:GO TO 4000
4070 IF b$="e" THEN GO TO 4200
4080 IF b$="z" THEN GO TO 4600
4090 IF b$="c" THEN LET x=c+37999:CLS :GO TO 3005
4100 IF m>19 OR m<0 THEN LET m= NOT PI:LET n= NOT PI
4110 GO TO 4030
4120 LET b= SGN PI
4130 GO SUB 85:GO SUB 100:IF c<640 THEN GO TO 4160
4140 LET v1=640:LET v2=26734:LET v3=c+37359:GO SUB 30
4150 CLS :GO SUB 2:PRINT 'a$;:GO TO 1000
4160 LET c=c- SGN PI:IF c= SGN PI THEN CLS :PRINT AT 21, NOT PI;:GO TO VAL "1000"
4170 LET v1=c:LET v2=27373:LET v3=37999+c:GO SUB 35:LET c=c+ SGN PI:GO TO 4150
4200 INPUT "D delete A Add";b$:IF c<321 THEN LET c=c-1
4205 IF b$ <>"d" OR c<1 OR c>c1 THEN GO TO 4300
4210 LET g=c:PRINT AT m,n; OVER SGN PI;"_"
4220 GO SUB 40:IF b$ <>"d" THEN GO TO 4220
4225 IF c<g OR c<1 OR c>c1 THEN GO TO 4000
4230 LET b=c-g+ SGN PI:LET v1=b:LET v2=37003:LET v3=te+g:GO SUB 30:RANDOMIZE b:POKE li,255:POKE 37001, PEEK q:POKE 37002, PEEK r:LET v1=c1-c:LET c=c+ SGN PI:LET v2=te+g:LET v3=te+c:GO SUB 30
4240 LET a=c-g:LET c=c-a:LET c1=c1-a:GO TO 4000
4300 IF b$ <>"a" OR c<1 OR c >=c1 THEN GO TO 4000
4310 LET c=c+ SGN PI:GO SUB 60
4320 LET a=c3-li:IF a<1 THEN GO TO 4000
4330 LET v1=c1-c+ SGN PI:LET v2=te+c1+a:LET v3=te+c1:GO SUB 35
4340 LET v1=a:LET v2=te+c:LET v3=li:GO SUB 30
4350 LET c1=c1+a:LET c=c+a:GO TO 4000
4600 GO SUB 85:PRINT FLASH SGN PI; AT m,n; SCREEN$ (m,n):INPUT "type?";b$:IF b$="z" THEN LET c=c+ SGN PI:GO TO 4120
4601 INPUT "edit?";b$:IF b$="z" THEN GO TO VAL "4000"
4602 INPUT "seek?";b$:IF b$="z" THEN GO TO VAL "4610"
4603 INPUT "alter";b$:IF b$="z" THEN GO TO VAL "4630"
4604 INPUT "move?";b$:IF b$="z" THEN GO TO VAL "4800"
4605 INPUT "menu?";b$:IF b$="z" THEN GO TO SGN PI
4606 GO TO VAL "4600"
4610 GO SUB 90:GO SUB 80
4615 IF f= NOT PI OR b>c1 THEN GO SUB 75:GO TO VAL "4600"
4620 LET c=b:GO SUB 95:INPUT "repeat?";b$:IF b$ <>"z" THEN LET c=c+ SGN PI:GO SUB 81:GO TO 4615
4625 GO TO VAL "4600"
4630 GO SUB 90:GO SUB 60:PRINT AT VAL "21", NOT PI;"NEW TEXT ",,;:LET b= VAL "12":LET v2=c3:GO SUB VAL "62":LET c4=c3:LET c3=v2:IF c3=c4 THEN GO TO VAL "4000"
4635 GO SUB 81:IF f= NOT PI OR b>c1 THEN GO SUB 75:GO TO VAL "4600"
4640 LET c=b:GO SUB 95:INPUT "replace?";b$:IF b$ <>"z" THEN GO TO 4665
4650 LET m=c3-li:LET n=c4-c3:LET v1=c1-c-m:LET v2=te+c:LET v3=v2+m:GO SUB 30:LET v2=37999+c1-m+n:LET v3=37999+c1-m:GO SUB 35:LET v1=n:LET v2=te+c:LET v3=li+m:GO SUB 30
4660 LET c1=c1-m+n:GO SUB 95
4665 INPUT "repeat?";b$:IF b$="z" THEN LET c=c+ SGN PI:GO TO 4635
4670 GO TO VAL "4600"
4800 IF PEEK li <>255 THEN GO TO 4000
4810 IF c=c1 THEN LET c1=c1+1
4820 LET b= VAL "PEEK 37001+256* PEEK 37002":LET v1=c1-c:LET v2=37999+c1+b:LET v3=c1+37999:GO SUB 35:LET v1=b:LET v2=c+te:LET v3=37003:GO SUB 30:LET c1=c1+b:GO TO 4000
5000 PRINT "Enter text name ":INPUT b$:PRINT b$''"C if OK":INPUT c$:CLS :IF c$ <>"c" THEN GO TO SGN PI
5010 RANDOMIZE c1:POKE VAL "37998", PEEK q:POKE VAL "37999", PEEK r
5020 PRINT " PULL OUT EAR PLUG ":SAVE b$ CODE VAL "37998", VAL "c1+2":INPUT "Key ""V"" TO VERIFY ";z$:IF z$ <>"v" THEN GO TO SGN PI
5030 CLS :PRINT FLASH SGN PI;" REPLACE EAR PLUG ":PRINT ''''"Rewind and play tape":VERIFY b$ CODE :GO TO SGN PI
5800 FOR j= NOT PI TO VAL "7":POKE USR "a"+j, NOT PI:NEXT j:POKE USR "a"+1, VAL "36":POKE USR "a"+ VAL "2", VAL "36"
5810 LOAD "text1 C"CODE
6010 CLS :LET te= VAL "38000":LET li= VAL "37000":LET x3= VAL "22":LET p= NOT PI:IF IN VAL "251"= VAL "58" THEN LET p= SGN PI:PRINT '"How many lines/page?":INPUT x3:PRINT x3'"C if OK":INPUT b$:IF b$ <>"c" THEN CLS :GO TO VAL "6000"
6020 LET c2= VAL "15000":LET q= VAL "23670":LET r= VAL "23671":PRINT '"Key T to set up text space."'"CAUTION destroys existing text":INPUT b$:IF b$ <>"t" THEN GO TO SGN PI
6030 LET b= SGN PI:LET c= SGN PI:LET c1= SGN PI:POKE VAL "23692", VAL "9":GO TO SGN PI
7000 PRINT AT VAL "9", VAL "8";"END OF PROGRAM"
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
