;
	TITLE TIDY - Alphabetizes diskette directory
;
; Tidy assumes C: and D: are DSDD 8" disks. Dangerous to SSSD
; Edit ATEDIRS ATELEN and ATEST below to change this.
;
; Call Walter Burt, 109 N. Few, Madison WI 53703, 257-0373 with gripes
;
PROGSEG	SEGMENT
	ASSUME CS:PROGSEG, SS:PROGSEG, DS:PROGSEG, ES:PROGSEG
	.XCREF
	.XLIST
	INCLUDE DEFMS.ASM
	.CREF
	.LIST
	ORG 100H
;
; Note; labels of variables are at the end.
;
TIDY:
EVAL:
	XOR DX,DX
	MOV SI, PHD_DIOA
	MOV DL,[SI]
	MOV SI,0081H
FIND:	CMP DX,0	; See if there is any parameter
	JE DEFAULT	; Otherwise, go get default drive
	MOV AL,[SI]
	CMP AL,SPACE	; If it's a space
	JE SKIPR
	CMP AL,COMMA	; or a comma,
	JNE LOOK
SKIPR:	DEC DX		; then look at the next character
	INC SI
	JMP SHORT FIND
LOOK:	CMP DX,2
	JB DRIVE	; If more than one char.
	MOV BL,[SI+1]	; then
	CMP BL,COLON	; it must be a colon
	JE DRIVE	; to reference a drive.
	CMP BL,SPACE	; or a space
	JE DRIVE
	CMP BL,COMMA	; or a comma
	JE DRIVE
ERROR:
	MOV DX, OFFSET ERRMSG  ; otherwise signal an error
	MOV AH, DOSF_OUTSTR
	INT DOSI_FUNC
	INT DOSI_TERM		; and quit.
DRIVE:
	CMP AL,61H	; Test for lower case
	JL DJST		; 
	SUB AL,20H	; If so, fix it.
DJST:	SUB AL,41H	; Turn ASCII to drive #
	JL ERROR	; Filter non drives out
	JMP SHORT KIND
DEFAULT:		; Read default disk
	MOV AH,DOSF_GETDISK
	INT DOSI_FUNC
KIND:			; See what kind of disk it is
	CMP AL,3	; If > D: then it's not supported
	JA ERROR
	MOV DRVN,AL	;Save drive number
	CMP AL,1	; If > B: then its 8"
	JA ATE
	MOV DX,1	; Parameters for start of FAT
	MOV BX,DIR
	MOV CX,1
	INT DOSI_ADREAD	; Get start of FAT
	JC DISKER
	POP BX		; Dummy POP
	MOV SI,DIR	; Get first byte (DISK ID)
	MOV AL,[SI]	;
	CMP AL,0FEH	; If DSDD
	JA READIN	;  it's OK
	JB TTPI		; If single-sided
	MOV BX,SDIRS	; Fix disk params
	MOV DIRSECS,BX
	JMP SHORT READIN
TTPI:	CMP AL,0FDH
	JB DISKER	; If 96 TPI
	MOV BX,DTPI
	MOV DIRSECS,BX
	JMP SHORT READIN
ATE:			; Fix for 8" drive
	MOV BX,ATEDIRS
	MOV DIRSECS,BX
	MOV BX,ATELEN
	MOV SECLEN,BX
	MOV BX,ATEST
	MOV STARTSEC,BX
READIN:
	MOV BX,DIR	; Parameters to read disk directory
	MOV CX,DIRSECS	; See ZDOS vol II: H.1 and I.4
	MOV DX,STARTSEC	; and LABEL definitions below.
	MOV AL,DRVN
	INT DOSI_ADREAD
	POP AX		; Dummy POP since INT 25 PUSHed the flags
	JNC SCAN	; Check for disk errors
DISKER:
	MOV DX,OFFSET DSKERM ; A disk error was detected.
	MOV AH,DOSF_OUTSTR	; so report it,
	INT DOSI_FUNC
	INT DOSI_TERM		; and quit
SCAN:
	MOV BX, DIRSECS	   ;Calculate the top of DIR
	MOV AX,SECLEN	   ; This will allow other disk formats.
	MUL BX		   ; by changing these parameters.
	MOV BX,DIR
	ADD AX,BX
	MOV TOP,AX
	ADD BX,64	; skip over system files
	MOV DI,BX
	LEA SI,COMMAND	; see if COMMAND.COM is there
	MOV CX,11
	CLD
REPE	CMPSB
	JNE DEFBOT	; and if it is then
	ADD BX,32	; skip over it, too.
DEFBOT: MOV BOT,BX	; This is the bottom of the files to sort.
	CALL DEPRESS	; Find the highest active file, make it TOP.
UP1:
	CMP BX,TOP	; Step up from BOT file to TOP file
	JNB SORT	; and then go on to sort them.
	MOV AL,[BX]	; If the current files isn't marked as
	CMP AL,0E5H	; deleted then, step on to the
	JNE NEXT1	; next file up, otherwise
	MOV DI,TOP	; put it at the top of the sorting area
	MOV SI,BX
	CALL SWAP	; by exchanging with TOP and
	CALL DEPRESS	; move TOP down to the next highest active file.
NEXT1:	ADD BX,32	; Then move up to the next file
	JMP SHORT UP1
