; FILTX v2 - 12/02/83 - Filters ASCII text files for unwanted characters ; ; COPYRIGHT 1983 ; ; This program copies any ASCII file and filters out all imbedded con- ; trol characters except CR, LF and TAB. When a CR is encountered, a ; LF is automatically appended to make the file compatible with CP/M ; editors. If an "orphan" LF is encountered, a CR and LF are written ; to the output. The program also resets the high order bit of all ; characters to zero so that files created with WordStar or other text ; processing programs can be read properly by normal routines. The end ; of the program is padded with continuous EOF (CTL-Z) characters to ; finish the sector. ; ; FILTX is also useful for fixing files which contain only CR's at the ; end of each line. ; ; NOTE: FILTX should not be used on MBASIC source code which contains ; lines which are "continued on next line". (MBASIC uses a special end- ; of-line sequence (LF then CR) which will be altered by this program.) ; Use FILTER.COM for these kinds of files. ; ; To use: ; ; B>FILTX HELLO.TXT (1) ; B>FILTX HELLO.TXT NUNAME.DOC (2) ; B>FILTX A:HELLO.TXT (3) ; B>FILTX A:HELLO.TXT B:NUNAME.DOC (4) ; ; (1) Cleans up a file named HELLO.TXT. When finished the original ; file is named HELLO.BAK and the new file has the normal name. ; (2) The original file keeps the original name. The new file is now ; named NUNAME.DOC. ; (3) Just shows you can use two disks. The backup file will be on ; the same disk as the original and assumes the original name.. ; (4) The original file remains intact, the new file is on another ; drive and is named NUNAME.DOC. ; ; - Notes by Keith Petersen W8SDZ ; and Irv Hoff W6FFC ; ;----------------------------------------------------------------------- ; ; 12/02/83 Rewrote portions of the program so it may be assembled with ; ASM.COM. (SEQIO.LIB and MAC no longer needed.) The program ; now renames the new file to the original name while the ori- ; ginal file is named .BAK. (You can specify a new name. In ; that case the original file remains intact.) Other modest ; changes. Renamed this version to FILTX2 so it may be placed ; on Compuserve and other systems limited to 6 character file- ; names. Added short help menu, extra notes on how to use. ; - Irv Hoff ; ; 06/10/81 Added routines to count and report number of high-order bits ; deleted and number of input and output lines. ; - Keith Petersen ; ; NOTE: If you add improvements or otherwise update this program, please ; send a copy of the new file to "TECHNICAL CBBS" in Dearborn, MI ; phone 313-846-6127 (110, 300, 450 or 600 baud). ; ;---------------------------------------------------------- ; ; Define write buffer size ; BSIZE: EQU 1024*16 ;set for 16k ; ; ; Equates ; CR: EQU 0DH ;carriage return EOF: EQU 1AH ;end of file - ^Z FCB: EQU 5CH ;default file control block FCB2: EQU 6CH ;second default file control block FILERR: EQU 0000H ;reboot after error LF: EQU 0AH ;line feed RLEN: EQU 128 ;record length SOURCE: EQU FCB ;address of source filename SPACE: EQU 20H ;space character TAB: EQU 09H ;horizontal tab TBUF: EQU 0080H ;default buffer address ;..... ; ; ; BDOS equates ; BDOS: EQU 0005H ;CP/M BDOS entry address WBOOT: EQU 0 ;warm boot entry address WRCON: EQU 2 ;write character to console PRINT: EQU 9 ;print string (DE) until '$' OPEN: EQU 15 ;open disk file CLOSE: EQU 16 ;close disk file DELET: EQU 19 ;delete file READ EQU 20 ;read sequential file WRITE: EQU 21 ;disk file write MAKE: EQU 22 ;make file RENAME: EQU 23 ;rename a file STDMA: EQU 26 ;set dma address ;..... ; ; ; Program starts here ; ; ORG 100H ; ; START: LXI H,0 DAD SP ;get 'CCP' stack SHLD STACK ;save it for exit LXI SP,STACK ;set stack pointer CALL ILPRT ;print: DB CR,LF,'FILTX v1.2 - ' DB 'ASCII file filter utility',CR,LF,CR,LF,0 LDA FCB+1 CPI ' ' ;filename there? JNZ START1 ;yes, go open it CALL EXIT ;print message then exit DB ' To use: B>FILTX A:HELLO.TXT 1)',CR,LF DB ' B>FILTX HELLO.TXT A:NAME.NEW 2)',CR,LF DB CR,LF,' 1) uses original name for new file, ' DB 'original now named .BAK' DB CR,LF,' 2) original file stays intact, new ' DB 'file has new name','$' ; ; ; Open source file ; START1: LDA FCB2+1 ;destination file named? CPI SPACE JNZ START2 ;if yes, exit LXI H,FCB ;otherwise use same filename LXI D,DEST ; with .$$$ extent for now MVI B,9 CALL MOVE JMP OPENIT ; START2: LXI H,FCB2 ;destination filename LXI D,DEST ;destination 'FCP' in 'TPA' MVI B,16 CALL MOVE ; OPENIT: XRA A STA SOURCE+32 ;zero current record byte STA DEST+32 LXI D,SOURCE MVI C,OPEN CALL BDOS INR A ;check for no open JNZ MM07 ;no error, continue CALL EXIT DB '++ SOURCE FILE NOT FOUND ++$' ; ; ; Output a character to the new file buffer - first, see if there is ; room in the buffer for this character. ; OUTCHR: PUSH PSW ;store the character for now LHLD OUTPUTSIZ ;get buffer size XCHG ;put in 'DE' LHLD OUTPUTPTR ;now get the buffer pointers MOV A,L ;check to see if room in buffer SUB E MOV A,H SBB D JC MM06 ;if room, go store the character LXI H,0 ;otherwise reset the pointers SHLD OUTPUTPTR ;store the new pointer address ; MM2: XCHG ;put pointer address into 'DE' LHLD OUTPUTSIZ ;get the buffer size MOV A,E SUB L MOV A,D SBB H JNC MM05 LHLD OUTPUTADR DAD D XCHG MVI C,STDMA CALL BDOS LXI D,DEST MVI C,WRITE CALL BDOS ORA A JNZ MM03 LXI D,RLEN LHLD OUTPUTPTR DAD D SHLD OUTPUTPTR JMP MM2 ; MM03: MVI C,PRINT LXI D,MM04 CALL BDOS POP PSW JMP FILERR ; MM04: DB CR,LF DB 'DISK FULL: OUTPUT' DB '$' ; MM05: LXI D,TBUF MVI C,STDMA CALL BDOS LXI H,0 SHLD OUTPUTPTR ; MM06: XCHG LHLD OUTPUTADR DAD D XCHG POP PSW ;get the character back STAX D ;store the character LHLD OUTPUTPTR ;get the buffer pointer INX H ;increment them SHLD OUTPUTPTR ;store the new pointer address RET ;..... ; ; MM07: XRA A STA DEST+12 STA DEST+32 LXI H,BSIZE SHLD OUTPUTSIZ LXI H,0 SHLD OUTPUTPTR MVI C,DELET LXI D,DEST CALL BDOS MVI C,MAKE LXI D,DEST CALL BDOS INR A JNZ MM09 MVI C,PRINT LXI D,MM08 CALL BDOS JMP FILERR ; MM08: DB CR,LF DB 'NO DIR SPACE: OUTPUT' DB '$' ; MM09: CALL ILPRT ;print: DB 'Input and output files open',CR,LF,CR,LF,0 ; ; ; Read sector from source file ; READLP: LXI D,80H MVI C,STDMA CALL BDOS LXI D,FCB MVI C,READ CALL BDOS ORA A ;read ok? JZ WRDISK ;yes, send it to output CPI 1 ;end-of-file? JZ TDONE ;transfer done, close, exit CALL ERXIT DB '++ SOURCE FILE READ ERROR ++$' ; ; ; Write sector to output file (with buffering) ; WRDISK: LXI H,80H ;read buffer address ; WRDLOP: MOV A,M ;get byte from read buffer CPI 1AH ;end of file marker ? JZ TDONE ;transfer done, close, exit ANI 80H ;hi-bit turned on? JZ WRDLP2 ;no, don'T COUNT IT PUSH H ;save input buffer address LHLD HCOUNT ;get deleted hi-bit count INX H ;add one SHLD HCOUNT ;save new count POP H ;get input buffer address back ; WRDLP2: MOV A,M ;get byte again ANI 7FH ;strip parity bit CPI 7FH ;del (rubout) ? JZ IGNORE ;yes, ignore it CPI ' ' ;space or above? JNC PUTCHR ;yes go write it CPI CR ;carriage return ? JNZ WRDLP3 ;skip line count PUSH H ;save input buffer address LHLD ICOUNT ;get input line count INX H ;add one SHLD ICOUNT ;save new count POP H ;get input buffer address back JMP WRCRLF ;yes go write cr and a lf ; WRDLP3: CPI LF ;line feed ? JZ WRLF ;yes process it CPI TAB ;tab character ? JZ PUTCHR ;yes, go write it ; ; ; Ignore character and add one to ignore count ; IGNORE: PUSH H ;save input buffer address LHLD DCOUNT ;get delete counter INX H ;add one SHLD DCOUNT ;save new count POP H ;get input buffer address back JMP TSTEND ;ignore character and continue ; ; ; This routine checks to see if the last character was a LF. If not, ; the current character is an "orphan" LF and we need to add a CR before ; it in the output file. ; WRLF: LDA LSTCHR ;get last character CPI LF ;was it a line feed? JZ TSTEND ;yes, ignore this one PUSH H ;save input buffer address LHLD OLFCNT ;get orphan lf count INX H ;add one SHLD OLFCNT ;save new count POP H ;get input buffer address back ; ; ; Write a CR and LF to the file. ; WRCRLF: PUSH H ;save input buffer address LHLD OCOUNT ;get output line count INX H ;add one SHLD OCOUNT ;save new count MVI A,CR ;get a cr CALL OUTCHR ;write cr to file POP H ;get input buffer address back MVI A,LF ;get a line feed, drop into putchr ; ; ; Write character to output buffer ; PUTCHR: STA LSTCHR ;save char for later PUSH H ;save input buffer address CALL OUTCHR POP H ;get input buffer address back ; TSTEND: INR L ;done with sector? JNZ WRDLOP ;no, get another byte JMP READLP ;go get another sector ;..... ; ; ; Transfer is done - close destination file ; TDONE: LHLD OUTPUTPTR MOV A,L ANI RLEN-1 JNZ MM10 SHLD OUTPUTSIZ ; MM10: MVI A,EOF PUSH PSW CALL OUTCHR POP PSW JNZ TDONE MVI C,CLOSE LXI D,DEST CALL BDOS INR A JNZ MM12 MVI C,PRINT LXI D,MM11 CALL BDOS JMP MM12 ; MM11: DB CR,LF DB 'CANNOT CLOSE OUTPUT' DB '$' ; MM12: CALL ILPRT ;print: DB 'Function complete.',CR,LF,CR,LF,0 LHLD ICOUNT ;get input line count CALL DECOUT ;print it CALL ILPRT ;print: DB ' input lines read' DB CR,LF,0 LHLD OCOUNT ;get output line count CALL DECOUT ;print it CALL ILPRT ;print: DB ' output lines written with:' DB CR,LF,TAB,0 LHLD DCOUNT ;get deleted char count CALL DECOUT ;print it CALL ILPRT ;print: DB ' CTL-characters deleted' DB CR,LF,TAB,0 LHLD HCOUNT ;get deleted hi-order bit count CALL DECOUT ;print it CALL ILPRT ;print: DB ' high-order bits deleted' DB CR,LF,TAB,0 LHLD OLFCNT ;get orphan lf count CALL DECOUT ;print it CALL ILPRT DB ' orphan LFs fixed',0 ; ; ; Rename both files if no destination file name was specified ; NUNAME: LDA DEST+9 CPI '$' JNZ EXIT1 LXI H,FCB LXI D,ONAME MVI B,16 CALL MOVE LXI H,FCB+1 LXI D,ONAME+17 MVI B,8 CALL MOVE LXI H,FCB LXI D,SNAME MVI B,9 CALL MOVE LXI D,SNAME MVI C,DELET CALL BDOS LXI D,ONAME MVI C,RENAME CALL BDOS ; ; ; Now rename the new file ; LXI H,FCB+1 LXI D,DEST+17 MVI B,16 CALL MOVE LXI D,DEST MVI C,RENAME CALL BDOS JMP EXIT1 ;..... ; ; ; Erase the incomplete output file, then exit ; ERXIT: LHLD OUTPUTPTR MOV A,L ANI RLEN-1 JNZ MM13 SHLD OUTPUTSIZ ; MM13: MVI A,EOF PUSH PSW CALL OUTCHR POP PSW JNZ ERXIT MVI C,CLOSE LXI D,DEST CALL BDOS INR A JNZ MM15 MVI C,PRINT LXI D,MM14 CALL BDOS JMP MM15 ; MM14: DB CR,LF DB 'CANNOT CLOSE OUTPUT' DB '$' ; MM15: MVI C,DELET LXI D,DEST CALL BDOS ; ; ; Print message then exit to CP/M ; EXIT: POP D ;get message address MVI C,PRINT ;print message CALL BDOS ; EXIT1: CALL ILPRT ;print crlf DB CR,LF,0 LHLD STACK SPHL RET ;..... ; ; ; Inline print routine - prints string pointed to by stack until a zero ; is found. Returns to caller at the next address after the zero ter- ; minator. ; ILPRT: XTHL ;save hl, get message address ; ILPLP: MOV A,M ;get char CALL TYPE ;output it INX H ;point to next MOV A,M ;test ORA A ;..for end JNZ ILPLP XTHL ;restore hl, ret address RET ;return past the end of the message ;..... ; ; MOVE: MOV A,M STAX D INX H INX D DCR B ;decrement byte count JNZ MOVE ;if not zero, move another byte RET ;..... ; ; ; Send character in A register to console ; TYPE: PUSH B PUSH D PUSH H MOV E,A ;char to e for cp/m MVI C,WRCON ;write to console CALL BDOS POP H POP D POP B RET ;..... ; ; ; Decimal output - print HL as decimal number with leading zero suppres- ; sion. ; DECOUT: PUSH B PUSH D PUSH H LXI B,-10 LXI D,-1 ; DECOU2: DAD B INX D JC DECOU2 LXI B,10 DAD B XCHG MOV A,H ORA L CNZ DECOUT MOV A,E ADI '0' CALL TYPE POP H POP D POP B RET ;..... ; ; ; 'Declare' output file ; DEST: DB 0,' $$$',0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0 ONAME: DB 0,' ',0,0,0,0,0,' BAK',0,0,0,0 SNAME: DB 0,' BAK',0,0,0,0,0 ; OUTPUTADR: DW BUFFER OUTPUTSIZ: DW BSIZE OUTPUTPTR: DS 2 ; ; ; LSTCHR: DB 0 ;last character reminder ICOUNT: DW 0 ;input line counter OCOUNT: DW 0 ;output line counter DCOUNT: DW 0 ;deleted character counter OLFCNT: DW 0 ;orphan line feed counter HCOUNT: DW 0 ;hi-order bits zeroed counter ;..... ; DS 100 ;room for 50-level stack ; ; ; Set write buffer to even page boundry ; ORG ($+255)/256*256 ; BUFFER: EQU $ ;write buffer starts here STACK: EQU BUFFER-2 ; END