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
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
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
