The Linear Search

See all articles from SYNC v3 n6

Do you want to store and retrieve information with your computer? This program uses a machine language search routine that is so fast you can blitz through a full 13000 bytes of files to find the one you want in less than a second!

The program uses Basic to create files and PRINT found ones. It is only the search which runs in assembly language. So even if you find Z80 source code a complete mystery, you can program “around” the machine language search to create your own data management program with super fast access to any file stored in memory.

The Concept

Linear data storage is a simple and straightforward method of holding information in your computer. Simply stated, a large block of memory is set aside for files. Data that you want to input is placed in that memory block one character at a time, one after another. When you need access to a particular file, you input a search word which can be found in the file you want. Then you scan the block of files until you find a match to the word you input. When a match is found, you PRINT the file.

The program creates a very large REM line for the data storage block; 13000 spaces to be exact. Data held in REM has the advantage of being saveable on your tape recorder. It is unaffected by CLEAR or RUN, and its position in memory is fixed. The block of data always begins at the same memory address. This makes programming a bit easier than when data is held in a string. Information to be stored in the Data REM Line is POKEd into it just like a machine code routine gets POKEd into REM.

When you want to access a file, you input a search command. This command can be any word, symbol, or phrase. Just as with the data files, the search command is POKEd into its own special REM line. The search routine then compares the characters of the search REM with the characters of the data REM until a match is found.

Figure 1. Data REM builder.

 1 REM 12E[gW]RNDLN[inv .][gD]TAN
2 LET D=PEEK 16396+256*PEEK 16397-2
3 FOR I=1 TO 13000
4 POKE 16515,INT ((D+I)/256)
5 POKE 16514,D+I-256*PEEK 16515
6 RAND USR 16516
7 POKE D+I,0
8 NEXT I
9 POKE D-1,INT ((13000+2)/256)
10 POKE D-2,13000+2-256*PEEK (D-1)
11 REM

After the word REM in line 1, enter the following characters:

the number 1
the number 2
the letter E
graphic shifted W
the token RND
the token LN
inverse period
graphic shifted D
the token TAN

There are no spaces in line 1.

Figure 2. Machine Code loader.

   1 REM (32 spaces)
5 REM (65 spaces)
6 REM (29 spaces)
1000 FOR X=16507 TO 17000
1005 PRINT AT 0,0;"HIT ENTER TO
GOTO NEXT ADDRESS ""P"" TO POKE
THIS ADDRESS";TAB 0;"""S"" TO S
TOP",,"""G"" TO GOTO A NEW ADDRE
SS";TAB 0;"""B"" TO BACK UP"
1010 PRINT AT 7,0;"ADDR PEEK CH
R$ "
1015 PRINT AT 8,0;X;" ";PEEK X;"
";TAB 12;CHR$ PEEK X;" "
1020 INPUT X$
1025 IF X$="S" THEN STOP
1030 IF X$="P" THEN GOTO 2000
1035 IF X$="B" THEN LET X=X-2
1040 IF X$="G" THEN GOTO 1500
1050 NEXT X
1060 STOP
1500 PRINT AT 10,0;"INPUT STARTI
NG ADDRESS"
1510 INPUT X
1520 PRINT AT 10,0;" "
1530 GOTO 1010
2000 PRINT AT 10,0;"INPUT A DECI
MAL VALUE"
2010 INPUT Y
2020 POKE X,Y
2030 GOTO 1520

1 REM: Type REM, then 32 spaces, then ENTER
Line 1 holds the search command
Line 5 holds the assembly routine
Line 6 is not used. DO NOT LEAVE OUT.
1005: 2 spaces between ENTER and TO
1015: Type 5 spaces between the quotes
1520: That’s 32 spaces

Entering the Program

Entering the program is a three step process.

Step 1

First, the large data REM is built. The program used to create this REM line was adapted from “Space in REM” by Frank O’Hara which appeared in the August issue of SYNTAX. After you enter and RUN the REM Builder listed in Figure 1, line 11 turns into a REM statement containing 13000 blank spaces. Imagine putting this line in manually!

The program takes about 7 minutes to run. When it finally does stop with a report 0/11, delete lines 1 through 10 by typing in the line number and ENTER. This will leave you with a single REM line —line 11— which consists of 13000 blank spaces.

Step 2

The second part of the program involves entering the search command REM, the search routine REM, and the loader program which lets you POKE in the machine code search routine. Add to line 11 the listing shown in Figure 2.

This program steps through each address of memory between 16507 and 17000. First the address is PRINTed, then the value stored in that byte. Finally the character the value represents is displayed. After display of each byte, the program gives you these options:

