title Word Count name ('WC') maclib base80 ; WC.COM is the CP/M implementation of the UNIX word counter ; ; Call it : WC {-cwlv} {du:}file(s) ; ; WC counts ; c Characters ; w Words ; l Lines in the file(s) ; v Be verbose on single files ; ; Without any option, WC reports all counts ; ; Files may hold wildcards ; Optional drive and user may be selected in either way ; ; Copyright (c) W.Cirsovius ; Hohe Weide 44 ; D-20253 Hamburg ; ; Phone +49 40 4223247 ; Version 1.0 ??-???-?? : Initial version ; Version 1.1 03-Dec-92 : Add wildsard support ; Version 1.2 16-Jul-95 : Change DU from u/d: to du: _VERS macro db '1.2' endm _PRG macro db 'WC' endm ext incasc,sumasc,string,crlf,cmdarg,UPPCON,Parse ext open,geteof,getver,curdrv,usrset,usrget,getdu ext dirmax,dirget,dirsta,rdbfp,prdufn,combrk _arg equ 2 NO equ FALSE YES equ TRUE .string equ 9 dseg $HELP: db cr,lf _PRG db ' v' _VERS db ' - Word count program',cr,lf,lf db 'Call it : WC {-cwlv} {du:}file(s)',cr,lf,lf _PRG db ' counts',cr,lf db tab,'c Characters',cr,lf db tab,'w Words',cr,lf db tab,'l Lines in the file(s)',cr,lf db tab,'v Be verbose on single files',cr,lf,lf db 'Without any option, ' _PRG db ' reports all counts' db cr,lf,lf db 'Files may hold wildcards',cr,lf db 'Optional drive and user may ' db 'be selected in either way' db cr,lf,eot $CANT: db 'Cannot find file',cr,lf,eot $NOFILE: db 'No file found',eot $SINGLE: db cr,lf,'Statistic of file : ',eot $ACTMESS: db cr,lf,'Counting file : ',eot $TOTAL: db cr,lf,'TOTAL STATISTIC OF ALL FILES :' db cr,lf,lf,eot $ILL.CPU: db 'Requires Z80 CPU',eot $ILL.CPM: db 'Requires CP/M 3.x',eot $ABORT: db cr,lf,'*** ABORTED ***',cr,lf,eot $OPT: db 'CWLV' OptLen equ $-$OPT OptTab: dw C.opt,W.opt,L.opt,V.opt WrdTab: db ' ',cr,lf,tab WrdLen equ $-WrdTab PB: dw 0,FCB ARGV: ds 2*_arg InWord: ds 1 DU: ds 2 $memry:: dw 0 CurFile: ds 2 Files: ds 2 MessPtr: dw $ACTMESS C.Cnt: db ' 0',eot W.Cnt: db ' 0',eot L.Cnt: db ' 0',eot C.Sum: db ' 0',eot W.Sum: db ' 0',eot L.Sum: db ' 0',eot $0.Cnt: db ' 0' cnt equ $-$0.cnt $$C: db 'Characters',eot $$W: db ' Words',eot $$L: db ' Lines',eot $File: db ' in file : ',eot $Files: db ' total : ',eot FP: ds 2 @C.F: db TRUE @W.F: db TRUE @L.F: db TRUE Verbose: db FALSE Cs.PB: dw @C.F,$$C,C.Sum Ws.PB: dw @W.F,$$W,W.Sum Ls.PB: dw @L.F,$$L,L.Sum Cf.PB: dw @C.F,$$C,C.Cnt Wf.PB: dw @W.F,$$W,W.Cnt Lf.PB: dw @L.F,$$L,L.Cnt cseg ; ; Get selected option ; ENTRY Reg HL points to string ; EXIT Carry set on error ; GetOpt: ld a,(hl) ; Get character cp '-' ; Must be sign scf ret nz inc hl ld a,(hl) or a scf ret z ; Must be at least one option call Verbose? ; Test verbose ret nz ; .. that's all ld a,FALSE ld (@C.F),a ; Reset all count options ld (@W.F),a ld (@L.F),a ex de,hl OptLoop: ld a,(de) ; Test end or a ret z call UPPCON ld hl,$OPT+OptLen-1 ld bc,OptLen cpdr ; Find option scf ret nz ld hl,OptTab add hl,bc add hl,bc ld a,(hl) ; Fetch address inc hl ld h,(hl) ld l,a call jp.r ; .. execute ret c inc de jr OptLoop jp.r: jp (hl) C.opt: ld hl,@C.F jr ..opt W.opt: ld hl,@W.F jr ..opt L.opt: ld hl,@L.F ..opt: ld a,(hl) ; Test already set or a scf ret nz ; .. yeap ld (hl),TRUE ; .. set it V.opt: or a ret ; ; Test option -V ; ENTRY Reg HL holds pointer to string ; EXIT Zero set if more options ; Verbose?: ld c,-1 ; Set flag ld e,l ; .. copy pointer ld d,h VerbLoop: ld a,(de) or a ; Test end jr nz,IsItVerb ld a,c or a ret IsItVerb: cp 'V' ; Test verbose jr z,IsVerb ld c,0 ; .. set more NxtVerb: inc de jr VerbLoop IsVerb: ld a,(Verbose) ; Test alredy set or a scf ret nz ld a,TRUE ld (Verbose),a jr NxtVerb ; ; Get file mask ; ENTRY Reg HL points to string ; EXIT Carry set on file error ; GetMask: call getdu ; .. find optional drive, user ld (DU),bc ; .. save ret c ld (PB),hl ; .. set pointer ld de,PB call Parse ; .. parse file ret c ld a,(DU) call usrset ; Set user ld a,(DU+1) ; Get drive ld (FCB),a dec a call dirmax ; Get max entries in drive ret c ; .. error ex de,hl ld a,(DU) ld c,a ; Get user ld hl,($memry) ; Get free location ld a,00100000b call dirget ; Get directory ret c ld (Files),hl ; Set count ld a,l or h scf ret z ld hl,($memry) call dirsta ; .. get sort ld (CurFile),de or a ret ; ; Get current file ; EXIT Carry set if not on disk ; GetFile: ld a,RecLng ld (rdbfp),a ; Force read ld de,FCB push de ld hl,(CurFile) ld a,(DU+1) ld (de),a ; .. set drive inc de ld bc,.fname ldir ; Get file name inc hl ld bc,.fext ldir ; .. and extension inc hl ld (CurFile),hl ; .. save top pop de call open ; .. open file ret ; ; Give report of count ; ENTRY Reg IX points to control block ; Report: ld l,(ix+0) ; Get address of flag ld h,(ix+1) ld a,(hl) or a ; Test enabled ret z ; .. nope ld e,(ix+2) ; Get message ld d,(ix+3) call string ld de,(FP) call string ; .. print ld e,(ix+4) ; Get address of count ld d,(ix+5) call string ; .. print call crlf ret ; ; Test BREAK and increment ASCII ; ENTRY Reg HL points to LSDigit ; BrkInc: call combrk ; Test character jr nc,Incr cp CtrlC ; .. maybe break jr nz,Incr ld de,$ABORT call string jp OS ; ; Increment ASCII ; ENTRY Reg HL points to LSDigit ; Incr: push af ld b,cnt call incasc ; .. do it pop af ret ; ; Prepare ASCII count ; ENTRY Reg DE points to count to be prepared ; PrepAsc: ld hl,$0.cnt ld bc,cnt ldir ; .. set it ret ; ; Count the parts ; Count: ld de,C.Cnt call PrepAsc ; .. prepare ASCII counts ld de,W.Cnt call PrepAsc ld de,L.Cnt call PrepAsc NoWord: ld a,NO Word: ld (InWord),a ; Set no word Count.Loop: call geteof ; Get from file ret c ; .. end of file ld hl,C.Cnt+cnt-1 call Incr ; .. increment character count cp lf ; Test new line ld hl,L.Cnt+cnt-1 call z,BrkInc ; .. increment line count if so ld hl,WrdTab ld bc,WrdLen cpir ; Test word jr z,NoWord ld a,(InWord) cp NO jr nz,Count.Loop ld hl,W.Cnt+cnt-1 call Incr ; .. increment word count ld a,YES jr Word ; .. set word ; ; Sum all ASCII counts ; GetSum: ld hl,C.Cnt+cnt-1 ld de,C.Sum+cnt-1 ld b,cnt call sumasc ; .. Get sum of ASCII ld hl,W.Cnt+cnt-1 ld de,W.Sum+cnt-1 ld b,cnt call sumasc ld hl,L.Cnt+cnt-1 ld de,L.Sum+cnt-1 ld b,cnt call sumasc ret ; ; Give statistic of all files ; Total: ld hl,$Files ld (FP),hl ld a,(Verbose) ; Test verbose or a ld de,$TOTAL call nz,string ld ix,Cs.PB call Report ; Tell result ld ix,Ws.PB call Report ld ix,Ls.PB call Report ret ; ; Tell activity ; Active: ld de,(MessPtr) call string ; .. tell it ld de,FCB call prdufn call crlf ret ; ; Give statistic of single file ; Single: ld hl,$File ld (FP),hl ld ix,Cf.PB call Report ; Tell result ld ix,Wf.PB call Report ld ix,Lf.PB call Report ret ; ; Tell Z80 required ; WC.Z80: ld de,$ILL.CPU ld c,.string call BDOS jp OS ; ; ############ ; ### MAIN ### ; ############ ; WC: sub a ; Test right machine jp pe,WC.Z80 call getver ; .. verify CP/M+ ld de,$ILL.CPM jr c,ABORTstr ld sp,(TPAtop) ; Get stack ld b,_arg ld hl,ARGV ld de,CCP-1 call cmdarg ; .. get arguments in line ld de,$HELP jr c,ABORTstr ; .. error dec a ; Test option jr z,NoOpt ; .. nope ld hl,(ARGV) call GetOpt ld de,$HELP jr c,ABORTstr ld hl,(ARGV+2) ; .. unpack argument ld (ARGV),hl ld a,(Verbose) ; Test verbose or a jr z,NoOpt ld hl,$SINGLE ld (MessPtr),hl ; Change message NoOpt: ld hl,(ARGV) ; Get file pointer call GetMask ; .. get mask ld de,$NOFILE jr c,ABORTstr ; .. none found FileLoop: call GetFile ; Prepare file ld de,$CANT jr c,ABORTstr ; .. not found call Active ; Tell running call Count ; .. do the job call GetSum ; Get sum of all ASCII counts ld a,(Verbose) ; Test tell single or a call nz,Single ; .. yeap ld hl,(Files) dec hl ld (Files),hl ld a,l or h jr nz,FileLoop call crlf call Total ; .. give total jp OS ABORTstr: call string ;Give message jp OS end WC