SORT:
	MOV BX,TOP
	SUB BX,BOT
	SHR BX,1
	AND BX,0FFE0H
OUTLP:	MOV DX,BOT	; Begin outer loop
MDLP:	MOV SI,DX	;       Middle loop
INRLP:	MOV AX,SI
	LEA DI, [BX][SI]	;compare filenames
	MOV CX,11
REPE	CMPSB
	MOV SI,AX
	JB NXTMDLP	; If in wrong order
	LEA DI,[BX][SI]
	CALL SWAP	; Exchange them.
	SUB SI,BX
	CMP SI,BOT
	JA INRLP	; Next Inrlp
NXTMDLP: ADD DX,32
	MOV AX,TOP
	SUB AX,BX
	CMP DX,AX
	JBE MDLP	;Next Mdlp
	SHR BX,1
	AND BX,0FFE0H
	JNZ OUTLP	; Next Outlp
WRTOUT:
	MOV AL,DRVN	; Retrieve disk parameters
	MOV BX,DIR
	MOV CX,DIRSECS
	MOV DX,STARTSEC
	INT DOSI_ADWRITE	; Write new directory to disk.
	POP AX		; Dummy POP
	JNC QUIT
	JMP DISKER
QUIT:	
	MOV BX,DIR2	; Read directory back in
	MOV AL,DRVN
	MOV CX,DIRSECS
	MOV DX,STARTSEC
	INT DOSI_ADREAD
	POP AX		; Another dummy POP
	JE  CHECK
	JMP DISKER
CHECK:	MOV SI,DIR
	MOV DI,DIR2
	MOV CX,DRSIZ
	CLD
REPE	CMPSB		; See if DIR was written correctly
	JE OK
	INC OOPS	; If not, try again
	MOV DX, OFFSET BAD
	MOV AH, DOSF_OUTSTR	; and report failure
	INT DOSI_FUNC
	MOV CL,OOPS
	CMP CL,2
	JB WRTOUT
	INT DOSI_TERM
OK:	MOV DX, OFFSET GOOD	; If directory OK
	MOV AH, DOSF_OUTSTR	; Report success
	INT DOSI_FUNC
	INT DOSI_TERM		; and return to ZDOS
;
;
;
;	SUBROUTINES:
;
;
SWAP	PROC NEAR
;
; SWAP exchanges the files pointed to by SI and DI
; no registers are thereby wiped
;
	PUSH BX
	PUSH AX
	MOV AX,DI
	MOV BX,SI
	LEA DI,BUF	; Move SI string into buffer
	MOV CX,32
REP	MOVSB
	MOV SI,AX	; Move DI string to SI
	MOV DI,BX
	MOV CX,32
REP	MOVSB
	MOV DI,AX	;Move Buffer to DI
	LEA SI,BUF
	MOV CX,32
REP	MOVSB
	MOV SI,BX	; Retrieve values
	MOV DI,AX
	POP AX
	POP BX
	RET
SWAP	ENDP
;
;
DEPRESS	PROC NEAR
;
; DEPRESS MOVES DOWN TO THE HIGHEST ACTIVE FILE, SETS TOP AND
; SI TO THAT. DESTROYS PREVIOUS SI AND AL
;
	MOV SI,TOP	; Get the old highest active file
DOWN1:	SUB SI,32
	MOV AL,[SI]	; And if that file was either
	CMP AL,0	; never written to
	JE DOWN1
	CMP AL,0E5H	; Or previously deleted then
	JE DOWN1	; Go down another file.
	MOV TOP,SI
	CMP SI,BOT	; If its also the lowest then
	JA BACK	; There's no need to sort anything.
	INT DOSI_TERM	; So quit.
BACK:	RET		; Else return to TIDY
DEPRESS	ENDP
;
;
;    DEFINE LABELS:
;
ERRMSG	DB '  Unknown parameter$'
DSKERM	DB '  Disk error!$'
GOOD	DB '  Tidy verified$'
BAD	DB 7,'  Tidy NOT verified$'
SPACE	DB ' '
COMMA	DB ','
COLON	DB ':'
COMMAND DB 'COMMAND COM'
OOPS	DB 0	; Times Tidy wasn't verified
DRVN	DB ?	; Number of disk drive
DIRSECS DW 7  	; Sectors of disk reserved for directory by ZDOS
STARTSEC DW 3 	; First sector of the directory
SECLEN  DW 512 	; Number of bytes in one sector.
DRSIZ	DW ?	; Size of directory read
DIR	DW 03000H  ; space to fill with directory
;	  (Will accommodate up to DSDD 8" floppies)
SDIRS	DW 4		; DIRSECS for single sided
DTPI	DW 9		;         for 96 TPI
ATEDIRS DW 6		;	  for 8" DSDD -> 26 for SSSD
ATELEN  DW 1024		; SECLEN  for 8" DSDD -> 80 for SSSD
ATEST	DW 5		; STARTSEC "		 10 for SSSD
TOP	DW ? 		; Pointer to top of area to be sorted
BOT	DW ? 		;	     bottom of same area.
BUF	DB 32 DUP (?) 	; transfer area for switching files.
DIR2	DW 06000H 	; Space for verified copy of DIR
;
PROGSEG ENDS
	END TIDY