1) Hit ENTER if you want to continue to the next address.

2) Press “S” to STOP.

3) Press “P” to POKE this address.

4) Press “B” to BACK UP one address

5) Press “G” to GOTO a different starting address.

Use the program to input the machine code search routine and to inspect important addresses to make sure everything is added properly.

Figure 3. System variables and key MC addresses.

Address
Decimal  Hex    Name         Function
16507    407B   FILE PEEK    -The last two bytes of the Sinclair system
                (2 bytes)     variables  area of memory. these bytes are
                              not used by the BASIC so you can use them
                              for whatever you want. FILE PEEK points to
                              the starting address of found files for
                              display.
16514    4082   SEARCH       -The first byte after 1 REM. This is where
                COMMAND       you store the search command word.
                WORD
                (32 Bytes)
16552    40A8   MC SEARCH    -The first byte after 5 REM. This is the
                (65 Bytes)    start of the assembly routine that does
                              the byte blitzing.
16583    40C7   LASTCHR      -Starting address of MC SEARCH which handles
                              found files.
16604    40DC   D Ptr        -This address resides in 5 REM. A 2 byte
                (2 bytes)     pointer which shows MC SEARCH where to begin
                              looking.
16606    40DE   BC Ctr       -Also located in 5 REM. Counts how many bytes
                (2 Bytes)     have been searched.
16608    40E0   NOGOT        -Starting address of MC SEARCH which handles
                              unlisted search commands.
16623    40F0   not used     -The first byte after 6 REM. These 29 bytes
                              are not used by the program but you must not
                              leave them out. They might someday be useful
                              for another assembly language routine.
16658    4112   DATA BYTE    -First byte of Data Storage REM. (line 11)

Figure 4. Code for MC SEARCH.

For address:  Poke the value:    For address:  Poke the value:
16552 42 16586 43
16553 220 16587 126
16554 64 16588 254
16555 237 16589 23
16556 75 16590 202
16557 222 16591 212
16558 64 16592 64
16559 17 16593 195
16560 130 16594 202
16561 64 16595 64
16562 26 16596 34
16563 237 16597 123
16564 177 16598 64
16565 226 16599 237
16566 224 16600 67
16567 64 16601 222
16568 19 16602 64
16569 26 16603 201
16570 254 Ptr 16604
16571 155 16605 0
16572 202 Ctr 16606
16573 199 16607 0
16574 64 16608 33
16575 237 16609 18
16576 161 16610 65
16577 202 16611 1
16578 184 16612 1
16579 64 16613 0
16580 195 16614 195
16581 175 16615 212
16582 64 16616 64
16583 34
16584 220
16585 64

The Linear Search routine uses several system variables the same way that the Sinclair Basic uses them. Figure 3 lists the addresses of these important bytes and describes their functions. Also listed are key addresses of the search routine.

Before you enter the MC SEARCH routine you should use the loader program (Figure 2) to make sure you entered the REM lines correctly. Check the program against these values. At each of the following addresses you should find the PEEK value of 118;

16546; The last byte of 1 REM
16617; The last byte of 5 REM
16652; The last byte of 6 REM

When you are sure everything is right, begin entering the MC SEARCH. Since the routine begins at 16552, type “G” and input this address when prompted. Begin POKEing the code from the table in Figure 4. Remember to push “P” for every byte you wish to POKE.

POKEing in the code from Figure 4 fills the 65 space REM line (line 5) with the MC SEARCH instructions.

[Figure: Cartoon of a king and a frog with a computer]

Step 3

When you are done, you are ready to enter the third and final phase of the program: Typing in the Basic. This part executes file inputs to the Data REM and displays found files.

There is no need to delete the loader program. When you are experimenting with the search routine, you can use the loader to PEEK into the various pointers as well as observe the search command and data REMs.

Figure 5 lists the Basic routines. Simply insert the lines into what you already have typed into your computer.

Figure 5. Basic Listing.

 12 LET P=0
