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:
- Lines 7–11: Variable initialization (
C,A$,C$,E$,F$). - Lines 19–28: Filename entry, reading exactly 10 keypresses with INKEY$ polling.
- Lines 29–38: Conditional SAVE (skipped when
C=1meaning a file-clear is in progress). - Lines 39–74: Main menu display and option dispatch.
- Lines 100–590: Menu handlers — save (100), print (200), clear page (300), clear file (400), write page (500+).
- Lines 595–670: Main editing loop — character input, cursor positioning, key dispatch.
- Lines 1100–2580: Editing operations (insert, delete, cut, paste, page navigation, etc.).
- Lines 3000–3820: Backspace and page overflow.
- Lines 7000–8020: Home cursor and clear-buffer subroutines.
- 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 660at line 569; however, the label dispatched to is660, 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 8000there duplicates the boundary check already performed at line 535. - Lines 2010–2020 (
GOSUB 2500thenGOTO 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=1and 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.
Content
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
\n1100 LET E$=A$(A,672)+E$
\n1120 LET A$(A)=A$(A,1 TO POS-1)+" "+A$(A,POS TO 672)
\n1130 LET POS=POS+1
\n1135 IF LEN E$>200 THEN GOTO 9090
\n1140 GOTO 515
\n1210 LET E$=A$(A,672-32 TO 672)+E$
\n1220 LET A$(A)=A$(A,1 TO POS-1)+" "+A$(A,POS TO 672)
\n1240 GOTO 515
\n1300 PRINT AT 21,13;"ENTER TEXT"
\n1320 INPUT X$
\n1330 LET X=LEN X$
\n1340 LET E$=A$(A,672-X TO 672)+E$
\n1350 LET A$(A)=A$(A,1 TO POS-1)+X$+A$(A,POS TO 672)
\n1360 IF LEN E$>200 THEN GOTO 9200
\n1365 PRINT AT 21,13;"% % % % % % % % % % "
\n1370 GOTO 515
\n1400 LET A$(A,POS)=" "
\n1410 PRINT AT WL,WC;A$(A,POS)
\n1420 GOTO 520
\n1500 GOSUB 2500
\n1510 IF A=5 THEN LET A=0
\n1520 LET A=A+1
\n1530 GOTO 511
\n1600 GOSUB 2500
\n1610 IF A=1 THEN LET A=6
\n1620 LET A=A-1
\n1630 GOTO 511
\n1710 PAUSE 100
\n1720 IF INKEY$="" THEN GOTO 1720
\n1740 LET A$(A,POS)=INKEY$
\n1750 GOTO 536
\n1800 PRINT AT 21,13;"AMOUNT?"
\n1810 INPUT X
\n1820 LET F$=A$(A,POS-X TO POS-1)
\n1830 LET A$(A)=A$(A,1 TO POS-X-1)+A$(A,POS TO 672)
\n1840 PRINT AT 21,13;"% % % % % % % "
\n1850 GOTO 515
\n1910 LET A$(A)=A$(A,1 TO POS-1)+F$+A$(A,POS TO 672)
\n1920 LET F$=""
\n1930 GOTO 515
\n2010 GOSUB 2500
\n2020 GOTO 515
\n2200 IF E$="" THEN LET A$(A)=A$(A,1 TO POS-2)+A$(A,POS TO 672)
\n2210 IF E$<>"" THEN LET A$(A)=A$(A,1 TO POS-2)+A$(A,POS TO 672)+E$(1)
\n2220 IF E$<>"" THEN LET E$=E$(2 TO )
\n2230 LET POS=POS-1
\n2240 GOTO 515
\n2500 IF E$="" THEN RETURN
\n2510 LET X=LEN E$
\n2520 FOR B=A+1 TO 4
\n2530 LET G$=A$(B,672-X TO 672)
\n2540 LET A$(B)=E$+A$(B,1 TO 672-X-1)
\n2550 LET E$=G$
\n2560 NEXT B
\n2570 LET E$=""
\n2580 RETURN
\n3000 LET POS=POS-1
\n3005 LET A$(A,POS)=" "
\n3006 PRINT AT WL,WC;A$(A,POS+1)
\n3010 GOTO 520
\n3800 LET A=A+1
\n3810 IF A>5 THEN GOTO 9100
\n3820 GOTO 511
\n7000 PRINT AT WL,WC;A$(A,POS)
\n7005 LET POS=1
\n7010 GOTO 520
\n7020 LET E$=""
\n7030 GOTO 520
\n8000 LET WC=31
\n8010 LET WL=WL-1
\n8020 RETURN
\n9000 PRINT AT 21,0;"%E%R%R%O%R:NO SUCH PAGE"
\n9010 FOR B=0 TO 30
\n9020 NEXT B
\n9030 PRINT AT 21,0;" "
\n9040 GOTO 51
\n9070 PRINT AT 21,13;"END OF PAGE"
\n9071 FOR B=0 TO 30
\n9072 NEXT B
\n9073 GOTO 38
\n9090 PRINT AT 21,13;"BUFFER FULL"
\n9091 FOR B=0 TO 30
\n9092 NEXT B
\n9093 GOTO 38
\n9100 PRINT AT 21,13;"ALL FILES USED"
\n9110 FOR B=0 TO 30
\n9120 NEXT B
\n9130 GOTO 38
\n9200 PRINT AT 21,13;"TOO MUCH% % "
\n9210 FOR B=0 TO 30
\n9220 NEXT B
\n9230 GOTO 38
\n9240 CLEAR
\n9250 SAVE "1008%7"
\n9260 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
