* DFree.a:	An assembler disk free space lister.  I came up with this
*		as a protest against INFO.  I don't CARE how many blocks
*		are free, I want to know how much space I've got in BYTES,
*		considering everything else tells me file sizes in bytes,
*		etc., etc.
*
*		Working version finished 12/14/86 jec
*		Added support for volume name 12/16/86 jec
*
* Included equate files.
* -----------------------------------------------------------------------
	NOLIST
	INCLUDE 'exec/types.i'
	INCLUDE 'exec/libraries.i'
	INCLUDE 'exec/memory.i'
	INCLUDE 'libraries/dos.i'
	INCLUDE 'libraries/dosextens.i'
	INCLUDE	'offsets/exec.i'
	INCLUDE	'offsets/dos.i'
	LIST

	ifd	CAPE
	EXEOBJ
	objfile	'ram:DFree'
	optimon	-1
	endc

* Local Equates
* ------------------------------------------------------------------------
TRUE	EQU	-1
FALSE	EQU	0
RAM	EQU	'RAM'<<8

* Stack frame variables
* ------------------------------------------------------------------------
v_STRPTR	EQU	-128
v_SIZE		EQU	-124
v_STRING	EQU	-120
v_OUTPUT	EQU	-88

* The code segment
* -------------------------------------------------------------------------
	link	a4,#-128
	jsr	argtrim 		; clean up command line
	MOVEM.L D0/A0-A2,-(SP)		; Save command line (OpenLibrary trashes).
	moveq	#0,d0

	;------ get Exec's library base pointer:
	LEA.L	DOSName(PC),A1		; name of dos library
	moveq	#33,d0			; at LEAST AmigaDOS 1.2

	move.l	_AbsExecBase,a6
	Call	OpenLibrary
	MOVE.L	D0,A6			; Save library pointer (always in A6).
	BNE.S	gotdos

	; Should really issue an alert here...
	moveq	#RETURN_FAIL,D0 	; give up
	bra	FINISHED

gotdos:

	; REGISTER USAGE:
	;	A0	= scratch after command line used.
	;	A4	= stack frame
	;	A5	= InfoData address
	;	A6	= dos library base pointer
	;	D1-3	= AmigaDOS scratch argument registers
	;	D4	= current directory lock
	;	D5	= output handle
	;	D6	= root lock flag

*	Obtain the output handle (needed for write)
	Call	Output
	MOVE.L	D0,D5			; Save for the write

	MOVEM.L (SP)+,D0/A0-A2		; restore command line etc.

*	Setup D6 as the restore directory flag
	moveq	#FALSE,D6

*	Now check if we have an argument. If we have, attempt to lock it.
*	Otherwise, go for current directory.
	cmpi.b	#0,(A0) 		; a null string for an argument ?
	beq.s	CURDIR			; yes

	; Lock to specified directory. Place name in D1, access mode in D2
	move.l	a0,d1
	move.l	#ACCESS_READ,d2
	Call	Lock
	move.l	d0,d4			; remember for later
	beq	nolock			; did we get a lock?
	bra.s	uselock 		; for the Examine

CURDIR:
	; Get lock to current directory. The most bulletproof way of doing this
	; (due to bugs in the V1.1 RAM: handler) is to make the root directory
	; the current one, because CurrentDir will return the old lock value.
	moveq	#0,D1
	Call	CurrentDir		; got the lock
	move.l	d0,d4			; for later
	moveq	#TRUE,d6		; remember to cd

uselock:
	; A lock in D1 and a InfoData address in D2 are all that are needed.
	; We allocmem the InfoData to assure alignment.

	move.l	#id_SIZEOF,D0		; size of the block
	move.l	#MEMF_PUBLIC,D1 	; memory requirement

	MOVEM.L D2-D7/A0-A6,-(SP)	; in case AllocMem trashes (it does...)
	move.l	_AbsExecBase,a6
	Call	AllocMem		; args D0, D1 returns into D0
	MOVEM.L (SP)+,D2-D7/A0-A6	; restore registers
	move.l	d0,a5			; save it for later
	beq	nomem			; but did it work?

	move.l	d0,d2			; InfoData address
	move.l	d4,d1			; the lock

	Call	Info			; see what the lock corresponds to.

	cmpi.l	#FALSE,d0		; don't need to cd in cleanup code
	beq	noinfo
	move.l	d2,a0			; infodata pointer into a0
	move.l	id_NumBlocks(a0),d2	; # of blocks on disk
	sub.l	id_NumBlocksUsed(a0),d2 ; # already used
	moveq	#0,d0
	move.l	d0,d1			; initialize multiplier
	move.l	id_BytesPerBlock(a0),d1
	subq.l	#1,d1			; adjust for loop
1$:
	add.l	d2,d0			; add to total
	dbra	d1,1$			; loop 'til done
	move.l	d0,v_SIZE(a4)		; save for print
	tst.l	id_VolumeNode(a0)	; ...RAM: doesn't have a Volume
	bne.s	df1			; ...Node, so returns 0.
	move.l	#RAM,v_STRING(a4)	; store RAM name in output string
	bra.s	df2
