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