;	SORTDIR - CP/M UTILITY TO SORT DISK DIRECTORY
;
	ORG	0100H
	JMP	SORTDIR
	DB	'(C) 1980 - N D H HAMMOND'
PRGNAME	DB	'SORTDIR V1.1 OF 22APR80'
	DB	0DH,0AH,'$'
;
;	DEFINITIONS
;
BOOT	EQU	0000H		;CP/M BOOT VECTOR
CBIOS	EQU	BOOT+1		;^CBIOS
ENTRY	EQU	0005H		;CP/M FDOS ENTRY
TBUFF	EQU	0080H		;DEFAULT BUFFER
DIRTRK	EQU	2		;DIRECTORY TRACK NO
NDIRSEC	EQU	16		;NO OF DIR SECTORS
NDIRENT	EQU	64		;MAX NO OF DIR ENTRIES
ENTLGTH	EQU	32		;ENTRY LGTH IN BYTES
NLGTH	EQU	8		;NAME FIELD LGTH
TLGTH	EQU	3		;TYPE FIELD LGTH
FNLGTH	EQU	NLGTH+TLGTH	;LENGTH OF FILENAME
FLSTEP	EQU	0FH		;OFFSET TO FL FIELD
DELCHR	EQU	0E5H		;DELETED DATA CHAR
NAME	EQU	0		;SORT BY FILE NAME
TYPE	EQU	0FFH		;SORT BY FILE TYPE
;
;	MAIN PROGRAM
;
SORTDIR	LXI	H,0		;SAVE SYSTEM SP
	DAD	SP
	SHLD	OLDSP
	LXI	SP,STACK
	LXI	D,PRGNAME	;PRINT SIGNON MSG
	CALL	WRITESTRING
	CALL	CHECKMODE
	CALL	GETDISK
	CALL	READDIR
	CALL	TIDY
	CALL	SORT
	CALL	WRITEDIR
	CALL	INITBDOS
	LXI	D,TERMMSG
	CALL	WRITESTRING
	LHLD	OLDSP		;RESTORE SYSTEM SP
	SPHL
	RET			;RETURN TO CP/M
;
;	SUBROUTINES
;
CHECKMODE	;CHECK FOR NAME-TYPE OR TYPE-NAME SORT
	MVI	A,NAME
	STA	MODE
	LXI	H,TBUFF
	MOV	A,M
	CPI	2
	JNZ	NOSTAR
	INX	H
	INX	H
	MOV	A,M
	CPI	'*'
	JNZ	NOSTAR
	MVI	A,TYPE
	STA	MODE
NOSTAR	RET
;
;
GETDISK	;PROMPT OPERATOR FOR DISK
	LXI	D,DSKMSG
	CALL	WRITESTRING
GET1	CALL	READCHAR
	CPI	0DH		;<CR> ?
	RZ
	CPI	03H		;<^C> ?
	JZ	BOOT
	JMP	GET1
;
;
READDIR	;READ DISK DIRECTORY INTO BUFFER
	MVI	C,DIRTRK	;SET TRACK NO
	CALL	SETTRK
	LXI	H,BUFFER	;INITIALIZE BUFFPT
	SHLD	BUFFPT
	XRA	A		;INITIALIZE SECTOR
	STA	SECTOR
READLP	CALL	NEXTSEC		;SET SECTOR NO
	LHLD	BUFFPT		;SET DMA ADDRESS
	MOV	B,H
	MOV	C,L
	CALL	SETDMA
	CALL	READ		;READ SECTOR
	LHLD	BUFFPT		;UPDATE DMA ADDRESS
	LXI	D,80H
	DAD	D
	SHLD	BUFFPT
	LDA	SECTOR		;UPDATE SECTOR
	INR	A
	STA	SECTOR
	CPI	NDIRSEC
	JNZ	READLP
	RET
;
;
WRITEDIR	;WRITE DISK DIRECTORY FROM BUFFER
	MVI	C,DIRTRK	;SET TRACK NO
	CALL	SETTRK
	LXI	H,BUFFER	;INITIALIZE BUFFPT
	SHLD	BUFFPT
	XRA	A		;INITIALIZE SECTOR
	STA	SECTOR
WRITELP	CALL	NEXTSEC		;SET SECTOR NO
	LHLD	BUFFPT		;SET DMA ADDRESS
	MOV	B,H
	MOV	C,L
	CALL	SETDMA
	CALL	WRITE		;WRITE SECTOR
	LHLD	BUFFPT	;UPDATE DMA ADDRESS
	LXI	D,80H
	DAD	D
	SHLD	BUFFPT
	LDA	SECTOR	;UPDATE SECTOR
	INR	A
	STA	SECTOR
	CPI	NDIRSEC
	JNZ	WRITELP
	RET
;
;
NEXTSEC	;SET SECTOR NO TO NEXT DIRECTORY SECTOR
	;MAPS SEQUENTIAL NO IN REG-A TO PHYSICAL
	;SECTOR ON DISK.
	LXI	H,SEGTABLE
	MVI	B,0
	MOV	C,A
	DAD	B
	MOV	C,M
	CALL	SETSEC
	RET
;
SEGTABLE
	DB	01H,07H,0DH,13H
	DB	19H,05H,0BH,11H
	DB	17H,03H,09H,0FH
	DB	15H,02H,08H,0EH
