--- title: "Typewriter" id: 56324 type: "computer_media" slug: "typewriter-2" url: "http://localhost/computer_media/typewriter-2/" markdown_url: "http://localhost/computer_media/typewriter-2.md" published_at: "2024-08-04T10:50:00+00:00" modified_at: "2026-03-30T21:46:08+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/08/SCR-20240804-iunb.png" excerpt: "A complete BASIC word processor with word-wrap, tab stops, insert/delete, and cassette save/load — all packed into a single string-array document buffer." 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 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Jack Dohany" slug: "jack-dohany" taxonomy: "indiv" url: "http://localhost/indiv/jack-dohany/" genre: - name: "Word Processor" slug: "word-processor" taxonomy: "genre" url: "http://localhost/type/word-processor/" media_contents: - id: 56277 title: "Timex Sinclair Public Domain Library Tape 2001" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-2001/" media_type: "Program" programmers: - name: "Jack Dohany" slug: "jack-dohany" taxonomy: "indiv" url: "http://localhost/indiv/jack-dohany/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Typewriter%20%28198x%29%28Dohany%2C%20Jack%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" producer_company: - id: 10976 title: "Jack Dohany" type: "company" url: "http://localhost/company/jack-dohany/" images: - url: "http://localhost/wp-content/uploads/2024/08/SCR-20240804-iunb.png" - url: "http://localhost/wp-content/uploads/2024/08/SCR-20240804-iuiz.png" - url: "http://localhost/wp-content/uploads/2024/08/SCR-20240804-iufy.png" related_content: - id: 56325 title: "Typewriter 64" type: "computer_media" url: "http://localhost/computer_media/typewriter64/" media_type_tags: "Word Processor" --- # Typewriter This program is a full-featured word processor. It stores the document as a single large string array `f$` dimensioned to a user-specified number of 32-character lines (up to 320 lines, 10,240 bytes). The editor supports cursor movement, word-wrap, tab stops, insert/delete of characters and lines, caps lock, a status bar on the lower screen, and cassette tape save/load of both the file and the program itself. Keyboard handling uses a two-level control scheme where Caps Shift keys dispatch to editing commands and a “Level Two” menu provides additional functions such as erasing the file, printing via LPRINT, and setting tab stops. Screen position tracking relies directly on system variables at addresses 23688 (column) and 23689 (row) rather than maintaining separate cursor variables. *** ## Program Analysis ### Program Structure The program is organised into clearly labelled functional blocks separated by REM statements. Execution begins at line 15 with a `GO TO 3000` for initialisation, then falls into the main edit loop at line 20. The broad structure is: 1. **Lines 20–99:** Main edit loop — display, cursor rendering, key polling, character insertion, and word-wrap logic. 2. **Lines 100–290:** Control-key dispatch table; each Caps Shift key (codes 1–28) jumps to `100+10*a`, placing handlers at lines 100, 110, 120, …, 280. 3. **Lines 300–320:** Symbol Shift and extended key handling. 4. **Lines 400–442:** Delete-character routine with held-key repeat detection via `IN 61438` / `IN 65278`. 5. **Lines 500–609:** “Level Two” command menu, dispatching on digit keys to secondary functions. 6. **Lines 840–848:** Jump-to-line function. 7. **Lines 1000–1044:** Toggle switches (beep, status, word-wrap) and status-bar subroutine. 8. **Lines 1090–1177:** Erase file, print via LPRINT, and tab-stop setup. 9. **Lines 1380–1389:** STOP / exit to BASIC. 10. **Lines 2000–2098:** Menu display (help screen). 11. **Lines 2100–2196:** Save/Load menu with five options. 12. **Lines 3000–3098:** Initialisation — prompts for file size, dimensions arrays, sets defaults. 13. **Lines 4000–5010:** Stubs for 80-column print and spare control (both jump to non-existent line 350). ### Document Storage Model The entire document is held in a single string variable `f$`, dimensioned to `bmax` characters where `bmax = 32 * lmax` and `lmax` is the user-specified line count (1–320). Each 32-character slice of `f$` corresponds to one screen line. The variable `by` is the logical byte-offset cursor into `f$` (1-based). A blank-line buffer `e$` is a 32-space string used for padding during insert/delete operations. The tab-stop map is held in `t$(32)`, a one-character-per-column string where `"1"` marks a tab stop. ### Key Polling and Auto-Repeat The main loop at line 40 polls `INKEY$` directly, rejecting codes below 4 (pure shift keys). A simple software auto-repeat mechanism uses variables `a` (last key code) and `c` (countdown): on a first press `c` is set to 12, and subsequent loops decrement it before accepting the key again, producing a short initial delay before repeat. The delete routine (line 400–442) uses a tighter hardware-level repeat: it reads the keyboard matrix ports `IN 61438` (half-row containing `0`) and `IN 65278` (half-row containing Caps Shift) to detect whether both Delete keys are still held, with a small counter `dcnt` providing a secondary delay before rapid deletion begins. `OUT 255,64` and `OUT 255,0` bracket the delete loop, presumably driving an external device or the border. ### System Variable Manipulation Rather than tracking screen cursor position in BASIC variables, the program reads and writes the Spectrum system variables directly: | Address | System Variable | Usage | | --- | --- | --- | | 23562 | ERR_SP / FLAGS | Set to 1 (edit mode) or 5 (suppress error reports) | | 23658 | FLAGS2 | POKEd 8 to set caps-lock flag, 0 to clear | | 23684–23685 | DF_CC (display file cursor low/high byte) | Direct cursor repositioning within the display file | | 23688 | S_POSN column | Current print column; used to compute horizontal offsets | | 23689 | S_POSN row | Current print row; used to detect screen boundaries | | 23560 | LAST_K | Read directly for Level Two menu key detection after `PAUSE 0` | | 65528–65535 | RAM top area | POKEd during init; likely clears UDG area or interrupt vector | This direct manipulation allows the program to reposition the print position after redrawing the screen without issuing a fresh `PRINT AT`, and to compute the cursor’s logical document position from `by` and the column/row registers. ### Word-Wrap Algorithm Word-wrap (lines 100–118) is triggered when the column counter (`PEEK 23688`) reaches 2 or below and the character being typed is not a space or hyphen. The routine scans backwards in `f$` up to 20 characters for the last space or hyphen (line 112), then uses a string slice assignment to shuffle characters: `f$(by-i TO by-1+i)=e$(1 TO i)+f$(by-i TO by-1)` inserts `i` spaces at the split point to push the wrapped word to the next line. The system variable `DF_CC` and column register are then adjusted to match. ### Level Two Command Dispatch Pressing Caps Shift + key 1 (code 1) enters “Level Two” at line 500. The menu waits for a digit key `0`–`9` (ASCII 48–57) and dispatches via `GO TO 600+k-48`, producing jump targets at lines 600–609. Each of these is a single `GO TO` stub pointing to the real handler, creating a clean indirection table: - 600 → 152 (delete line) - 601 → 520 (exit level two) - 602 → 1170 (set tabs) - 603 → 1010 (status toggle) - 604 → 1000 (beep toggle) - 605 → 1020 (wrap toggle) - 606 → 2100 (tape save/load) - 607 → 1090 (erase file) - 608 → 1150 (print) - 609 → 141 (insert line) ### ON ERR Usage The program uses the TS2068 `ON ERR` keyword (displayed here as `{` per preprocessing rules — but written as `ON ERR` in the source) at several points: line 25 redirects tape errors and user breaks back to the main loop at line 40; line 1151 catches printer errors; line 2102 catches tape errors in the save/load section; and line 1388 calls `RESET` followed by `STOP` to cleanly exit. This confirms the program targets the TS2068, which has `ON ERR` as a native keyword. ### Status Bar The lower screen (stream `#1`) provides a persistent status bar. Subroutine 1030 draws a row of inverse-video spaces on row 0 and a blank line on row 1. Subroutine 1040/90 overlays live cursor position information: horizontal offset (`34-PEEK 23688`), vertical position (`25-PEEK 23689`), and logical line number (`1+INT((by-1)/32)`). Toggle states CAPS, BEEP, and WRAP are also displayed in fixed columns of the status line. ### Tape Save/Load The save/load section (lines 2100–2196) offers five options. Options 1 and 4 use `SAVE/LOAD q$ DATA f$()` to serialise or restore just the document array, allowing the program itself to remain in RAM. Option 2 uses `SAVE q$ LINE 20` to save the whole program with auto-run at line 20, which also preserves the current `f$` contents embedded in the saved file. Option 3 resets `bmax=1` and re-dimensions `f$(1)` before saving, stripping the document to save tape space. Verify prompts follow each save operation. ### Notable Anomalies and Observations - Lines 120, 130, 260, 270, 280, 290 all contain only `GO TO 40`; these are placeholder stubs for Caps Shift codes 2, 3, 6, 7, 8, and 9 that have real handlers elsewhere but are reached via the `GO TO 100+10*a` dispatch — code 2 (Caps Lock) is actually at 160, code 3 (TAB) at 140, etc., so lines 120/130 being simple pass-throughs is consistent. - Line 87 uses `f$(x-95 TO x)`, which could produce a negative index if `x` is small; this path is only taken when `x < bmax-32` but the guard on `x` being large enough for the 96-character back-window is implicit rather than explicit. - Lines 4000 and 5010 jump to line 350, which does not exist. These are declared stubs for “80-column print” and “spare control” features that were never implemented. - Line 522 and 1030 use `\u` escape sequences to print UDG character ‘u’ (char 157) filling the top status row — this is used as a solid inverse block to create the status-bar background. - The `POKE 23562,1` at line 22 sets the error stack pointer flag to suppress the normal “0 OK” report, keeping the lower screen clean for the status bar. ## Source Code ``` 1 REM ***TYPEWRITER*** 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 19 BORDER 0: PAPER 0: INK 7 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=703: 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=32*INT ((by-1)/32) 87 IF x2 THEN GO TO 82 104 IF CHR$ a=" " OR CHR$ a="-" THEN GO TO 82 106 IF PEEK 23689<4 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 POKE 23688,PEEK 23688+i-1: POKE 23684,PEEK 23684-i+1: 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-32) 143 PRINT 'f$(by+x-1 TO by+x-3+32*(y-3));: PRINT AT 24-y,33-x; 144 GO TO 500 150 GO TO 840: REM jump 152 REM DELETE LINE 154 LET by=1+(32*INT (by/32)): POKE 23684,PEEK 23684-(33-PEEK 23688): POKE 23688,33 155 LET f$(by TO bmax)=f$(by+32 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+32*(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=34-PEEK 23688: REM TAB 172 IF hp>31 THEN GO TO 175 173 FOR i=hp+1 TO 32: 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 POKE 23684,PEEK 23684-(33-PEEK 23688)+tab: POKE 23688,33-tab 179 LET by=1+(32*INT (by/32))+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,33-PEEK 23688: POKE 23685,PEEK 23685+8: LET by=by+32: GO TO 30 204 POKE 23684,PEEK 23684+32: LET by=by+32: GO TO 30 205 IF by>(bmax-32) THEN GO TO 40 206 LET s1=PEEK 23688: LET s2=PEEK 23689: LET s3=PEEK 23684: LET s4=PEEK 23685: LET by=by+32: LET x=1+(32*INT (by/32)) 207 CLS : PRINT f$(x-672 TO x+31);: 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-32: GO TO 30 214 POKE 23684,PEEK 23684-32: LET by=by-32: GO TO 30 215 IF by<33 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-32: LET x=1+(32*INT (by/32)) 217 CLS : PRINT f$(x TO x+703);: 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=32*INT ((by-1)/32): IF x>=bmax-32 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=33+x: GO TO 30 236 CLS : PRINT f$(x-639 TO x+31);AT 21,0;: LET by=33+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 402 OUT 255,64 404 LET dcnt=10 410 IF by<2 THEN OUT 255,0: 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 OUT 255,0: 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" 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+(32*(fl-1)) 844 LET tb=by+703: 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";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";34-PEEK 23688;" ";AT 1,10;"V";25-PEEK 23689;" ";AT 1,14;"L";1+INT ((by-1)/32);" " 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+(32*(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=32+(32*(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-32)/ENT=done: "; LINE q$: IF q$="" THEN GO SUB 1030: GO TO 500 1172 DIM t$(32) 1173 LET tab=INT VAL q$: IF tab<1 OR tab>32 THEN GO TO 1176 1174 LET t$(tab)="1" 1176 INPUT "SET TABS (1-32)/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-32" 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 2040" 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 COPY : 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 BORDER 0: PAPER 0: INK 7: CLS 3010 PRINT AT 0,5;"*** TYPEWRITER ***" 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 320:"''"(A large file takes longer to"'"save on tape.)" 3012 INPUT "FILE SIZE (1-320): ";lmax: LET lmax=INT lmax: IF lmax<1 OR lmax>320 THEN PRINT "Please Try again.": GO TO 3012 3013 CLS 3015 DIM t$(32): LET wrap=1: LET cs=0: LET s=1: LET beep=1: LET e$=" " 3016 FOR i=1 TO 32 STEP 4: LET t$(i)="1": NEXT i 3017 POKE 65528,255: FOR i=65529 TO 65535: POKE i,0: NEXT i 3018 LET bmax=32*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 print 80-col 4010 GO TO 350 5000 REM spare control 5010 GO TO 350 ```