Tomorrow Lies in Ambush!

Developer(s): Emmett Jenkins
Date: 1984
Type: Program
Platform(s): TS 2068

This program is a 32-column word processor capable of storing up to 600 lines of text in a string array, with options to enter, edit, print (to printer via LPRINT), save, load, and display text on screen. It loads a font (“BOLD.COD”) and patches the system variable at address 23607 to redirect printer output through the bold character generator; POKEing 23607 back to 60 restores normal printing. The program uses a subroutine dispatch pattern with a variable G (initialized to 9000) that increments by 2 each iteration to step through labeled LET/RETURN pairs at lines 9000–9004, providing a simple string-lookup mechanism for color attribute names. Text storage uses a DIM T$(600,32) array, and end-of-text is detected by searching for the sentinel string “END” (padded to 32 characters).

The word processor was authored by Emmett Jenkins in April 1984 and merged with the bold print routine from the LIST 3.5 library tape.

The name of the word processor comes from a collection of short stories with the same title.


Program Analysis

Program Structure

The program is organized into clearly separated functional blocks, each anchored at a round-line-number boundary. Control flows through a central menu at line 200 and dispatches to numbered routines:

Line RangePurpose
10–40Startup: load machine code, patch printer vector, title pause
101–107Title screen (“TOMORROW LIES IN AMBUSH!”) and array initialization
108–199Color setup loop using the G-dispatch subroutine
200–370Main menu with 8 options
700–750Option 7: display stored text on screen
1000–1051Option 1: text input routine
2000–2120Option 2: printer output via LPRINT
3000–3040Option 3: save text array to tape
4000–4040Option 4: load text array from tape
5000–5240Option 5: line-by-line editor
6000–6010Option 6: STOP
8000–8040Search routine — finds end-of-text sentinel, sets X
9000–9005G-dispatch table for color attribute name strings
9100–9160Input instructions subroutine
9990–9998STOP and SAVE commands

Machine Code Usage

Lines 20–30 handle the machine code component. CLEAR 56575 protects RAM from address 56576 upward, and LOAD "BOLD.COD" CODE 56576,768 places a 768-byte routine there. POKE 23607,220 writes to the system variable CHARS (the character set base pointer, stored as the high byte), redirecting the ROM’s character lookup to the custom bold font at 56576. Restoring the value to 60 (i.e., high byte pointing to the ROM font at 15360) reverts to normal characters. This is an elegant, non-destructive way to substitute an entire font for both screen and printer output without patching any ROM vectors directly.

Text Storage and Sentinel Detection

Text is stored in DIM T$(600,32), a fixed-width string array of 600 rows each 32 characters wide. Since the Spectrum pads fixed-length strings with spaces, the end-of-text sentinel comparison must match the full padded string: T$(N)="END " (31 trailing spaces). This same pattern appears in the input routine (line 1020), edit routine (line 5040), and search routine (line 8020). The search subroutine at line 8000 sets the global variable X to the index of the sentinel line, which is then used as the loop bound in print and edit loops.

G-Dispatch Subroutine Pattern

Lines 9000–9005 implement a rudimentary computed-GOSUB table. The variable G is initialized to 9000 at line 105 and incremented by 2 after each call (LET G=G+2 at line 140), so the three iterations of the color-setup loop call lines 9000, 9002, and 9004 in sequence, each setting A$ to "BORDER", "PAPER", and "INK" respectively. This drives the prompt at line 130: PRINT AT 10,3;"INPUT:",A$;AT 12,7;"COLOR", asking the user to enter a numeric value for each attribute in turn.

Key BASIC Idioms

  • Keypress debounce pattern: Lines 280–290 use the standard idiom of waiting for INKEY$ to be empty then non-empty before reading a key, preventing held-key false triggers.
  • POKE 23692,255: Used at line 5050 to reset the FRAMES-based scroll counter, suppressing the “scroll?” prompt during the edit display loop.
  • PAUSE 0 at line 9150: Halts until any key is pressed, used after instructions screen.
  • Line 366 layout: CLS : IF INKEY$="8" THEN GO TO 1010 — the CLS before the INKEY$ test means a brief flash of a cleared screen occurs even for other keypresses, a minor cosmetic side effect of the structure.

Bugs and Anomalies

  • Lines 5125 and 700 unreachable/missing: Lines 5170 and 5180 branch to line 5125, which does not exist in the listing; this will cause a “Line does not exist” error if the user presses 3 or 4 in the edit menu. Line 705 exists but line 700 is the target of line 365 — the actual code begins at 705, so branching to 700 simply falls through to 705, which works correctly.
  • Line 5070 logic: IF LEN INKEY$=0 THEN NEXT F: PRINT LEN INKEY$: GO TO 205 — the NEXT F is executed inside the IF branch, then falls through to PRINT LEN INKEY$ (which will always print 0 here) and jumps to the menu. The intent appears to be to advance to the next line silently, but the extra PRINT and GO TO 205 make this a premature exit from the edit loop rather than a quiet continuation.
  • Line 1020 sentinel match: The string "END " has 31 trailing spaces but the array width is 32, so the padded stored string would be 32 characters. The comparison string is one character short and will never match, meaning the user cannot exit text input by typing “END”. The same issue affects line 5040. The search routine at line 8020 shares the same mismatch.
  • Line 9160: RETURN : GO TO 1010 — the GO TO 1010 after RETURN is unreachable dead code.
  • Line 8999: GO TO 9998 redirects to the SAVE command line, which would execute a tape save if ever reached from normal flow — this appears to be a utility line for the author’s own use rather than program logic.

