;
;			SD.ASM
;		  (revised 2/6/81)
;
;		SUPER DIRECTORY	PROGRAM
;		  by Bruce R. Ratoff
;
;Displays the directory	of a CP/M disk,	sorted alphabetically,
;with the file size in K, rounded to the nearest CP/M block size.
;
;This latest variation on a common theme will automatically adjust
;itself	for any	block size and directory length	under CP/M 1.4 or 2.x
;or MP/M (any version).	 If the	screen fills, program will pause until
;a key is struck (see NPL and LPS equates below).  Total space used
;and number of files are printed at end.
;
;Command: SD FILENAME.FILETYPE or just SD
;
;Allows	'*' or '?' type	specifications.	 Drive name may	also be
;specified.  Ignores "SYS" files unless	SOPT is	TRUE and 'S' option
;is given (i.e., SD *.*	S will print all files).
;
;
;
;2/6/81	  CHANGED SORT TO HAVE ODD GAP(K+P SAY ITS FASTER)
;
;1/6/80	  CHANGED SORT FROM BUBBLE SORT	TO SHELL SHORT
;	  FOR FASTER SPEED.
;
;12/24/80 CHANGED BIOS CONOUT TO BDOS CONOUT
;	  TO ALLOW PRINTING OF DIRECTORY WITH
;	  CONTROL P.
;	  ALSO ADDED PRINT OF REMAINING	SPACE 
;	  EVEN IF FILE NOT FOUND.(STEVE	NOSSEN)
;
;12/15/80 Added	space suppression when printing	file
;	  totals.  (KBP)
;
;12/14/80 Added	logic to print space remaining on disk.
;	  Changed ^C test so that interrupting character is
;	  not echoed (makes remote use cleaner).  (BRR)
;
;12/02/80 Fixed	bug in print routine which compared last file
;	  against garbage before printing. (BRR)
;
;11/29/80 Changed to allow printing 4 file names. (Ben Bronson
;	  and Keith Petersen)
;
;11/22/80 Fixed	bug in handling	>256 files.  Changed abort test	in
;	  print	routine	to only	abort on control-c.  (brr)
;
;Based on 'DIRS' by Keith Petersen, W8SDZ
;
;Set 'RMAC' TRUE to assemble with relocating assembler (requires
;link with PAGE	0 equates in separate file).
;
FALSE	EQU	0		;DEFINE	LOGICAL	FALSE
TRUE	EQU	NOT FALSE	;DEFINE	LOGICAL	TRUE
;
ALTCPM	EQU	FALSE	;PUT TRUE HERE FOR H8 OR TRS-80
RMAC	EQU	FALSE	;PUT TRUE HERE FOR ASSEMBLY BY RMAC
SOPT	EQU	TRUE   ;PUT TRUE TO ALLOW 'DIR *.* S' FORM
WIDE	EQU	TRUE	;PUT TRUE TO ALLOW 4 NAMES ACROSS
;
	IF	ALTCPM
BASE	EQU	4200H
TPA	EQU	4300H
	ENDIF
;
	IF	RMAC
	EXTRN	BASE,FCB,BDOS	;MAKE BASE EXTERNAL
	ENDIF
;
	IF	(NOT ALTCPM) AND (NOT RMAC)
BASE	EQU	$	;WILL DEFAULT TO 0 (OR 100H WITH MAC +R	OPTION)
TPA	EQU	100H
	ENDIF
;
	IF	NOT RMAC
FCB	EQU	BASE+5CH
BDOS	EQU	BASE+5
	ENDIF
;
	IF	WIDE
NPL	EQU	4	;NUMBER	OF NAMES PER LINE
	ENDIF
;
	IF	NOT WIDE
NPL	EQU	3	;NUMBER	OF NAMES PER LINE
	ENDIF
;
LPS	EQU	23	;NUMBER	OF LINES PER SCREEN
DELIM	EQU	':'	;FENCE (DELIMITER) CHARACTER
;
	IF	NOT RMAC
	ORG	TPA
	ENDIF
;
;Save the stack
START:	LXI	H,0
	DAD	SP	;H=STACK
	SHLD	STACK	 ;SAVE IT
	LXI	SP,STACK ;GET NEW STACK
