Wordfix

Products: Wordfix
Date: 198x
Type: Program
Platform(s): TS 1000

This program is a full-screen text editor for the ZX81/TS1000, written entirely in BASIC and copyrighted N. Godwin 1982. It maintains a single string variable Z$ as the document buffer, with an integer cursor position A tracking the insertion point within that string. The editor supports cursor movement, character insertion and deletion, word-wrap printing with configurable left and right margins, and file load/save operations using PEEK and POKE to manipulate system variables directly. Key presses are read via a PAUSE/INKEY$ polling loop, and characters are identified by their CHR$ codes; control functions are dispatched through computed GOSUB targets of the form X*30+1000. The program also includes a 704-byte block copy routine that transfers text to and from a fixed RAM area at address 32000.


Program Analysis

Program Structure

The program is organised as a set of loosely coupled subroutines grouped by function, with a main edit loop beginning at line 130. The initial GOTO 130 at line 1 skips past short utility stubs at lines 2–7 that are called by number from elsewhere. The high-level flow is:

  1. Lines 100–169: Initialisation and main insert-mode loop. Z$ is the document buffer; A is the cursor position (0 = before first character).
  2. Lines 200–329: Secondary input loop used in certain modes; dispatches keyword/symbol lookup against a packed string at line 250.
  3. Lines 400–499: Display refresh — clears screen, prints prompt and buffer, then falls through to the keypress routine at 1000.
  4. Lines 500–609: Control-key dispatcher for non-printable key codes.
  5. Lines 1000–1099: Core keypress engine: highlights the character under the cursor by OR-ing 128 into its display code via POKE, then waits for a key with PAUSE 40000 / INKEY$.
  6. Lines 1100–1519: Word-wrap printer with configurable left (L) and right (R) margins.
  7. Lines 1600–1889: File management (load/save with variable-name indirection) and block-selection/cut routines.
  8. Lines 4360–4630: Cursor-movement primitives (page up/down, character left/right, etc.), each terminated with RETURN.
  9. Lines 7540–7899: High-level menu actions: go to load (7540), clear and load 704-byte block from address 32000 (7570–7609), enter block-select mode (7660), go to save (7750), program-name input (7780), and a tape-based block load (7870).
  10. Line 9000: Copyright notice: N. Godwin 1982.

Document Buffer Management

The entire document is held in the single string Z$. The cursor position is the integer A, meaning the insertion point is between characters A and A+1. Three cases are handled explicitly at lines 450–470:

  • A=0: prepend — Z$=X$+Z$
  • 0 < A < LEN Z$: insert — Z$=Z$(1 TO A)+X$+Z$(A+1 TO )
  • A=LEN Z$: append — Z$=Z$+X$

Deletion at line 4570–4589 mirrors this three-way split, removing the character at position A and decrementing A. Because BASIC string slicing allocates new strings on every operation, heavy editing will fragment the string area and may trigger garbage collection pauses.

Computed GOSUB Dispatch

Control characters are dispatched using the idiom GOSUB X*30+1000 (lines 230, 520, 772). The key code X is multiplied by 30 to produce a line-number target. The cursor-movement stubs at lines 4360, 4390, 4420, 4450, 4510, 4540, 4570, 4630 correspond to specific computed targets. For example:

X (key code)X*30+1000Routine
1124360Cursor page-up (A−32)
1134390Cursor page-down (A+32)
1144420Cursor left (A−1)
1154450Cursor right (A+1)
1174510Go to print/margin routine
1184540Set X=0 (newline/clear flag)
1194570Delete character
1214630Set X=12 (form-feed/CLS flag)

Cursor Highlighting via PEEK/POKE

The character under the cursor is highlighted by directly poking the display file. Routine at lines 1000–1050 computes the display-file address of the cursor character using the system variable at 16396/16397 (D-FILE pointer), accounting for the newline byte at the end of each 32-character row with INT((A-1)/32). The character code is read with PEEK Q, converted via GOSUB 1080 (which maps code 192 to 11, i.e. treats the cursor-block graphic as a space), and if it is a printable ASCII character, OR-ed with 128 via POKE Q, X+128 to display it in inverse video as the cursor. This avoids any flicker from re-printing and works directly on the hardware display file.

