--- title: "Linear Search" id: 71341 type: "computer_media" slug: "linear-search" url: "http://localhost/computer_media/linear-search/" markdown_url: "http://localhost/computer_media/linear-search.md" published_at: "2026-09-02T00:17:12+00:00" modified_at: "2026-09-02T00:17:21+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/09/Linear-Search.png" excerpt: "A RAM-based file manager and keyword search tool that pokes records directly into memory and calls machine code to hunt through them instantly." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "1983" slug: "year-1983" taxonomy: "post_tag" url: "http://localhost/tag/year-1983/" - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Thomas B. Woods" slug: "thomas-b-woods" taxonomy: "indiv" url: "http://localhost/indiv/thomas-b-woods/" genre: - name: "Database" slug: "database" taxonomy: "genre" url: "http://localhost/type/database/" media_type: "Program" programmers: - name: "Thomas B. Woods" slug: "thomas-b-woods" taxonomy: "indiv" url: "http://localhost/indiv/thomas-b-woods/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Linear%20Search%20(1983)(Woods%2C%20Thomas)(TS2068)(US)(Program).zip" mediadate: "1983" images: - url: "http://localhost/wp-content/uploads/2026/09/Linear-Search.png" article_media: - id: 24522 title: "The Linear Search" type: "article" url: "http://localhost/article/the-linear-search/" related_products: - id: 35078 title: "Linear Search" type: "product" url: "http://localhost/product/linear-search/" media_type_tags: "Database" --- # Linear Search 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 `p` is 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 separate `IF` statement. - Lines 227–228 implement a key-wait idiom: `y$` is set by `INKEY$`, then a second `INKEY$` 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. ## 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 ```