;
	IF	SOPT
	LDA	FCB+17	 ;SAVE S OPTION	FLAG
	STA	SOPFLG	 ;(BLANK OR LETTER S)
	ENDIF
;
	SUB	A
	STA	USERNO	 ;DEFAULT TO USER 0
	STA	LINCNT	 ;CLEAR	COUNT OF LINES ON SCREEN
	MVI	C,12
	CALL	BDOS	 ;CHECK	CP/M VERSION
	SHLD	VERFLG	 ;LO ORD >0 IF 2.X, HI ORD>0 IF	MP/M
	MOV	A,L	 ;2.X?
	ORA	A
	JZ	CHKDRV	 ;SKIP USER NUMBER STUFF IF 1.4
	MVI	E,0FFH
	MVI	C,CURUSR ;INTERROGATE USER NUMBER
	CALL	BDOS
	STA	USERNO
	LDA	MPMFLG	 ;MP/M?
	ORA	A	;IF SO,	TYPE HEADING LINE
	JZ	CHKDRV	 ; ELSE	SKIP IT
	LXI	D,USRMSG ;DISPLAY IT
	MVI	C,PRINT
	CALL	BDOS	 ;FIRST	PART OF	MESSAGE
	LDA	USERNO
	CPI	10	;IF USER NO. > 9 PRINT LEADING 1
	JC	DUX
	MVI	A,'1'
	CALL	TYPE
	LDA	USERNO	 ;PRINT	LOW DIGIT OF USER NO.
	SUI	10
;
DUX:	ADI	'0'
	CALL	TYPE
	LXI	D,USRMS2 ;PRINT	TAIL OF	MESSAGE
	MVI	C,PRINT
	CALL	BDOS
	MVI	A,1
	STA	LINCNT	;WE USED A LINE
;
CHKDRV:	LXI	H,FCB
	MOV	A,M	;GET DRIVE NAME
	ORA	A	;ANY SPECIFIED?
	JNZ	START2	;YES SKIP NEXT ROUTINE
	MVI	C,CURDSK
	CALL	BDOS	;GET CURRENT DISK NR
	INR	A	;MAKE A:=1
	STA	FCB
;
START2:	ADI	'A'-1	;MAKE IT PRINTABLE
	STA	DRNAM	;SAVE FOR LATER
	LXI	H,FCB+1	;POINT TO NAME
	MOV	A,M	;ANY SPECIFIED?
	CPI	' '
	JNZ	GOTFCB
;No FCB	- make FCB all '?'
	MVI	B,11	;FN+FT COUNT
;
QLOOP:	MVI	M,'?'	;STORE '?' IN FCB
	INX	H
	DCR	B
	JNZ	QLOOP
;
GOTFCB:	MVI	A,'?'	;FORCE WILD EXTENT
	STA	FCB+12
	LDA	FCB	;CHECK FOR EXPLICIT DRIVE
	DCR	A
	MOV	E,A	;SELECT	SPECIFIED DRIVE
	MVI	C,SELDSK
	CALL	BDOS
	SUB	A	;ZAP DRIVE NO. IN FCB SO SELECTED DRIVE	IS USED
	STA	FCB
	LDA	VERFLG	;CHECK VERS.
	ORA	A
	JZ	V14	;PRE-2.X...GET PARAMS THE 1.4 WAY
;
	MVI	C,CURDPB;IT'S 2.X OR MP/M...REQUEST DPB
	CALL	BDOS
	INX	H
	INX	H
	MOV	A,M	;GET BLOCK SHIFT
	STA	BLKSHF
	INX	H	;BUMP TO BLOCK MASK
	MOV	A,M
	STA	BLKMSK	;GET IT
	INX	H
	INX	H
	MOV	E,M	;GET MAX BLOCK #
	INX	H
	MOV	D,M
	XCHG
	SHLD	BLKMAX	;SAVE IT
	XCHG
	INX	H
	MOV	E,M	;GET DIRECTORY SIZE
	INX	H
	MOV	D,M
	XCHG
	SHLD	DIRMAX	;SAVE IT
	JMP	SETTBL	;DONE...GO SET UP ORDER	TABLE