System Variable Manipulation for File I/O

Rather than using a high-level LOAD/SAVE with a fixed name, the file routines at lines 1670–1682 patch system variables in RAM to redirect the tape filename at runtime. POKE 16559 sets the filename character, POKE 16562/16563 sets associated length or type bytes, allowing the editor to load or save named string variables (e.g. A$ through W$) by writing their letter code directly into the system area before falling through to line 4 (LET Z$="") or line 5 (RETURN).

Word-Wrap Printer

The print routine (lines 1220–1519) implements a simple word-wrap algorithm. Starting from position J in Z$, it attempts to advance 32−R characters (where R is the right margin). If that position is not a space, it walks backwards to find the nearest preceding space and breaks there. Left-margin padding is handled by subroutine 1370, which prints L spaces before each line. The routine checks PEEK 16442 (the display scroll counter) to detect a full screen, then pauses for a keypress (lines 1490–1519) before continuing or scrolling/clearing. A CHR$ 67 (the letter C) embedded in Z$ acts as a hard line-break sentinel (lines 1430, 7690).

Fixed RAM Buffer at Address 32000

Lines 7570–7609 implement a 704-byte (22 rows × 32 columns) snapshot of the display file, stored at the fixed address 32000. Loading reads the buffer back through PEEK and rebuilds Z$; saving copies the D-FILE contents (again compensating for end-of-line newline bytes with INT((J-1)/32)) into the block. This provides a crude fast-save to a fixed RAM location, presumably in a RAM pack, bypassing tape entirely.

Keyword Lookup Table

Line 250 defines a 43-character lookup string X$ containing block-graphic symbols and BASIC keywords. The loop at lines 260–280 searches this string for a character matching the current key code; if found, the corresponding single character at offset J-21 is used as the inserted text. This allows the editor to insert printable representations of ZX81 block graphics and keywords into the document buffer.

Notable Anomalies and Dead Code

  • Lines 1045 and 1820 are REM-commented-out conditionals that would have prevented re-highlighting a character already under the cursor (code 67). They appear to have been disabled during development.
  • Line 1231 is referenced by GOTO 1231 at line 1519 but does not exist as a distinct line; execution will fall to line 1235, which is the correct continuation — a deliberate jump-to-next-line technique.
  • Line 1246 is referenced at line 1449 but does not exist; execution continues at 1250. Similarly a known ZX81 BASIC technique.
  • Lines 4520, 7689, and 7899 are bare RETURN statements that appear unreachable given the preceding GOTOs at lines 4510, 7660, and 7870 respectively. They may be defensive stubs.
  • The SAVE X$ at line 530 saves the filename string itself to tape when key code 226 is received and X$ is non-empty — an unconventional use that saves the variable name as a tape file.

Content

Appears On

Related Products

Effective mini word processing program. Enter unformatted text, process in any way. 16K.

Related Articles

Related Content

Image Gallery

Wordfix