df1:
	move.l	id_VolumeNode(a0),d0	; here goes a mess caused by
	asl.l	#2,d0			; ...using BPTRs to show where
	move.l	d0,a0			; ...things are.  We need all
	move.l	40(a0),d0		; ...of this mess just to find
	asl.l	#2,d0			; ...the Volume Name for the
	move.l	d0,a0			; ...requested drive.
	moveq	#0,d0
	move.b	(a0)+,d0		; get length of Volume name
	move.l	a4,d1			; and find
	add.l	#v_STRING,d1		; ...where to store it
	move.l	d1,a1
	move.l	d1,v_STRPTR(a4) 	; ...(also, save for RawDoFmt)
dlp:
	move.b	(a0)+,(a1)+		; copy name to string storage
	dbra	d0,dlp
	move.b	#0,(a1) 		; ...and remember to NULL term!
df2:
	lea	FMT(pc),a0		; ...the format string
	lea	v_STRPTR(a4),a1		; ...the first print parm
	lea	store(pc),a2		; ...the storage routine address
	lea	v_OUTPUT(a4),a3		; ...the storage area
	movem.l a3/a6,-(sp)		; save a couple registers
	move.l	_AbsExecBase,a6
	Call	RawDoFmt		; and figure it out!
	movem.l (sp)+,a3/a6
	move.l	d5,d1
	move.l	a3,d2
	moveq	#127,d0
	moveq	#0,d3
lenloop:
	tst.b	(a3)+			; look for null term
	beq.s	printit
	addq.l	#1,d3
	dbra	d0,lenloop
printit:
	Call	Write			; then print when found
	bra.s	cleanup 		; and quit.

nomem:
	move.l	d5,d1
	move.l	#S_NOMEM,d2
	move.l	#S_NOMSIZ,d3
	Call	Write
	bra.s	afterfree

noinfo:
	move.l	d5,d1
	move.l	#S_NOINFO,d2
	move.l	#S_NINFSIZ,d3
	Call	Write
	bra.s	cleanup

nolock:
	move.l	d5,d1
	move.l	#S_NLOCK,d2
	move.l	#S_NLKSIZ,d3
	Call	Write
	bra.s	FINISHED

cleanup:
	; start off by freeing allocated memory.
	move.l	a5,a1
	MOVEM.L D1-D7/A0-A6,-(SP)	; in case FreeMem trashes
	move.l	#id_SIZEOF,D0
	move.l	_AbsExecBase,a6
	Call	FreeMem
	MOVEM.L (SP)+,D1-D7/A0-A6	; restore registers

afterfree:

	; May have to throw away two locks and do a cd here
	move.l	d4,d1
	cmpi.l	#FALSE,d6
	beq.s	nocd

	Call	CurrentDir		; get back to where we were
	move.l	d0,d1
nocd:
	Call	UnLock
	moveq	#RETURN_OK,D0
FINISHED:
	unlk	a4
	rts

* Subroutines
* ------------------------------------------------------------------------

********************************************************************************
* argtrim:	a routine to trim the end of a command line and null terminate
*		it. This is achieved in the following manner:
*		Start at the end and run back until a non-whitespace (nl/blank)
*		character is encountered. If this is a quote, toss it.
*		If the *first* character is a quote, bump the start address by
*		one. No pretense of quote matching here.
*		 Inputs:	address in A0, length in D0
*		 Outputs:	address in A0.
********************************************************************************

argtrim:
	movem.l d1-d7/a1-a6,-(sp)	; save registers

	cmpi.b	#'"',(a0)               ; starts with a quote?
	bne.s	checkline		; no
	subq	#1,d0			; yes - decrement count
	addq	#1,a0			; and bump start address

checkline:
	cmpi.b	#1,D0			; length includes the newline
	bne.s	isline			; yes - there is something there
	move.b	#0,(a0) 		; create null string
	bra.s	argfini 		; done

isline:
;	strip off any run of blanks on the end...
	move.l	a0,a1			; computing end address of line
	add.l	d0,a1			;
	subq	#2,a1			;

toploop:
	cmp.l	a0,a1
	beq.s	empty			; single char or run of blanks

	cmpi.b	#' ',(a1)
	bne.s	endloop 		; finished the scan
	subq	#1,a1			; else back one more
	bra.s	toploop 		; and try again

endloop:
	cmpi.b	#'"',(a1)
	beq.s	nullit
nullnext:
	addq	#1,a1
nullit:
	move.b	#0,(a1)
	bra.s	argfini
empty:					; could be blanks or a single char
	cmpi.b	#' ',(a1)
	bne.s	endloop 		; or maybe a single quote!
	move.b	#0,(a0)

argfini:
	movem.l (sp)+,d1-d7/a1-a6	; restore registers
	rts

********************************************************************************
* STORE:	routine used by _LVORawDoFmt to store output string
********************************************************************************

store:
	move.b	d0,(a3)+
	rts

********************************************************************************
* Data declarations
********************************************************************************

	CNOP	0,4
DOSName 	DOSNAME
S_NLOCK 	DC.B	'directory or file name not found',10
S_NLKSIZ	equ	*-S_NLOCK
S_NOINFO	DC.B	'Couldn''t get info for disk',10
S_NINFSIZ	equ	*-S_NOINFO
S_NOMEM 	DC.B	'No memory',10
S_NOMSIZ	equ	*-S_NOMEM
FMT		DC.B	'Volume "%s:" has %ld bytes free.',10,0
	END
