	TITLE	'SAP - SORT AND PACK DIRECTORY'
;
;	L.E. HUGHES	8080SDC
;
;	FIX 1/23/81 W. EARNEST FOR CP/M 2.2 & 1.4
;	FIX FOR ANY SIZE SYSTEM TO 256 DIRECT ENTRIES
;	FIX FOR ANY DRIVE UP TO 4
;
;	OFFSET FROM WARM BOOT VECTOR
;
SELDSK	EQU	24
SETTRK	EQU	27
SETSEC	EQU	30
SETDMA	EQU	33
READ	EQU	36
WRITE	EQU	39
XLT	EQU	45
BDOS	EQU	5
 
	ORG	100H
SAP:	LXI	SP,STACK+32
	MVI	C,12	;CHECK VERSION
	CALL	BDOS
	MOV	A,H
	ORA	L
	STA	VERFLG
	MVI	C,25	;GET CURR DSK
	CALL	BDOS
	MOV	C,A	;SELECT IT ASSUMED
	LDA	5CH	;FCB
	ORA	A	;TEST IF DEFINED
	JZ	SEDRV	;NO, USE DEFAULT
	DCR	A	;ADJUST FOR BIOS
	MOV	C,A
SEDRV:	MVI	E,SELDSK
	CALL	XCPM
	LDA	VERFLG
	ORA	A
	JZ	SELSKP	;NOT 2.X
	MOV	A,H
	ORA	L
	JZ	0	;ABORT IF ILLEGAL
	MOV	E,M
	INX	H
	MOV	D,M	;XLATE MAP ADDRESS
	XCHG
	SHLD	ADMAP
	LXI	H,9	;DPB OFFSET
	DAD	D
	MOV	A,M
	INX	H
	MOV	H,M	;DPB ADDR
	MOV	L,A
	MOV	E,M
	INX	H
	MOV	D,M	;SECTORS PER TRK
	XCHG
	SHLD	SPERT
	LXI	H,6
	DAD	D
	MOV	E,M
	INX	H
	MOV	D,M	;DIRECT ENTRIES
	XCHG
	SHLD	DIRENT
	LXI	H,5
	DAD	D
	MOV	E,M
	INX	H
	MOV	D,M
	XCHG
	SHLD	TKOFFS	;OFFSET TO FIRST DIR TRK
;
SELSKP:	LHLD	TKOFFS
	SHLD	CURTRK
	CALL	DOTRK
	XRA	A		;SECNO=0 LOGICAL
	STA	SECNO
	STA	LSEC
	LXI	H,BUF		;ADDR = FWA OF BUFFER
	SHLD	ADDR
;
SAP1:	CALL	XLATS	;SET TO SECTOR "SECNO"
	LHLD	ADDR		;SET DMA ADDRESS TO "ADDR"
	MOV	B,H
	MOV	C,L
	MVI	E,SETDMA
	CALL	XCPM
	MVI	E,READ
	CALL	XCPM		;READ SECTOR INTO MEMORY
	LHLD	ADDR		;ADDR = ADDR + 80H
	LXI	D,128
	DAD	D
	SHLD	ADDR
	LDA	SECNO		;SECNO = SECNO + 1
	INR	A
	STA	SECNO
	LXI	H,SPERT
	CMP	M
	JC	SAMTK1
	LHLD	CURTRK
	INX	H
	SHLD	CURTRK
	XRA	A
	STA	SECNO
	CALL	DOTRK
SAMTK1:	LXI	H,LSEC
	INR	M
	MOV	A,M
	ADD	A
	ADD	A	;TIMES 4ENT/TRK
	DCR	A
	LXI	H,DIRENT
	CMP	M
	JNZ	SAP1
;
	CALL	CLEAN		;CLEAN THE DIRECTORY
	CALL	SORT		;SORT THE DIRECTORY
	CALL	PACK		;PACK THE DIRECTORY
	XRA	A		;SECNO = 0 LOGICAL
	STA	SECNO
	STA	LSEC
	LHLD	TKOFFS
	SHLD	CURTRK
	CALL	DOTRK
	LXI	H,BUF		;ADDR = FWA OF BUFFER
	SHLD	ADDR
;
SAP2:	CALL	XLATS
	LHLD	ADDR		;SET DMA ADDRESS TO "ADDR"
	MOV	B,H
	MOV	C,L
	MVI	E,SETDMA
	CALL	XCPM
	MVI	E,WRITE
	CALL	XCPM		;WRITE SECTOR TO DISK
	LHLD	ADDR		;ADDR = ADDR + 80H
	LXI	D,128
	DAD	D
	SHLD	ADDR
	LDA	SECNO		;SECNO = SECNO + 1
	INR	A
	STA	SECNO
	LXI	H,SPERT
	CMP	M
	JC	SAMTK2
	LHLD	CURTRK
	INX	H
	SHLD	CURTRK
	XRA	A
	STA	SECNO
	CALL	DOTRK
SAMTK2:	LXI	H,LSEC
	INR	M
	MOV	A,M
	ADD	A
	ADD	A
	DCR	A
	LXI	H,DIRENT
	CMP	M
	JNZ	SAP2
	JMP	0		;EXIT TO CP/M WARM BOOT
;
DOTRK:	MOV	B,H
	MOV	C,L
	MVI	E,SETTRK
	JMP	XCPM