Save / Persistence

Line 9997 saves the BASIC program itself as "BOLDTOMORO" with LINE 1 for auto-run. Line 9998 saves the machine code block from address 56576 for 768 bytes as "BOLD.COD". Text data is saved and loaded via SAVE/LOAD S$ DATA T$() at lines 3030 and 4030, using the array save/load facility to persist the full 600×32 text buffer to tape.

Content

Related Products

Related Articles

Related Content

Image Gallery

Tomorrow Lies in Ambush!

Source Code

   10 REM bold print
   20 CLEAR 56575
   30 LOAD "BOLD.COD"CODE 56576,768: POKE 23607,220
   35 PRINT "Bold print now loaded"
   37 PRINT "Please use this program for all listings you send to LIST"
   38 PRINT "To return to regular printing,  just POKE 23607,60"
   39 PRINT "To get these heavy characters,  Poke 23607,220"
   40 PAUSE 390: CLS 
  101 REM "tomorrow" by EMMETT JENKINS 04/15/84 merged with "bold" from LIST 3.5 library tape--renamed "BOLDTOMORO"
  102 PRINT AT 1,5; FLASH 1;"TOMORROW LIES IN AMBUSH!"; FLASH 0;AT 4,5;"WORD PROCESSOR",AT 6,5;"CREATED FOR:",AT 8,5; FLASH 1;"L.I.S.T!": FLASH 0
  103 FLASH 1: PRINT AT 12,5;"BY EMMETT JENKINS": FLASH 0: PRINT AT 15,5;"PRESS ANY KEY TO START!",AT 18,5;"32 CHARACTERS",AT 20,5;"578 LINES DEEP"
  104 PAUSE 4000
  105 LET X=0: LET B=0: LET G=9000: DIM A (3)
  106 DIM T$(600,32)
  107 CLS 
  108 FOR L=0 TO 32
  109 BRIGHT 1
  110 FOR F=1 TO 3
  113 CLS 
  120 GO SUB G
  130 PRINT AT 10,3;"INPUT:",A$;AT 12,7;"COLOR"
  140 LET G=G+2
  150 INPUT A(F)
  155 CLS 
  160 NEXT F
  170 BORDER A(1): PAPER A(2): INK A(3) 
  180 CLS 
  199 CLS 
  200 REM OPTIONS
  205 CLS : PRINT AT 1,5; FLASH 1;"PRESS NUMBER OF OPTION": FLASH 0
  210 PRINT AT 5,0;"OPTION 1";TAB 10;"ENTER TEXT"     
  215 PRINT 
  220 PRINT "OPTION 2";TAB 10;"PRINTOUT TEXT"
  225 PRINT 
  230 PRINT "OPTION 3";TAB 10;"SAVE TEXT"
  235 PRINT 
  240 PRINT "OPTION 4";TAB 10;"LOAD TEXT"
  245 PRINT 
  250 PRINT "OPTION 5";TAB 10;"EDIT TEXT"
  255 PRINT 
  270 PRINT "OPTION 6";TAB 10;"END"
  275 PRINT AT 17,0;"OPTION 7";TAB 10;"PRINT TEXT ON SCREEN"
  276 PRINT AT 19,0;"OPTION 8";TAB 10;"ADD TEXT"
  277 PRINT AT 21,0; FLASH 1;"TO ADD TO TEXT; PRESS '8' TWICE!"
  280 IF INKEY$<>"" THEN GO TO 280
  290 IF INKEY$="" THEN GO TO 290
  300 IF INKEY$="1" THEN GO TO 1000
  310 IF INKEY$="2" THEN GO TO 2000
  330 IF INKEY$="3" THEN GO TO 3000
  340 IF INKEY$="4" THEN GO TO 4000
  350 IF INKEY$="5" THEN GO TO 5000
  360 IF INKEY$="6" THEN GO TO 6000
  365 IF INKEY$="7" THEN GO TO 700
  366 CLS : IF INKEY$="8" THEN GO TO 1010
  370 GO TO 290
  705 CLS 
  710 GO SUB 8000
  720 FOR F=1 TO X
  730 PRINT T$(F)
  740 NEXT F
  745 PRINT AT 21,3; FLASH 1;"PRESS ANY KEY TO CONTINUE"; FLASH 0: PAUSE 0
  750 GO TO 200
 1000 REM INPUT ROUTINE
 1001 CLS 
 1002 GO SUB 9100
 1005 LET C=1
 1008 IF T$(C)=CHR$ 32 THEN BEEP .03,6
 1009 IF C=578 THEN PRINT AT 10,0; FLASH 1;"THAT WAS YOUR LAST LINE"; FLASH 0; FLASH 1;AT 13,0;"PRESS ANY KEY TO CONTINUE"; FLASH 0: PAUSE 500: GO TO 1051
 1010 INPUT T$(C):
 1020 IF T$(C)="END                             " OR T$(C)="end                             " THEN GO TO 205:                 
 1030 PRINT T$(C):
 1040 LET C=C+1
 1050 GO TO 1009
 1051 PRINT AT 15,3; FLASH 1;"NOW TYPE END"; FLASH 0: GO TO 1010
 2000 REM OUTPUT ROUTINE
 2050 GO SUB 8000
 2100 FOR F=1 TO X
 2110 LPRINT T$(F)
 2115 NEXT F
 2120 GO TO 200
 3000 REM SAVE ROUTINE
 3010 CLS : PRINT AT 10,0; FLASH 1;"INPUT NAME OF TEXT"; FLASH 0
 3020 INPUT S$
 3030 SAVE S$ DATA T$()
 3040 GO TO 200
 4000 REM LOAD TEXT ROUTINE
 4010 CLS : PRINT AT 10,0; FLASH 1;"INPUT NAME OF TEXT"; FLASH 0
 4020 INPUT S$
 4025 PRINT FLASH 1;"START TAPE"; FLASH 0
 4030 LOAD S$ DATA T$()
 4035 PRINT AT 16,10; FLASH 1;"STOP TAPE"; FLASH 0: PAUSE 500
 4040 GO TO 200
 5000 REM EDIT ROUTINE
 5001 CLS 
 5010 GO SUB 8000
 5020 PRINT FLASH 1;"TO EDIT LAST LINE PRESS '0'"; FLASH 0
 5025 PRINT 
 5030 FOR F=1 TO X
 5040 IF T$(F)="END                             " OR T$(F)="end                             " THEN GO TO 205
 5050 PRINT T$(F): POKE 23692,255
 5060 PAUSE 300
 5070 IF LEN INKEY$=0 THEN NEXT F: PRINT LEN INKEY$: GO TO 205
 5080 CLS : PRINT FLASH 1;"PRESS APPROPRIATE KEY"; FLASH 0
 5090 PRINT : PRINT "1 TO CONTINUE"
 5100 PRINT : PRINT "2 TO EDIT THIS LINE"
 5110 PRINT : PRINT "3 UP ONE LINE"
 5120 PRINT : PRINT "4 DOWN ONE LINE"
 5130 IF INKEY$<>"" THEN GO TO 5130
 5140 IF INKEY$="" THEN GO TO 5140
 5150 IF INKEY$="1" THEN CLS : NEXT F
 5160 IF INKEY$="2" THEN GO TO 5200
 5170 IF INKEY$="3" THEN LET F=F-1: GO TO 5125
 5180 IF INKEY$="4" THEN LET F=F+1: GO TO 5125
 5190 GO TO 5130
 5200 CLS : PRINT AT 5,0; FLASH 1;"RE-WRITE THIS LINE CORRECTLY!"; FLASH 0
 5210 PRINT AT 16,0;T$(F)
 5220 INPUT T$(F)
 5225 CLS : PRINT FLASH 1;"TO EDIT LAST LINE PRESS '0'"; FLASH 0: PRINT : PRINT T$(F)
 5230 NEXT F
 5240 GO TO 200
 6000 REM END ROUTINE
 6010 STOP 
 8000 REM SEARCH ROUTINE
 8010 FOR N=1 TO 600
 8020 IF T$(N)="END                             " OR T$(N)="end                             " THEN LET X=N: RETURN 
 8030 NEXT N
 8040 RETURN 
 8999 GO TO 9998
 9000 LET A$="BORDER"
 9001 RETURN 
 9002 LET A$="PAPER"
 9003 RETURN 
 9004 LET A$="INK"
 9005 RETURN 
 9100 PRINT AT 0,5;"THIS WORD PROCESSOR",AT 2,3;"WORKS JUST LIKE A TYPEWRITER",AT 4,5;"AT THE END OF EACH LINE",AT 6,5;"YOU PRESS THE ENTER KEY",AT 8,0;"YOU MAY ONLY ENTER 32 CHARACTERS",AT 12,2; INVERSE 1;"TO END TEXT INPUT,TYPE 'END'"; INVERSE 0
 9110 PRINT : PRINT : PRINT : PRINT 
 9130 PRINT AT 17,3; FLASH 1;"PRESS ANY KEY TO CONTINUE!": FLASH 0
 9140 PRINT 
 9150 PAUSE 0
 9155 CLS 
 9160 RETURN : GO TO 1010
 9990 STOP 
 9997 SAVE "BOLDTOMORO" LINE 1
 9998 SAVE "BOLD.COD"CODE 56576,768

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

Scroll to Top