14 CLS
15 PRINT " ZX FILE/FINDE
R ",,"ENTER A SEARCH C
OMMAND OR TYPE "A" TO ADD A NEW
FILE "
20 INPUT X$
21 IF X$="" THEN GOTO 20
30 IF X$="A" THEN GOTO 500
35 LET X$=X$+"[inv .]"
50 FOR X=1 TO LEN X$
60 POKE 16513+X,CODE X$(X)
70 NEXT X
80 POKE 16606,P-256*INT (P/256
)
90 POKE 16607,INT (P/256)
100 POKE 16604,18
110 POKE 16605,65
120 CLS
122 LET B=USR 16552
125 PRINT X$( TO LEN X$-1);TAB
0;"FILE/SEARCH",,,,
130 LET X=PEEK 16507+256*PEEK 1
6508
135 FOR Y=X TO X+P
140 IF PEEK Y<>192 THEN PRINT C
HR$ PEEK Y;
150 IF PEEK (Y+1)=192 OR PEEK (
Y+1)=23 THEN GOTO 200+(20*(PEEK
(Y+1)=23))
170 NEXT Y
180 GOTO 220
200 PRINT
210 NEXT Y
220 PRINT AT 16,0;"HIT ENTER TO
CONTINUE SEARCHING "R" TO RETUR
N TO PREVIOUS FILES "N" TO BEGIN
A NEW FILE/SEARCH "
230 INPUT Y$
235 IF Y$="R" THEN GOTO 80
240 IF B AND Y$="" THEN GOTO 12
0
245 IF Y$<>"N" THEN GOTO 220
250 GOTO 14
500 PRINT AT 7,5;"ADD/FILE"
510 FOR X=1 TO 4
520 PRINT AT 7,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 8+X,0;X$
570 NEXT X
580 PRINT AT 16,0;"HIT ENTER TO
LOG THIS LISTING OR""C"" TO COR
RECT IT";" "
585 INPUT X$
590 CLS
595 IF X$="C" THEN GOTO 500
600 FOR X=1 TO LEN A$
610 POKE 16658+P,CODE A$(X)
620 LET P=P+1
630 NEXT X
635 POKE 16658+P,23
660 GOTO 14

Notes:

12: P indicates the no. of DATA BYTES poked.
15: The search command input menu.
30: Type “A” to add a new file.
35: Otherwise the word you input is poked into the first rem line.
80: Lines 80 and 90 poke the value of P into BC Ctr. This variable tells the computer how many bytes to check.
100: Lines 100 and 110 load D Ptr with the address of the first byte of 11 rem.
122: The machine language search.
130: The variable X takes on the value of the address held in FILE PEEK.
135: The loop then Prints the file beginning at address X.
150: If a “*” or “””” is encountered, the program jumps to either 200 or 220.
200: A quote image will lower the printing one line.
220: An asterisk indicates the end of a file. You jump to the display option menu.
235: Type “R” to start the same search over.
240: Type ENTER to continue searching.
245: Type “N” to start a new search.
500: ADDING new files begins here.
510: This loop lets you input 4 lines of data.
540: The first line always starts with “*”.
550: Lines 2 to 4 begin with a quote image.
580: After you input your new file, it gets printed and this line lets you change your mind about entering it into REM. (40 spaces between the quotes)
595: Type “C” to go back to re-enter the file. Otherwise, each character of the new file is poked into the next free byte of 11 REM. After each Poke, P is incremented.
635: Then a “*” is planted at the end.
660: When ADD/FILE is complete, the computer returns to the search command menu.

How The Program Works

When you RUN the program, the first line to be executed is

12 LET P=0

This variable represents the number of data characters used in the data REM line. Since you have not added any files yet, P is initialized with the value of zero.

Line 15 prints the search command menu. From here you can either input a command word or let the computer know that you want to ADD a new file. If you type “A”, line 30 sends you off to the ADD/FILE routine beginning at line 500.

ADD/FILE uses a FOR-NEXT loop to let you input four lines of data. For each value of the loop, you input a line of information at line 530.

This program “marks” each line you input with two very important symbols. These file markers are used by both the machine code search and the Basic display routines. Every file begins with a “*” and each new line of data begins with a quote image. Lines 535 and 540 insert these symbols into the string of data you input. For each iteration of the loop, these lines put the text you input into one long string (A$). If you are inputting the first line, A$ becomes “*”+X$ (the line you input). If you are adding lines 2 through 4, line 540 adds a quote image, then the line of text.

Line 545 displays your new file. After all four lines are put into A$, lines 580 to 595 are executed. The prompt tells you that if you see a mistake in the new file, you can correct it by pressing the letter “C”.

Press any other key and the file gets added to the data REM line. This is done in lines 600 to 635. The FOR-NEXT loop takes each character of A$ and POKEs it into the next unused byte of the data REM. After each POKE, the variable P is incremented by line 620.

Before ADD/FILE is complete, line 635 POKEs a file marker (*) into the space immediately following the last character of the newly added file. This marker tells the computer to stop PRINTing when it is displaying files.

The line says

POKE 16658+P,23.

