PAGE    60
       TITLE   'ENTAB - REPLACE SPACES WITH TABS V1.3 2/5/81'
;
;     A SOFTWARE TOOL AS DESRIBED 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.
;
BDOS    EQU     5       ;CPM ENTRY
FCB     EQU     5CH     ;DEFAULT FCB
;
PRINT   EQU     9
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
       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     GTFCB
SGNMSG: DB      CR,LF,'ENTAB  V1.3  2/5/81',CR,LF,DOLLAR
;
GTFCB:  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  ;GET DESTINATION DRIVE
       ORA     A       ;HAS USER ENTERED VALUE
       JZ      DEL
       SBI     'A'-1   ;MAKE IT A NUMBER
       STA     FCB2    ;FILL IT IN
;
DEL:    MVI     A,0     ;MAKE NEXT RECORD 0
       STA     FCB1+32
       STA     FCB2+32
       LXI     D,FCB2
       MVI     C,DELETE
       CALL    BDOS    ;DELETE IT JUST IN CASE
;
       LXI     D,FCB2
       MVI     C,CREATE
       CALL    BDOS    ;NOW CREATE IT
       INR     A
       JNZ     ENTAB   ;FILE CREATED
       LXI     D,CRMSG ;'NO DIRECTORY SPACE'
       MVI     C,PRINT
       CALL    BDOS
       JMP     EXIT    ;CAN'T KEEP GOING
CRMSG:  DB      'CANT CREATE DESTINATION FILE',CR,LF,DOLLAR
;
;
ENTAB:  MVI     A,0     ;COL=0
       STA     COL
NXTCHR: LDA     COL     ;NEWCOL=COL
       STA     NEWCOL
BLNK:   CALL    GETC    ;GET A CHARACTER
       STA     CHAR
       CPI     BLANK   ;IS IT A BLANK?
       JNZ     NTBLNK
       LDA     NEWCOL
       INR     A
       STA     NEWCOL  ;NEWCOL=NEWCOL+1
       ANI     7       ;CHECK FOR TAB POS
       JNZ     BLNK    ;GUESS NOT!
       MVI     C,TAB
       CALL    PUTC
       LDA     NEWCOL
       STA     COL
       JMP     BLNK    ;GET ANOTHER
NTBLNK: LDA     CHAR
       CPI     TAB
       JNZ     NOTTAB
       LDA     NEWCOL  ;HAVE A TAB SO
       ADI     8       ;.GET TO NEXT
       ANI     0F8H    ;.TAB POSITION
       STA     NEWCOL  ;UPDATE POINTERS
       STA     COL
       MVI     C,TAB   ;NOW PUT OUT THE TAB CHAR
       CALL    PUTC
       JMP     BLNK    ;GO FOR MORE CHARACTERS
NOTTAB: LDA     COL     ;IF COL<NEWCOL
       LXI     H,NEWCOL
       SUB     M
       JP      EOFCHK
       MVI     C,BLANK
       CALL    PUTC    ;FILL IN THE BLANKS
       LXI     H,COL   ;COL=COL+1
       INR     M
       JMP     NOTTAB
EOFCHK: LDA     CHAR
       MOV     C,A     ;FIRST OUTPUT THE CHAR
       CALL    PUTC
       LDA     CHAR
       CPI     EOF
       JZ      DONE
       CPI     0FFH    ;NO DATA LEFT
       JZ      DONE
       CPI     LF      ;TREAT LF AS NEWLINE
       JZ      ENTAB
       CPI     CR      ;ALONG WITH CR
       JZ      ENTAB
       LXI     H,COL
       INR     M       ;COL=COL+1
       JMP     NXTCHR  ;ELSE CONTINUE ON THIS LINE
;
;
DONE:   CALL    PUTBUF  ;WRITE UNFINISHED BUFFER
       LXI     D,FCB2
       MVI     C,CLOSE
       CALL    BDOS    ;CLOSE THE NEW FILE
;

       LXI     D,FCB1
       MVI     C,DELETE
       CALL    BDOS    ;NOW DELETE THE ORIGINAL
;
       LXI     H,FCB1  ;MOVE THE NEW FILE NAME
       LXI     D,FCB2+16       ;TO FCB2
       MVI     C,16
       CALL    MOVE
       MVI     A,0
       STA     FCB2+16 ;MAKE SURE ITS 0
;
       LXI     D,FCB2
       MVI     C,RENAME
       CALL    BDOS    ;RENAME .$$$ TO ORIGINAL
;
       LXI     D,DNMSG ;TELL THEM WERE DONE
       MVI     C,PRINT
       CALL    BDOS
       JMP     EXIT
DNMSG:  DB      'ENTAB DONE',CR,LF,DOLLAR
;
EXIT:   LXI     D,80H   ;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,C     ;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,WERMSG        ;'WRITE ERROR'
       MVI     C,PRINT
       CALL    BDOS
       JMP     EXIT    ;THIS WILL FIX STACK
WERMSG: DB      'WRITE ERROR',CR,LF,DOLLAR
       DS      48      ;SOME STACK SPACE
STACK:  DW      0
COL:    DB      0
NEWCOL: 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