; ; AN.MAC -- Version 1.2 ; ; Checks for matching ^A's (select alternate pitch) and ^N's (select ; normal pitch) in WordStar document files. ; ; USAGE: ; ; AN {dir:} ; ; An input filename is required. If a DIR or DU specification is not ; given, the current drive/user is assumed. ; ; If the number of ^A's and ^N's are not equal, AN will display the ; total number of each. Each time a ^A or ^N are found an "A" or "N" ; are printed at the console, which should help in locating non-matching ; pairs. ; ; HISTORY: ; ; Version 1.0 -- February 9, 1988 -- Original version for CP/M Plus only. ; ; Version 1.1 -- October 15, 1989 -- Modified to remove CP/M Plus ; dependencies. ; ; Version 1.2 -- August 18, 1989 -- Added DU support and on-screen "AN" ; display, eliminated warm boot on exit, and made several other ; minor code changes. ; ; Gene Pizzetta ; 481 Revere Street ; Revere, MA 02151 ; ; Voice: (617) 284-0891 ; Newton Centre Z-Node: (617) 965-7259 ; Lilliput Z-Node: (312) 649-1730 ; CompuServe: 72060,505 ; GEnie: E.Pizzetta ; ; This utility was developed with SLRMAC. It may be re-assembled with ; MAC (Z80.LIB is required). ; WBoot equ 00h ; warm boot Bdos equ 05h ; BDOS entry MemTop equ Bdos+1 ; --> top of memory CpmFcb equ 05Ch ; default file control block FcbName equ CpmFcb+1 ; filename FcbEx equ CpmFcb+12 ; current file extent FcbUsr equ CpmFcb+13 ; du user code (set by ZCPR3) FcbCr equ CpmFcb+32 ; current file record TPA equ 100h ; program load address Fail equ 0FF00h ; failure code ; ; BDOS service functions ; ConIn equ 1 ; get character ConOut equ 2 ; print character PrtStr equ 9 ; print string ConSt equ 11 ; console status FOpen equ 15 ; open file FClose equ 16 ; close file SetDMA equ 26 ; set DMA address FRead equ 20 ; read file SetUsr equ 32 ; set user area MultSec equ 44 ; set multi-sector count BdosRet equ 108 ; set BDOS return code ; ; character codes ; CtrlA equ 01h ; control-A CtrlC equ 03h ; control-C BEL equ 07h ; bell LF equ 0Ah ; linefeed CR equ 0Dh ; carriage return CtrlN equ 0Eh ; control-N CpmEOF equ 1Ah ; CP/M end of file (^Z) ; MACLIB Z80 ; org TPA ; jmp MAIN ; ; messages and tables . . . ; db 'Z3ENV' db 1 Z3EAdr: dw 0FE00h ; address of environment descriptor ; MsgSOn: db 'AN Version 1.2',CR,LF,'$' MsgUse: db 'Checks for matching ^A''s and ^N''s in WordStar files.',CR,LF db 'USAGE:',CR,LF db ' AN {dir:}',CR,LF db 'An input filename is required.',CR,LF,'$' MsgFNF: db BEL,'Input file not found.',CR,LF,'$' MsgCan: db BEL,CR,LF,'Cancelled by user.',CR,LF,'$' MsgWkg: db ' Checking file for ^A''s and ^N''s . . .',CR,LF,'$' MsgMat: db CR,LF,' All ^A''s and ^N''s match.',CR,LF,'$' MsgNMt: db BEL,CR,LF,' NO MATCH --',CR,LF,' $' MsgAlt: db ' total ^A''s (alternate pitch)',CR,LF,' $' MsgNrm: db ' total ^N''s (normal pitch)',CR,LF,'$' AltCnt: db 0 ; count of ^A's NrmCnt: db 0 ; count of ^N's OldStk: dw 0 ; ; Start of program . . . ; MAIN: sspd OldStk ; save old stack pointer lhld MemTop ; set stack to top of memory mov a,h ; move high byte to A sui 16 ; preserve 4K for CCP and safety mov h,a ; put it back sphl ; ..and set new stack pointer ; lxi d,MsgSOn ; sign on mvi c,PrtStr call Bdos lda FcbName ; check for input file cpi '"' jc NoTail ; (no file given) cpi '/' ; check for slash jnz IsTail ; (no) lda FcbName+1 cpi '/' ; a second slash? jz NoTail ; (yes, print help message) IsTail: lda FcbUsr ; get user and set it mov e,a mvi c,SetUsr call Bdos mvi a,0 ; set extent to 0 sta FcbEx sta FcbCr lxi d,CpmFcb ; open file mvi c,FOpen call Bdos inr a ; does it exist? jz NoFile ; (no) lxi d,DMABuf ; set DMA buffer address mvi c,SetDMA call Bdos ; ; We're all set up, now we start reading the file ; lxi d,MsgWkg ; say we're working mvi c,PrtStr call Bdos call RDFILE ; load file (or part of it) Loop: mov a,m ; get a character cpi CpmEOF ; end of file? jrz Match ; (yes) ani 7Fh ; reset high bit cpi CtrlA ; control-A? cz ISA ; (yes) cpi CtrlN ; control-N? cz ISN ; (yes) call CONCHK ; check for user cancel inx h ; increment pointer djnz Loop ; loop if there's more call RDFILE ; buffer finished, read some more file jr Loop ; ; now we check to make sure we have the same number of ^A's and ^N's ; Match: lda NrmCnt ; get number of ^N's mov b,a lda AltCnt ; get number of ^A's cmp b ; do they match? jrnz NoMat ; (no) lxi d,MsgMat ; report everything is okay mvi c,PrtStr call Bdos call CLOSE jr EXIT ; ; We're aborting here under various circumstances ; NoMat: lxi d,MsgNMt ; report things aren't right mvi c,PrtStr call Bdos lda AltCnt ; get count of ^A's call BINDEC ; ..and print in ASCII lxi d,MsgAlt mvi c,PrtStr call Bdos lda NrmCnt ; get count of ^N's call BINDEC ; ..and print in ASCII lxi d,MsgNrm mvi c,PrtStr call Bdos jr EXIT ; ..and abort ; NoTail: lxi d,MsgUse ; tell 'em how to use it mvi c,PrtStr call Bdos jr EXIT ; ..and abort ; NoFile: lxi d,MsgFNF ; say we couldn't find it mvi c,PrtStr call Bdos jr EXIT ; ..and abort ; CANCEL: lxi d,MsgCan ; report user cancel mvi c,PrtStr call Bdos ; ..and abort ; EXIT: call CLOSE ; close file lspd OldStk ; restore old stack ret ; ..and go home ; ; Subroutines . . . ; ; ISA increments count of control-A's encountered ; ISA: push psw ; save character push b ; save counter push d push h ; save pointer lda AltCnt ; get count inr a ; increment it sta AltCnt ; store it back mvi c,ConOut ; and print it to screen mvi e,'A' call Bdos pop h ; recover pointer pop d pop b ; recover counter pop psw ; recover character ret ; ; ISN increments count of control-N's encountered ; ISN: push psw ; save character push b ; save counter push d push h ; save pointer lda NrmCnt ; get count inr a ; increment it sta NrmCnt ; store it back mvi c,ConOut ; and print it to screen mvi e,'N' call Bdos mvi c,ConOut mvi e,' ' call Bdos pop h ; recover pointer pop d pop b ; recover counter pop psw ; recover character ret ; ; RDFILE reads a segment of the disk file into memory and resets ; the counter and buffer pointer ; RDFILE: mvi c,FRead lxi d,CpmFcb ; read in a file segment call Bdos mvi b,128 ; buffer size lxi h,DMABuf ; set pointer to start of DMA buffer cpi 0FFh ; check for end-of-file rnz ; (no) mvi a,1Ah ; yes, so stuff ^Z in buffer mov m,a ret ; ..and return ; ; CLOSE closes file ; CLOSE: lxi d,CpmFcb mvi c,FClose call Bdos ret ; ; CONCHK checks for user cancel from console ; CONCHK: push psw push b push d push h mvi c,ConSt ; check for character call Bdos cpi 0 ; do we have one? jz NoAbrt ; (no) mvi c,ConIn ; yes, so get it call Bdos cpi CtrlC ; is it ^C? jz CANCEL ; (yes, so let's get out of here) NoAbrt: pop h ; no, we're not quiting pop d pop b pop psw ret ; ; BINDEC prints binary number (1 byte) at console in ASCII. Binary ; number is expected in A. ; BINDEC: mvi b,0 ; make B the no print flag mvi d,100 ; divide by 100 call BDLoop mvi d,10 ; divide by 10 call BDLoop mvi d,1 ; divide by 1 call BDLoop ret ; BDLoop: mvi c,0 ; initialize count BDL1: cmp d ; compare A to divisor jc BDLess ; (it's less) inr c ; it's greater, so increment C sub d ; substract divisor jr BDL1 ; BDLess: push psw ; count finished, save binary number mov a,c cpi 0 ; is the count 0? jrnz Less1 ; (no) cmp b ; if both C and B are 0, jrz IsSpc ; ..then print a space Less1: mvi a,30h add c ; convert to ASCII mov e,a ; ..and print it mvi c,ConOut call Bdos mvi b,1 ; set print flag pop psw ret ; IsSpc: push b ; ..and print flag mvi e,' ' ; print space instead of '0' mvi c,ConOut call Bdos pop b pop psw ret ; DMABuf: equ $+128 ; buffer for file loading ; end