;
V14:	LHLD	BDOS+1	;GET PARAMS 1.4	STYLE
	MVI	L,3BH	;POINT TO DIRECTORY SIZE
	MOV	E,M	;GET IT
	MVI	D,0	;FORCE HI ORD TO 0
	PUSH	D	;SAVE FOR LATER
	INX	H	;POINT TO BLOCK	SHIFT
	MOV	A,M	;FETCH
	STA	BLKSHF	;SAVE
	INX	H	;POINT TO BLOCK	MASK
	MOV	A,M	;FETCH IT
	STA	BLKMSK	;AND SAVE IT
	INX	H
	MOV	E,M	;GET MAX. BLOCK	NO.
	MVI	D,0
	XCHG
	SHLD	BLKMAX	;SAVE IT
	POP	H	;RESTORE DIRECTORY SIZE
	SHLD	DIRMAX	;SAVE IT
;
SETTBL:	INX	H	;DIRECTORY SIZE	IS DIRMAX+1
	DAD	H	;DOUBLE	DIRECTORY SIZE
	LXI	D,ORDER	;TO GET	SIZE OF	ORDER TABLE
	DAD	D	;ALLOCATE ORDER	TABLE
	SHLD	TBLOC	;NAME TABLE BEGINS WHERE ORDER TABLE ENDS
	SHLD	NEXTT
	XCHG
	LHLD	BDOS+1	;MAKE SURE WE HAVE ROOM	TO CONTINUE
	MOV	A,E
	SUB	L
	MOV	A,D
	SBB	H
	JNC	OUTMEM
;
;Look up the FCB in the	directory
SFIRST:	MVI	C,FSRCHF ;GET 'SEARCH FIRST' FNC
	LXI	D,FCB
	CALL	BDOS	;READ FIRST
	INR	A	;WERE THERE ANY?
	JNZ	SOME	;GOT SOME
;
NONE:	LXI	D,FNF	;PREPARE MP/M ERROR MESSAGE
	LDA	MPMFLG
	ORA	A	;USE IT	IF REALLY MP/M
	JNZ	ERXIT1
	CALL	ERXIT	;ELSE USE CP/M ERROR MESSAGE
	DB	'NO FILE$'
FNF:	DB	'File not found.$'
;
USRMSG:	DB	'Directory for user $'
USRMS2:	DB	':',13,10,'$'
;
;Read more directory entries
MORDIR:	MVI	C,FSRCHN ;SEARCH NEXT
	LXI	D,FCB
	CALL	BDOS	;READ DIR ENTRY
	INR	A	;CHECK FOR END (0FFH)
	JZ	SPRINT	;NO MORE - SORT	& PRINT