;
;
TIDY	;TIDY DIRECTORY BY COMPLETELY DELETING 
	;ERASED ENTRIES AND ENTRIES OF ZERO LENGTH
	MVI	D,NDIRENT
	LXI	H,BUFFER
TIDYLP	MOV	A,M		;CHECK FOR ERASED FILE
	PUSH	H
	CPI	DELCHR
	CZ	DELETE
	LXI	B,FLSTEP	;CHECK FOR ZERO LGTH
	DAD	B
	MOV	A,M
	POP	H
	PUSH	H
	CPI	0
	CZ	DELETE
	LXI	B,ENTLGTH	;STEP TO NEXT ENTRY
	POP	H
	DAD	B
	DCR	D
	JNZ	TIDYLP
	RET
;
;
DELETE	;DELETE FILE ENTRY AT HL^
	;PRESERVE HL
	PUSH	H
	MVI	B,ENTLGTH
DELLP	MVI	M,DELCHR
	INX	H
	DCR	B
	JNZ	DELLP
	POP	H
	RET
;
;
SORT	;BUBBLE SORT DIRECTORY INTO ALPHABETICAL ORDER
	MVI	A,NDIRENT-1
	STA	OPC		;OUTER LOOP PASSES
SORTOLP	STA	IPC		;INNER LOOP PASSES
	LXI	B,2*ENTLGTH
	LXI	H,BUFFER
	LXI	D,BUFFER+ENTLGTH
SORTILP	PUSH	B
	PUSH	H
	PUSH	D
	LDA	MODE
	CPI	NAME
	JNZ	CTYP
	CALL	COMPNAME
	JMP	CKSWP
CTYP	CALL	COMPTYPE
CKSWP	CC	SWAP
	POP	D
	POP	H
	POP	B
	DAD	B
	XCHG
	LDA	IPC
	DCR	A
	STA	IPC
	JNZ	SORTILP	;END INNER LOOP
	LDA	OPC
	DCR	A
	STA	OPC
	JNZ	SORTOLP	;END OUTER LOOP
	RET
;
;
COMPNAME	;COMPARE FILES BY NAME:TYPE
	MVI	B,FNLGTH
	CALL	COMPARE
	RET
;
;
COMPTYPE	;COMPARE BY TYPE:NAME
	PUSH	H
	PUSH	D
	LXI	B,NLGTH+1
	DAD	B
	XCHG
	DAD	B
	XCHG
	MVI	B,TLGTH
	CALL	COMPARE
	POP	D
	POP	H
	RNZ
	MVI	B,NLGTH
	CALL	COMPARE
	RET
;
;
COMPARE	;COMPARE FIELDS (LENGTH B) OF ENTRIES AT HL^
	;AND DE^. SET C AND Z FLAGS (C => DE^
	;FILENAME SMALLER).
	;PRESERVE REGS HL AND DE
	PUSH	D
	PUSH	H
COMPLP	LDAX	D
	CMP	M
	JNZ	ENDCOMP
	INX	D
	INX	H
	DCR	B
	JNZ	COMPLP
	XRA	A
ENDCOMP	POP	H
	POP	D
	RET
;
;
SWAP	;SWAP ENTRIES AT HL^ AND DE^
	MVI	B,ENTLGTH
SWAPLP	LDAX	D
	MOV	C,A
	MOV	A,M
	MOV	M,C
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	SWAPLP
	RET
;
;	I/O ROUTINES
;
WRITESTRING	;WRITE STRING TO CONSOLE
	MVI	C,9
	JMP	ENTRY
;
;
READCHAR	;READ CHARACTER FROM CONSOLE
	MVI	C,1
	JMP	ENTRY
;
;
INITBDOS	;INITIALIZE BDOS, LOG IN DISK A
	MVI	C,13
	JMP	ENTRY
;
;
;	WARNING - THESE LOW LEVEL DISK I/O ROUTINES
;	ACCESS THE CP/M CBIOS DIRECTLY.  THEY MAY
;	NEED MODIFICATION WITH NON STANDARD SYSTEMS.
;
;
SETTRK	;SET TRACK (C-REG)
	LHLD	CBIOS
	MVI	L,1EH
	PCHL
;
;
SETSEC	;SET SECTOR (C-REG)
	LHLD	CBIOS
	MVI	L,21H
	PCHL
;
;
SETDMA	;SET TRANSFER ADDRESS (BC-REG)
	LHLD	CBIOS
	MVI	L,24H
	PCHL
;
;
READ	;READ A SECTOR
	LHLD	CBIOS
	MVI	L,27H
	PCHL
;
;
WRITE	;WRITE A SECTOR
	LHLD	CBIOS
	MVI	L,2AH
	PCHL
;
;
;	DATA AREA
;
DSKMSG	DB	'INSERT DISK, <CR> TO CONTINUE'
	DB	0DH,0AH,'$'
TERMMSG	DB	'FUNCTION COMPLETE'
	DB	0DH,0AH,'$'
OLDSP	DS	2	;SYSTEM STACK POINTER
SECTOR	DS	1	;CURRENT SECTOR SEQUENCE NO
MODE	DS	1	;SORT MODE FLAG
IPC	DS	1	;INNER PASS COUNTER
OPC	DS	1	;OUTER PASS COUNTER
BUFFPT	DS	2	;BUFFER POINTER
	DS	20H	;STACK SPACE
STACK	EQU	$	;GROWS DOWN
BUFFER	EQU	$	;GROWS UP
;
	END