;
CLEAN:	MVI	A,0		;I = 0
CLEAN1:	STA	I
	CALL	INDEX		;HL = BUF + 32 * I
	MOV	A,M		;JUMP IF THIS IS A DELETED FILE
	CPI	0E5H
	JZ	CLEAN2
	LXI	D,9		;OFFSET TO R/O FLG
	DAD	D
	MOV	A,M
	ANI	80H
	JNZ	CLEAN4
	LXI	D,6		;HL = HL + 6
	DAD	D
	MOV	A,M		;CHECK RECORD COUNT FIELD
	ORA	A
	JNZ	CLEAN4		;JUMP IF NON-ZERO
CLEAN2:	LDA	I		;CLEAR ALL 32 BYTES OF
	CALL	INDEX		;  DIRECTORY ENTRY TO E5
	MVI	C,32
CLEAN3:	MVI	M,0E5H
	INX	H
	DCR	C
	JNZ	CLEAN3
CLEAN4:	LDA	I		;I = I + 1
	LXI	H,DIRENT
	CMP	M
	RZ
	INR	A
	JMP	CLEAN1
;
XLATS:	LDA	VERFLG
	ORA	A
	LDA	SECNO
	JNZ	XLT2
	LXI	H,LPMAP
	ADD	L
	MOV	L,A
	JNC	NOCRY
	INR	H
NOCRY:	MOV	C,M
XLT3:	MVI	E,SETSEC
	JMP	XCPM
;
XLT2:	MOV	C,A
	MVI	B,0
	LHLD	1
	LXI	D,XLT
	DAD	D
	LXI	D,XRSLT
	PUSH	D	;FAKE CALL
	XCHG
	LHLD	ADMAP
	XCHG
	PCHL
;
XRSLT:	MOV	C,L
	JMP	XLT3
;
ADMAP:	DW	LPMAP
;
LPMAP:	DB	01,07,13,19,25,05,11,17,23,03,09,15,21
	DB	02,08,14,20,26,06,12,18,24,04,10,16,22
 
COMP:	LDA	I		;HL = BUF + 32 * I
	CALL	INDEX
	PUSH	H
	LDA	J		;HL = BUF + 32 * J
	CALL	INDEX
	XCHG
	POP	H
	MVI	C,13		;NUMBER OF BYTES TO COMPARE
COMP1:	MOV	A,M	;GET NEXT BYTE
	ANI	7FH	;REMOVE ATTRIBUTE
	MOV	B,A
	LDAX	D		;COMPARE NEXT BYTE
	ANI	7FH	;REMOVE ATTRIBUTES
	CMP	B
	RNZ			;RETURN IF NOT EQUAL
	INX	D
	INX	H
	DCR	C		;LOOP THRU FIRST 13 BYTES
	JNZ	COMP1
	XRA	A		;CLEAR FLAGS AND EXIT
	RET
 
SORT:	MVI	A,0		;I = 0
	STA	I
SORT1:	LDA	I		;J = I + 1
	INR	A
	STA	J
SORT2:	CALL	COMP		;IF NAME(J)<NAME(I), SWAP
	CC	SWAP
	LDA	J		;J = J + 1
	INR	A
	STA	J
	JZ	SORT3
	LXI	H,DIRENT
	CMP	M
	JNZ	SORT2
SORT3:	LDA	I		;I = I + 1
	INR	A
	STA	I
	LXI	H,DIRENT
	RZ
	CMP	M
	JC	SORT1
	RET
 
SWAP:	LDA	I
	CALL	INDEX
	PUSH	H
	LDA	J
	CALL	INDEX
	XCHG
	POP	H
	MVI	C,32
SWAP1:	LDAX	D
	MOV	B,A
	MOV	A,M
	STAX	D
	MOV	M,B
	INX	D
	INX	H
	DCR	C
	JNZ	SWAP1
	RET
 
INDEX:	MOV	L,A
	MVI	H,0
	DAD	H
	DAD	H
	DAD	H
	DAD	H
	DAD	H
	LXI	D,BUF
	DAD	D
	RET
 
PACK:	MVI	A,0		;I = 0
PACK1:	STA	I
	CALL	INDEX		;HL = BUF + 32 * I
	MOV	A,L		;HL = HL + 9
	ADI	9
	MOV	L,A
	JNC	$+4
	INR	H
	MOV	A,M		;JUMP IF FILETYPE NOT 'X$$'
	SUI	'0'		;  WHERE 0.LE.X.LE.9
	JC	PACK2
	CPI	10
	JNC	PACK2
	STA	J
	INX	H
	MOV	A,M
	CPI	'$'
	JNZ	PACK2
	INX	H
	MOV	A,M
	CPI	'$'
	JNZ	PACK2
	INX	H		;SET EXTENT NUMBER TO X
	LDA	J
	MOV	M,A
	DCX	H		;SET FILETYPE TO '$$$'
	MVI	M,'$'
	DCX	H
	MVI	M,'$'
	DCX	H
	MVI	M,'$'
PACK2:	LDA	I		;I = I + 1
	LXI	H,DIRENT
	CMP	M
	RZ
	INR	A
	JMP	PACK1
;
XCPM:	MVI	D,0	;CLEAR HI BYTE
	LHLD	1	;WARM BOOT VECT ADDR
	DAD	D	;CALC VECTOR
	PCHL
;
;	DATA AREA
CURTRK:	DW	2
SPERT	DW	26	;1.4 DEFLT
DIRENT:	DW	63	;1.4
TKOFFS:	DW	2	;1.4
VERFLG:	DB	0
LSEC:	DB	0
STACK:	DS	32
SECNO:	DS	1
ADDR:	DS	2
I:	DS	1
J:	DS	1
	DS	1	;MAKE EVEN
BUF:	DS	1
;
	END