;
;Point to directory entry 
SOME:	DCR	A	;UNDO PREV 'INR	A'
	ANI	3	;MAKE MODULUS 4
	ADD	A	;MULTIPLY...
	ADD	A	;..BY 32 BECAUSE
	ADD	A	;..EACH	DIRECTORY
	ADD	A	;..ENTRY IS 32
	ADD	A	;..BYTES LONG
	LXI	H,BASE+81H ;POINT TO BUFFER
			;(SKIP TO FN/FT)
	ADD	L	;POINT TO ENTRY
	ADI	9	;POINT TO SYS BYTE
	MOV	L,A	;SAVE (CAN'T CARRY TO H)
;
	IF	SOPT
	LDA	SOPFLG	;DID USER REQUEST SYS FILES?
	CPI	'S'
	JZ	SYSFOK
	ENDIF
;
	MOV	A,M	;GET SYS BYTE
	ANI	80H	;CHECK BIT 7
	JNZ	MORDIR	;SKIP THAT FILE
;
SYSFOK:	MOV	A,L	;GO BACK NOW
	SUI	10	;BACK TO USER NUMBER (ALLOC FLAG)
	MOV	L,A	;HL POINTS TO ENTRY NOW
;
	LDA	USERNO	;GET CURRENT USER
	CMP	M
	JNZ	MORDIR	;IGNORE	IF DIFFERENT
	INX	H
;
;Move entry to table
	XCHG		;ENTRY TO DE
	LHLD	NEXTT	;NEXT TABLE ENTRY TO HL
	MVI	B,12	;ENTRY LENGTH (NAME, TYPE, EXTENT)
;
TMOVE:	LDAX	D	;GET ENTRY CHAR
	ANI	7FH	;REMOVE	ATTRIBUTES
	MOV	M,A	;STORE IN TABLE
	INX	D
	INX	H
	DCR	B	;MORE?
	JNZ	TMOVE
	INX	D
	INX	D	;POINT TO SECTOR COUNT
	LDAX	D	; GET IT
	MOV	M,A	;STORE IN TABLE
	INX	H
	SHLD	NEXTT	;SAVE UPDATED TABLE ADDR
	XCHG
	LHLD	COUNT	;GET PREV COUNT
	INX	H
	SHLD	COUNT
	LXI	H,13	;SIZE OF NEXT ENTRY
	DAD	D
	XCHG		;FUTURE	NEXTT IS IN DE
	LHLD	BDOS+1	;PICK UP TPA END
	MOV	A,E
	SUB	L	;COMPARE NEXTT-TPA END
	MOV	A,D
	SBB	H
	JC	MORDIR	;IF TPA	END>NEXTT THEN LOOP BACK FOR MORE
;
OUTMEM:	CALL	ERXIT
	DB	'Out of	memory.',13,10,'$'
;
;Sort and print
SPRINT:	LHLD	COUNT	;GET FILE NAME COUNT
	MOV	A,L
	ORA	H	;ANY FOUND?
	JZ	NONE	;NO, EXIT
	PUSH	H	;SAVE FILE COUNT
;Init the order	table
	LHLD	TBLOC	;GET START OF NAME TABLE
	XCHG		;INTO DE
	LXI	H,ORDER	;POINT TO ORDER	TABLE
	LXI	B,13	;ENTRY LENGTH
;
BLDORD:	MOV	M,E	;SAVE LO ORD ADDR
	INX	H
	MOV	M,D	;SAVE HI ORD ADDR
	INX	H
	XCHG		;TABLE ADDR TO HL
	DAD	B	;POINT TO NEXT ENTRY
	XCHG
	XTHL		;SAVE TBL ADDR,	FETCH LOOP COUNTER
	DCX	H	;COUNT DOWN LOOP
	MOV	A,L
	ORA	H	;MORE?
	XTHL		;(RESTORE TBL ADDR, SAVE COUNTER)
	JNZ	BLDORD	;..YES,	GO DO ANOTHER ONE
	POP	H	;CLEAN LOOP COUHTER OFF	STACK
	LHLD	COUNT	;GET COUNT
	SHLD	SCOUNT	;SAVE AS # TO SORT
	DCX	H	;ONLY 1	ENTRY?
	MOV	A,L
	ORA	H
	JZ	DONE	;..YES,	SO SKIP	SORT
;
; THIS SORT ROUTINE IS ADAPTED FROM SOFTWARE TOOLS
; BY KERNIGAN AND PLAUGHER.
;
SORT:	LHLD	SCOUNT	;NUMBER	OF ENTRIES
L0:	ORA	A	;CLEAR CARRY
	MOV	A,H	;GAP=GAP/2
	RAR
	MOV	H,A
	MOV	A,L
	RAR
	MOV	L,A
	ORA	H	;IS IT ZERO?
	JZ	DONE	;THEN NONE LEFT
	MOV	A,L	;MAKE GAP ODD
	ORI	01
	MOV	L,A
	SHLD	GAP
	INX	H	;I=GAP+1
L2:	SHLD	I
	XCHG
	LHLD	GAP
	MOV	A,E	;J=I-GAP
	SUB	L
	MOV	L,A
	MOV	A,D
	SBB	H
	MOV	H,A
L3:	SHLD	J
	XCHG
	LHLD	GAP	;JG=J+GAP
	DAD	D
	SHLD	JG
	MVI	A,12	;COMPARE 12 CHARS
	CALL	COMPARE	;COMPARE (J) AND (JG)
	JP	L5	;IF A(J)<=A(JG)
	LHLD	J
	XCHG
	LHLD	JG
	CALL	SWAP	;EXCH A(J) AND A(JG)
	LHLD	J	;J=J-GAP
	XCHG
	LHLD	GAP
	MOV	A,E
	SUB	L
	MOV	L,A
	MOV	A,D
	SBB	H
	MOV	H,A
	JM	L5	;IF J>0	GOTO L3
	ORA	L	;CHECK FOR ZERO
	JZ	L5
	JMP	L3
L5:	LHLD	SCOUNT	;FOR LATER
	XCHG
	LHLD	I	;I=I+1
	INX	H
	MOV	A,E	;IF I<=N GOTO L2
	SUB	L
	MOV	A,D
	SBB	H
	JP	L2
	LHLD	GAP
	JMP	L0
;
;Sort is all done - print entries
DONE:	LXI	H,ORDER
	SHLD	NEXTT
;
;Print an entry
	IF	NOT WIDE
	CALL	DRPRNT	;PRINT DRIVE NAME
	ENDIF
	MVI	C,NPL	;NR. OF	NAMES PER LINE
	LXI	H,0	;ZERO OUT
	SHLD	TOTSIZ	; TOTAL	K USED
	SHLD	TOTFIL	; AND TOTAL FILES
;
ENTRY:	LHLD	COUNT	; CHECK	COUNT OF REMAINING FILES
	DCX	H	;  1 LEFT?
	MOV	A,L	; IF ONLY 1 LEFT, SKIP COMPARE WITH NEXT
	ORA	H	;  (SINCE THERE	ISN'T ANY NEXT)
	JZ	OKPRNT
	PUSH	B
	MVI	C,0BH	;CHECK CONSOLE STATUS
	CALL	BDOS
	ORA	A
	JZ     NOBRK   ;NO, CONTINUE
	JMP	EXIT
;
NOBRK:	LHLD	NEXTT
	MVI	A,11
	CALL	COMPR	;DOES THIS ENTRY MATCH NEXT ONE?
	POP	B
	JNZ	OKPRNT	;NO, PRINT IT
	INX	H
	INX	H	;SKIP, SINCE HIGHEST EXTENT COMES LAST IN LIST
	SHLD	NEXTT
	LHLD	COUNT
	DCX	H
	SHLD	COUNT	;COUNT DOWN
	JMP	ENTRY	;GO GET	NEXT
;
GOHL:	PCHL		;KLUDGE	TO ALLOW CALL TO ADDRESS IN HL
;
OKPRNT:	IF	NOT WIDE
	CALL	FENCE	;PRINT FENCE CHAR AND SPACE
	ENDIF
	LHLD	NEXTT	;GET ORDER TABLE POINTER
	MOV	E,M	;GET LO	ADDR
	INX	H
	MOV	D,M	;GET HI	ADDR
	INX	H
	SHLD	NEXTT	;SAVE UPDATED TABLE POINTER
	XCHG		;TABLE ENTRY TO	HL
	MVI	B,8	;FILE NAME LENGTH
	CALL	TYPEIT	;TYPE FILENAME
	MVI	A,' '	;SPACE AFTER FN
	CALL	TYPE
	MVI	B,3	;GET THE FILETYPE
	CALL	TYPEIT
	MOV	E,M	;GET EXTENT #
	MVI	D,0
	INX	H
	MOV	A,M	;GET SECTOR COUNT OF LAST EXTENT
	XCHG
	DAD	H	;# OF EXTENTS TIMES 16K
	DAD	H
	DAD	H
	DAD	H
	XCHG		;SAVE IN DE
	LXI	H,BLKMSK
	ADD	M	;ROUND LAST EXTENT TO BLOCK SIZE
	RRC
	RRC		;CONVERT FROM SECTORS TO K
	RRC
	ANI	1FH
	MOV	L,A	;ADD TO	TOTAL K
	MVI	H,0
	DAD	D
	LDA	BLKMSK	;GET SECTORS/BLK-1
	RRC
	RRC		;CONVERT TO K/BLK
	RRC
	ANI	1FH
	CMA		;USE TO	FINISH ROUNDING
	ANA	L
	MOV	L,A
	XCHG		;SAVE FILE SIZE	IN DE
	LHLD	TOTSIZ
	DAD	D	;ADD TO	TOTAL USED
	SHLD	TOTSIZ
	LHLD	TOTFIL	;INCREMENT FILE	COUNT
	INX	H
	SHLD	TOTFIL
	XCHG		;GET BACK FILE SIZE
	CALL	DECPRT	; AND PRINT IT
	MVI	A,'k'	;FOLLOW	WITH K
	CALL	TYPE
;
	IF	NOT WIDE
	CALL	SPACE
	ENDIF
;
;See if	more entries
	LHLD	COUNT	;COUNT DOWN ENTRIES
	DCX	H
	MOV	A,L
	ORA	H
	JZ	PRTOTL	;IF OUT	OF FILES, PRINT	TOTALS
	SHLD	COUNT
	DCR	C	;ONE LESS ON THIS LINE
;
	IF	WIDE
	PUSH	PSW
	CNZ	FENCE	;NO CR-LF NEEDED, DO FENCE
	POP	PSW
	ENDIF
;
	CZ	CRLF	;CR-LF NEEDED
	JMP	ENTRY
;
;Print HL in decimal with leading zero suppression
DECPRT:	SUB	A	;CLEAR LEADING ZERO FLAG
	STA	LZFLG
	LXI	D,-1000	;PRINT 1000'S DIGIT
	CALL	DIGIT
	LXI	D,-100	;ETC
	CALL	DIGIT
	LXI	D,-10
	CALL	DIGIT
	MVI	A,'0'	;GET 1'S DIGIT
	ADD	L
	JMP	TYPE
;
DIGIT:	MVI	B,'0'	;START OFF WITH	ASCII 0
;
DIGLP:	PUSH	H	;SAVE CURRENT REMAINDER
	DAD	D	;SUBTRACT
	JNC	DIGEX	;QUIT ON OVERFLOW
	POP	PSW	;THROW AWAY REMAINDER
	INR	B	;BUMP DIGIT
	JMP	DIGLP	;LOOP BACK
;
DIGEX:	POP	H	;RESTORE POINTER
	MOV	A,B
	CPI	'0'	;ZERO DIGIT?
	JNZ	DIGNZ	;NO, TYPE IT
	LDA	LZFLG	;LEADING ZERO?
	ORA	A
	MVI	A,'0'
	JNZ	TYPE	;PRINT DIGIT
	LDA	SUPSPC	;GET SPACE SUPPRESSION FLAG
	ORA	A	;SEE IF	PRINTING FILE TOTALS
	RZ		;YES, DON'T GIVE LEADING SPACES
	JMP	SPACE	;LEADING ZERO...PRINT SPACE
;
DIGNZ:	STA	LZFLG	;SET LEADING ZERO FLAG SO NEXT ZERO PRINTS
	JMP	TYPE	;AND PRINT DIGIT
;
;Show total space and files used
PRTOTL:	XRA	A	;GET A ZERO TO...
	STA	SUPSPC	;SUPPRESS LEADING SPACES IN TOTALS
	CALL	CRLF	;NEW LINE (WITH	PAUSE IF NECESSARY)
;
	IF	WIDE
	LXI	D,TOTMS1 ;PRINT	FIRST PART OF TOTAL MESSAGE
	ENDIF
;
	IF	NOT WIDE
	LXI	D,TOTMS1+1 ;PRINT FIRST	PART OF	TOTAL MESSAGE
	ENDIF
;
	MVI	C,PRINT
	CALL	BDOS
	LHLD	TOTSIZ	;PRINT TOTAL K USED
	CALL	DECPRT
	LXI	D,TOTMS2;NEXT PART OF MESSAGE
	MVI	C,PRINT
	CALL	BDOS
	LHLD	TOTFIL	;PRINT COUNT OF	FILES
	CALL	DECPRT
	LXI	D,TOTMS3;TAIL OF MESSAGE
	MVI	C,PRINT
	CALL	BDOS
PRT1:	MVI	C,GALLOC	;GET ADDRESS OF	ALLOCATION VECTOR
	CALL	BDOS
	XCHG
	LHLD	BLKMAX	;GET ITS LENGTH
	INX	H
	LXI	B,0	;INIT BLOCK COUNT TO 0
;
GSPBYT:	PUSH	D	;SAVE ALLOC ADDRESS
	LDAX	D
	MVI	E,8	;SET TO	PROCESS	8 BLOCKS
;
GSPLUP:	RAL		;TEST BIT
	JC	NOTFRE
	INX	B
;
NOTFRE:	MOV	D,A	;SAVE BITS
	DCX	H	;COUNT DOWN BLOCKS
	MOV	A,L
	ORA	H
	JZ	ENDALC	;QUIT IF OUT OF	BLOCKS
	MOV	A,D	;RESTORE BITS
	DCR	E	;COUNT DOWN 8 BITS
	JNZ	GSPLUP	;DO ANOTHER BIT
	POP	D	;BUMP TO NEXT BYTE
	INX	D	;OF ALLOC. VECTOR
	JMP	GSPBYT	;PROCESS IT
;
ENDALC:	MOV	L,C	;COPY BLOCKS TO	HL
	MOV	H,B
	LDA	BLKSHF	;GET BLOCK SHIFT FACTOR
	SUI	3	;CONVERT FROM SECTORS TO K
	JZ	PRTFRE	;SKIP SHIFTS IF	1K BLOCKS
;
FREKLP:	DAD	H	;MULT BLKS BY K/BLK
	DCR	A
	JNZ	FREKLP
;
PRTFRE:	CALL	DECPRT	;PRINT K FREE
	LXI	D,TOTMS4
	MVI	C,PRINT
	CALL	BDOS
	JMP	EXIT	;ALL DONE...RETURN TO CP/M
;
DRNAM	EQU	$	;SAVE DRIVE NAME HERE
TOTMS1:	DB	' : Total of $'
TOTMS2: DB	'k in $'
TOTMS3: DB	' files with $'
TOTMS4: DB	'k space remaining.$'
;
FENCE:	IF	WIDE
	CALL	SPACE
	ENDIF
	MVI	A,DELIM	;FENCE CHARACTER
	CALL	TYPE	;PRINT IT, FALL	INTO SPACE
;
SPACE:	MVI	A,' '
;
;Type character	in A
TYPE:	PUSH	B
	PUSH	D
	PUSH	H
	MOV	E,A
	MVI	C,2		;BDOS CONOUT
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	RET
;
TYPEIT:	MOV	A,M
	CALL	TYPE
	INX	H
	DCR	B
	JNZ	TYPEIT
	RET
;
;Fetch character from console (without echo)
CINPUT:	LHLD	BASE+1
	MVI	L,9
	CALL	GOHL
	ANI	7FH
	RET
;
CRLF:	LDA	LINCNT	;CHECK FOR END OF SCREEN
	INR	A
	CPI	LPS
	JC	NOTEOS	;SKIP MESSAGE IF MORE LINES LEFT ON SCREEN
	LXI	D,EOSMSG;SAY WE'RE PAUSING FOR INPUT
	MVI	C,PRINT
	CALL	BDOS
	CALL	CINPUT	;WAIT FOR CHAR.
	SUB	A	;SET UP	TO ZERO	LINE COUNT
;
NOTEOS:	STA	LINCNT	;SAVE NEW LINE COUNT
	MVI	A,13	;PRINT CR
	CALL	TYPE
	MVI	A,10	;LF
	CALL	TYPE
;
	IF	NOT WIDE
	CALL	DRPRNT	;DRIVE NAME
	ENDIF
;
	MVI	C,NPL	;RESET NUMBER OF NAMES PER LINE
	RET
;
EOSMSG:	DB	13,10,'(Strike any key to continue)$'
;
	IF	NOT WIDE
DRPRNT:	LDA	DRNAM
	JMP	TYPE
	ENDIF
;
;Compare routine for sort
COMPR:	PUSH	H	;SAVE TABLE ADDR
	MOV	E,M	;LOAD LO
	INX	H
	MOV	D,M	;LOAD HI
	INX	H
	MOV	C,M
	INX	H
	MOV	B,M
;BC, DE	now point to entries to	be compared
	XCHG
	MOV	E,A	;GET COUNT
;
CMPLP:	LDAX	B
	CMP	M
	INX	H
	INX	B
	JNZ	NOTEQL	;QUIT ON MISMATCH
	DCR	E	;OR END	OF COUNT
	JNZ	CMPLP
;
NOTEQL:	POP	H
	RET		;COND CODE TELLS ALL
;
;Swap entries in the order table
SWAP:	LXI	B,ORDER-2	;TABLE BASE
	DAD	H	;*2
	DAD	B	;+ BASE
	XCHG
	DAD	H	;*2
	DAD	B	;+ BASE
	MOV	C,M
	LDAX	D
	XCHG
	MOV	M,C
	STAX	D
	INX	H
	INX	D
	MOV	C,M
	LDAX	D
	XCHG
	MOV	M,C
	STAX	D
	RET
;
;
; NEW COMPARE ROUTINE
;
COMPARE:	LXI	B,ORDER-2
	DAD	H
	DAD	B
	XCHG
	DAD	H
	DAD	B
	XCHG
	MOV	C,M
	INX	H
	MOV	B,M
	XCHG
	MOV	E,M
	INX	H
	MOV	D,M
	XCHG
	MOV	E,A	;COUNT
CMPLPE:	LDAX	B
	CMP	M
	INX	B
	INX	H
	RNZ
	DCR	E
	JNZ	CMPLPE
	RET
;
;Error exit
ERXIT:	POP	D	;GET MSG
;
ERXIT1:	MVI	C,PRINT
;
CALLB:	CALL	BDOS	;PERFORM REQUESTED FUNCTION
	CALL	CRLF
	LXI	D,TOTMS1
	MVI	C,PRINT
	CALL	BDOS
	XRA	A
	STA	SUPSPC	;SUPPRESS LEADING ZEROS
	JMP	PRT1	;PRINT SPACE REMAINING
;
;(fall into exit)
;Exit -	all done, restore stack
EXIT:	LHLD	STACK	;GET OLD STACK
	SPHL		;MOVE TO STACK
	RET		;..AND RETURN
;
;Temporary storage area
;
I	DW	0
J	DW	0
JG	DW	0
GAP	DW	0
;
BLKSHF	DB	0	;# SHIFTS TO MULT BY SEC/BLK
BLKMSK	DB	0	;SEC/BLK - 1
BLKMAX	DW	0	;HIGHEST BLOCK # ON DRIVE
DIRMAX	DW	0	;HIGHEST FILE #	IN DIRECTORY
TOTSIZ	DW	0	;TOTAL SIZE OF ALL FILES
TOTFIL	DW	0	;TOTAL NUMBER OF FILES
LINCNT	DB	0	;COUNT OF LINES	ON SCREEN
TBLOC	DW	0	;POINTER TO START OF NAME TABLE
NEXTT	DW	0	;NEXT TABLE ENTRY
COUNT	DW	0	;ENTRY COUNT
SCOUNT	DW	0	;# TO SORT
SWITCH	DB	0	;SWAP SWITCH FOR SORT
SUPSPC	DB	0FFH	;LEADING SPACE FLAG FOR	DECIMAL	RTN.
BUFAD	DW	BASE+80H ;OUTPUT ADDR
	DS	60	;STACK AREA
STACK	DS	2	;SAVE OLD STACK	HERE
SOPFLG	DS	1	;SET TO	'S' TO ALLOW SYS FILES TO PRINT
USERNO	DS	1	;CONTAINS CURRENT USER NUMBER
TEMP	DS	2	;SAVE DIR ENTRY
VERFLG	DS	1	;VERSION FLAG
MPMFLG	DS	1	;MP/M FLAG
LZFLG	DS	1	;0 WHEN	PRINTING LEADING ZEROS
ORDER	EQU	$	;ORDER TABLE STARTS HERE
;
;BDOS equates
;
RDCHR	EQU	1	;READ CHAR FROM	CONSOLE
WRCHR	EQU	2	;WRITE CHR TO CONSOLE
PRINT	EQU	9	;PRINT CONSOLE BUFF
CONST	EQU	11	;CHECK CONS STAT
SELDSK	EQU	14	;SELECT	DISK
FOPEN	EQU	15	;0FFH=NOT FOUND
FCLOSE	EQU	16	;   "	"
FSRCHF	EQU	17	;   "	"
FSRCHN	EQU	18	;   "	"
CURDSK	EQU	25	;GET CURRENTLY LOGGED DISK NAME
GALLOC	EQU	27	;GET ADDRESS OF	ALLOCATION VECTOR
CURDPB	EQU	31	;GET CURRENT DISK PARAMETERS
CURUSR	EQU	32	;GET CURRENTLY LOGGED USER NUMBER (2.x ONLY)
;
	END
