;		    SD.ASM ver 2.2
;		   (revised 6/5/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).
;
;==============================================================
;
;Fixes/updates (in reverse order to minimize reading time):
;
;06/05/81 Added PGPAWZ (page pause) conditional for remote
;	  CP/M systems where pausing may not be wanted.
;	  Setting PGPAWZ and REPSIZ to FALSE will result in
;	  a display like DIR, but sorted and with the stat
;	  of space remaining.  Rearranged equates to allow
;	  15 lines per page when narrow display is chosen.
;	  (KBP)
;
;06/01/81 Added version number, restored CTL-C break, added
;	  CTL-C test to allow break at page pause, added
;	  routine to gobble up any waiting console character
;	  at EXIT, added conditional assembly to allow no
;	  report of file sizes, added conditional assembly
;	  for direct console I/O for remote CP/M systems
;	  where phone line noise would garbage display.  (KBP)
;
;05/06/81 Corrected double printing of drive name in CALLB.
;	  Error only occurred with narrow display when file
;	  wasn't found. (Tim Nicholas)
;
;02/06/81 Changed sort to have odd gap (K+P say its faster)
;
;01/06/80 Changed sort from bubble sort to shell sort
;	  for faster speed.
;
;12/24/80 Changed BIOS conout to BDOS conout to allow
;	  printing of directory with CTL-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
;
;NOTE: If you add improvements or otherwise update
;this program, please modem a copy of the new file
;to "TECHNICAL CBBS" in Dearborn, Michigan - phone
;313-846-6127 (110, 300, 450 or 600 baud).  Use the
;filename SD-NEW.NEW. (KBP)
;
;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 'SD *.* S' FORM
WIDE	EQU	TRUE 	;PUT TRUE TO ALLOW 4 NAMES ACROSS
REPSIZ	EQU	TRUE 	;PUT TRUE TO REPORT FILE SIZES
PGPAWZ	EQU	TRUE 	;PUT TRUE FOR PAUSE AFTER EACH PAGE
DIRCON	EQU	FALSE	;PUT TRUE FOR DIRECT CONSOLE OUTPUT
;
DELIM	EQU	':'	;FENCE (DELIMITER) CHARACTER
;
	IF	WIDE
NPL	EQU	4	;NUMBER OF NAMES PER LINE
LPS	EQU	23	;NUMBER OF LINES PER SCREEN
	ENDIF
;
	IF	NOT WIDE
NPL	EQU	3	;NUMBER OF NAMES PER LINE
LPS	EQU	15	;NUMBER OF LINES PER SCREEN
	ENDIF
;
	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	NOT RMAC
	ORG	TPA
	ENDIF
;
START:	LXI	H,0
	DAD	SP	;HL=OLD 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 COUNTER 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
;
	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
;
;Print an entry
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
;
	LHLD	BASE+1
	MVI	L,6	;CK STATUS OF KB
	CALL	GOHL	;ANY KEY PRESSED?
	ORA	A
	JZ	NOBRK	;NO, CONTINUE
	CALL	CINPUT	;GET CHARACTER
	CPI	'C'-40H	;CTL-C?
	JZ	EXIT	;IF CTL-C THEN QUIT
	CPI	'S'-40H	;CTL-S?
	JNZ	NOBRK	;NO, CONTINUE
	CALL	CINPUT	;YES, WAIT FOR ANOTHER CHAR.
	CPI	'C'-40H	;MIGHT BE CTL-C
	JZ	EXIT	;EXIT IF CTL-C, ELSE FALL THRU AND CONTINUE
;
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,'.'	;PERIOD 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
;
	IF	REPSIZ	;FILE SIZE REPORT WANTED
	CALL	DECPRT	; AND PRINT IT
	MVI	A,'k'	;FOLLOW WITH K
	CALL	TYPE
	ENDIF
;
	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
;
	IF	NOT REPSIZ
	CALL	SPACE	;PRINT AN EXTRA SPACE
	ENDIF
;
	MVI	A,DELIM	;FENCE CHARACTER
	CALL	TYPE	;PRINT IT, FALL INTO SPACE
;
	IF	NOT REPSIZ
	CALL	SPACE	;PRINT ANOTHER SPACE
	ENDIF
;
SPACE:	MVI	A,' '
;
;Type character	in A
;
	IF	DIRCON	;DIRECT CONSOLE OUTPUT
TYPE:	PUSH	B
	PUSH	D
	PUSH	H
	LHLD	BASE+1
	MVI	L,12
	MOV	C,A
	CALL	GOHL
	POP	H
	POP 	D
	POP	B
	RET
	ENDIF		;DIRCON
;
	IF	NOT DIRCON ;USE BDOS CONSOLE OUTPUT
TYPE:	PUSH	B
	PUSH	D
	PUSH	H
	MOV	E,A
	MVI	C,WRCHR	;CHAR TO CONSOLE
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	RET
	ENDIF		;NOT DIRCON
;
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
;
	IF	PGPAWZ	;PAUSE AFTER EACH PAGE
	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.
	CPI	'C'-40H	;CTL-C ?
	JZ	EXIT
	SUB	A	;SET UP TO ZERO LINE COUNT
	ENDIF		;PGPAWZ
;
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
	CALL	BDOS
	CALL	CRLF
;
	IF	WIDE
	LXI	D,TOTMS1
	ENDIF
;
	IF	NOT WIDE
	LXI	D,TOTMS1+1 ;SKIP PRINTING DRIVE NAME
	ENDIF
;
	MVI	C,PRINT
	CALL	BDOS
	XRA	A
	STA	SUPSPC	;SUPPRESS LEADING ZEROS
	JMP	PRT1	;PRINT SPACE REMAINING
;
;Exit -	all done, restore stack
;
EXIT:	MVI	C,CONST	;CHECK CONSOLE STATUS
	CALL	BDOS
	ORA	A	;CHAR WAITING?
	MVI	C,RDCHR
	CNZ	BDOS	;GOBBLE UP CHAR
	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
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
	DS	60	;STACK AREA
STACK	DS	2	;SAVE OLD STACK HERE
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