Source Code

   1 GOTO 130
   2 IF C$="" THEN LET X=999
   3 RETURN 
   4 LET Z$=""
   5 RETURN 
   6 LET Z$=Z$+""
   7 RETURN 
 100 LET Z$=""
 120 LET A=0
 130 GOSUB 400
 140 IF X=227 THEN STOP 
 150 IF X>63 AND X<>192 THEN GOTO 500
 160 LET X$=CHR$ X
 165 GOSUB 450
 169 GOTO 130
 200 GOSUB 400
 210 IF X=116 THEN GOTO 130
 220 IF X=119 THEN GOTO 330
 230 IF X=121 OR X=118 THEN GOSUB X*30+1000
 235 GOSUB 1080
 240 IF X>10 AND X<63 THEN GOTO 300
 250 LET X$="'  ' .. : ..'' :.::.:'':.''.##~~,,!!;;@@% "+CHR$ 117+" AND THEN TO "+CHR$ 114+CHR$ 113+CHR$ 112+CHR$ 115+""" OR STEP <=<>>= STOP LPRINT SLOW FAST LLIST **"+CHR$ 118
 260 FOR J=22 TO 42
 270 IF X=CODE X$(J) THEN GOTO 290
 280 NEXT J
 289 GOTO 200
 290 LET X$=X$(J-21)
 299 GOTO 320
 310 LET X=X+128
 320 GOSUB 450
 329 GOTO 200
 330 GOSUB 4570
 339 GOTO 200
 400 CLS 
 410 IF A=0 THEN PRINT ">";
 420 PRINT Z$
 449 GOTO 1000
 450 IF A=0 THEN LET Z$=X$+Z$
 460 IF A>0 AND A<LEN Z$ THEN LET Z$=Z$(1 TO A)+X$+Z$(A+1 TO )
 470 IF A=LEN Z$ THEN LET Z$=Z$+X$
 480 LET A=A+1
 499 RETURN 
 500 IF X=116 THEN GOTO 200
 505 IF X=227 THEN GOTO 140
 510 IF X=228 THEN GOTO 100
 520 GOSUB X*30+1000
 530 IF X=226 AND X$>"" THEN SAVE X$
 560 IF X=117 THEN GOTO 600
 570 IF X=0 OR X=12 OR X=67 THEN GOTO 160
 580 IF A>LEN Z$ THEN LET A=LEN Z$
 590 IF A<1 THEN GOTO 120
 599 GOTO 130
 600 GOSUB 1060
 608 IF X=118 OR X=121 THEN GOTO 130
 609 GOTO 500
 1000 GOSUB 1090
 1010 LET Q=Q+A+INT ((A-1)/32)
 1020 IF A=0 THEN LET Q=Q+2
 1030 LET X=PEEK Q
 1040 GOSUB 1080
 1045 REM IF A>0 THEN IF CODE Z$(A)=67 THEN GOTO 1051
 1050 IF X=0 OR X>10 AND X<64 THEN POKE Q,X+128
 1060 PAUSE 40000
 1061 POKE 16437,255
 1062 LET X=CODE INKEY$
 1069 RETURN 
 1080 IF X=192 THEN LET X=11
 1089 RETURN 
 1090 LET Q=PEEK 16396+256*PEEK 16397
 1099 RETURN 
 1100 PRINT AT 20,0;
 1110 FOR J=28 TO 59
 1120 PRINT CHR$ J;
 1130 NEXT J
 1140 PRINT "ENTER L.H. MARGIN"
 1150 GOSUB 1060
 1160 IF X<28 OR X>59 THEN GOTO 1180
 1170 LET L=X-28
 1180 PRINT AT 21,6;"R"
 1190 GOSUB 1060
 1200 IF X<28 OR X>59 THEN GOTO 1220
 1210 LET R=60-X
 1220 CLS 
 1230 FOR J=1 TO LEN Z$
 1235 IF PEEK 16442<3 THEN GOTO 1490
 1240 GOSUB 1370
 1245 GOTO 1420
 1250 LET K=J
 1260 LET J=J+32-R
 1270 IF J<=LEN Z$ THEN GOTO 1290
 1280 PRINT Z$(K TO )
 1289 GOTO 1360
 1290 IF Z$(J)>" " THEN GOTO 1320
 1300 PRINT Z$(K TO J-1)
 1310 GOTO 1350
 1320 LET J=J-1
 1330 IF Z$(J)=" " THEN GOTO 1300
 1340 GOTO 1320
 1350 NEXT J
 1365 LET X=117
 1369 RETURN 
 1370 IF L=0 THEN RETURN 
 1380 FOR L=1 TO L
 1390 PRINT " ";
 1400 NEXT L
 1410 LET L=L-1
 1419 RETURN 
 1420 FOR K=J TO J+32-R
 1425 IF K>LEN Z$ THEN GOTO 1449
 1430 IF Z$(K)=CHR$ 67 THEN GOTO 1450
 1440 NEXT K
 1449 GOTO 1246
 1450 IF K=J THEN GOTO 1480
 1460 PRINT Z$(J TO K-1);
 1470 LET J=K
 1479 GOTO 1240
 1480 PRINT 
 1489 GOTO 1350
 1490 GOSUB 1060
 1500 IF X<>121 AND X<>118 THEN RETURN 
 1510 IF X=118 THEN SCROLL 
 1511 IF X=121 THEN CLS 
 1519 GOTO 1231
 1520 PRINT AT 21,0;"FILE REF (A TO W)"
 1529 GOTO 1060
 1600 GOSUB 1520
 1610 IF X<38 OR X>59 THEN RETURN 
 1620 POKE 16529,X
 1630 GOSUB 2
 1640 IF X=999 THEN GOTO 1670
 1650 PRINT AT 21,0;"WARNING - ";CHR$ X;"$ IN USE"
 1660 GOSUB 1060
 1669 IF X<>PEEK 16529 THEN GOTO 1610
 1670 POKE 16559,PEEK 16529
 1671 POKE 16562,63
 1672 POKE 16563,13
 1679 GOTO 4
 1680 POKE 16559,61
 1681 POKE 16562,X
 1682 POKE 16563,13
 1689 RETURN 
 1700 GOSUB 1520
 1710 IF X<38 OR X>59 THEN RETURN 
 1720 GOSUB 1680
 1750 GOSUB 4
 1759 GOTO 450
 1760 LET J=A
 1770 GOSUB 1060
 1772 IF X>111 AND X<116 THEN GOSUB X*30+1000
 1773 IF A>LEN Z$ THEN LET A=LEN Z$
 1774 IF A<J THEN LET A=J
 1775 IF X=119 THEN GOTO 1840
 1776 IF X<112 OR X>119 THEN GOTO 1880
 1778 GOSUB 1090
 1780 LET Q=Q+A+INT ((A-1)/32)
 1790 IF A=0 THEN LET Q=Q+2
 1800 LET X=PEEK Q
 1810 GOSUB 1080
 1820 REM IF A>0 THEN IF CODE Z$(A)=67 THEN GOTO 1770
 1830 IF X=0 OR X>10 AND X<64 THEN POKE Q,X+128
 1839 GOTO 1770
 1840 IF J<2 THEN LET Z$=Z$(A+1 TO )
 1850 IF J>1 AND A<LEN Z$ THEN LET Z$=Z$(1 TO J-1)+Z$(A+1 TO )
 1860 IF J>1 AND A>=LEN Z$ THEN LET Z$=Z$(1 TO J-1)
 1880 LET A=J
 1889 RETURN 
 4360 LET A=A-32
 4369 RETURN 
 4390 IF A=0 AND Z$>"" THEN LET A=1
 4400 LET A=A+32
 4409 RETURN 
 4420 LET A=A-1
 4429 RETURN 
 4450 LET A=A+1
 4459 RETURN 
 4510 GOTO 1100
 4520 RETURN 
 4540 LET X=0
 4549 RETURN 
 4570 IF A=LEN Z$ THEN GOTO 4580
 4572 IF A<2 THEN LET Z$=Z$(2 TO )
 4574 IF A>1 THEN LET Z$=Z$(1 TO A-1)+Z$(A+1 TO )
 4579 GOTO 4581
 4580 LET Z$=Z$(1 TO LEN Z$-1)
 4582 LET A=A-1
 4589 RETURN 
 4630 LET X=12
 4639 RETURN 
 7540 GOTO 1700
 7570 LET Z$=""
 7571 FOR J=1 TO 704
 7573 LET Z$=Z$+CHR$ PEEK (32000+J)
 7574 NEXT J
 7580 FOR J=704 TO 1 STEP -1
 7582 IF Z$(J)>" " THEN RETURN 
 7584 LET Z$=Z$(1 TO J-1)
 7586 NEXT J
 7600 GOSUB 1090
 7602 FOR J=1 TO 704
 7604 POKE 32000+J,PEEK (Q+J+INT ((J-1)/32))
 7606 NEXT J
 7609 RETURN 
 7660 GOTO 1760
 7689 RETURN 
 7690 LET X=67
 7699 RETURN 
 7750 GOTO 1600
 7780 PRINT AT 21,0;"ENTER PROGRAM NAME"
 7790 INPUT X$
 7799 RETURN 
 7870 GOSUB 1520
 7872 POKE 16559,X
 7873 POKE 16562,11
 7874 POKE 16563,11
 7879 GOTO 4
 7899 RETURN 
 9000 REM COPYRIGHT N.GODWIN 1982

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top