; ---------------------------------------------------------- ; Reassembly of FIND.COM, which was originally extracted ; from the CBBS(R) package available from Ward Christensen ; and Randy Suess. However, considerable rearrangement has ; taken place, most notably the following: ; - results in a screen of information ; - the search pattern may be a regular expression ; - instance count reported, both per file and globally ; To achieve compatibility with MicroShell the vertical bar ; was replaced by exclamation point; all syntactic elements ; are defined by EQU's and may be redefined. LABEL!PATTERN ; is checked for balanced parentheses and non-null arguments ; to forestall the most common failure modes. Had MicroShell ; not been available, an option to direct the output to some ; disk file would probably have been included. STUTE.ASM ; differs from FIND in that the patterns found are replaced ; by a constant rather than just being located. ; ; STUTE.ASM Copyright (C) 1983 ; Universidad Autonoma de Puebla ; ; [Harold V. McIntosh, 28 February 1983] ; ---------------------------------------------------------- HT equ 09H ;horizontal tab LF equ 0AH ;line feed CR equ 0DH ;carriage return KZ equ 1AH ;^Z ; Delimiters for the command line LSQ equ '[' ;begin alternative list RSQ equ ']' ;end alternative list LBR equ '{' ;begin iterated expression RBR equ '}' ;end iterated expression ORR equ '!' ;separate alternatives ; Representatives of characters or classes. TAB equ '_' ;substitute for tab QUE equ '?' ;represent any byte ALF equ '@' ;represent any alphanumeric ; CPM locations and parameters cfcb equ 005CH ;CP/M's file control block cblk equ 007CH ;CP/M's block counter csiz equ 0080H ;CP/M's record size cbuf equ 0080H ;CP/M's record buffer ksiz equ 26 ;sector capacity of IN buffer isiz equ ksiz*128 osiz equ 128 ; ------------- org 0100H ; ------------- begn: lxi h,0000 dad sp shld stak lxi sp,stak lda cfcb+1 ;file name cpi ' ' jnz X0143 lxi h,tuto ;tutorial message call mssg jmp gbye X0143: lxi h,logo ;identification line call mssg mvi c,12 lxi d,cfcb ;CP/M's FCB lxi h,file ;generic filename call miuc lda file ;generic filename sta kfil ;backup file (.BAK) sta ifil ;input file (.EXT) sta ofil ;output file (.$$$) sta ufil ;active output (.$$$) xra a sta enth lxi h,cbuf ;CP/M's record buffer mov e,m mov c,e mov d,a xchg inx d dad d mov m,a xchg X0152: inx h dcr c mov a,m ora a jz X029C cpi ' ' jnz X0152 inx h call bala ;check balance of [], {}. call nula ;check for null alternatives lxi d,patt ;command line pattern call muve xchg dcx h shld sund mvi c,4 lxi d,lzer lxi h,dtot call miuc lxi h,patt ;command line pattern shld papo call next shld supo ;substitute pointer ; Scan the directory for file names. prep: xra a inr a sta dctr ;directory counter lxi h,diry ;directory extract shld dptr ;directory pointer push h mvi c,26 ;(1A) set DMA address lxi d,cbuf ;CP/M's record buffer call 0005 ; - B D O S - mvi c,17 ;(11) search once lxi d,file ;generic filename call 0005 ; - B D O S - fnth: pop h inr a jz scan ;all relevant files located push h dcr a ani 03 add a add a add a add a add a adi 81H mov e,a mvi d,00 lxi h,8 dad d push h mov a,m cpi 'B' jnz nbak inx h mov a,m cpi 'A' jnz nbak inx h mov a,m cpi 'K' pop h jz omit jmp nbac nbak: pop h nbac: mvi a,'$' cmp m jnz ndol inx h cmp m jnz ndol inx h cmp m jz omit ndol: mvi c,12 pop h call miuc push h lxi h,dctr ;directory counter inr m omit: mvi c,18 ;(12) search again lxi d,file ;generic filename call 0005 ; - B D O S - jmp fnth ; We're all done. done: lxi h,dtot call mssg gbye: lhld stak sphl ret ; A prospective file has been located scan: lxi h,dctr dcr m jz done lhld dptr xchg lxi h,12 dad d shld dptr push d mvi c,8 pop d push d lxi h,kfil+1 ;backup file (.BAK) call miuc mvi c,11 pop d push d lxi h,ifil+1 ;input file (.EXT) call miuc mvi c,8 pop d push d lxi h,ofil+1 ;output file (.$$$) call miuc mvi c,8 pop d push d lxi h,ufil+1 ;active output (.$$$) call miuc mvi c,12 pop d lxi h,cfcb+1 ;CP/M's file control block call miuc mvi c,19 ;(13) delete file lxi d,kfil ;backup file (.BAK) call 0005 ; - B D O S - mvi c,19 ;(13) delete file lxi d,ofil ;output file (.$$$) call 0005 ; - B D O S - mvi c,22 ;(16) create file lxi d,ufil ;active output (.$$$) call 0005 ; - B D O S - mvi a,00 sta urec mvi c,15 ;(0F) open file lxi d,cfcb ;CP/M's FCB call 0005 ; - B D O S - inr a jz gbye ;quit [without message] xra a sta cblk ;block pointer mvi c,4 lxi d,lzer lxi h,lnum ;'line number' call miuc mvi c,4 lxi d,lzer lxi h,ftot ;'file total' call miuc mvi c,8 lxi d,cfcb+1 ;file name lxi h,fnam ;'file name' call miuc mvi c,3 lxi d,0065H ;extension lxi h,fext ;'file extension' call miuc lxi h,fhed call mssg ;message to console lxi b,2006H ;six spaces lxi h,llbl call fiuc ;fill until count X01C2: lxi h,0000 shld ictr lxi h,0080H shld octr lxi h,ubuf shld optr X01C8: lxi h,lnum+3 ;increment l.c. call inco ;increment line counter lxi h,lbuf ;line buffer mvi b,0FFH X01E0: inr b jm X01FD push b push h call inch ;char from big bffr to line bffr pop h pop b mov m,a inx h cpi KZ jnz X01E8 lxi h,ftot call mssg ; Close out last, incomplete record. lare: lhld octr mov a,h ora l jz clof mvi a,1AH call ouch jmp lare clof: mvi c,21 ;(15) write one record lxi d,ufil ;active output (.$$$) call 0005 ; - B D O S - mvi c,16 ;(10) close file lxi d,ufil ;active output (.$$$) call 0005 ; - B D O S - mvi c,23 ;(17) rename file lxi d,ifil ;input file (.EXT) call 0005 ; - B D O S - mvi c,23 ;(17) rename file lxi d,ofil ;output file (.$$$) call 0005 ; - B D O S - jmp scan X01E8: cpi LF jnz X01E0 jmp X0202 X01FD: mvi m,CR inx h mvi m,LF inx h ; Check console for termination request. If one ; is present, clear it out before leaving. X0202: mvi m,00 ;guarantee right hand fence mvi c,11 ;(0B) console status call 0005 ; - B D O S - ora a jz culi mvi c,1 ;(01) read console call 0005 ; - B D O S - lxi h,M4 ;"search terminated" call mssg jmp gbye ; Scan the current line. culi: lxi h,lbuf ;line buffer shld alfa shld beta X021A: lhld papo ;substitute pointer xchg lhld beta mov a,m cpi CR jz nuli call chek jnz fail push d push h lxi h,llbl call mssg lxi h,lbuf call mssg lxi h,ftot+3 call inco lxi h,dtot+3 call inco lhld beta xchg lhld alfa call ouli lhld sund xchg lhld supo call ouli pop h shld alfa dcx h shld beta pop d fail: lhld beta inx h shld beta jmp X021A nuli: lhld beta inx h inx h xchg lhld alfa call ouli jmp X01C8 ;increment l.c. at X026A ; Increment ASCII counter at (HL-3). inco: mov a,m ori 30H inr a mov m,a cpi ':' rnz mvi m,'0' dcx h jmp inco ; Memory to console mssg: mov e,m inx h push h mvi c,2 ;(02) write console call 0005 ; - B D O S - pop h mov a,m ora a jnz mssg ret X029C: lxi h,M3 ;"bad pattern" call mssg jmp gbye inch: lhld ictr mov a,h ora l cz indi ;disk to IN area lhld ictr dcx h shld ictr lhld iptr mov a,m cpi KZ rz inx h shld iptr ret indi: mvi b,ksiz lxi h,isiz shld ictr lxi h,ibuf shld iptr indd: mvi m,KZ push h push b xchg mvi c,26 ;(1A) set DMA address call 0005 ; - B D O S - lxi d,cfcb ;CP/M's file control block mvi c,20 ;(14) read one record call 0005 ; - B D O S - pop b pop h ora a rnz dcr b rz lxi d,csiz ;CP/M's record size dad d jmp indd ; Send a "line" [(HL) to (DE)] to out file ouli: mov a,e sub l mov c,a mov a,d sbb h mov b,a oulj: mov a,b ora c rz mov a,m call ouch dcx b inx h jmp oulj ; Send one character to the output file, conserve BC, HL ouch: push b push h push psw lhld octr mov a,h ora l cz oudi ;OUT area to disk lhld octr dcx h shld octr pop psw lhld optr mov m,a inx h shld optr pop h pop b ret oudi: lxi h,osiz shld octr lxi h,ubuf shld optr xchg mvi c,26 ;(1A) set DMA address call 0005 ; - B D O S - lxi d,ufil ;active output (.$$$) mvi c,21 ;(15) write one record call 0005 ; - B D O S - ora a ret ; Advance to next alternative nexx: mov e,m inx h mov d,m xchg next: mov a,m ora a rz inx h call enda rz call begb jz nexx jmp next ; Fill (with B) until count (C). fiuc: mov m,b inx h dcr c jnz fiuc ret miuc: ldax d mov m,a inx d inx h dcr c jnz miuc ret ; Move and semi-compile the command line. muve: mov a,m cpi TAB jnz munt mvi a,HT munt: stax d inx h inx d cpi RBR jz murb cpi RSQ jz murb cpi LBR jz mulb cpi LSQ jz mulb must: dcr c jnz muve ret murb: xthl mov m,e inx h mov m,d pop h jmp must mulb: push d inx d inx d jmp must ; Check balance of []'s and {}'s. bala: push h push b lxi b,0101H balb: mov a,m inx h cpi LSQ jnz balc inr b jmp balb balc: cpi RSQ jnz bald dcr b jz balx jmp balb bald: cpi LBR jnz bale inr c jmp balb bale: cpi RBR jnz balf dcr c jz balx jmp balb balf: ora a jnz balb mov a,c cpi 01 jnz balx mov a,b cpi 01 pop b pop h rz balx: lxi h,M3 ;"bad pattern" call mssg jmp gbye ;PDL unbalanced but doesn't matter ; Check for termination of alternative. enda: cpi ORR rz endb: cpi RSQ rz cpi RBR rz ora a ret ; Check for beginning of alternative. bega: cpi ORR rz begb: cpi LSQ rz cpi LBR ret ; Check for null alternative. nula: push h call nulb pop h ret nulb: mov a,m inx h ora a rz call bega jnz nulb mov a,m call enda jnz nulb jmp balx ; Check for given expression. chek: ldax d inx d call enda rz mov b,a mov a,m cpi CR jz chno mov a,b cpi LBR jz chlb cpi LSQ jz chsq mov c,m inx h cpi QUE jz chek cpi ALF jz chal cmp c jz chek mov b,a mov a,c cpi 'a' jc chno cpi '{' jnc chno ani 05FH cmp b jz chek chno: ori 0FFH ret ; Check alphanumeric. chal: mov a,c cpi '0' jc chno cpi ':' jc chek cpi 'A' jc chno cpi '[' jc chek cpi 'a' jc chno cpi '{' jc chek jmp chno ; Check list of alternatives. chsq: mov c,l mov b,h lhld sqxx push h lhld sqaa push h lhld sqzz push h mov l,c mov h,b shld sqxx xchg mov e,m inx h mov d,m inx h shld sqaa xchg shld sqzz chaa: lhld sqxx call chek jz chff chbb: lhld sqaa ;fail so find next alternative chcc: call next cpi RSQ jz chdd ;no more alternatives, so fail cpi ORR jnz chcc shld sqaa xchg jmp chaa ;try next alternative chdd: lhld sqxx ori 0FFH chee: mov c,l mov b,h pop h shld sqzz pop h shld sqaa pop h shld sqxx mov l,c mov h,b ret chff: xchg ;good alternative, try rest lhld sqzz xchg call chek jz chee jmp chbb ; Check iterative pattern. chlb: mov c,l mov b,h lhld text push h lhld texx push h lhld rest push h lhld rept push h lhld repp push h mov l,c mov h,b shld text shld texx xchg mov e,m inx h mov d,m inx h shld rept shld repp xchg shld rest chlc: lhld rest xchg lhld text call chek ;check rest jz chzz chii: lhld rept ;rest failed xchg lhld text ;keep same text call chek ;try out the repeater jnz choo shld text ;repeater worked, record progress lhld repp ;start alternatives over again shld rept jmp chlc choo: lhld rept ;repeater failed, try next chxx: call next cpi RBR jz chyy ;this was the last, quit cpi ORR jnz chxx shld rept jmp chii chyy: lhld texx ori 00 ;emphasize the RBR chzz: mov c,l mov b,h pop h shld repp pop h shld rept pop h shld rest pop h shld texx pop h shld text mov l,c mov h,b ret tuto: db 'The command line',CR,LF db ' STUTE D:FILE.EXT PATTERN!SKELETON',CR,LF db 'will search through all instances of FILE.EXT',CR,LF db '(which may be an ambiguous reference) on disk D',CR,LF db 'to find lines containing PATTERN. Such lines will',CR,LF db 'be shown on the console preceded by a line number,',CR,LF db 'classified by file. Whenever the regular expression',CR,LF db 'PATTERN is found, it will be replaced by the constant',CR,LF db 'SKELETON. The PATTERN may contain:',CR,LF db ' [p1!p2!...!pn] alternative strings',CR,LF db ' {p1!p2!...!pn} repeated alternatives',CR,LF db ' ? any single character',CR,LF db ' @ for any alphanumeric: a-z, A-Z, 0-9',CR,LF db ' _ in place of horizontal tab',CR,LF db 'A general PATTERN must be used with extreme caution',CR,LF db 'because the same constant will replace it, whatever',CR,LF db 'its form. The PATTERN may not involve more than one',CR,LF db 'single line, but more than one instance of the PATTERN',CR,LF db 'may occupy the same line.',CR,LF db 00 logo: db 'STUTE.COM 28/FEB/83 ICUAP',CR,LF,00 M3: db '-- Bad Pattern --',00 M4: db CR,LF,'-- Substitution Terminated --',00 ; The following file control segments are arranged in just ; the form shown so that they will be properly paired for ; the renaming which has to be done after closing each file. enth: ds 1 file: db 'DFilenameEXT',00,00,00,00 ;generic filename ds 16 ofil: db 'DFilename$$$',00,00,00,00 ;output file (.$$$) ifil: db 'DFilenameEXT',00,00,00,00 ;input file (.EXT) kfil: db 'DFilenameBAK',00,00,00,00 ;backup file (.BAK) ufil: db 'Dfilename$$$',00,00,00,00 ;active output (.$$$) ds 16 urec: ds 1 ubuf: ds 80H optr: ds 2 octr: ds 2 ; All the relevant files are located and noted before any ; substitutions are made, to avoid a newly created file ; being placed in the dictionary, being encountered again ; later on and then being processed a second time. The worst ; case would be to have to use all 64 files (minus one, for ; elbow room) in the directory. dctr: ds 1 ;directory counter dptr: ds 2 ;directory pointer diry: ds 1024 ;directory of file names, if needed ; Temporary storage for the regular expression parser. sqxx: ds 2 sqaa: ds 2 sqzz: ds 2 text: ds 2 texx: ds 2 rest: ds 2 rept: ds 2 repp: ds 2 alfa: ds 2 beta: ds 2 patt: ds 256 ;command line pattern ds 100 ;stack area stak: ds 2 ;initialize stack pointer papo: ds 2 ;pattern pointer supo: ds 2 ;substitute pointer sund: ds 2 fhed: db '----> File ' fnam: db 'xxxxxxxx.' ;filename fext: db 'xxx',CR,LF,00 ;file extension llbl: db ' +' lnum: db ' ',00 lzer: db ' 0' ftot: db ' lines found',CR,LF,00 dtot: db ' instances in the entire disk',CR,LF,00 db 00 ;fence for line buffer lbuf: ds 85H ;line buffer ictr: ds 2 iptr: ds 2 ibuf: ds isiz fini: ds 0 end