	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