23 is the code number for an asterisk. See the ZX81 owners manual for a complete list of all characters and their codes. The file is added. We now jump back to line 14; the search command menu.

Before you actually add your first file, you should note how the machine code search works. If the search routine cannot find a file which contains the search word you input, the computer PRINTs the first file of the data REM line. Therefore, your first file should be an informative statement like “SEARCH IS COMPLETE”. Even though the program asks for four lines of data per file, it is perfectly legal to input a one liner. To add empty line, just hit ENTER when lines 520 and 530 ask you to INPUT a line of text.

Finding and PRINTing Files

The linear search hunts for any word, symbol, or phrase you want. Every file which contains the words or characters in question get PRINTed. This “seek and print” routine begins at line 15, the search command menu. This is where we ADDed new files by typing “A”. If you do not type “A”, the computer tacks an inverse period onto the end of the word you INPUT when line 35 is executed. This symbol indicates to the computer that it is the last character of the search command word.

Next, lines 50 to 70 POKE the search command into the first REM line of the program.

Before the MC SEARCH is called, lines 80 to 110 initialize both BC Ctr and D Ptr to their proper values. At the beginning of every search, BC Ctr takes the value of P. D Ptr receives the address of DATA BYTE, the first character of the data REM line (address 16658). When BC Ctr and D Ptr have these values, the MC SEARCH knows it must begin searching at the beginning of the data REM line and continue searching until it has gone through every used byte of stored data.

The hunt for the first file which contains the search command word is ready to commence. Line

122 LET B=USR 16552

breaks the computer from Basic and executes the assembly language instructions beginning at address 16552. This line does more that just jump to the USR code. It also sets up the variable B. The value that B assumes is the number which is held in the BC register pair on return to Basic . In the assembly language routine, the BC pair acts as a counter of each byte of data searched. BC starts off equal as a counter of each byte of data searched. BC starts off equal to P and decrements with each byte until it reaches zero. The variable B, then, does the same thing. When B=0, the computer knows that the search is complete.

Figure 6 shows exactly what the MC SEARCH does.

Figure 6. MC SEARCH Routine.

        Decimal      Hex
Addr. Code Addr. Code Mnemonic Notes
16552 42 40A8 2A LD HL,(NN) load HL with value held in D Ptr
16553 220 40A9 DC 40DC=D Ptr
16554 64 40AA 40
16555 237 40AB ED LD BC, (NN) Load BC with BC Ctr contents
16556 75 40AC 4B
16557 222 40AD DE 40DE=BC Ctr
16558 64 40AE 40
16559 17 40AF 11 LD DE,NN load DE with addr. of first byte
16560 130 40B0 82 4082=com. of command word
16561 64 40B1 40
16562 26 40B2 1A LD A, (DE) put the character in Accumulator
16563 237 40B3 ED CPIR compare value in A with the value
16564 177 40B4 B1 at addr. specified by HL;inc HL;
16565 226 40B5 E2 JP PO,NN decr. BC; repeat.
16566 224 40B6 E0 Is BC=0? Yes? Goto NOGOT
16567 64 40B7 40 40E0=NOGOT
16568 19 40B8 13 INC DE Does Chr match? Take next Chr.
16569 26 40B9 1A LD A, (DE) and put it in Accumulator.
16570 254 40BA FE CP N -is it an inverse period?
16571 155 40BB 9B 9B=inverse "."
16572 202 40BC CA JP Z, NN Yes? Goto LASTCHR
16573 199 40BD C7 40C7=LASTCHR
16574 64 40BE 40
16575 237 40BF ED CPI No? Compare it w/next search
16576 161 40C0 A1 command chr; inc HL; dec BC.
16577 202 40C1 CA JP Z, NN Match? Go back-check next chr.
16578 184 40C2 B8 40B8
16579 64 40C3 40
16580 195 40C4 C3 JP NN No match? Goto 40AF to check
16581 175 40C5 AF 40AF another first character.
16582 64 40C6 40
LASTCHR 16583 34 40C7 22 LD (NN), HL put HL in D Ptr
16584 220 40C8 DC 40DC=D Ptr
16585 64 40C9 40
16586 43 40CA 2B DEC HL Step back-put value located at
16587 126 40CB 7E LD A, (HL) addr. specified by HL in Accum.
16588 254 40CC FE CP N is it a "*"?
16589 23 40CD 17 17="*"
16590 202 40CE CA JP Z, NN Yes? Goto 40D4
16591 212 40CF D4 40D4
16592 64 40D0 40
16593 195 40D1 C3 JP NN No? Go back to 40CA to look more.
16594 202 40D2 CA 40CA
16595 64 40D3 40
16596 34 40D4 22 LD (NN). HL Put HL in FILEPEEK
16597 123 40D5 7B 407B=FILEPEEK
16598 64 40D6 40
16599 237 40D7 ED LD (NN), BC Put BC in BC Ctr
16600 67 40D8 43
16601 222 40D9 DE 40DE=BC Ctr
16602 64 40DA 40
16603 201 40DB C9 RET Return to BASIC
D Ptr 166040 40DC0 Bytes 40DC and 40DD are D Ptr
16605 0 40DD 0
BC Ctr 166060 40DE0 Bytes 40DE and 40DF are BC Ctr
16607 0 40DF 0
NOGOT 16608 33 40E0 21 LD HL, NN Put Address of 1st DATA BYTE in HL
16609 18 40E1 12 4112=DATA BYTE
16610 65 40E2 41
16611 1 40E3 1 LD BC, NN Load BC with 1.
16612 1 40E4 1 01
16613 0 40E5 0
16614 195 40E6 C3 JP NN Goto 40D4
16615 212 40E7 D4 40D4
16616 64 40E8 40

