This program is a full-featured word processor designed specifically for use with the OS-64 cartridge, which extends the display to 64 columns. It maintains a flat string array (f$) as the document buffer, sized by the user at startup from 1 to 150 lines of 64 characters each (up to 9,600 bytes). The editor supports cursor movement, word-wrap, tab stops, line insertion and deletion, jump-to-line navigation, and both SAVE/LOAD of the file data and the program itself to tape. A two-level key command system (Level One for direct editing, Level Two accessed by a shifted key) provides additional functions including a print routine using LPRINT, an erase command, and a soft caps-lock implemented by POKEing system variable 23658. Status information including horizontal position, vertical position, and current line number is displayed in the lower border area using stream #1.
Program Analysis
Program Structure
The program is organized into clearly commented functional blocks, with a dispatch table driven by computed GO TO targets. Initialization runs once at line 3000, then control passes to the main editor loop at line 20. The overall flow is:
- Lines 3000–3098: Initialization — prompts for file size, allocates
f$(bmax), sets defaults. - Lines 20–98: Main display refresh and entry into the keypress loop.
- Lines 40–49: Key debounce and auto-repeat throttle loop.
- Lines 50–130: Printable character handler, word-wrap logic.
- Lines 140–290: Sparse jump table for control codes (computed
GO TO 100+10*a). - Lines 300–320: Caps-Shift / Symbol-Shift key dispatcher.
- Lines 400–442: Delete character with held-key repeat support.
- Lines 500–609: Level Two command menu — waits for a digit key and dispatches via
GO TO 600+k-48. - Lines 840–848: Jump-to-line function.
- Lines 1000–1044: Toggle switches (BEEP, STATUS, WRAP) and status-bar subroutine.
- Lines 1090–1094: Erase file command.
- Lines 1150–1158: LPRINT file or range to printer.
- Lines 1170–1177: Tab-stop setup.
- Lines 1380–1389: STOP / return-to-BASIC handler.
- Lines 2000–2098: Help menu with optional screen copy to printer.
- Lines 2100–2196: SAVE / LOAD tape menu.
- Lines 4000–4040: 80-column screen copy via LPRINT SCREEN$.
- Lines 5000–5010: Spare/unused control stub.
Document Buffer Design
The entire document is stored as a single flat string f$ dimensioned to bmax characters, where bmax = 64 * lmax. Each logical line occupies exactly 64 characters (matching the OS-64 cartridge column width), making line arithmetic trivial: line n starts at 1 + 64*(n-1). The cursor position within the buffer is tracked solely by the integer variable by. A 64-character blank string e$ is used as a fill/shift register throughout insert and delete operations.
OS-64 Cartridge Integration
The program explicitly targets the OS-64 cartridge, which remaps the display to 64 columns. All column arithmetic uses 64 as the line width, and screen position is read back from the cartridge’s system variables rather than the standard ones. POKEs to addresses around 63416–63423 at line 3017 appear to configure cartridge hardware or workspace. The status bar is written to stream #1 (the lower two-line area), keeping it separate from the main 22-line editing area.
System Variable Usage
The program makes heavy use of POKEs and PEEKs to system variables to read and restore the current print position, enabling it to save cursor coordinates, perform screen output, and then restore the cursor exactly:
| Address | Standard meaning | Use in program |
|---|---|---|
| 23560 | Last key pressed (LAST K) | Read after PAUSE 0 for menu keypresses |
| 23562 | REPDEL / FLAGS2 | Set to 1 (enable key repeat) or 5 (disable) |
| 23658 | FLAGS (caps/shift) | POKEd to 8 to enable caps lock, 0 to clear |
| 23684–23685 | Display file / print position high bytes | Saved and restored around screen writes |
| 23688 | Column of print position (S_POSN) | Extensively read for horizontal cursor position |
| 23689 | Row of print position (S_POSN) | Extensively read for vertical cursor position |
Saving and restoring s1–s4 from these addresses before and after print operations (e.g. lines 414–424, 254–256) is the core technique used to keep the logical cursor position independent of any side-effects of PRINT.
Key Input and Debounce
The main input loop at lines 40–49 implements a software debounce and auto-repeat throttle. When a new key is detected (a<>b), a counter c is set to 12; subsequent loops decrement c before accepting another event, preventing accidental repeats. The variable a holds the last accepted key code. Fast-repeat for the delete key (lines 430–442) uses a secondary counter dcnt and polls hardware ports directly with IN 61438 and IN 65278 to detect the key combination being held.
Control-Code Dispatch Table
At line 301, control characters (codes 1–31) are dispatched with the idiom GO TO 100+10*a, mapping each code to a decade of line numbers:
| Code (a) | Target line | Function |
|---|---|---|
| 4 | 140 | TAB |
| 5 | 150 | JUMP |
| 6 | 160 | CAPS LOCK toggle |
| 7 | 170 | Level Two command mode |
| 8 | 180 | LEFT |
| 9 | 190 | RIGHT |
| 10 | 200 | DOWN |
| 11 | 210 | UP |
| 12 | 220 | DELETE character |
| 13 | 230 | ENTER / newline |
| 15 | 250 | INSERT SPACE |
| others | 260–290 | GO TO 40 (ignored) |
Word-Wrap Algorithm
When word-wrap is enabled (wrap=1), after a character is typed near the right margin (column ≤ 2, line ≥ 5 from bottom), the program scans backwards up to 20 characters for a space or hyphen (lines 112–114). If found, it shifts the tail of the word onto the next line by splicing e$(1 TO i) (spaces) in front of it in the buffer (line 116) and reprints the affected region.
Cursor Rendering
The text cursor is rendered in software using PRINT OVER 1; INVERSE 1;" ";CHR$ 8;. The OVER 1 attribute causes the cursor block to XOR with the character beneath it, making it visible on any background. CHR$ 8 (backspace) moves the print position back so the cursor remains under the current by position. This cursor is redrawn after virtually every editing operation.
Tape Save/Load
The tape menu (lines 2100–2196) offers five options. Option 1 saves only the file array with SAVE q$ DATA f$(). Option 2 saves the program with the file embedded using SAVE q$ LINE 20 (auto-start at line 20). Option 3 reduces bmax to 1 and re-dimensions f$ before saving, producing a compact program-only save. Option 4 loads a previously saved file array. A verify step is offered after each save. Error handling uses ON ERR GO TO to catch tape errors.
Notable Techniques and Anomalies
- Line 26 clamps
ytobmaxon every display refresh, preventing out-of-bounds string slices when the buffer is small. - Line 87 uses a negative-offset slice
f$(x-191 TO x)to display the preceding three lines when scrolling right — the offset of 191 is 3×64 minus 1, aligning to the 64-column grid. - Line 522 and line 1030 fill the status bar row with a string of
\uUDG characters, which are presumably defined elsewhere (likely by the OS-64 cartridge) as a horizontal rule or separator graphic. - The
ON ERR GO TO 40at line 25 provides a global safety net, catching string-range errors that could occur ifbyreaches the buffer boundary. - The
lmaxvariable is set toINT (bmax/32)after a file load (line 2153) — this is half the actual line count (since lines are 64 chars wide), suggesting a possible off-by-factor-of-two bug in the line count display after loading. - Lines 140 and 150 use bare
GO TOto enter TAB and JUMP handlers; these lines are reachable only from the control-code dispatch table, making theREMcomments on lines 140 and 150 serve as the only documentation of their entry points. - Line 5010 jumps to line 350, which does not exist in the listing — a placeholder for future expansion.
Content
Source Code
1 REM ***TYPEWRITER***FOR USE WITH OS-64 CARTRIDGE
2 REM VERSION: 841009
5 REM A public-domain word-processor written by Jack Dohany
6 REM (415) 321-7684
10 REM OK TO RUN
15 GO TO 3000: REM INIT
20 CLS : GO SUB 1030
21 LET a=0: LET c=0
22 POKE 23562,1
25 ON ERR GO TO 40
26 LET y=1407: IF y>bmax THEN LET y=bmax
27 LET by=1: PRINT f$(by TO y);AT 0,0;
30 PRINT OVER 1; INVERSE 1;" ";CHR$ 8;
31 IF s=0 THEN GO TO 40
32 GO SUB 90
40 IF INKEY$="" THEN LET a=0: GO TO 40
42 LET b=CODE INKEY$: IF b<4 THEN GO TO 40
44 IF a<>b THEN LET a=b: LET c=12: GO TO 50
49 IF c>0 THEN LET c=c-1: GO TO 40
50 IF a<32 OR a>127 THEN GO TO 300
60 IF beep=1 THEN BEEP .002,25
70 IF by>=bmax-1 THEN GO TO 98
80 LET f$(by)=CHR$ a: LET by=by+1
81 IF wrap=1 THEN GO TO 100
82 IF PEEK 23689<5 AND PEEK 23688<3 THEN GO TO 86
84 PRINT CHR$ a;: GO TO 30
86 CLS : LET x=64*INT ((by-1)/64)
87 IF x<bmax-64 THEN BEEP .008,30: PRINT f$(x-191 TO x);: GO SUB 1030: GO TO 30
88 PRINT f$(x-1279 TO x);: GO TO 30
90 PRINT #1;AT 1,7;66-PEEK 23688;" ";AT 1,11;25-PEEK 23689;" ";AT 1,15;1+INT ((by-1)/64);" "
92 RETURN
98 PRINT '"END OF FILE": GO TO 40
100 REM WRAP?
102 IF PEEK 23688>2 THEN GO TO 82
104 IF CHR$ a=" " OR CHR$ a="-" THEN GO TO 82
106 IF PEEK 23689<5 THEN GO TO 82
110 REM WRAP!
112 BEEP .02,27: FOR i=1 TO 20: IF f$(by-i-1)=" " OR f$(by-i-1)="-" THEN GO TO 116
114 NEXT i: GO TO 82
116 LET f$(by-i TO by-1+i)=e$(1 TO i)+f$(by-i TO by-1)
117 PRINT f$(by-i TO by-1+i);: LET by=by+i
118 GO TO 30
120 GO TO 40
130 GO TO 40
140 GO TO 171: REM tab
141 REM INSERT LINE
142 LET x=PEEK 23688: LET y=PEEK 23689: LET f$(by+x-1 TO bmax)=e$+f$(by+x-1 TO bmax-64)
143 PRINT 'f$(by+x-1 TO by+x-3+64*(y-3));: PRINT AT 24-y,65-x;
144 GO TO 500
150 GO TO 840: REM jump
152 REM DELETE LINE
154 LET by=1+(64*INT (by/64)): POKE 23684,PEEK 23684-(65-PEEK 23688): POKE 23688,65
155 LET f$(by TO bmax)=f$(by+64 TO bmax)+e$
156 LET s1=PEEK 23684: LET s2=PEEK 23685: LET s3=PEEK 23688: LET s4=PEEK 23689: PRINT f$(by TO by-1+64*(s4-2));
157 POKE 23684,s1: POKE 23685,s2: POKE 23688,s3: POKE 23689,s4
158 PRINT OVER 1; INVERSE 1;" ";CHR$ 8;
159 GO TO 500
160 REM CAPS
161 LET cs=1-cs
162 IF cs=1 THEN POKE 23658,8
163 IF cs=0 THEN POKE 23658,0
164 PRINT #1;AT 1,0;" "
165 IF cs=1 THEN PRINT #1;AT 1,0;"CAPS"
166 GO TO 40
170 GO TO 500: REM command
171 LET hp=66-PEEK 23688: REM TAB
172 IF hp>63 THEN GO TO 175
173 FOR i=hp+1 TO 64: IF t$(i)="1" THEN GO TO 177
174 NEXT i
175 FOR i=1 TO hp-1: IF t$(i)="1" THEN GO TO 177
176 NEXT i: GO TO 40
177 LET tab=i-1: PRINT OVER 1; INVERSE 1;" ";CHR$ 8;
178 FOR i=66-PEEK 23688 TO tab: PRINT OVER 1;" ";: NEXT i
179 LET by=1+(64*INT (by/64))+tab: GO TO 30
180 REM LEFT
181 IF PEEK 23689>23 AND PEEK 23688>32 THEN GO TO 40
182 PRINT OVER 1; INVERSE 1;" ";CHR$ 8;CHR$ 8;: LET by=by-1
186 GO TO 30
190 REM RIGHT
191 IF by>=bmax-1 OR (PEEK 23689<4 AND PEEK 23688<3) THEN GO TO 30
192 PRINT OVER 1; INVERSE 1;" ";: LET by=by+1: GO TO 30
200 REM DOWN
201 IF PEEK 23689<4 THEN GO TO 205
202 PRINT OVER 1; INVERSE 1;" ";CHR$ 8;: POKE 23689,PEEK 23689-1
203 IF PEEK 23689=16 OR PEEK 23689=8 THEN POKE 23684,PEEK 23684-224: POKE 23685,PEEK 23685+8: LET by=by+64: GO TO 30
204 POKE 23684,PEEK 23684+32: LET by=by+64: GO TO 30
205 IF by>(bmax-64) THEN GO TO 40
206 LET s1=PEEK 23688: LET s2=PEEK 23689: LET s3=PEEK 23684: LET s4=PEEK 23685: LET by=by+64: LET x=1+(64*INT (by/64))
207 CLS : PRINT f$(x-1344 TO x+63);: POKE 23688,s1: POKE 23689,s2: POKE 23684,s3: POKE 23685,s4: PRINT ;: GO SUB 1030: GO TO 30
210 REM UP
211 IF PEEK 23689>23 THEN GO TO 215
212 PRINT OVER 1; INVERSE 1;" ";CHR$ 8;: POKE 23689,PEEK 23689+1
213 IF PEEK 23689=17 OR PEEK 23689=9 THEN POKE 23684,PEEK 23684+224: POKE 23685,PEEK 23685-8: LET by=by-64: GO TO 30
214 POKE 23684,PEEK 23684-32: LET by=by-64: GO TO 30
215 IF by<65 THEN BEEP .02,20: GO TO 40
216 LET s1=PEEK 23688: LET s2=PEEK 23689: LET s3=PEEK 23684: LET s4=PEEK 23685: LET by=by-64: LET x=1+(64*INT (by/64))
217 CLS : PRINT f$(x TO x+1407);: POKE 23688,s1: POKE 23689,s2: POKE 23684,s3: POKE 23685,s4: PRINT ;: GO SUB 1030: GO TO 30
220 REM DELETE CH
221 IF by<2 THEN GO TO 40
222 GO TO 400
230 REM ENTER
231 LET x=64*INT ((by-1)/64): IF x>=bmax-64 THEN PRINT "FILE FULL": GO TO 40
232 PRINT OVER 1; INVERSE 1;" ";CHR$ 8;
233 IF PEEK 23689<4 THEN GO TO 236
235 PRINT CHR$ 13;: LET by=65+x: GO TO 30
236 CLS : PRINT f$(x-1279 TO x+64);AT 21,0;: LET by=65+x: GO SUB 1030: GO TO 30
250 REM INSERT SP
252 IF by>=bmax OR (PEEK 23689<4 AND PEEK 23688<4) THEN BEEP .01,20: GO TO 40
254 LET by=by+1: PRINT " ";: LET s1=PEEK 23684: LET s2=PEEK 23685: LET s3=PEEK 23688: LET s4=PEEK 23689
255 LET f$(by-1 TO by+s3-2)=" "+f$(by-1 TO by+s3-3)
256 PRINT f$(by TO by+s3-2);: POKE 23684,s1: POKE 23685,s2: POKE 23688,s3: POKE 23689,s4: GO TO 30
260 GO TO 40
270 GO TO 40
280 GO TO 40
290 GO TO 40
300 REM CS&SS KEYS
301 IF a<32 THEN GO TO 100+10*a
302 IF a=226 THEN GO TO 1380
303 IF a=197 THEN LET a=164: GO TO 60: REM UNDERLINE
304 IF a=199 THEN GO SUB 2000: GO TO 20
305 IF a=195 THEN LET a=123: GO TO 60
306 IF a=205 THEN LET a=125: GO TO 60
307 IF a=201 THEN LET a=127: GO TO 60
308 IF a=204 THEN LET a=91: GO TO 60
309 IF a=200 THEN LET a=92: GO TO 60
310 IF a=203 THEN LET a=93: GO TO 60
320 GO TO 40
400 REM DELETE
404 LET dcnt=10
410 IF by<2 THEN GO TO 40
414 LET by=by-1: PRINT OVER 1; INVERSE 1;" ";CHR$ 8;CHR$ 8;: LET s1=PEEK 23688: LET s2=PEEK 23689: LET s3=PEEK 23684: LET s4=PEEK 23685
418 LET f$(by TO by+s1-1)=f$(by+1 TO by+s1-2)+" "
424 PRINT f$(by TO by+s1-2);: POKE 23688,s1: POKE 23689,s2: POKE 23684,s3: POKE 23685,s4
428 PRINT OVER 1; INVERSE 1;" ";CHR$ 8;
429 IF s=1 THEN GO SUB 90
430 IF IN 61438=30 AND IN 65278=30 THEN GO TO 440
432 GO TO 31
440 IF dcnt=0 THEN GO TO 410
442 LET dcnt=dcnt-1: GO TO 430
500 REM LEVEL TWO
501 PRINT #1;AT 0,0;" **LEVEL TWO** "
502 PAUSE 0: LET k=PEEK 23560
506 IF k=13 THEN GO TO 520
508 IF k<48 OR k>57 THEN GO TO 500
510 BEEP .01,20
512 GO TO 600+k-48
520 REM exit edit-mode
522 PRINT #1;AT 0,0;"\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u"
524 GO TO 31
600 GO TO 152: REM delete ln
601 GO TO 520: REM exit
602 GO TO 1170: REM set tabs
603 GO TO 1010: REM status sw
604 GO TO 1000: REM beep sw
605 GO TO 1020: REM wrap sw
606 GO TO 2100: REM tape
607 GO TO 1090: REM erase
608 GO TO 1150: REM print
609 GO TO 141: REM insert ln
840 REM JUMP
841 INPUT ("JUMP TO LINE (1-";lmax;"): "); LINE q$: IF q$="" THEN GO TO 40
842 LET fl=VAL q$
843 LET by=1+(64*(fl-1))
844 LET tb=by+1407: IF tb>bmax THEN LET tb=bmax
848 CLS : PRINT f$(by TO tb);AT 0,0;: LET cm=0: GO SUB 1030: GO TO 30
1000 REM BEEP SW
1002 LET beep=1-beep
1004 PRINT #1;AT 1,20;" "
1006 IF beep=1 THEN PRINT #1;AT 1,20;"BEEP"
1008 GO TO 502
1010 REM STATUS SW
1012 LET s=1-s
1014 PRINT #1;AT 1,6;" "
1016 IF s=1 THEN GO SUB 1040
1018 GO TO 502
1020 REM WRAP SW
1022 LET wrap=1-wrap
1024 PRINT #1;AT 1,26;" "
1026 IF wrap=1 THEN PRINT #1;AT 1,26;"WRAP"
1028 GO TO 502
1030 PRINT #1;AT 0,0;"\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u";AT 1,0;e$(1 TO 31)
1031 IF s=1 THEN GO SUB 1040
1032 IF cs=1 THEN PRINT #1;AT 1,0;"CAPS"
1034 IF beep=1 THEN PRINT #1;AT 1,20;"BEEP"
1036 IF wrap=1 THEN PRINT #1;AT 1,26;"WRAP"
1038 RETURN
1040 REM print status
1042 PRINT #1;AT 1,6;"H";66-PEEK 23688;" ";AT 1,10;"V";25-PEEK 23689;" ";AT 1,14;"L";1+INT ((by-1)/64);" "
1044 RETURN
1090 REM ERASE FILE
1092 INPUT "ERASE FILE? (Y=YES)"; LINE q$: IF q$="y" OR q$="Y" THEN DIM f$(bmax): GO TO 20
1094 GO SUB 1030: GO TO 500
1150 REM PRINT
1151 ON ERR GO TO 1158
1152 INPUT ("PRINT FROM LINE (1-";lmax;"): "); LINE q$: IF q$="" THEN GO TO 1158
1153 LET fl=VAL q$: LET fb=1+(64*(fl-1)): IF fl>lmax THEN GO TO 1152
1154 INPUT ("PRINT LINE ";fl;" TO:(";fl+1;"-";lmax;"): "); LINE q$
1155 IF q$="" THEN LET tb=bmax: GO TO 1157
1156 LET tb=64+(64*(VAL q$-1)): IF fb>=tb THEN GO TO 1152
1157 LPRINT f$(fb TO tb)
1158 BEEP .01,25: PAUSE 100: ON ERR GO TO 40: GO TO 20
1170 REM SET TABS
1171 INPUT "SET TABS (1-64)/ENT=done: "; LINE q$: IF q$="" THEN GO SUB 1030: GO TO 500
1172 DIM t$(64)
1173 LET tab=INT VAL q$: IF tab<1 OR tab>64 THEN GO TO 1176
1174 LET t$(tab)="1"
1176 INPUT "SET TABS (1-64)/ENT=done: "; LINE q$: IF q$="" THEN GO SUB 1030: GO TO 500
1177 GO TO 1173
1380 REM STOP
1382 CLS : PRINT AT 10,0;"TO RETURN, GO TO 20."
1384 POKE 23562,5
1388 ON ERR RESET : STOP
1389 GO TO 20
2000 REM MENU
2010 CLS
2015 PRINT TAB 4;"(Caps Shift)";TAB 18;"(Unshifted)"
2016 PRINT "KEY LEVEL ONE";TAB 18;" LEVEL TWO"
2020 PRINT "\u\u\u \u\u\u\u\u\u\u\u\u\u\u\u \u\u\u\u\u\u\u\u\u\u\u"
2022 PRINT " 1";TAB 4;"CHANGE LEVEL";TAB 18;"CHANGE LEVEL"
2024 PRINT " 2 CAPS LOCK";TAB 18;"SET TABS 1-64"
2026 PRINT " 3 TAB";TAB 18;"STATUS ON/OFF"
2028 PRINT " 4 JUMP TO LINE";TAB 18;"BEEP ON/OFF"
2030 PRINT " 5 LEFT";TAB 18;"WRAP ON/OFF"
2032 PRINT '" 6 DOWN";TAB 18;"TAPE"
2034 PRINT " 7 UP";TAB 18;"ERASE FILE"
2036 PRINT " 8 RIGHT";TAB 18;"PRINT FILE"
2038 PRINT " 9 INSERT SPACE";TAB 18;"INSERT LINE"
2040 PRINT " 0 DELETE LEFT";TAB 18;"DELETE LINE"
2042 PRINT '"KEY SYMBOL SHIFT";TAB 18;"-For fast key"'"\u\u\u \u\u\u\u\u\u\u\u\u\u\u\u";TAB 18;" response,"
2044 PRINT " A STOP";TAB 18;" turn off BEEP"
2046 PRINT " Q MENU";TAB 18;" and STATUS."
2048 PRINT " U UNDERLINE"
2090 PRINT #1;AT 0,0;"COPY?"
2092 PAUSE 0: IF INKEY$="y" THEN GO SUB 4000: RETURN
2098 RETURN
2100 REM SAVE/LOAD
2102 ON ERR GO TO 2170: POKE 23562,5
2104 GO SUB 2190
2110 PAUSE 0: LET a=PEEK 23560: PRINT AT 20,0;e$: IF a<49 OR a>53 THEN GO TO 2110
2112 GO TO 2120+10*(a-49)
2120 REM SAVE FILE
2122 INPUT "FILE NAME: ";q$: IF q$="" THEN GO TO 2104
2124 SAVE q$ DATA f$()
2125 GO SUB 2190: PRINT AT 20,0;"VERIFY? (y/n) ": PAUSE 0: IF INKEY$="y" THEN PRINT "REWIND, then press PLAY": VERIFY q$ DATA f$(): GO SUB 2190: PRINT AT 20,0;"VERIFY OK.": GO TO 2110
2126 GO TO 2110
2130 REM SAVE PR & FL
2132 INPUT " ENTER PROGRAM NAME: ";q$: IF q$="" THEN LET q$="TYPEWRITER"
2134 SAVE q$ LINE 20
2135 GO TO 2145
2140 REM SAVE PROG
2142 PRINT AT 20,0;"ARE YOU SURE?": PAUSE 0: IF INKEY$<>"y" THEN GO TO 2110
2144 PRINT AT 20,0;e$: LET bmax=1: DIM f$(1): SAVE "TYPEWRITER"
2145 GO SUB 2190: PRINT AT 20,0;"VERIFY? (y/n) ": PAUSE 0: IF INKEY$="y" THEN PRINT AT 20,0;"REWIND, then press PLAY": VERIFY "": GO SUB 2190: PRINT AT 20,0;"VERIFY OK.": GO TO 2110
2146 GO TO 2110
2147 GO TO 20
2150 REM LOAD FILE
2151 INPUT "Enter File Name: ";q$: PRINT AT 20,0;"LOADING ";q$
2152 LOAD q$ DATA f$()
2153 BEEP .01,25: LET bmax=LEN f$(): LET lmax=INT (bmax/32)
2154 PRINT AT 20,0;e$;AT 20,0;q$;" LOADED. ": GO TO 2110
2160 REM RETURN
2162 IF bmax<2 THEN GO TO 3000
2164 GO TO 20
2170 GO SUB 2190: PRINT AT 20,0;"TAPE ERROR...or BREAK pressed.": GO TO 2110
2190 REM SL-MENU
2192 CLS : PRINT AT 0,0;" *** SAVE / LOAD ***"
2194 PRINT ''"1: SAVE FILE"''"2: SAVE PROGRAM AND FILE"''"3: CLEAR FILE AND SAVE PROGRAM"''"4: CLEAR FILE AND LOAD FILE"''"5: RETURN"
2196 RETURN
3000 REM INITIALIZATION
3005 PAPER 7: CLS
3008 PRINT AT 0,15;"*** T Y P E W R I T E R ***"
3010 PRINT AT 1,11;"*** FOR USE WITH OS-64 CARTRIDGE ***"
3011 PRINT AT 10,0;"Greetings! You have no file."''"Please tell me how big a file you need...that is, how many"'"lines maximum: from 1 to 150: (A large file takes longer to"'"save on tape.)"
3012 INPUT "FILE SIZE (1-150): ";lmax: LET lmax=INT lmax: IF lmax<1 OR lmax>150 THEN PRINT "Please Try again.": GO TO 3012
3013 CLS
3015 DIM t$(64): LET wrap=1: LET cs=0: LET s=1: LET beep=1: LET e$=" "
3016 FOR i=1 TO 64 STEP 4: LET t$(i)="1": NEXT i
3017 POKE 63416,255: FOR i=63417 TO 63423: POKE i,0: NEXT i
3018 LET bmax=64*lmax: DIM f$(bmax): LET by=1
3040 CLS : PRINT AT 10,0;"Your file has ";lmax;" lines."''"Would you like to see the menu?"
3042 PAUSE 0: IF INKEY$="y" THEN GO SUB 2000: GO TO 20
3098 GO TO 20
4000 REM COPY 80-col
4010 FOR x=0 TO 21: FOR y=0 TO 63
4020 LPRINT SCREEN$ (x,y);
4030 NEXT y: LPRINT : NEXT x
4040 RETURN
5000 REM spare control
5010 GO TO 350
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

