MediaWiki:Sitenotice:
2024-03-02: The wiki ran out of disk space, so things were not working. This has been resolved by adding another 5GB of quota ;-) Thanks to Tim Lindner for reporting the issues.
2020-05-17: If a page gives you an error about some revision not being found, just EDIT the page and the old page should appear in the editor. If it does, just SAVE that and the page should be restored. OS-9 Al (talk) 12:22, 17 May 2020 (CDT)
Undercolor/850103/Find
Home Articles Companies Publications Hardware People Software Timeline ... Emulators Internet Resources
(Don't see something listed? Click "edit" and add it! Together we can build this database. When making a new info page, refer to this InfoBox Template for guidelines.)
UnderColor, Volume 1, Number 3, January 11, 1985
- Title: Find
- Author: Stephen Allen
- Synopsis: A new word in Basic.
- Page Scans: Link
Article
Remember "System Horizons" (TCCM, July ’84)? "Find" is a follow-up to that article, and it has finally found a home!
To disassemble Basic ROMs; to be an "insider" on the real processes taking place in your computer; these impart fun and satisfaction, but more satisfying is taking Basic’s own subroutines and using them to create your own programs. You’ll get a great deal of power from a very small piece of code.
What does Find do?
Say you’ve been working on a long Basic program and you keep getting ?FC ERROR in a line you know is legal. Suddenly you realize you need to change a single occurrence
of N$(A) to N$(B). You can do nothing but List the program, hitting Shift @ ’til you find it (if you find it; oops! Try again . . .), then Break and Edit the correct line. A drag, right'?
The Find utility lets you type FINDN$(A) and enter. A listing instantly appears and scrolls furiously by, just as in List. When a line containing the target string is listed, however, the display freezes and a gentle blue cursor marks (in this case) N$(A)'s position in the line.
At this point you have three options. You can hit Break and break out of Find, or you can hit Enter and continue the listing and search. Or (and this is the best part), you can
hit E and go immediately to Extended Color Basic’s Edit routine.
Want to search for the same string a second time? Just type FIND and enter. Find has its own 10-character buffer, so that’s your maximum target string length.
How about wild card searches? Sure! The symbol is #. Searching for PR##T will locate PRINT, PRESTO, PR$(T), etc.
If you're searching for a string containing a Basic word, use a single quotation mark before the word. For example: FIND"'PUT. The quotation mark keeps Basic from turning the string into a token, and is good practice generally, since (for example) NONE; without the mark is tokenized into N/ token for ON/E. Find understands the quotation mark and skips it when it’s the first character.
If your Basic program is already in memory and you need to load Find, don’t worry. Find has two parts: the guts, which contain the routine, and the Pretty Smart Loader, used only once, which sets up operation of the routine. Together, they load into low graphics memory. Even if you've executed PCLEAR1 you're OK. Just (C)LOADM and Execute to set it up, and you're in business.
All this power takes only 250 bytes!
Details
Note: from here on, if there’s something you don't understand, please refer back to "Exploring System Horizons"
(TCCM, July ’84).
Here's the sequence of operations for The Pretty Smart Loader:
1. Get the highest RAM address from Basic's Pointer. Subtract the length of the "guts." Give the new value back to Basic.
2. Copy the "guts" up to that high RAM space.
3. Use the existing RAM token tables to compute a new token for Find, then create a new table for Find. POKE the calculated token value into the guts, to be used as a validation check.
4. Since we don't want this loader executed more than once, change the EXEC address to 41175. If you Execute again, you’ll get Color Basic's sign-on message.
5. If you`re running Extended Color Basic, there'll be a conflict between the new token table and the USR address table. Disk Basic also has this problem, but resolves it by
moving the USR table up into Disk RAM. My solution is to move the USR table up two bytes, keeping USR0 and 1, but taking away USR9, whose address becomes part of the keyboard roll-over table! (When is the last you saw DEFUSR9?) It’s the best trade-off I could think of.
The Guts: Find is always entered with its token in the A register. A quick check is done to see if Basic got there by mistake. If everything's OK (always is), then proceed.
1. Evaluate and store the target string. This is the string which Find will try to match. If no string is specified, use the
last string.
2. Use a ROM call to de—tokenize the next line into a buffer at $2DD.
3. Print a character from the buffer, testing for a match. If there is no match, keep printing and checking.
4. If the character matches, suspend printing and compare the rest of the target string. If the rest of the match fails, resume printing. If the match is successful, set a flag and
pay attention to the match’s position in the line (Line 2100, CLRB). Resume printing and checking.
5. At the end of the line test the flag. If there is no match, do another line.
6. There's a match. Get the screen position of the end of the line, move back to the point of the match, and set a cursor there. Wait for a key press. The instruction INCB in Line 2300 adjusts for the fact that the cursor points one byte ahead of the last printed character.
7. Key Press: If the key was Enter, do another line. If Break, exit Find and jump to Basic’s Break routine. If E, then exit
Find and jump to Edit in ROM. If none of the above, go back and wait. (end)
Listings
00100 ************************* 00110 ** ** 00120 ** FIND ** 00130 ************************* 00140 ** A New Word For ** 00150 ** Basic ** 00160 ************************* 00170 * by * 00180 * Stephen P. Allen * 00190 00200 00210 00220 00230 * For Disk Basic use this ORG 0F00 00240 ORG $F00 00250 00260 * For Extended Basic use this ORG 00270 * ORG $700 00280 00290 ************************* 00300 * THE * 00310 * PRETTY SMART * 00320 * LOADER * 00330 ************************* 00340 00350 00360 00370 *** MAKE ROOM UP TOP *** 00380 00F9 00390 LENGTH EQU ZEND-TITLE 00400 0F00 DC 74 00410 START LDD <$74 High Ram address 0F02 83 00F9 00420 SUBD #LENGTH —Find's length 0F05 DD 74 00430 STD <$74 =New "High Ram" address 0F07 DD 27 00440 STD <$27 and "Top of String Space" 0F09 DD 23 00450 STD <$23 and pointer to next string 00460 0F0B 83 00C8 00470 SUBD #200 default total string space 0F0E DD 21 00480 STD <$21 to "Start of String Space" 0F10 10DE 21 00490 LDS <$21 Stack goes below strings 00500 00510 *** MOVE IT UP *** 00520 0F13 DE 74 00530 LDU <$74 New "Top of Ram" 0F15 33 42 00540 LEAU 2,U (a little space, just in case) 0F17 30 8C 41 00550 LEAX <TITLE,PCR Start of "FIND" 0F1A 108E 00F9 00560 LDY #LENGTH of "FIND" 0F1E A6 80 00570 PUTHI LDA ,X+ 0F20 A7 C0 00580 STA ,U+ 0F22 31 3F 00590 LEAY -1,Y 0F24 26 F8 00600 BNE PUTHI 00610 00620 00630 *** TELL BASIC WHERE TO FIND IT *** 00640 0F26 CE 0116 00650 LDU #$116 Address of (token tables-10) 0F29 5F 00660 CLRB Token will form here 00670 00680 0F2A 33 4A 00690 TABLE LEAU 10,U Move into next Token Table 0F2C EB C4 00700 ADDB ,U add # of entries this table 0F2E 6D C4 00710 TST ,U At end of tables yet? 0F30 26 F8 00720 BNE TABLE no, keep going 00730 0F32 CB 80 00740 ADDB #$80 Make negative, signal as token 0F34 6F 4A 00750 CLR 10,U Signal new "End of Tables" 0F36 86 01 00760 LDA #1 One new entry here 0F38 A7 C0 00770 STA ,U+ At start this new table 00780 00790 * Recalculate start of "FIND" 00800 0F3A 9E 74 00810 LDX <$74 High Ram address 0F3C 30 02 00820 LEAX 2,X plus that two (just in case) 0F3E AF C1 00830 STX ,U++ Address of word into Table 00840 0F40 30 04 00850 LEAX 4,X Address of routine... 0F42 AF C4 00860 STX ,U into the table 00870 00880 * New token also goes directly into routine * 00890 0F44 E7 01 00900 STB 1,X 00910 00920 *Change EXEC address to disable Loader 00930 0F46 8E A0D7 00940 LDX #41175 Color Basic's Sign-on msg. 0F49 9F 9D 00950 STX <$9D to EXEC pointer 00960 00970 00980 *Move DEFUSR table if necessary* 00990 0F4B DC B0 01000 LDD <$B0 Points to DEFUSR table 0F4D 1083 013E 01010 CMPD #$13E Extended Basic's table? 0F51 26 04 01020 BNE JUMP if not, then Disk: OK 0F53 C6 40 01030 LDB #$40 Else Make new table at $140 0F55 DD B0 01040 STD <$B0 01050 0F57 6E 9F FFFE 01060 JUMP JMP [$FFFE] Done! Go do a warm start. 01070 01080 01090 ************************ 01100 * THE GUTS * 01100 ************************* 01120 01130 * "FIND" with "D" made negative 01140 0F5B 46 01150 TITLE FCC /FIN/ 49 4E 0F5E C4 01160 FCB $80+'D 01170 01180 01190 * Routine starts here * 01200 0F5F 81 CE 01210 FIND CMPA #$CE If disk, this will change 0F61 27 03 01220 BEQ OK yes, correct token 0F63 7E B277 01230 JMP $B277 else ?SN ERROR 01240 01250 01260 *** GET THE PARAMETERS *** 01270 0F66 9D 9F 01280 OK JSR <$9F next character 0F68 27 1C 01290 BEQ FIND2 if null, use previous string 01300 01310 * A string is specified 01320 0F6A 30 8D 00DC 01330 LEAX TARGET,PCR Point to buffer 0F6E 5F 01340 CLRB Length of string so far, 0 0F6F 81 22 01350 CHPA #'" String delimiter? 0F7l 26 04 01360 BNE LOOP1 OF73 9D 9F 01370 JSR <$9F if so, skip it OF75 27 0F 01380 BEQ FIND2 if nothing else specified 01390 0F77 A7 80 01400 LOOP1 STA ,X+ character into FIND's buffer 0F79 5C 01410 INCB length=1ength+1 0F7A C1 0A 01420 CMPB #10 max # of chars? 0F7C 24 04 01430 BHS DONE if yes, skip the rest 0F7E 9D 9F 01440 JSR <$9F else get next char. 0F80 26 F5 01450 BNE LOOP1 if another char, loop back 01460 0F82 E7 8D OOC3 01470 DONE STB LENTS,PCR Store string length 01480 0F86 32 62 01490 FIND2 LEAS 2,S Drop return address 0F88 8E 0019 01500 LDX #$19 Has address of first line 0F8B 9F 66 01510 STX <$66 Save for LIST loop 01520 01530 01540 *** LIST A LINE: TEST FOR MATCH *** 01550 0F8D BD B95C 01560 NXTLIN JSR $B95C Do a linefeed 0F9O BD A549 01570 JSR $A549 Test for (Break}, (shift @> 01580 0F93 9E 66 01590 LDX <$66 get address of last line 0F95 AE 84 01600 LDX ,X Point to next line 0F97 EC 84 01610 LDD ,X End of Basic program? 0F99 26 03 01620 BNE CONT if not end of Basic program 0F9B 7E AC73 01630 JMP $AC73 Exit here if End of Program 01640 0F9E 9F 66 01650 CONT STX <$66 Update Low Ram Line Pointer 0FA0 6F 8D 00A2 01660 CLR FFLAG,PCR No matches this line yet 01670 0FA4 EC 02 01680 LDD 2,X Get line number 0FA6 BD BDCC 01690 JSR $BDCC Print line number 0FA9 BD B9AC 01700 JSR $B9AC print a space 01710 0FAC 9E 66 01720 LDX <$66 Point to Basic line again 0FAE BD B7C2 01730 JSR $B7C2 De-Tokenize into buffer 0FBl CE 02DD 01740 LDU #$2DD Point to buffer 0FB4 31 8D 0092 01750 LEAY TARGET,PCR Point to Target string 0FB8 A6 C0 01780 PRINT LDA ,U+ Next char. from buffer 0FBA 27 2E 01790 BEQ TEST if End of Line 0FBC AD 9F A002 01800 JSR [$A002] Print the next character ] 0FC0 5C 01810 INCB Keep track of match position 0FC1 A1 A4 01820 CMPA ,Y Match on first letter? 0FC3 26 F3 01830 BNE PRINT if not, keep going 01840 01850 * MATCH ON FIRST LETTER * 01860 0FC5 34 64 01870 MATCH1 PSHS U,Y,B Save important registers 0FC7 33 5F 01880 LEAU -1,U Prepare for following loop 0FC9 E6 8D 007C 01890 LDB LENTS,PCR Length of Target string 0FCD 5A 01900 MATCH2 DECB One less Target char to match 0FCE 27 12 01910 BEQ FOUND If match on total string 0FD0 33 41 01920 LEAU 1,U Else move up in buffer... 0FD2 31 21 01930 LEAY 1,Y and Target buffer 0FD4 A6 A4 01940 LDA ,Y Next target character 0FD6 81 23 01950 CMPA #'# Is it a "Wildcard?" 0FD8 27 F3 01960 BEQ MATCH2 if yes, automatic match 0FDA A1 C4 01970 CMPA ,U else test for match 0FDC 27 EF 01980 BEQ MATCH2 so far so good 01990 02000 *Match fails in mid—string 02010 0FDE 35 64 02020 PULS B,Y,U Restore crunched registers 0FE0 20 D6 02030 BRA PRINT and keep going 02040 02050 02060 *** FOUND A MATCH *** 02070 0FE2 6C 8C 61 02080 FOUND INC <FFLAG,PCR Flag a match on this line 0FE5 35 64 02090 PULS B,Y,U restore crunched registers 0FE7 5F 02100 CLRB Print distance from this 02110 * match=0 0FE8 20 CE 02120 BRA PRINT Keep listing to End of Line 02130 02140 02150 * END OF LINE: 02160 * IF THERE'S A MATCH THEN SHOW IT, 02170 * ELSE DO NEXT LINE 02180 0FEA EF 8C 5A 02190 TEST STU <BUFEND,PCR Save in case of EDIT 0FED 6D 8C 56 02200 TST <FFLAG,PCR Any matches? 0FF0 27 9B 02210 BEQ NXTLIN if not, do next line 02220 02230 02240 * GOT A MATCH: 02250 * PUT CURSOR AND WAIT FOR KEYPRESS 02260 02270 * First, move cursor to start of last match 02280 0FF2 DE 88 02290 SHOWIT LDU <$88 Get current cursor position 0FF4 5C 02300 INCB Adjust for offset 0FF5 33 5F 02310 FINDIT LEAU -1,U Move cursor pos. back... 0FF7 5A 02320 DECB 0FF8 26 FB 02330 BNE FINDIT till start of match B 0FFA A6 C4 0234O LDA ,U Save for non—destructive... 0FFC A7 8C 47 02350 STA <FFLAG,PCR cursor routine 02360 02370 * Now wait for keypress 0FFF 86 AF 02390 CURSOR LDA #$AF blue graphics block... 1001 A7 C4 02400 STA ,U to screen 1003 8D 21 02410 BSR CRSKEY try for keypress 1005 26 09 02420 BNE PRESS if keypress detected 02430 1007 A6 8C 3C 02440 LDA <FFLAG,PCR Else get first letter 100A A7 C4 02450 STA ,U and store on screen 100C 8D 18 02460 BSR CRSKEY and try for keypress 100E 27 EF 02470 BEQ CURSOR Keep trying if nothing 02480 02490 02500 *** GOT A KEYPRESS *** 02510 1010 E6 8C 33 02520 PRESS LDB <FFLAG,PCR Restore first letter... 1013 E7 C4 02530 STB ,U to screen 02540 1015 81 0D 02550 CMPA #$0D Keypress was <Enter>? 1017 1027 FF72 02560 LBEQ NXTLIN If yes, do next lines 101B 81 45 02570 CMPA #'E 'Keypress was "EDIT?" 101D 27 16 02580 BEQ EDIT if yes 101F 81 03 02590 CMPA #3 Keypress was <Break>? 1021 26 DC 02600 BNE CURSOR if not, keep trying for 02610 * legal key 02620 1023 7E AE09 02630 JMP $AE09 Exit here on <Break> 02640 02650 1026 108E 028A 02660 CRSKEY LDY #650 Delay value 02670 102A AD 9F A000 02680 DELAY JSR [$A000] Poll keyboard 102E 26 04 02690 BNE KEYEND Exit if keypress 1030 31 3F 02700 LEAY -1,Y else delay a little 1032 26 F6 02710 BNE DELAY 1034 39 02720 KEYEND RTS Return with or without keypress 02730 02740 02750 *** SET UP EDIT ROUTINE *** 02760 1035 BD B95C 02770 EDIT JSR $B95C Do an <Enter> 1038 9E 66 02780 LDX <$66 Point to start of line 103A EC 02 02790 LDD 2,X grab line number... 103C DD 2B 02800 STD <$2B and save for printout 103E 0F D8 02810 CLR <$08 List flag: don't re-list 1040 EC 8C 04 02820 LDD <BUFEND,PCR 1043 7E 8548 02830 JMP $8548 Go Edit 02840 1046 02850 FFLAG RMB 1 <>0 if match found, 02860 * also holds letter under cursor 1047 02870 BUFEND RMB 2 End of line in print buffer 1049 02880 LENTS RMB 1 Length of target string 104A 02890 TARGET RMB 10 Buffer for Target string 1054 02900 ZEND EQU . End of program is here 02910 0F00 02920 END START Exec address is at "START" 00000 TOTAL ERRORS START 0F00 BUFEND 1047 DONE 0F82 FINDIT 0FF5 LENTS 1049 OK 0F66 TABLE 0F2A CONT 0F9E EDIT 1035 FOUND 0FE2 LOOP1 0F77 PRESS 1010 TARGET 104A CRSKEY 1026 FFLAG 1046 JUMP 0F57 MATCH1 0FC5 PRINT 0FB8 TEST 0FEA CURSOR 0FFF FIND 0F5F KEYEND 1034 MATCH2 0FCD PUTHI 0F1E TITLE 0F5B DELAY 102A FIND2 0F86 LENGTH 00F9 NXTLIN 0F8D SHOWIT 0FF2 ZEND 1054