Essentially, the Machine Code Search takes the first character of the search command word and checks it against every character held in the data storage REM. When it finds a match, the routine compares the next character of the search word with the next character of the data REM. With every match the operation repeats until the computer reaches the last character of the search word (an inverse period) or until it finds 2 non-matching characters. If the last character of the search word is encountered, the computer steps back through the REM until it finds a file marker (*). This indicates the beginning of a found file. The variable FILEPEEK is loaded with the address the marker is occupying, D Ptr marks the spot where the file was found, and BC Ctr is loaded with the number of data bytes still unchecked. Completing this, the computer returns to Basic.

If the search resulted in a non-match, the computer simply resumes searching for a match of the first character of the search word until the entire block of occupied loads FILEPEEK with the address of the first file in the data REM. Then it returns to Basic.

File Display

With FILEPEEK loaded and the computer back in Basic, line 130 takes FILEPEEK’s address and assigns it to the variable X. Then lines 135 to 210 display the file. At 135, a “Y” loop is initialized. Its first value is X or the address held in FILEPEEK. The next line checks each byte of data held in address Y to see if it is a quote image (CHR$ 192). If it is not, the character held in that address gets PRINTed.

Line 150 checks the next byte for a quote image or an asterisk. If the computer finds one of these file markers, the command:

GOTO 200+(20*(PEEK (Y+1)=23))

is executed. The expression

(PEEK (Y+1)=23

is actually a number.

If PEEK (Y+1) really does equal 23, the number is 1.

If PEEK (Y+1) does not equal 23, the number is 0.

So depending on the PEEK value of address (Y+1), the computer will

GOTO 200+(20*1) or 220

if it finds an asterisk (PEEK Y+1=23), or

GOTO 200+(20*0) or 200

if it finds a quote image.

If the quote image is encountered, lines 200 to 210 simply move the PRINTing down one line. Then the computer jumps right back into the loop to PRINT more characters.

But, if the asterisk is found, we have come to the end of the file, or more precisely, the beginning of the next file: GOTO 220.

Here, we find a list of display options. After the text of the menu is PRINTed, line 230 lets you make your selection.

If you type “R” meaning RETURN to previous file displays, line 235 sends you back to line 80. This has the effect of making the same search over again. This is useful when you have several files that contain the same search word. If, after printing the third or fourth file, you want to go back to look at the first one, type “R” to RETURN.

Line 240 says that, if B is not equal to zero (the search has not yet progressed through all occupied bytes of the data REM) and you press just ENTER, then GOTO 120. This jumps you back into the MC SEARCH. D Ptr and BC Ctr remember where the computer stopped before it printed the last file, and searching resumes from that point. Hitting ENTER, therefore, lets you continue the search through the remainder of the Data REM.

Finally, if you type “N”, line 245 sends you back to line 14. This breaks the search entirely and you can INPUT a new search command word.

[Figure: Cartoon: “First you lull them into a false sense of confidence with a couple of perfect runs…”]

Conclusion

This program showed you one way to store information, find it with lightning speed, and display that information once it is found. A good data base must also take into consideration many other design parameters. How do you edit existing files? How do you delete those that are out of date? What other display options need to be included? What about SAVEing the program on tape? How can files longer than four lines be stored?

Every new capability added to a program uses valuable memory space which could otherwise be used for data storage. Finding ways to combine the most function with the most data capacity is perhaps the greatest challenge of all.

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