; ; File: CNTLH.Z80 ; Author: D. McCord ; Last Revised: 10 Sept 89 ; Version: 1.1 ; ; 1.1 Revision - added proper handling for an existing .BAK file and ; processing of orphan cr's (adds lf's) ; ; Purpose: Text filtering for captured telecomm conversation files. This ; program cleans up such "chat" files in several different ways: ; 1. resets the high-order bit of all characters in the input ; file, making it also usable to change a WS document-format ; file to plain ASCII (non-document). ; 2. Filters out any control-h (backspace) characters and ; processes these implied edits (deleting the immediately- ; previous character also). ; 3. adds linefeed characters as needed to "orphan" carriage ; returns. ; ; This software is not copyrighted. ; ; assembly command lines: ; ; a0:command>zas cntlh ; a0:command>zlink cntlh,z3lib/,syslib/ ; ; Equates ; CR EQU 13 ; carriage return LF EQU 10 ; linefeed Z3ENV EQU 0FE00h ; address of your ENV VERSION EQU 11 ; 11 = 1.1 FCB1 EQU 5Ch ; 1st default fcb BUFFER$SIZE EQU 16 ; 16k each input and output file buffers PIPE$SIZE EQU 64 ; maximum active control h's in process CONTROLH EQU 'H'-40h ; control h character ; ; SYSLIB declarations ; extrn print,phlfdc,phl4hc,subhd,comphd extrn getud,putud,logud,codend,fxi$open,fxo$open extrn fxi$close,fxo$close,fx$get,fx$put,f$rename,f$delete extrn pfn2,retud ; ; Z3LIB declarations ; extrn z3init ; ; Z3 Utility header ; beglow: jp start db 'Z3ENV' db 1 ; external ENV envadr: dw z3env start: ld hl,(envadr) call z3init ; init Z3 stuff ld (oldstk),sp ; save old stack ld sp,stack ; set internal stack call banner ; print name of program and version ld a,(fcb1+1) ; look at first char on command line cp '/' ; help request? jp z,help cp ' ' ; no parameters? jp z,help ; ; determine DU: of input file ; call putud ; save current DU: call retud ; get current DU: in BC ld a,(fcb1+13) ; get parsed user area ld c,a ld a,(fcb1) ; and parsed disk or a jr z,start1 ; if no parsed disk, use what RETUD gave us dec a ; adjust ld b,a start1: call logud ; set it ; ; init fcb of input file ; ld bc,12 ld de,iniocbfcb ld hl,fcb1 ldir ; move default fcb to iniocb call codend ; get end of code address ld (inbuff$add),hl ; init buffer pointer in iniocb ; ; init fcb of output file ; ld de,buffer$size*1024 add hl,de ; set output to start one ; buffer$size after input ld (outbuff$add),hl ; init buffer pointer in outiocb push hl ; save start of outbuf for use below ld bc,12 ld de,outiocbfcb ld hl,fcb1 ldir ; move default fcb to outiocb ld bc,3 ld de,outiocbfcb+9 ld hl,tempext ldir ; setup output file to have $$$ extension ; ; setup character processing pipe ; pop hl ; get back start of outbuf ld de,buffer$size*1024 add hl,de ; set pipe to start one ; buffer$size after output ld (lowpipe$add),hl ; init pointer to lower boundary ld (pipepointer),hl ; init pipe pointer ld de,pipe$size ; size of pipe add hl,de ; determine upper boundary of pipe ld (highpipe$add),hl ; init pointer to high boundary ; ; Inform operator of memory usage ; push hl call print db ' Highest memory address used is ',0 pop hl call phl4hc call print db cr,lf,0 ; ; setup of unitialized data complete. Now open files for use. ; open$input: ld de,iniocb ; prep for open call fxi$open ; open input file jp z,inopen$error ; did an error occur? call print db ' Opened input file: ',0 ld de,iniocbfcb+1 call pfn2 call print db cr,lf,0 open$output: ld de,outiocb ; prep for open call fxo$open ; open output file jp z,outopen$error ; any errors? call print db ' Output file opened successfully' db cr,lf,0 ; ; All files opened successfully... enter main loop ; loop01: call abort ; check for operator termination call getinput ; get an input character, maybe set endflag ld c,a ; save input character ld a,(endflag) ; end of input? or a jr nz,loop10 ; if end, jump to closing stuff ld a,c ; get input character back res 7,a ; reset high bit cp controlh ; is it a control-h? jp nz,loop02 ; if not, go to loop02 ld hl,(ctlh$count) ; increment statistics inc hl ld (ctlh$count),hl call takefrompipe ; yes it was a ^H, back up the pipe jr loop01 ; go get next character loop02: call putinpipe ; put it in the pipe jr loop01 loop10: call flush ; flush whatever's in the pipe call close ; close output file call print db ' Processing completed - ',0 ld hl,(ctlh$count) call phlfdc call print db ' control-h''s processed',cr,lf,0 call rename ; rename original to .bak, .$$$ to original jp exit1 ; ; getinput reads the next character from the input file, sets endflag if ; the end is reached. ; getinput: ld de,iniocb ; point to input file call fx$get ; read it into A ret nz ; return, no error ld a,0ffh ld (endflag),a ; set end of file ret ; ; push character in A into character pipe. If overflow, write an output ; character. ; putinpipe: push hl ; save registers push de push bc ld c,a ; save character in C ld hl,(pipepointer) ; get current top ld de,(highpipe$add) ; get upper boundary call comphd ; compare 'em jr nz,nowrite ; if they are equal, write a character ; ; get a character out of the far end of the pipe and write it ; writeone: dec hl ; bump pipepointer down 1 ld (pipepointer),hl ; store new pipepointer call write$hl ; go write character at (HL) to output ; ; if we needed to write, we did. now, shift pipe if needed. ; nowrite: ld hl,(pipepointer) ld de,(lowpipe$add) call subhd ; get length to shift pipe ld a,h ; test if HL is zero... or l jr z,noshift ; might be first character in pipe ; ; we need to, so shift pipe one inward ; push bc ; save character in C push hl pop bc ; length to shift in BC ld de,(pipepointer); destination ld hl,(pipepointer) dec hl ; one less than destination lddr ; block load with decrement [ (DE) <- (HL), ; decrement HL & DE, repeat (BC) times ] pop bc ; get character back noshift: ld a,c ld hl,(lowpipe$add) ld (hl),a ; put character at front of pipe ld hl,(pipepointer) inc hl ld (pipepointer),hl; increment pipepointer appropriately pop bc ; restore registers pop de pop hl ret ; ; takefrompipe empties the nearest character from the pipe ; takefrompipe: push hl ; save registers push de push bc ld hl,(pipepointer) ld de,(lowpipe$add) call subhd ld a,h ; test if HL is zero... or l jr z,notake ; must be empty pipe if Z, don't do anything push hl ; get size of pipe pop bc ; ...into BC ld hl,(lowpipe$add) inc hl ; DE already has (lowpipe$add) in it ldir ; (DE) <- (HL), autoincrement (BC) times ld hl,(pipepointer) dec hl ld (pipepointer),hl notake: pop bc pop de pop hl ret ; ; some error when opening input file brings us here ; inopen$error: call print db ' Error opening input file - probably no file with ' db 'that name - aborting',cr,lf,0 exit: call getud jp exit1 ; ; some error when opening output file brings us here ; outopen$error: call print db ' Error opening output file - aborting',cr,lf,0 jr exit ; ; write$hl writes the character at (HL) to the output file after control-h ; processing. here we fix orphan cr's. ; write$hl: ld a,(was$a$cr) ; was the previous character a cr? or a jr z,write$hl10 ; if not, skip ld a,(hl) cp lf ; is a linefeed following prev. cr? jr z,write$hl05 ; if yes, reset things to normal ld a,lf ; load A with linefeed call write$hl20 ; go write it and come back write$hl05: ld a,0h ; make A zero ld (was$a$cr),a ; reset flag write$hl10: ld a,(hl) ; get character to write cp cr ; is a cr? jr nz,write$hl20 ; if not, go finish ld (was$a$cr),a ; set flag to cr (0dh), non-zero write$hl20: ld de,outiocb ; point to output call fx$put ; write character in A to it ret nz ; if no error, return, else fall to... ; ; an error writing to output brings us here ; outwrite$error: call print db ' Error writing output file - aborting',cr,lf,0 jp exit ; ; print program name and version info ; banner: call print db 'CNTLH, Version ' db version/10+'0','.',(version mod 10)+'0',cr,lf,0 ret ; ; Built-in help ; help: call print db ' Text filtering and processing for captured "chat" files.' db cr,lf db 'Syntax:',cr,lf db ' CNTLH ',cr,lf db ' may use DU:, DIR: as needed. Original ' db cr,lf db ' is renamed to .BAK, filtered file is named .' db cr,lf,0 exit1: ld sp,(oldstk) ret ; ; flush takes whatever is in the pipe and writes it to the output file ; flush: ld hl,(pipepointer) ld de,(lowpipe$add) call subhd ld a,h or l ret z ; nothing in pipe if Z push hl pop bc ; BC now has # of items in pipe ld hl,(pipepointer) dec hl floop: call write$hl ; write (HL) to output file dec bc ld a,b or c ; if NZ, more to do ret z ; return if done dec hl jr floop ; go do more ; ; close all files ; close: ld de,iniocb call fxi$close ; close input ld de,outiocb call fxo$close ; close output ret nz ; return if no errors call print db ' Error closing output file',cr,lf,0 jp exit ; ; rename deletes any existing filename.BAK, then renames the original ; file to .BAK, new file to original's name ; rename: ld de,renamefcb ; set up to move input filename to renamefcb ld hl,iniocbfcb ld bc,12 ldir ; zap! ld bc,3 ; setup renamed input file to have BAK ld de,renamefcb+9 ; extension ld hl,bakext ldir ; zap! ld de,renamefcb call f$delete ; delete an existing .BAK file, if any ld de,iniocbfcb ; point to old name ld hl,renamefcb ; point at new name call f$rename ; go rename input file to .BAK ld de,renamefcb ; move original filename to renamefcb ld hl,iniocbfcb ld bc,12 ldir ; zap! ld de,outiocbfcb ; point to old name ld hl,renamefcb ; point to new name call f$rename ; go rename output file to what original was ret ; ; abort checks for operator abort ; abort: ld hl,abort1 push hl ; we return to abort1 after the jp (hl) below ld hl,(1) inc hl inc hl inc hl ; HL points to BIOS CONST jp (hl) abort1: or a ret z ; return if nothing waiting call print db cr,lf,'[User Abort]',cr,lf,0 ; ; gobble the pending character which caused the abort ; ld hl,exit push hl ; we return to exit after the jp (hl) below ld hl,(1) ld de,6 add hl,de ; HL points to BIOS CONIN jp (hl) ; ; initialized data area ; tempext: db '$$$' bakext: db 'BAK' ; iniocb: db buffer$size*8 db 0 dw 0 dw 0 inbuff$add: dw 0 iniocbfcb: ds 36 outiocb: db buffer$size*8 db 0 dw 0 dw 0 outbuff$add: dw 0 outiocbfcb: ds 36 lowpipe$add: dw 0 highpipe$add: dw 0 pipepointer: dw 0 ; where the NEXT character would go in the pipe endflag: db 0 ctlh$count: dw 0 was$a$cr: db 0 ; 0 = previous character was not a cr ; ; uninitialized data area ; renamefcb: ds 36 ds 64 stack: oldstk: ds 2