; Aida::Search.Mac.26, 13-Nov-90 04:32:13, Ed: PEM ; 17 Fixed a bug in perr: (didn't check if prompting). ; Added the /Positions: switch (don't print file positions if no) ; and the /Files: switch (don't print file names if no), ; and added parser code, updated printm:, pfilen: and $show:, ; accordingly. ; Aida::Search.Mac.22, 18-Oct-89 01:14:34, Ed: PEM ; 16 Fixed bug in ofil: now handle empty files (page count zero) ; with corrupted byte count correctly. ; Aida::Search.Mac.20, 4-Jan-88 19:03:10, Ed: PEM ; 15 Lines with multiple occurences is now written once only. ; Aida::Search.Mac.17, 9-Jul-87 19:23:26, Ed: PEM ; 14 Modified ctrl-z (always print message). Warn isto Error when no ; read access. All diagnostic to Process Controlling Terminal ; now (made /output: work). ; Aida::Search.Mac.16, 20-Jun-87 17:15:51, Ed: PEM ; 13 Don't consider an error when opening a file for reading as fatal. ; Just print the error message and proceed to the next file. ; Aida::Search.Mac.13, 20-Jun-87 17:01:22, Ed: PEM ; 12 Fixed minor bug in ctrlz. ; Aida::Search.Mac.12, 17-Jun-87 17:17:52, Ed: PEM ; 11 Changed interrupt characers : ; ^X skips current file, ^Z aborts current search. ; Aida::Search.Mac.11, 17-Jun-87 01:49:27, Ed: PEM ; 10 Prints out the filenamen when skipping. ; Carmen::Search.Mac.11, 17-Jun-87 01:09:09, Ed: PEM ; 9 Implemented a lot of interrupt handling. ^T is handled, ^N skips ; current file, ^A aborts current search. Illegal Memory Read is taken ; care of, so holes in files is not a problem any moore. ; Carmen::Search.Mac.10, 30-Mar-87 22:05:01, Ed: PEM ; 8 Unmade the previous edit due to braindamaged Ed: but kept the ; default-string feature. ; Carmen::Search.Mac.9, 30-Mar-87 17:30:38, Ed: PEM ; 7 Implemented 'String (default)' due to stupidity in COMND% (.CMQST); ; 'tis impossible to quote a '"' in a quoted string. ; Carmen::Search.Mac.8, 28-Sep-86 03:46:27, Ed: PEM ; 6 Changed default file version from .GJALL to .GJDEF . ; Carmen::Search.Mac.7, 21-Sep-86 17:46:18, Ed: PEM ; 5 Made searching for empty pattern work and gave the filename ; enough room. ; Carmen::Search.Mac.6, 20-Sep-86 16:18:24, Ed: PEM ; 4 Rewrote Printm completely. ; Carmen::Search.Mac.5, 14-Sep-86 16:18:01, Ed: PEM ; 3 Implemented /Output:, modified the printm routine and fixed ; the CCOC-stuff. ; Carmen::Search.Mac.13, 24-Aug-86 17:39:37, Ed: PEM ; 2 Made searching in files with zero page or byte count possible. ; Carmen::Search.Mac.8, 23-Aug-86 14:28:10, Ed: PEM ; 1 Added S as an abbreviation for Search in Keytb. ; Carmen::Search.Mac.4, 22-Aug-86 18:01:33, Ed: PEM ; 0 First release. Everything seems to work now... title search search monsym,macsym,cmdmac(hax:cmdmac) .requi hax:error extern warn,fatal,error ;;; **************************************************************** ;;; ;;; ;;; Search ;;; ;;; by ;;; ;;; Per-Erik Martin, Uppsala University, 1986-08-22. ;;; ;;; ;;; This program is in public domain. ;;; ;;; Share and enjoy. ;;; ;;; ;;; **************************************************************** ;;; Timer. ifndef timerp, ; No, we usually don't want a timer. ;;; Flags in right half of AC0. bm$fnd=1 ; Found. bm$cas=2 ; Case is significant. bm$fnp=4 ; File name is printed. bm$pgc=10 ; File size is printed. bm$nmt=20 ; Don't print out matched line. bm$cnt=40 ; Don't print out # of occurences. bm$prm=100 ; Prompting. bm$def=200 ; Parsing default flags. bm$skp=400 ; Skip after Skip matches. bm$out=1000 ; Output file should be open. bm$inf=2000 ; Input file open (for int. handlers). bm$npo=4000 ; Don't print matching positions. bm$nfi=10000 ; Don't print file names. ifn timerp, ; Print timer. ;;; ---------------------------------------------------------------- poff=6 ; First page. pub=776 ; Last page. The printer may need an extra ; page after this one. If you want to run ; DDT start Search in any of the sections ; 1 through 36 (with the GET command). pspc= ; Page space. ;;; ---------------------------------------------------------------- ;;; The AC's. ;;; Preferable, use AC1 through AC4 for work. At least, don't touch ;;; i, patmax, strmax or p. ch1=5 re1=6 ; Not used explicitly but getc may use it. ch2=7 re2=10 ; Not used explicitly but getc may use it. i=11 j=12 jj=13 k=14 patmax=15 strmax=16 p=17 ;;; **************************************************************** ;;; Data area. ;;; Keyword tables. The second value is address to the parsing routine, ;;; exept in Prntb and Alltb. invtb: kwdtb kwd (Search,$srch) kwdte keytb: kwdtb kwd (Default,$deflt) kwd (Exit,$exit) kwd (Quit,$quit,cm%inv) kwd (S,sea,) sea:! kwd (Search,$srch) kwd (Show,$show) kwdte switb: kwdtb kwd (At-least:,$least) kwd (Case:,$case) kwd (Files:,$files) kwd (Language:,$lang) kwd (Lines:,$lines) outs: kwd (Output:,$outpt) kwd (Positions:,$posit) kwd (Sizes:,$sizes) kwd (Skip-after:,$skip) kwd (Summary:,$summa) ifn timerp, kwdte castb: kwdtb kwd (Insignificant,$insig) kwd (Significant,$signf) kwdte lantb: kwdtb kwd (D47-Swedish,$d47) kwd (E47-Swedish,$e47) kwd (USASCII,$usasc) kwdte prntb: kwdtb kwd (No,0) kwd (Yes,1) kwdte alltb: kwdtb kwd (All,0) kwdte maxpat=^d80 ;;; Command state block. The prompt goes to .nulio from start. csb: cmdsb(,repa,.priin,.nulio,Search>,^d240,maxpat,jfnbl) ;;; GTJFN argument block and some field descriptor blocks. jfnbl: block .gjatr+1 fdqst: flddb.(.cmqst,,,,/FOO/,fdcfm) fdcfm: flddb.(.cmcfm) ;;; ---------------------------------------------------------------- ;;; Interrupt stuff. ctchn=1 cxchn=2 czchn=3 lev1pc: block 1 lev2pc: block 1 levtab: 0,,lev1pc 0,,lev2pc 0,,0 chntab: 0 2,,ctrlt ; 1. Ctrl-T 2,,ctrlx ; 2. Ctrl-X 1,,ctrlz ; 3. Ctrl-Z exp 0,0,0,0,0,0,0,0,0,0,0,0 2,,illmrd ; 16. Illegal Memory Read exp 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ifn timerp, ; Timer value. flags: exp 0 ; Default language offset and flags. lantab: exp point 7,[asciz /USASCII/] ; 0 exp point 7,[asciz /D47-Swedish/] ; 1 exp point 7,[asciz /E47-Swedish/] ; 2 slantb: exp jrst usasc ; 0 exp jrst d47 ; 1 exp jrst e47 ; 2 ccoc: block 2 ; Output Control Word. radix ^d4 ;;; Ctrl-@ABCDEFGHIJKLMNOPQ RSTUVWXYZ tmpcoc: exp <111111111321121111>,<111111111111110000> radix ^d8 outjfn: exp .priou ; Output JFN. jfn: block 1 ; Input file JFN. ofjfn: block 1 ; Output file JFN. szcnt: block 2 ; FDB. Byte size, page and byte count. files: block 1 ; Filesize in ASCII bytes. spos: block 1 ; Accumulated char position. tmplim: block 1 ; Report limit (lower). deflim: exp 1 ; Default report limit. tmpskp: block 1 ; Skip rest of file after this # of occ. defskp: exp 1 ; Default skip. lastpr: exp 0 ; Last printed position. occnt: block 1 ; # of occurrences. srcher: block 1 ; Address to the search-routine. pat: exp point 7,pats str: exp point 7, large: block 1 large1: block 1 pcnt: block 1 ; # of mapped pages (so far). pim: block 1 ; # of currently mapped pages. pdl: block ;;; No::S : < Dir > Name . Type . Gen filen: block <<6+2+6+1+1+^d39+1+^d39+1+^d39+1+6>/5+1> ; Filename. delta0: block 200 ; Room for 7-bit ASCII. delta2: block maxpat pats: block ; The key. defpat: block ; The default key. ;;; ---------------------------------------------------------------- ;;; Case table. castab: c=-1 repeat 141,> ; NUL - ` c=100 repeat 32,> ; a - z is A - Z c=172 repeat 5,> ; { - DEL purge c ;;; **************************************************************** ;;; Character access and test macros. ;;; Get the IN'th character from ST into AC. ST is a bytepointer. define getc (ac,st,in) < move ac,in adjbp ac,st ildb ac,ac ; idivi ac,5 ; ldb ac,[point 7,st(ac),35 ; point 7,st(ac),26 ; point 7,st(ac),17 ; point 7,st(ac),10 ; point 7,st(ac),1](ac+1) > ;;; Compare characters, skip if equal; case is significant. define ccce (c1,c2) < came c1,c2 > ;;; Compare characters, skip if equal; case is NOT significant. define ccne (c1,c2) < came c1,castab(c2) > ;;; ---------------------------------------------------------------- ;;; Macro instructions. ;;; Maximum. define max (ac,e) < camge ac,e move ac,e > ;;; Maximum immediate. define maxi (ac,e) < caige ac,e movei ac,e > ;;; Minimum. define min (ac,e) < camle ac,e move ac,e > ;;; Minimum immediate. define mini (ac,e) < caile ac,e movei ac,e > ;;; ---------------------------------------------------------------- ;;; Filesize macros. ;;; Deposit file page count. define fbpgcm (ac) < hrrm ac,szcnt > ;;; File page count. define fbpgc (ac) < hrrz ac,szcnt > ;;; Number of bytes in file. define fbsiz (ac) < move ac,szcnt+1 > ;;; File byte size. define fbbsz (ac) < move 2,szcnt and 2,[fb%bsz] lsh 2,-30 > ;;; ---------------------------------------------------------------- ;;; Parser macros. define cmerr$ < tdne 1,[cm%nop] jrst perr > define cnfrm$ < call cnfrm jrst perr > define swret$ < trnn bm$def jrst swipar jrst $defswi > ;;; **************************************************************** ;;; This is the string searching procedure and the table making routines. ;;; The algorithm is written by Robert S. Boyer and J. Strother Moore and ;;; was published in the article "A Fast String Searching Algorithm" in ;;; CACM October 1977, Volume 20, Number 10. ;;; ;;; It is very optimized, hairy and, here, totaly free from documentation. ;;; Don't hack in this section unless you're absolutely sure that you think ;;; you know what you are doing! ;;; ---------------------------------------------------------------- ;;; The searching procedure 'Boym' is a macro since one may want routines ;;; with different accessors or comparators. ;;; The macro GETCHR loads the i'th character from str into ch1. ;;; It should be as short *and* fast as possible. ;;; CCC compares the characters and skips if equal (case may or may not ;;; be significant). ;;; The index i should be the index where the search starts ;;; (patmax, not 0, when searching from the beginning). define boym (getchr,ccc,%fast,%f0,%slow) < camle i,strmax ret %fast:! getchr ch1,str,i add i,delta0(ch1) %f0:! camg i,strmax jrst %fast camg i,large ret sub i,large1 move j,patmax sos j %slow:! jumpl j,[aos i tro bm$fnd ret ] getchr ch1,str,i getchr ch2,pat,j ccc ch2,ch1 jrst [ move 1,delta0(ch1) camn 1,large movei 1,0 move 2,delta2(j) max 1,2 add i,1 jrst %f0 ] sos j soja i,%slow > ;;; ---------------------------------------------------------------- ;;; Make table Delta0 except delta0(pat(patmax)):=large which is ;;; done by init. ;;; If case is insignificant the pattern must be in uppercase. mkd0: move 1,patmax aos 1 movei i,177 d0: movem 1,delta0(i) sojge i,d0 setzm i d1: camle i,patmax ret getc ch1,pat,i move k,patmax sub k,i movem k,delta0(ch1) trne bm$cas aoja i,d1 addi ch1,40 caile ch1,177 aoja i,d1 move ch2,castab(ch1) ccce ch1,ch2 movem k,delta0(ch1) aoja i,d1 ;;; Make table Delta2. mkd2: move 1,patmax lsh 1,1 aos 1 push p,1 movei i,1 movem i,delta2(patmax) move j,patmax sos i,j loop1: move jj,j move k,patmax loop2: camg k,i jrst [ jumpl jj,loop3b getc ch1,pat,i getc ch2,pat,jj ccce ch1,ch2 jrst [ move 1,patmax sub 1,jj movem 1,delta2(i) soja i,loop1 ] move 1,(p) sub 1,i movem 1,delta2(i) soja i,loop1 ] jumpl jj,loop3a getc ch1,pat,k getc ch2,pat,jj ccce ch1,ch2 soja j,loop1 sos jj soja k,loop2 loop3a: sub jj,patmax add jj,i loop3b: aos k,i l3: sosge k jrst [ pop p,1 ret ] move 1,patmax sub 1,jj movem 1,delta2(k) soja jj,l3 ;;; ---------------------------------------------------------------- ;;; Here are two searching routines. bmc: boym(getc,ccce) ; Case is significant. bmn: boym(getc,ccne) ; Case is NOT significant. ;;; **************************************************************** ;;; This section contains the framework of the parser and the file- ;;; and memory-management. ;;; Here we go... search: reset% move p,[iowd pdlen,pdl] call setint ; Set up the interrupt system. movei 1,.priou rfcoc% dmovem 2,ccoc ; Save the original output control word. call getdef ; Get defaults. movei 1,.rsini rscan% ercal fatal movei 1,csb ; Init parsing. movei 2,[flddb.(.cmini)] comnd% ercal fatal movei 1,csb movei 2,[flddb.(.cmkey,,invtb)] ; Parse the keyword (Search). comnd% tdnn 1,[cm%nop] ; Was it right? jrst $srch ; Yes. ;; Invoked with Run, Start, Search.exe or something. parse: tro bm$prm ; Prompting now. movem flags setz 1, hrrm 1, ; No .cmcfm alternative to .cmqst. movei 1,.priou hrrm 1,csb+.cmioj ; Let us see the prompt. move 1,[point 7,defpat] ; Set default string. movem 1,fdqst+.cmdef ; (Replace FOO) ;; Prompt. Restore defaultvalues and init. parsing. prompt: call enaint ; Enable interrupt system. call getdef ; Get defaults. call fixdp ; Fix default key. movei 1,csb movei 2,[flddb.(.cmini)] comnd% ; Init. again. ercal fatal repa: movei 1,csb movei 2,[flddb.(.cmkey,,keytb)] ; Parse keywords. comnd% cmerr$ hrrz 2,(2) jrst (2) ; Dispatch. ;;; Keyword Search given. $srch: movei 1,csb movei 2,[flddb.(.cmnoi,,)] comnd% cmerr$ ;; Parse quoted string (and, when not prompting, eol). movei 1,csb movei 2,fdqst comnd% cmerr$ hlrz 1,3 hrrz 2,3 came 1,2 ; Parsed a quoted string? jrst parse ; No, an eol. move 2,pat ; Yes, move it movei 3,csb move 1,.cmabp(3) move 3,.cmabc(3) setz 4, sin% movei 1,csb ; and calculate the length... move 1,.cmabc(1) sub 1,3 sos 1 sos patmax,1 ; minus one. There. ;; Parse filespec. movei 1,csb movei 2,[flddb.(.cmnoi,,)] comnd% cmerr$ move 1,[gj%old!gj%ifg!.gjdef] movem 1, move 1,[point 7,[asciz /*/]] movem 1, movem 1, movei 1,csb movei 2,[flddb.(.cmfil)] comnd% ; Parse a (possibly wild) filespec. cmerr$ movem 2,jfn ; Store the JFN. ;; Parse a switch or eol. swipar: hlrz 1,outs move 2,(1) tdz 2,[cm%inv] ; Turn /output: on. movem 2,(1) movei 1,csb movei 2,[flddb.(.cmswi,,switb,,,fdcfm)] comnd% cmerr$ hrrz 2,(2) hlrz 1,3 hrrz 3,3 camn 1,3 ; Parsed a switch? jrst (2) ; Yes, dispatch. ;; Parsed EOL... jumpl patmax,exit ; An empty pattern. ;; Prepare searching. trnn bm$cas ; Is case significant? call ucase ; No. Uppercase pattern. call mkd0 ; Make tables delta0 and call mkd2 ; delta2. move 1,[jrst bmn] ; Use this searching procedure. trne bm$cas move 1,[jrst bmc] ; No, use this one. Case is significant. movem 1,srcher trne bm$out ; Output to file? call opnojf ; Yes, open it. ;; Init. file. thisf: hrrz 1,jfn ; See if this file is interesting. move 2,[1,,.fbctl] movei 3,3 gtfdb% tdne 3,[fb%nex!fb%del!fb%nxf!fb%dir!fb%bat!fb%off] jrst nextf move 2,[2,,.fbbyv] ; It is. movei 3,szcnt gtfdb% ; Get the size. fbpgc 1 fbsiz 2 skipn 1 jumpe 2,nextf ; Page count and byte count zero. call ofil ; Open the file. ;; Prepare the first scan. fbpgc 3 ; # of pages in file. mini 3,pspc movem 3,pcnt movem 3,pim hrlz 1,jfn ; From file, page 0. move 2,[.fhslf,,poff] ; To process, page poff hll 3,[pm%cnt!pm%rd] pmap% setzm spos setzm occnt setzm lastpr ; Last printed position. move i,patmax ; Start position for search. ifn timerp,< movei 1,.fhslf runtm% ; Start time. movem 1,timer > ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - grp0: call init call srcher ; Search. trzn bm$fnd ; Found? jrst [ move 1,tmplim ; No. camle 1,occnt jrst mapr trnn bm$fnp call pfilen jrst mapr ] aos occnt ; Found. move 1,tmplim camle 1,occnt ; If less than tmplim matches... jrst grp1 ; don't print. trnn bm$fnp ; File name yet printed? call pfilen ; No. Print it. trnn bm$nmt ; Print matching line? call printm ; Yes. grp1: trnn bm$skp ; Skipping? jrst grp2 ; No. move 1,tmpskp camg 1,occnt ; If more than tmpskp matches... jrst clsf ; skip this file. grp2: add i,patmax ; Next start position-1. aoja i,grp0 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;;; Here if the search failed. mapr: ;; Map pages starting at poff. fbpgc 3 ; # of pages in file. camg 3,pcnt ; Mapped the last page? jrst clsf ; Yes. sub 3,pcnt ; # of pages not yet mapped. aos 3 mini 3,pspc movem 3,pim ; # of pages now (soon) mapped. hll 3,[pm%cnt!pm%rd] move 2,[.fhslf,,poff] sos 1,pcnt ; Map next page hrl 1,jfn ; from file. pmap% hrli 3,0 addm 3,pcnt ; # of searched pages. move 1,[pspc*5000] addm 1,spos sub i,[*5000] ; Start position for next search. move 1,lastpr ; Adjust last printed position. sub 1,[*5000] movem 1,lastpr jrst grp0 ; Search the next section. ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - clsf: ;; Unmap pspc+1 pages starting with poff. seto 1, move 2,[.fhslf,,poff] move 3,[pm%cnt!] pmap% move 1,tmplim camle 1,occnt jrst clsf0 trnn bm$cnt ; Print # of matches? call prcnt ; Yes. clsf0: trz bm$inf hrrz 1,jfn ; Close the file. hll 1,[co%nrj] closf% ercal fatal nextf: trz bm$fnp move 1,jfn gnjfn% ; Get the next one. jrst exit ; Wasn't any. jrst thisf exit: trze bm$out ; An open output file? call clsojf ; Yes, close it. ifn timerp,< movei 1,.fhslf runtm% ; Stop time. subm 1,timer trne bm$tim ; Print timer? call prtim ; Yes. > trne bm$prm ; Prompting? jrst prompt ; Yes. stopp: call disint haltf% jrst parse ;;; **************************************************************** ;;; Parser routines. ;;; The parser is 'flat' (jrst everywhere). A routine can end in one of ;;; three different ways: ;;; Dispatch to the next field, ;;; jrst to Prompt when EOL is parsed ;;; or jrst to the switch parser with swret$, which knows where to go. $least: movei 1,csb movei 2,[flddb.(.cmnum,,^d10,,1)] comnd% cmerr$ movem 2,tmplim swret$ $case: movei 1,csb movei 2,[flddb.(.cmkey,cm%dpp,castb,,insignificant)] comnd% cmerr$ hrrz 2,(2) jrst (2) ; Dispatch. $signf: troa bm$cas $insig: trz bm$cas swret$ $lang: movei 1,csb movei 2,[flddb.(.cmkey,cm%dpp,lantb,,USASCII)] comnd% cmerr$ hrrz 2,(2) jrst (2) ; Dispatch. $usasc: trz bm$cas hrli 0 call usasc swret$ $e47: hrli 2 call e47 jrst $swed $d47: hrli 1 call d47 $swed: trz bm$cas swret$ ;;; Parse switches for default settings. $deflt: movei 1,csb movei 2,[flddb.(.cmnoi,,)] comnd% cmerr$ tro bm$def hlrz 1,outs move 2,(1) tdo 2,[cm%inv] ; Turn /output: off. movem 2,(1) $defsw: movei 1,csb movei 2,[flddb.(.cmswi,,switb,,,fdcfm)] comnd% cmerr$ hrrz 2,(2) ; Prepare dispatching. hlrz 1,3 hrrz 3,3 camn 1,3 ; Parsed a switch? jrst (2) ; Yes, dispatch. trz bm$def movem flags ; New default flags. move 1,tmpskp ; New skip limit. movem 1,defskp move 1,tmplim ; New default report limit. movem 1,deflim jrst prompt $outpt: movei 1,csb movei 2,[flddb.(.cmofi)] comnd% cmerr$ tro bm$out movem 2,ofjfn swret$ $summa: movei 1,csb movei 2,[flddb.(.cmkey,cm%dpp,prntb,,yes)] comnd% cmerr$ hrrz 2,(2) skipn 2 troa bm$cnt trz bm$cnt swret$ $files: movei 1,csb movei 2,[flddb.(.cmkey,cm%dpp,prntb,,yes)] comnd% cmerr$ hrrz 2,(2) skipn 2 troa bm$nfi trz bm$nfi swret$ $lines: movei 1,csb movei 2,[flddb.(.cmkey,cm%dpp,prntb,,yes)] comnd% cmerr$ hrrz 2,(2) skipn 2 troa bm$nmt trz bm$nmt swret$ $posit: movei 1,csb movei 2,[flddb.(.cmkey,cm%dpp,prntb,,yes)] comnd% cmerr$ hrrz 2,(2) skipn 2 troa bm$npo trz bm$npo swret$ $sizes: movei 1,csb movei 2,[flddb.(.cmkey,cm%dpp,prntb,,no)] comnd% cmerr$ hrrz 2,(2) skipn 2 trza bm$pgc tro bm$pgc swret$ $skip: movei 1,csb movei 2,[flddb.(.cmnum,,^d10,,all,[flddb.(.cmkey,,alltb)])] comnd% cmerr$ hlrz 1,3 hrrz 3,3 camn 1,3 ; Parsed a number? troa bm$skp ; Yes. trza bm$skp ; No, keyword All. movem 2,tmpskp swret$ $show: movei 1,csb movei 2,[flddb.(.cmnoi,,)] comnd% cmerr$ cnfrm$ hrroi 1,[asciz \Default /At-least:\] psout% movei 1,.priou move 2,deflim move 3,[no%mag!fld(^d10,no%rdx)] nout% ercal fatal hrroi 1,[asciz \ /Case:\] psout% hrroi 1,[asciz \Insignificant\] trne bm$cas hrroi 1,[asciz \Significant\] psout% hrroi 1,[asciz \ /Files:\] psout% hrroi 1,[asciz \Yes\] trne bm$nfi hrroi 1,[asciz \No\] psout% hrroi 1,[asciz \ /Language:\] psout% hlrz 1,0 move 1,lantab(1) psout% hrroi 1,[asciz \ /Lines:\] psout% hrroi 1,[asciz \Yes\] trne bm$nmt hrroi 1,[asciz \No\] psout% hrroi 1,[asciz \ /Positions:\] psout% hrroi 1,[asciz \Yes\] trne bm$npo hrroi 1,[asciz \No\] psout% hrroi 1,[asciz \ /Sizes:\] psout% hrroi 1,[asciz \Yes\] trnn bm$pgc hrroi 1,[asciz \No\] psout% hrroi 1,[asciz \ /Skip-after:\] psout% trne bm$skp jrst [ movei 1,.priou move 2,defskp move 3,[no%mag!fld(^d10,no%rdx)] nout% ercal fatal jrst $sh0 ] hrroi 1,[asciz \All\] psout% $sh0: hrroi 1,[asciz \ /Summary:\] psout% hrroi 1,[asciz \Yes\] trne bm$cnt hrroi 1,[asciz \No\] psout% ifn timerp,< hrroi 1,[asciz \ /Timer:\] psout% hrroi 1,[asciz \Yes\] trnn bm$tim hrroi 1,[asciz \No\] psout% > jrst prompt ifn timerp,< $timer: movei 1,csb movei 2,[flddb.(.cmkey,cm%dpp,prntb,,no)] comnd% cmerr$ hrrz 2,(2) skipn 2 trza bm$tim tro bm$tim swret$ > ;;; Exit or quit command given. $exit: $quit: cnfrm$ ; Parse eol... jrst stopp ; and halt. ;;; Parse EOL. Return +1 if error occurred, +2 otherwise. cnfrm: movei 1,csb movei 2,fdcfm comnd% tdnn 1,[cm%nop] aos (p) ret ;;; Parse error. perr: call error trne bm$prm jrst prompt haltf% ; Not prompting. jrst .-1 ;;; **************************************************************** ;;; Odds and ends. ;;; Intialize strmax,large,large1 and delta0(pat(patmax)). ;;; If case is insignificant the pattern must be in uppercase. ;;; Note that Large and Large1 is adjusted for origo zero which ;;; differs from the article. init: fbpgc 1 move 2,pcnt came 1,2 ; Mapped the last page yet? jrst [ move 1,[pspc*5000] jrst i0 ] sub 2,pim ; Total # of pages - # of searched pages. imuli 2,5000 ; # of searched ASCII bytes. move 1,files sub 1,2 ; # of bytes currently in map. i0: sos strmax,1 add 1,patmax aos 1 getc ch1,pat,patmax movem 1,delta0(ch1) ; Large here... movem 1,large ; and here... aos 1 movem 1,large1 ; and plus one here. trne bm$cas ret addi ch1,40 ; Case's insignificant so we must caile ch1,177 ; set the entry for ch1's lowercase ret ; mate to large as well. sos 1 move ch2,castab(ch1) ccce ch1,ch2 movem 1,delta0(ch1) ret ;;; ---------------------------------------------------------------- getdef: move flags ; Default language and flags. move 1,defskp ; Default skip value. movem 1,tmpskp move 1,deflim ; Default report limit. movem 1,tmplim hlrz 1,flags ; Get default language call slantb(1) ; and set up lantab. ret ;;; ---------------------------------------------------------------- ;;; Copy the key to the default buffer with every '"' doubled and ;;; wrap it up in '"'s with a trailing NULL. fixdp: move 1,pat move 2,[point 7,defpat] movei 4,42 ; Leading ". idpb 4,2 fixdp0: ildb 3,1 skipn 3 jrst fixdp1 cain 3,42 ; "? idpb 3,2 ; Double ". idpb 3,2 jrst fixdp0 fixdp1: idpb 4,2 ; Trailing ". idpb 3,2 ; NULL. ret ;;; ---------------------------------------------------------------- ;;; Castab in USASCII mode. usasc: movei 1,"`" movem 1,castab+"`" movei 1,"{" movem 1,castab+"{" movei 1,"|" movem 1,castab+"|" movei 1,"}" movem 1,castab+"}" movei 1,"~" movem 1,castab+"~" ret ;;; Castab in Swedish mode. e47: movei 1,"@" movem 1,castab+"`" movei 1,"^" movem 1,castab+"~" d47: movei 1,"[" movem 1,castab+"{" movei 1,"\" movem 1,castab+"|" movei 1,"]" movem 1,castab+"}" ret ;;; Uppercase pattern. ucase: move 1,pat move 2,patmax uc0: ildb 3,1 move 3,castab(3) dpb 3,1 sojge 2,uc0 ret ;;; ---------------------------------------------------------------- ;;; Open a file and find out some things about it. ;;; ;;; What's the size of a file in TOPS-20? ;;; There are three parameters specifying the file size: ;;; Page count, byte count and byte size. ;;; Anyone with write access can change the byte count and size, while ;;; changing the page count requires privileges. ;;; The following heuristics are used to determine the number of pages ;;; and (7-bit) bytes in a file: ;;; 1) If the page count *and* the byte count is zero the file is empty. ;;; (This is tested in the routine 'thisf' above.) ;;; 2) If the byte count is zero the page count is the size of the file. ;;; 3) If the page count is *not* zero and the byte count puts the end- ;;; of-file in the last page they both are assumed to be correct. ;;; 4) If the page count and byte count doesn't match, the page count ;;; is assumed to be correct. ;;; 5) With one exception: When the page count is zero the byte count ;;; is assumed to be correct (for active batch logs). ;;; ofil: hrrz 1,jfn move 2,[fld(7,of%bsz)!of%her!of%rd!of%pdt!of%nwt!of%pln!of%dud] openf% jrst [ call warn ; Don't crash if read protected or tro bm$inf ; something like that. jrst ctrlx ] ; Just skip it. tro bm$inf fbsiz 1 jumpe 1,[ fbpgc 1 ; Byte count=0. lsh 1,^d9 imuli 1,5 movem 1,files ; Use .fbsiz*1000*5 as filesize. ret ] ;; Byte count<>0, scale it to 7-bit bytes. fbbsz 2 cain 2,7 jrst [ fbsiz 2 ; Byte size=7. movem 2,files idivi 2,5 ; ASCII factor. jumpe 3,ofil0 ; # of words in AC2. aoja 2,ofil0 ] ;; Byte size<>7. movei 1,^d36 idiv 1,2 ; Factor in AC1. fbsiz 2 idiv 2,1 skipe 3 ; # of words in AC2. aos 2 move 3,2 imuli 3,5 ; ASCII factor. movem 3,files ; File length in ASCII bytes. ofil0: idivi 2,1000 ; # of pages covered by .fbsiz . skipe 3 aos 2 fbpgc 1 camn 1,2 ; EOF in last page. ret ; Yes. ;; Page count and byte count doesn't match. jumpe 1,[ fbpgcm 2 ; Page count=0, use byte count. ret ] ;; Page count<>0. lsh 1,^d9 ; Use the page count times 1000 as movem 1,files ; 'true' file size. ret ;;; ---------------------------------------------------------------- ;;; Open output file in append mode. It is normally a new file but if ;;; the user may concatenate the consequent searches into the same file. opnojf: move 1,ofjfn move 2,[fld(7,of%bsz)!of%app!of%nwt] openf% ercal fatal movem 1,outjfn ; Use this for output from now. ret ;;; Close output file. clsojf: move 1,ofjfn closf% ercal fatal movei 1,.priou ; Use primary output for output from now. movem 1,outjfn ret ;;; **************************************************************** ;;; The printing routines. ;;; Print the match. Position in I. printm: camge i,lastpr ; Printed this position before? ret ; Yes. trne bm$npos ; Don't print positions. jrst pm00 move 1,outjfn move 2,i add 2,spos move 3,[no%mag!no%ast!fld(^d10,no%rdx)] nout% ercal fatal move 1,outjfn movei 2,":" bout% ;; Scan the preceding 80 characters for a CRLF. pm00: move 1,i move 2,i subi 2,^d79 add 2,patmax skipge 2 setz 2, sos 1 pm0: camge 1,2 jrst 1,pm1 getc 3,str,1 caie 3,.chlfd ; LF? soja 1,pm0 ; No. sos 1 ; Yes. getc 3,str,1 caie 3,.chcrt ; CR? jrst pm0 ; No. aos 1 ; Yes. pm1: aos 1 push p,1 ;; Check if we have to map the next page. move 2,patmax maxi 2,^d79 add 2,i camle 2,strmax ; May the line reach beyond string end? call [ fbpgc 1 ; Yes. camg 1,pcnt ; In files last page? ret ; Yes. push p,2 ; No. Map the next page. move 1,pcnt hrl 1,jfn move 2,[.fhslf,,pub+1] move 3,[pm%cnt!pm%rd!1] pmap% pop p,2 ret ] ;; Scan the next 80 characters for a CRLF. move 1,i add 1,patmax aos 1 pm2: caml 1,2 jrst pm3 getc 3,str,1 caie 3,.chcrt ; CR? aoja 1,pm2 ; No. aos 1 getc 3,str,1 ; Yes. caie 3,.chlfd ; LF? jrst pm2 ; No. sos 1 pm3: push p,1 ;; Use the temporary output ctrl word. movei 1,.priou dmove 2,tmpcoc sfcoc% ;; Print a line. pop p,3 ; End. movem 3,lastpr ; Last printed pos. pop p,4 ; Start. move 2,4 subm 4,3 ; - (End - Start) move 1,outjfn adjbp 2,str sout% ;; Restore the original output ctrl word. movei 1,.priou dmove 2,ccoc sfcoc% call crlf ret ;;; Print the filename. pfilen: trne bm$nfi ret ; Don't print file names. call crlf move 1,outjfn movei 2,.chtab bout% call pfile ; Dest. desig. in AC1. trne bm$pgc ; Print page count? call ppgc ; Yes. tro bm$fnp ; Filename is printed. call crlf ret ;;; Print the files page count. ppgc: hrrz 1,jfn ; Get the real page count, the one in move 2,[1,,.fbbyv] ; szcnt may be different. movei 3,3 gtfdb% hrrz 2,3 move 1,outjfn move 3,[no%mag!no%lfl!no%ast!fld(^d10,no%col)!fld(^d10,no%rdx)] nout% ercal fatal ret ;;; Print the number of occurrences. prcnt: move 1,outjfn move 2,occnt move 3,[no%mag!no%lfl!no%ast!fld(^d10,no%col)!fld(^d10,no%rdx)] nout% ercal fatal move 3,2 move 2,[point 7,[asciz / occurrences /]] cain 3,1 move 2,[point 7,[asciz / occurrence /]] setz 3, sout% ret ifn timerp,< ;;; Print the timer value. prtim: call crlf move 1,outjfn move 2,[point 7,[asciz \Time: \]] setz 3, sout% move 2,timer move 3,[no%mag!fld(^d10,no%rdx)] nout% ercal fatal hrroi 1,[asciz / ms/] psout% ret > ;;; Print the file name. Dest. desig. in AC1. pfile: push p,1 ; Save dest. move 1,[point 7,filen] hrrz 2,jfn move 3,[fld(.jsssd,js%dev)!fld(.jsssd,js%dir)!fld(.jsaof,js%nam)!fld(.jsaof,js%typ)!fld(.jsaof,js%gen)!js%tmp!js%paf] jfns% pop p,1 ; Get dest. move 2,[point 7,filen] setz 3, sout% ret ;;; Print a CRLF. crlf: move 1,outjfn movei 2,.chcrt bout% movei 2,.chlfd bout% ret ;;; Set up the interrupt system (but do not assign terminal codes). setint: movei 1,.fhslf move 2,[levtab,,chntab] sir% ; Set up the interrupt system. eir% ; Enable it. move 2,[1b+1b+1b+1b<.icird>] aic% move 1,[.ticct,,ctchn] ati% move 1,[.ticcx,,cxchn] ati% move 1,[.ticcz,,czchn] ati% ret ;;; Enable interrupt system. enaint: cis% movei 1,.fhslf eir% ret ;;; Disabel interrupt system. disint: movei 1,.fhslf dir% cis% ret ;;; Ctrl-T handler. Prints something like : ;;; 87-06-17 SEARCHing PS:FOO.TXT.42 in page 666, Load 3.21 ctrlt: push p,1 push p,2 push p,3 movei 1,.cttrm movei 2,.chspc bout% ;; Print current time. movei 1,.cttrm seto 2, move 3,[ot%nda] odtim% hrroi 2,[asciz / SEARCHing /] setz 3, sout% trnn bm$inf ; Inputfile open? jrst [ hrroi 2,[asciz /for /] ; No. sout% move 2,[point 7,pats] sout% jrst ctrlt0 ] ;; Print filename. movei 1,.cttrm call pfile ;; Print current page number. movei 1,.cttrm hrroi 2,[asciz / in page /] setz 3, sout% move 2,spos ; Accumulated count add 2,i ; plus current idivi 2,<5*777> ; div #bytes per page aos 2 ; plus 1. movei 1,.cttrm move 3,[no%mag!no%ast!fld(^d10,no%rdx)] nout% ercal fatal ;; Print 1 min load avarage. ctrlt0: hrroi 2,[asciz /, Load /] setz 3, sout% move 1,[14,,.systa] ; Get 1-min load av. getab% ercal fatal move 2,1 movei 1,.cttrm move 3,[fld(.flspc,fl%sgn)!fld(.fllsp,fl%jus)!fl%one!fl%pnt!fld(.flexn,fl%exp)!fl%ovl!fld(3,fl%fst)!fld(2,fl%snd)] flout% ercal fatal hrroi 2,[asciz / /] setz 3, sout% pop p,3 pop p,2 pop p,1 debrk% ercal fatal ;;; Ctrl-X handler. Skip current file. ctrlx: trnn bm$inf debrk% movei 1,.cttrm hrroi 2,[asciz / [Skipping /] setz 3, sout% call pfile ; Dest. desig. in AC1. movei 1,.cttrm hrroi 2,[asciz /] /] setz 3, sout% move p,[iowd pdlen,pdl] ; Reset the stack. seto 1, move 2,[.fhslf,,poff] move 3,[pm%cnt!] pmap% ; Unmap the file. trz bm$inf move 1,[co%nrj] hrr 1,jfn closf% ; Close the searched file. nop ; Ignore errors. cis% ; Clear system. jrst nextf ; Next file. ;;; Ctrl-Z handler. Abort current search. ctrlz: movei 1,.cttrm hrroi 2,[asciz / [Aborting...] /] setz 3, sout% move p,[iowd pdlen,pdl] ; Reset the stack. seto 1, move 2,[.fhslf,,poff] move 3,[pm%cnt!] pmap% ; Unmap the file. trz bm$out!bm$inf ; No open files. move 1,[cz%abt!cz%nud!.fhslf] ; Abort output, no update. clzff% ; Close all files. cis% ; Clear system. jrst exit ; Exit. ;;; Illegal Memory Read handler. illmrd: trnn bm$inf debrk% movei 1,.cttrm hrroi 2,[asciz /%Holes in file/] setz 3, sout% jrst ctrlx ;;; **************************************************************** end search .../PEM