--- title: "Word Wizard" id: 57138 type: "computer_media" slug: "word-wizard" url: "http://localhost/computer_media/word-wizard/" markdown_url: "http://localhost/computer_media/word-wizard.md" published_at: "2024-10-04T00:11:30+00:00" modified_at: "2026-04-03T07:58:43+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/87_WrdWz.png" excerpt: "A full-featured five-page text editor with cut, paste, insert, delete, and printer support — built entirely in BASIC with its own cursor and buffer system." 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/" indiv: - name: "Ryan Gray" slug: "ryan-gray" taxonomy: "indiv" url: "http://localhost/indiv/ryan-gray/" genre: - name: "Word Processor" slug: "word-processor" taxonomy: "genre" url: "http://localhost/type/word-processor/" media_contents: - id: 56733 title: "Timex Sinclair Public Domain Library Tape 1002" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1002/" media_type: "Program" programmers: - name: "Ryan Gray" slug: "ryan-gray" taxonomy: "indiv" url: "http://localhost/indiv/ryan-gray/" mediadate: "1983" images: - url: "http://localhost/wp-content/uploads/2024/10/87_WrdWz.png" media_type_tags: "Word Processor" --- # Word Wizard Word Wizard is a multi-page text editor that stores up to five pages of 672 characters each in a two-dimensional string array, allowing the user to write, edit, save, and print documents. The editor features cursor movement, character insertion and deletion, a cut buffer for block operations, and a paste function, all driven by INKEY$ polling for keyboard input. Pages are displayed 32 characters wide across 21 lines, with the status bar on line 21 showing the current page number in inverse video. The program saves the entire file to tape using the filename entered at startup, and can send any page to a printer via LPRINT. An overflow buffer string E$ acts as a soft-wrap mechanism, carrying displaced characters from the end of one page when text is inserted. *** ## Program Analysis ### Program Structure The program is organized into a startup/initialization block, a main menu, and a collection of subroutines and handler sections addressed by line number. The flow is: 1. Lines 7–11: Variable initialization (`C`, `A$`, `C$`, `E$`, `F$`). 2. Lines 19–28: Filename entry, reading exactly 10 keypresses with INKEY$ polling. 3. Lines 29–38: Conditional SAVE (skipped when `C=1` meaning a file-clear is in progress). 4. Lines 39–74: Main menu display and option dispatch. 5. Lines 100–590: Menu handlers — save (100), print (200), clear page (300), clear file (400), write page (500+). 6. Lines 595–670: Main editing loop — character input, cursor positioning, key dispatch. 7. Lines 1100–2580: Editing operations (insert, delete, cut, paste, page navigation, etc.). 8. Lines 3000–3820: Backspace and page overflow. 9. Lines 7000–8020: Home cursor and clear-buffer subroutines. 10. Lines 9000–9260: Error/status message handlers and program end. ### Data Storage All text is held in `A$(5,672)` — a five-element array where each element is a fixed-length 672-character string, equivalent to 21 rows of 32 characters per page. Position within the current page is tracked by the integer variable `POS` (1–672). ### Cursor Display Technique The editor simulates a blinking cursor by alternating between printing the character at the current position normally and printing it in inverse video (character code + 128). The loop at lines 537–551 prints the inverse character, polls INKEY$, then restores the normal character and polls again, creating a flicker effect without any PAUSE.`537 PRINT AT WL,WC;CHR$ (CODE A$(A,POS)+128)` ### Screen Position Calculation Row and column are derived arithmetically from `POS` on every iteration. `WL` (line) is `INT(POS/32)` and `WC` (column) is `POS - WL*32 - 1`. A special boundary fix at line 535/8000 corrects the case where `POS` falls exactly on a 32-character boundary, forcing the cursor back to column 31 of the previous row. ### Key Dispatch Table After filtering printable characters (code ≥ 64), the editor checks a long series of IF statements at lines 568–590 for control characters. The mappings are: | CHR$ Code | Action / Target | | --- | --- | | 112–115 | Cursor movement (up/down/left/right) → line 660 | | 116 | Return to main menu → line 38 | | 117 | Next page → line 1500 | | 118 | NEWLINE remapped to space (line 565) | | 119 | Backspace/delete → line 3000 | | 121 | End-of-line jump → line 631 | | 192 | Special character input mode → line 1700 | | 216 | Home (POS=1) → line 7000 | | 217 | Clear character at cursor → line 1400 | | 218 | Previous page → line 1600 | | 219 | Unknown/extended → line 2000 | | 220 | Insert line → line 1200 (handler at 1210) | | 221 | Clear E$ buffer → line 7020 | | 222 | Cut block → line 1800 | | 223 | Paste block → line 1900 (handler at 1910) | | 224 | Insert text string → line 1300 | | 225 | Insert single space → line 1100 | | 228 | Backspace with buffer restore → line 2200 | | 229 | Remapped to £ (line 567) | ### Overflow Buffer (E$) When characters are inserted, the rightmost character(s) pushed off the end of the current page’s 672-character string are prepended to the string variable `E$`. The subroutine at line 2500 distributes any accumulated `E$` content to subsequent pages (pages A+1 through 4), displacing their own tail characters down the chain. This implements a rudimentary soft-flow between pages, though it is limited: `E$` is capped at 200 characters (checked at line 1135) before an error is raised. ### Cut and Paste The cut operation (line 1800) prompts for a character count `X`, copies `A$(A, POS-X TO POS-1)` into the paste buffer `F$`, then removes those characters from the page string. Paste (line 1910) inserts `F$` back at the current position. Note that this is a destructive cut (not a copy), and `F$` is cleared after pasting. ### End-of-Line Jump The jump-to-end-of-line shortcut at line 631 calculates the remaining columns on the current screen row as `UU = (WL+1)*32 - POS` and advances `POS` by `UU+1`, effectively moving the cursor to the start of the next line. ### Bugs and Anomalies - Lines 660–665 handle cursor movement, but line 661 is reached by a fall-through from a `GOTO 660` at line 569; however, the label dispatched to is `660`, which does not exist in the listing — line 661 is the first line in that block. This is a harmless off-by-one in label naming, not in logic, since GO TO a missing line runs the next higher line. - Lines 1200 and 1700/1740/1750 are referenced (line 581 → 1200; line 571 → 1700) but their entry points at 1200 and 1700 are absent from the listing — execution falls through to lines 1210 and 1710 respectively, which is the intended behavior given the GO TO missing-line idiom. - Line 785 is unreachable dead code; the `GOSUB 8000` there duplicates the boundary check already performed at line 535. - Lines 2010–2020 (`GOSUB 2500` then `GOTO 515`) are reached from line 574 (CHR$ 219) but the intent of this key is unclear — it flushes the overflow buffer without any other action. - The “clear file” path at line 409 sets `C=1` and jumps to line 8, which does not exist; execution falls to line 9 (the variable init block), effectively re-initializing without saving. This is the intended clear-file behavior. - Lines 9240–9260 (`CLEAR`, `SAVE`, `RUN`) appear to be a developer utility to save the program itself and are never reached by any normal execution path. ### SLOW Mode Usage `SLOW` is called at lines 38 and 536 to switch the display to the standard 50% CPU / display-generation sharing mode. This is used deliberately in the editor loop to keep the screen stable during cursor blinking, accepting the performance trade-off. ## Source Code ``` 1 REM ::::::::::::::: 2 REM ::WORD WIZARD:: 3 REM :: BY :: 4 REM :: RYAN GRAY :: 5 REM :: 3/3/83 :: 6 REM ::::::::::::::: 7 LET C=0 8 DIM A$(5,672) 9 LET C$="" 10 LET E$="" 11 LET F$="" 19 CLS 20 PRINT AT 10,0;" ENTER FILE NAME. ----------" 21 FOR A=1 TO 10 22 LET B$=INKEY$ 23 IF B$="" THEN GOTO 22 24 IF B$=CHR$ 118 THEN LET B$=" " 25 PRINT AT 10,A+17;B$ 26 LET C$=C$+B$ 27 NEXT A 28 LET D$=C$ 29 IF C=1 THEN GOTO 38 30 PRINT ,,,," SAVING:";C$ 31 PAUSE 200 32 SAVE C$ 38 SLOW 39 LET C=0 40 CLS 41 PRINT "CURRENT FILE:";D$ 42 PRINT ,," WORD WIZARD BY RYAN GRAY " 43 PRINT "................................................................" 44 PRINT ,," MENU:" 45 PRINT ,," 1:SAVE FILE" 46 PRINT ,," 2:SEND PAGE TO PRINTER" 47 PRINT ,," 3:CLEAR PAGE" 48 PRINT ,," 4:CLEAR FILE" 49 PRINT ,," 5:WRITE PAGE" 51 PRINT AT 21,0;"OPTION? " 52 PRINT AT 21,6;"?" 53 LET B$=INKEY$ 54 IF B$<>"" THEN GOTO 60 55 PRINT AT 21,6;"%?" 56 GOTO 52 60 IF B$<"1" OR B$>"6" THEN GOTO 55 70 IF B$="1" THEN GOTO 100 71 IF B$="2" THEN GOTO 200 72 IF B$="3" THEN GOTO 300 73 IF B$="4" THEN GOTO 400 74 IF B$="5" THEN GOTO 500 100 CLS 110 GOTO 9 200 PRINT AT 21,0;"WHICH PAGE?" 210 INPUT A 211 IF A<1 OR A>5 THEN GOTO 9000 212 LPRINT "PAGE:";A 213 LPRINT 220 LPRINT A$(A) 230 GOTO 51 300 PRINT AT 21,0;"WHICH PAGE?" 310 INPUT A 311 IF A<1 OR A>5 THEN GOTO 9000 312 LET A$(A)="" 317 GOTO 51 400 PRINT AT 21,0;"CONFIRM.Y/N" 401 IF INKEY$="" THEN GOTO 401 402 IF INKEY$="Y" THEN GOTO 409 403 GOTO 51 409 LET C=1 410 GOTO 8 500 PRINT AT 21,0;"WHICH PAGE?" 505 INPUT A 510 IF A<1 OR A>5 THEN GOTO 9000 511 CLS 512 LET POS=1 513 LET B$=CHR$ (CODE (STR$ A)+128) 514 PRINT AT 21,0;"% %W%O%R%D% %W%I%Z%A%R%D% % % % % % % % % % % % % %P%A%G%E%:";B$;"% " 515 PRINT AT 0,0;A$(A) 520 LET WL=INT (POS/32) 530 LET WC=POS-WL*32-1 535 IF POS/32=INT (POS/32) THEN GOSUB 8000 536 SLOW 537 PRINT AT WL,WC;CHR$ (CODE A$(A,POS)+128) 538 LET X$=INKEY$ 539 IF X$<>"" THEN GOTO 560 540 PRINT AT WL,WC;A$(A,POS) 550 LET X$=INKEY$ 551 IF X$="" THEN GOTO 537 560 REM 565 IF X$=CHR$ 118 THEN LET X$=" " 567 IF X$=CHR$ 229 THEN LET X$="£" 568 IF CODE X$<64 THEN GOTO 595 569 IF CODE X$>111 AND CODE X$<116 THEN GOTO 660 570 IF X$=CHR$ 116 THEN GOTO 38 571 IF X$=CHR$ 192 THEN GOTO 1700 572 IF X$=CHR$ 217 THEN GOTO 1400 573 IF X$=CHR$ 224 THEN GOTO 1300 574 IF X$=CHR$ 219 THEN GOTO 2000 575 IF X$=CHR$ 117 THEN GOTO 1500 576 IF X$=CHR$ 221 THEN GOTO 7020 577 IF X$=CHR$ 216 THEN GOTO 7000 578 IF X$=CHR$ 225 THEN GOTO 1100 579 IF X$=CHR$ 228 THEN GOTO 2200 580 IF X$=CHR$ 121 THEN GOTO 631 581 IF X$=CHR$ 220 THEN GOTO 1200 586 IF X$=CHR$ 119 THEN GOTO 3000 588 IF X$=CHR$ 218 THEN GOTO 1600 589 IF X$=CHR$ 222 THEN GOTO 1800 590 IF X$=CHR$ 223 THEN GOTO 1900 595 LET A$(A,POS)=X$ 600 PRINT AT WL,WC;A$(A,POS) 610 LET POS=POS+1 620 IF POS>672 OR POS<1 THEN GOTO 3800 630 GOTO 520 631 LET UU=(WL+1)*32-POS 632 LET POS=POS+UU+1 633 PRINT AT WL,WC;A$(A,POS-UU-1) 634 GOTO 620 661 PRINT AT WL,WC;A$(A,POS) 665 LET POS=POS+(X$=CHR$ 115)-(X$=CHR$ 114)+32*(X$=CHR$ 113)-32*(X$=CHR$ 112) 670 GOTO 620 785 IF POS/32=INT (POS/32) THEN GOSUB 8000 1100 LET E$=A$(A,672)+E$ 1120 LET A$(A)=A$(A,1 TO POS-1)+" "+A$(A,POS TO 672) 1130 LET POS=POS+1 1135 IF LEN E$>200 THEN GOTO 9090 1140 GOTO 515 1210 LET E$=A$(A,672-32 TO 672)+E$ 1220 LET A$(A)=A$(A,1 TO POS-1)+" "+A$(A,POS TO 672) 1240 GOTO 515 1300 PRINT AT 21,13;"ENTER TEXT" 1320 INPUT X$ 1330 LET X=LEN X$ 1340 LET E$=A$(A,672-X TO 672)+E$ 1350 LET A$(A)=A$(A,1 TO POS-1)+X$+A$(A,POS TO 672) 1360 IF LEN E$>200 THEN GOTO 9200 1365 PRINT AT 21,13;"% % % % % % % % % % " 1370 GOTO 515 1400 LET A$(A,POS)=" " 1410 PRINT AT WL,WC;A$(A,POS) 1420 GOTO 520 1500 GOSUB 2500 1510 IF A=5 THEN LET A=0 1520 LET A=A+1 1530 GOTO 511 1600 GOSUB 2500 1610 IF A=1 THEN LET A=6 1620 LET A=A-1 1630 GOTO 511 1710 PAUSE 100 1720 IF INKEY$="" THEN GOTO 1720 1740 LET A$(A,POS)=INKEY$ 1750 GOTO 536 1800 PRINT AT 21,13;"AMOUNT?" 1810 INPUT X 1820 LET F$=A$(A,POS-X TO POS-1) 1830 LET A$(A)=A$(A,1 TO POS-X-1)+A$(A,POS TO 672) 1840 PRINT AT 21,13;"% % % % % % % " 1850 GOTO 515 1910 LET A$(A)=A$(A,1 TO POS-1)+F$+A$(A,POS TO 672) 1920 LET F$="" 1930 GOTO 515 2010 GOSUB 2500 2020 GOTO 515 2200 IF E$="" THEN LET A$(A)=A$(A,1 TO POS-2)+A$(A,POS TO 672) 2210 IF E$<>"" THEN LET A$(A)=A$(A,1 TO POS-2)+A$(A,POS TO 672)+E$(1) 2220 IF E$<>"" THEN LET E$=E$(2 TO ) 2230 LET POS=POS-1 2240 GOTO 515 2500 IF E$="" THEN RETURN 2510 LET X=LEN E$ 2520 FOR B=A+1 TO 4 2530 LET G$=A$(B,672-X TO 672) 2540 LET A$(B)=E$+A$(B,1 TO 672-X-1) 2550 LET E$=G$ 2560 NEXT B 2570 LET E$="" 2580 RETURN 3000 LET POS=POS-1 3005 LET A$(A,POS)=" " 3006 PRINT AT WL,WC;A$(A,POS+1) 3010 GOTO 520 3800 LET A=A+1 3810 IF A>5 THEN GOTO 9100 3820 GOTO 511 7000 PRINT AT WL,WC;A$(A,POS) 7005 LET POS=1 7010 GOTO 520 7020 LET E$="" 7030 GOTO 520 8000 LET WC=31 8010 LET WL=WL-1 8020 RETURN 9000 PRINT AT 21,0;"%E%R%R%O%R:NO SUCH PAGE" 9010 FOR B=0 TO 30 9020 NEXT B 9030 PRINT AT 21,0;" " 9040 GOTO 51 9070 PRINT AT 21,13;"END OF PAGE" 9071 FOR B=0 TO 30 9072 NEXT B 9073 GOTO 38 9090 PRINT AT 21,13;"BUFFER FULL" 9091 FOR B=0 TO 30 9092 NEXT B 9093 GOTO 38 9100 PRINT AT 21,13;"ALL FILES USED" 9110 FOR B=0 TO 30 9120 NEXT B 9130 GOTO 38 9200 PRINT AT 21,13;"TOO MUCH% % " 9210 FOR B=0 TO 30 9220 NEXT B 9230 GOTO 38 9240 CLEAR 9250 SAVE "1008%7" 9260 RUN ```