Linear Search is a file-management and search utility that stores records as raw character data in a fixed memory region starting at address 29658, using POKE and PEEK operations to read and write entries directly to RAM. The program embeds a machine code routine called via USR 29552 that performs the actual string search, with the search target written into memory at address 29513 and a result pointer passed back through PEEK 23748/23749. Records are delimited by quote characters (ASCII 34) and asterisks (ASCII 42), which the BASIC display loop interprets as field and record separators respectively. Data is persisted across sessions using a two-part SAVE: the BASIC program itself is saved with an auto-run line, and the raw data block starting at 29552 is saved as a separate CODE file with a length calculated from the current record pointer p.
Program Structure
The program is organized into four functional blocks. Lines 5–35 handle startup, menu display, and routing. Lines 45–250 implement the search and results-display loop. Lines 500–660 implement the record-entry (“Add/File”) routine. Lines 9000–9999 handle saving and reloading the data store.
A persistent variable p (initialized at line 5) acts as a byte-offset pointer into the raw data area beginning at address 29658. Every added record advances p by the number of characters stored, so p always reflects how many bytes of data have been written.
Machine Code Integration
The heart of the search engine is a machine code routine loaded separately at address 29552. Before calling it, the BASIC program prepares its input in memory:
- The search string (with a sentinel
\::█character appended) is POKEd byte-by-byte into addresses 29513 onward (lines 45–70). - The current data-end pointer
pis stored little-endian at addresses 29606–29607 (lines 80–90). - Addresses 29604–29605 are set to
218, 115, forming the little-endian 16-bit value 29658 — the start of the data block (lines 100–110).
The routine is invoked with LET b= USR 29552 at line 122. The result pointer for the found match is read back from the system variables at addresses 23748–23749 (line 130), giving a 16-bit address into the data block where the match was found.
Record Format and Display Logic
Records are stored as flat byte sequences in memory with two delimiter conventions:
- ASCII 34 (
") separates fields within a record. - ASCII 42 (
*) marks the end of a record.
The display loop (lines 135–210) walks from the match address x through x+p, printing each non-quote byte. When it encounters a quote or asterisk at PEEK (y+1), it either issues a newline (line 200) or jumps to line 220 (end-of-record, via GO TO 200+(20*(PEEK (y+1)=42))) — a compact computed GO TO that selects between line 200 and line 220 using Boolean arithmetic.
Add/File Routine
Lines 500–660 collect exactly four lines of input from the user. The first field is prefixed with * (an asterisk and space) to mark the record start; subsequent fields are concatenated with leading quote characters into the string a$. After confirmation, the string is written byte-by-byte into the data area via POKE (lines 600–630), p is incremented for each byte, and a terminating ASCII 42 (*) is appended at line 635. A rudimentary overflow check at line 625 flashes “OUT OF MEMORY” if p exceeds 35600.
Search Navigation
After displaying a match, lines 220–250 prompt the user for three actions:
- ENTER — re-enters the machine code search from the current position to find the next match (line 231 → line 120, re-calling USR).
R— jumps to line 80 to reissue the USR call with an adjusted pointer, intended to step backward through results.N— returns to the main menu at line 14 (a non-existent line, causing a clean fall-through to line 28).
Line 240 contains an apparent debugging remnant: PRINT "line 240b=";b prints the return value of the machine code call unconditionally, followed by a conditional that is never true in normal operation (IF B AND Y$=""). This was likely left in during development and not removed before publication.
Persistence
Line 9000 saves the BASIC program, then saves the combined machine code and data block as a separate CODE file. The length of the CODE save is computed as 107+p, covering the 107-byte machine code routine at 29552 plus all data bytes accumulated at 29658 onward. On next run, line 9999 reloads the CODE file back to its original address and jumps to line 14 to restart.
Notable Idioms and Anomalies
POKE 23658,8(line 30) sets the TS2068 system variable to enable lowercase input.- Line 33 routes an empty INPUT directly to
GO TO 20, a non-existent line, which silently falls through to line 27 — a deliberate technique to skip re-displaying the header REM blocks. - The
GO TO 200+(20*(PEEK (y+1)=42))expression (line 150) is a concise way to branch to either line 200 or line 220 based on a Boolean result, avoiding a separateIFstatement. - Lines 227–228 implement a key-wait idiom:
y$is set byINKEY$, then a secondINKEY$loop waits for key release before proceeding, preventing key repeat from triggering multiple actions. - The sentinel character appended to the search string at line 45 (
\::█, a block graphic) acts as an end-of-string marker for the machine code routine, since it is unlikely to appear in user data.
Content
Source Code
5 LET p=0
10 REM LINEAR SEARCH
11 REM \''\''\''\''\''\''\''\''\''\''\''\''\''
12 REM A program from the Nov/Dec 1983 issue of SYNC magazine
13 REM
14 REM Adapted for the TIMEX 2068
15 REM
16 REM by G.F.Chambers
17 REM in 1984
18 REM
27 REM
28 CLS
30 POKE 23658,8
31 PRINT " TIMEX File/Finder"''" Enter a SEARCH STRING, or"''" type ""A"" to add a new file"''" or ""S"" to save this program"
32 INPUT x$
33 IF x$="" THEN GO TO 20
34 IF x$="A" THEN GO TO 500
35 IF x$="S" THEN GO TO 9000
45 LET x$=x$+"\::"
50 FOR x=1 TO LEN x$
60 POKE 29513+x, CODE x$(x)
70 NEXT x
80 POKE 29606,p-256* INT (p/256)
90 POKE 29607, INT (p/256)
100 POKE 29604,218
110 POKE 29605,115
120 CLS
122 LET b= USR 29552
125 PRINT x$( TO LEN x$-1); TAB 0;"File/Search"
130 LET x= PEEK 23748+256* PEEK 23749
133 PRINT AT 7,0;
135 FOR y=x TO x+p
140 IF PEEK y <>34 THEN PRINT CHR$ PEEK y;
150 IF PEEK (y+1)=34 OR PEEK (y+1)=42 THEN GO TO 200+(20*(PEEK (y+1)=42))
170 NEXT y
180 GO TO 220
200 PRINT
210 NEXT y
220 PRINT AT 16,0;"Press ENTER to continue search,",,"""R"" to return to previous files,",,"or ""N"" to begin new file search."
225 LET y$=""
227 LET y$= INKEY$
228 IF INKEY$="" THEN GO TO 228
231 IF CODE y$=13 THEN GO TO 120
232 IF y$ <>"N" AND y$ <>"R" THEN GO TO 225
235 IF y$="R" THEN GO TO 80
240 PRINT "line 240b=";b:IF B AND Y$="" THEN GO TO 120
250 GO TO 14
500 PRINT AT 8,5;"Add/File"
510 FOR x=1 TO 4
520 PRINT AT 8,14;"Input line ";x
530 INPUT x$
540 IF x=1 THEN LET a$="* "+x$
550 IF x>1 THEN LET a$=a$+""""+x$
560 PRINT AT 9+x,0;x$
570 NEXT x
580 PRINT AT 17,0;"Press ENTER to log this listing,",,"or ""C"" to correct it."
585 INPUT x$
590 CLS
595 IF x$="C" THEN GO TO 500
600 FOR x=1 TO LEN a$
610 POKE 29658+p, CODE a$(x)
620 LET p=p+1
625 IF p>35600 THEN PRINT AT 10,8; FLASH 1;"OUT OF MEMORY"
630 NEXT x
635 POKE 29658+p,42
660 GO TO 14
9000 SAVE "Search" LINE 9999:BEEP .4,15:SAVE "search C"CODE 29552,(107+p):STOP
9999 PRINT AT 10,3;"Now loading 'search' data.":LOAD "search C"CODE :GO TO 14
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
