; TITLE 'ENTAB - REPLACE SPACES WITH TABS V1.5 ' ; ; A SOFTWARE TOOL AS DESCRIBED BY KERNIGAN AND PLAUGHER ; WHICH COMPRESSES SPACES INTO APPROPRIATE TABS AS PER ; CP/M CONVENTIONS. IT IS USEFUL FOR COMPACTING A PROGRAM ; AFTER A MODEM TRANSFER WHICH EXPANDS THE TABS. ; ; ; REVISION HISTORY ; ;10/10/81. ; ; ADDED EQU FOR MODIFIED CP/M AND QUOTE AS DEFAULT DELIM. T. SHAPIN ; ; 9/5/81 ; 1. REWROTE COMPRESSION ROUTINE TO WORK PROPERLY ; ; 2. ADDED FEATURE TO DISABLE COMPRESSION INSIDE ; QUOTED STRINGS, SINCE SOME LANGUAGES AND ; ASSEMBLERS DON'T LIKE TABS IN THEIR STRINGS. ; FOR EXAMPLE, AN ASSEMBLY FILE MAY HAVE A LINE: ; ; PASSWORD: DB ' ' ; ; IS THAT THE SAME THING AS THIS LINE? ; ; PASSWORD: DB 09H ; ; MOST DEFINITELY NOT, BUT THAT IS WHAT WE WOULD ; GET IF ENTAB COMPRESSED THOSE BLANKS INTO 1 TAB ; CHARACTER. ENTAB WILL PROMPT FOR THE STRING ; FIELD DELIMITING CHARACTER EACH TIME IT IS RUN ; (NORMALLY ' FOR ASSEMBLERS, AND " FOR BASICS). ; ; 3. MODIFIED OUTPUT FILE CODE TO SAVE THE ORIGINAL ; FILE AS A "BAK" FILE IF THE OUTPUT FILE IS GOING ; TO THE SAME DRIVE AS THE INPUT FILE. IF THE ; OUTPUT FILE IS GOING TO A DIFFERENT DRIVE, THEN ; THE ORIGINAL FILE WILL BE LEFT UNCHANGED. ; PREVIOUSLY, THE ORIGINAL FILE WAS ALWAYS ERASED. ; BIAS EQU 0H ; 0 FOR STANDARD CP/M, 4200H FOR MODIFIED BDOS EQU 5+BIAS ;CPM ENTRY FCB EQU 5CH+BIAS ;DEFAULT FCB ; PRINT EQU 9 BUFFIN EQU 10 OPEN EQU 15 CLOSE EQU 16 DELETE EQU 19 READ EQU 20 WRITE EQU 21 CREATE EQU 22 RENAME EQU 23 SETDMA EQU 26 BLANK EQU ' ' TAB EQU 9 CR EQU 0DH LF EQU 0AH EOF EQU 1AH ;CONTROL Z DOLLAR EQU '$' ; REC EQU 16 ;NUMBER OF SECTORS PER TRANSFER ; ORG 100H+BIAS LXI H,0 ;SET UP OUR OWN STACK DAD SP ;SAVE THEIRS SHLD STACK LXI SP,STACK ; LXI D,SGNMSG ;TELL THE FOLKS OUR NAME MVI C,PRINT CALL BDOS JMP GETFCB ; SGNMSG: DB CR,LF,'ENTAB - VERS 1.5 - 10/9/81',CR,LF,LF,'$' ; GETFCB: LXI H,FCB ;GET THE TYPED IN FILE NAME LXI D,FCB1 MVI C,16 CALL MOVE ;AND MOVE IT TO OUR OWN LXI H,FCB LXI D,FCB2 MVI C,16 CALL MOVE ;AND AGAIN ; LXI D,FCB1 MVI C,OPEN CALL BDOS ;OPEN IT INR A JNZ FILSEC ;NO ERROR LXI D,FNFMSG ;'FILE NOT FOUND' MVI C,PRINT CALL BDOS JMP EXIT ; FNFMSG: DB 'File Not Found',CR,LF,DOLLAR ; FILSEC: LXI H,FCB2+9 ;SEC NAME MVI M,DOLLAR ;MAKE IT '.$$$' INX H MVI M,DOLLAR INX H MVI M,DOLLAR LDA FCB+16 ;IF USER ENTERS A DESTINATION ORA A ;.. DRIVE CODE ... JNZ DEFALT LDA FCB1 DEFALT: STA FCB2 ;.. STASH IT IN OUTPUT FILE FCB ; DEL: MVI A,0 ;MAKE NEXT RECORD 0 STA FCB1+32 STA FCB2+32 LXI D,FCB2 ;DELETE ANY EXISTING TEMPORARY FILES MVI C,DELETE CALL BDOS ; LXI D,FCB2 MVI C,CREATE CALL BDOS ;NOW CREATE TEMPORARY OUTPUT FILE INR A JNZ GTDEL ;FILE CREATED LXI D,DSKMSG ;'NO DIRECTORY SPACE' MVI C,PRINT CALL BDOS JMP EXIT ;CAN'T KEEP GOING ; PROMPT: DB 'Enter the String Delimiter (CR='') ? $' BEGMSG: DB CR,LF,'Beginning Blanks Compression',CR,LF,'$' ; GTDEL: LXI D,PROMPT ;ASK FOR DELIMITER CHARACTER MVI C,PRINT CALL BDOS ; ;WE INPUT THE DELIMITER CHARACTER BY USING THE BUFFER INPUT ;ROUTINE TO ALLOW THE USER TO CORRECT AN INPUT ERROR, OR TO ;ABORT TO CP/M. A SINGLE CONIN CALL, ALTHOUGH REQUIRING LESS ;CODE, WOULD NOT ALLOW ANY MARGIN FOR ERROR IN SPECIFYING THE ;DELIMITER CHARACTER. ; LXI D,CIBUF ;SETUP CONSOLE INPUT BUFFER MVI A,2 STAX D ;ALLOW 2 CHARACTERS MAXIMUM MVI C,BUFFIN ;GET THE DELIMITER CHARACTER CALL BDOS LDA CIBUF+1 ;HOW MANY CHARACTERS ENTERED? ORA A MVI A,'''' ;DEFAULT TO QUOTE JZ SAVDEL ;USE DELIMITER OF 0 IF NO INPUT LDA CIBUF+2 ;ELSE, EXTRACT 1ST CHARACTER SAVDEL: STA DELIM+1 ;SAVE IT IN-LINE FOR COMPARISON LXI D,BEGMSG ;TELL USER WE'VE BEGUN MVI C,PRINT CALL BDOS ; ;BEGIN SCANNING INPUT BUFFER AND PACK THE SPACES INTO TABS ; ENTAB: XRA A STA COLUMN ;INITIALIZE TAB POSITION STA BLANKS ;CLEAR BLANK ACCUMULATOR STA SFLG ;CLEAR STRING FLAG NEXCHR: CALL GETC ;GET NEXT CHARACTER FROM FILE STA CHAR ;SAVE INPUT CHARACTER CPI TAB JNZ NOTAB CALL DUMBLK ;ON TAB, DUMP PENDING BLANKS TABIT: MVI A,TAB ;PASS THE TAB ALONG CALL PUTC XRA A STA COLUMN ;CLEAR TAB POSITION JMP NEXCHR ;GET THE NEXT CHARACTER ; NOTAB: CPI LF ;END OF LINE MARKERS? JZ EOL CPI CR JNZ NOEOL EOL: CALL DUMBLK ;DUMP TRAILING BLANKS IF SO LDA CHAR ;THEN DUMP THE CR OR LF CALL PUTC JMP ENTAB ;AND START NEXT LINE ; NOEOL: CPI BLANK ;SPACE CHARACTER? JNZ NOBLK LXI H,BLANKS ;INCREMENT BLANK COUNTER INR M LDA SFLG ;ARE WE IN A QUOTED STRING? ORA A JNZ STRING ;BLANK NOT SIGNIFICANT IF SO CALL BUMCOL ;BUMP TAB POSITION JNZ NEXCHR ;CONTINUE SCANNING IF NOT AT TAB STOP STA BLANKS ;OTHERWISE, CLEAR BLANKS COUNTER JMP TABIT ;PUT TAB INTO OUTPUT FILE ; STRING: CALL BUMCOL ;INSIDE QUOTED STRING, BUMP TAB POSITION JMP NEXCHR ;CONTINUE SCANNING TIL END OF STRING ; NOBLK: CPI EOF ;CP/M FILE EOF? JZ EOFILE CPI 0FFH ;GETBUF EOF? JZ EOFILE CALL DUMBLK ;CHARACTER NONE OF ABOVE - FLUSH BLANKS CALL BUMCOL ;BUMP TAB POSITION LDA CHAR PUSH PSW CALL PUTC ;SEND LITERAL CHARACTER POP PSW DELIM: CPI 0 ;IS CHARACTER STRING DELIMITER? JNZ NEXCHR LDA SFLG ;TOGGLE STRING FLAG IF SO CMA STA SFLG JMP NEXCHR ;SCAN FOR NEXT CHARACTER ; DUMBLK: LDA BLANKS ;FLUSH THE ACCUMULATED BLANKS ORA A RZ DCR A STA BLANKS MVI A,' ' CALL PUTC JMP DUMBLK ; BUMCOL: LDA COLUMN ;INCREMENT TAB POSITION INR A ANI 7 STA COLUMN RET ; EOFILE: CALL PUTC ;OUTPUT EOF CHARACTER CALL PUTBUF ;WRITE UNFINISHED BUFFER LXI D,FCB2 MVI C,CLOSE CALL BDOS ;CLOSE THE NEW FILE ; LDA FCB2 ;GET DESTINATION DR CODE TO INPUT FCB STA FCB1 LXI H,FCB1 ;SETUP RENAME FCB FOR ORIGINAL FILENAME LXI D,FCB1+16 PUSH D ;SAVE POINTER TO 2ND RENAME FIELD PUSH D MVI C,9 CALL MOVE ;MOVE FILENAME TO 2ND RENAME FIELD XCHG MVI M,'B' ;MAKE 2ND RENAME FILETYPE="BAK" INX H MVI M,'A' INX H MVI M,'K' POP D ;RECALL POINTER TO 2ND RENAME FIELD MVI C,DELETE ;ERASE ANY EXISTING BAK FILE ON OUTPUT DRIVE CALL BDOS POP H ;RECALL RENAME FIELD POINTER AGAIN MVI M,0 ;CLEAR DR IN 2ND RENAME FIELD ; LXI D,FCB1 ;RENAME ANY FILE ON OUTPUT DRIVE WITH INPUT MVI C,RENAME ;..FILENAME TO TYPE "BAK" CALL BDOS ; KEEPIT: LXI H,FCB1+1 ;MOVE THE NEW FILE NAME LXI D,FCB2+16 ;TO FCB2 XRA A STAX D INX D MVI C,11 CALL MOVE ; LXI D,FCB2 MVI C,RENAME CALL BDOS ;RENAME .$$$ TO ORIGINAL ; LXI D,DNMSG ;TELL THEM WE'RE DONE MVI C,PRINT CALL BDOS JMP EXIT ; DNMSG: DB 'Blanks Compression Completed',CR,LF,DOLLAR ; EXIT: LXI D,80H+BIAS ;RESET DEFAULT DMA MVI C,SETDMA CALL BDOS ; LHLD STACK SPHL RET ;BACK TO CP/M ; ; ; MOVE -MOVE (HL -> (DE) FOR C BYTES ; MOVE: MOV A,M STAX D INX H INX D DCR C JNZ MOVE RET ; ; GETC: LHLD CICNT ;ANY CHAR IN BUFFER? MOV A,H ORA L CZ GETBUF ;GET SOME IF NOT LHLD CIPNT ;POINTER TO CHAR MOV A,M ;GET THE CHARACTER INX H ;INCREMENT THE POINTER SHLD CIPNT LHLD CICNT ;REDUCE THE COUNT DCX H SHLD CICNT RET ; GETBUF: MVI A,REC ;RECORDS PER BUFFER LXI H,0 SHLD CICNT ;INIT FO READ LXI H,CIBUF SHLD CIPNT ;INIT THE POINTER GBUF: SHLD DMAADD ;IPDATE DMA ADDRESS XCHG ;FOR BDOS CALL STA SECCNT ;UPDATE SECTORS TO GO ORA A RZ ;RETURN IF NONE MVI C,SETDMA CALL BDOS ;SET LOAD ADDRESS LXI D,FCB1 MVI C,READ CALL BDOS ;GET A SECTOR PUSH PSW ;SAVE DISK STATUS LHLD CICNT LXI D,128 ;# OF BYTES READ DAD D SHLD CICNT ;UPDATE IT LHLD DMAADD ;UPDATE POINTER POP PSW ;GET DISK STATUS ORA A JZ ROK ;READ WAS OK MVI M,0FFH ;OUR OWN END OF FILE RET ROK: DAD D ;THIS TO LDA SECCNT DCR A ;ONE LESS LEFT JMP GBUF ; PUTC: LHLD COPNT ;POINTER MOV M,A ;PUT CHAR IN BUFFER INX H SHLD COPNT ;INCREMENT POINTER LHLD COCNT INX H ;BUMP IT SHLD COCNT MOV A,H ;SEE IF END OF BUFFER CPI REC*128/256 CZ PUTBUF RET ; PUTBUF: LHLD COCNT ;# OF CHAR IN BUFFER SHLD TEMP LXI H,0 SHLD COCNT ;REINIT FOR NEXT TIME LXI H,COBUF SHLD COPNT ;REINIT FOR NEXT TIME PBUF: SHLD DMAADD ;UPDATE WRITE ADDRESS XCHG ;TO DE FOR CPM CALL LHLD TEMP ;ANY LEFT TO WRITE MOV A,L ORA H RZ ;IF NOT MVI C,SETDMA CALL BDOS LXI D,FCB2 ;WRITE FILE BLOCK MVI C,WRITE CALL BDOS ORA A ;CHECK FOR ERROR JNZ WRERR ;.AND TAKE CARE OF IT LHLD TEMP ;BYTE COUNT LXI D,-128 ;PER SECTOR DAD D ;THIS MANY LEFT SHLD TEMP MOV A,H ;GET SIGN BIT ORA A ;TEST IT RM ;ALL DATA WRITTEN (NOT A FULL BUFFER) LHLD DMAADD ;UPDATE BUFFER LXI D,128 DAD D JMP PBUF ; WRERR: LXI D,DSKMSG ;'WRITE ERROR' MVI C,PRINT CALL BDOS JMP EXIT ;THIS WILL FIX STACK ; DSKMSG: DB 'Disk or Directory Full',CR,LF,DOLLAR ; DS 48 ;SOME STACK SPACE STACK: DW 0 COLUMN: DB 0 BLANKS: DB 0 SFLG: DB 0 CHAR: DB 0 ;INPUT CHAR SECCNT: DB 0 ;SECTORS TO READ CICNT: DW 0 COCNT: DW 0 TEMP: DW 0 DMAADD: DW 0 FCB1: DS 33 FCB2: DS 33 CIPNT: DW CIBUF COPNT: DW COBUF CIBUF: DS 128*REC COBUF: DS 128*REC END @