;********************************************************************
;
; NAME		: Du v1.0
;
; TEMPLATE	: Du <dir name>,...
;
; DESCRIPTION	: print disk usage for a given set of directories
;
; AUTHOR	: Stuart Mitchell
;
; DATE		: 25-11-90
;
; NOTES 	: 1) Du requires the ARP shared library (v39.0+)
;
;********************************************************************

		section du,code

		opt	o+

		incdir	"include:"

		include "libraries/arpbase.i"
		include "libraries/dos.i"
		include "exec/memory.i"

_LVOOpenLibrary 	equ	-$228
_LVOCloseLibrary	equ	-$19e

CALL		macro	(name)
		jsr	_LVO\1(a6)
		endm

r_anchor	equr	a2
r_finfo 	equr	a3
r_current_arg	equr	a4

r_flags		equr	d1
r_files 	equr	d2
r_dirs		equr	d3
r_size		equr	d4
r_blocks	equr	d5
r_num_arg	equr	d6
r_zero		equr	d7

; bitdefs for dir scan - should really be picked up from ArpBase.i ...

DIDDIR		equ	3
DODIR		equ	2

;********************************************************************

start:		move.l	d0,d2			; cache command line
		move.l	a0,a2

		moveq.l #0,r_zero

; open ARP library

		move.l	4.w,a6
		lea	arplib(pc),a1
		move.l	r_zero,d0
		CALL	OpenLibrary
		tst.l	d0
		beq	exit
		move.l	d0,a6

; parse command line

		move.l	a2,a0			; string
		move.l	d2,d0			; length
		lea	help(pc),a1
		lea	args(pc),a2             ; pointer to arg array
		lea	tplate(pc),a3
		CALL	GADS
		move.l	d0,r_num_arg		; count

; allocate memory for AnchorPath structure - note freed automatically

		move.l	#ap_SIZEOF,d0
		move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
		CALL	ArpAllocMem
		tst.l	d0
		beq	closearp
		move.l	d0,r_anchor

; set up registers

		lea	ap_Info(r_anchor),r_finfo
		move.l	args,r_current_arg	; get base args

; main loop

main_loop:	tst.l	r_num_arg		; if count==0 then exit
		beq	closearp

init_regs:	move.l	r_zero,r_files		; zero results
		move.l	r_zero,r_dirs
		move.l	r_zero,r_size
		move.l	r_zero,r_blocks

		move.b	#%00100001,ap_Flags(r_anchor)   ; DOWILD|DODOT

; find first file/directory

		move.l	(r_current_arg),d0
		move.l	r_anchor,a0
		CALL	FindFirst
		tst.l	d0
		bne.s	no_files

; loop around in directory until all subdirectories/files exhausted
; first check if CNTL-C pressed

du_loop:	move.l	r_zero,a1
		CALL	CheckAbort
		tst.l	d0
		bne.s	break_pressed

		move.b	ap_Flags(r_anchor),r_flags

; if DirEntryType <0 then we have a file

		move.l	fib_DirEntryType(r_finfo),d0
		blt.s	do_file

do_dir: 	btst	#DIDDIR,r_flags		; DIDDIR bit set
		beq.s	enter_dir		; no ... enter dir

; have just popped out of a directory, mark as finished & increment count

exit_dir:	bclr	#DIDDIR,r_flags

		addq.l	#1,r_dirs
		bra.s	find_next

; found a new directory, so enter it at next FindNext

enter_dir:	bset	#DODIR,r_flags
		bra.s	find_next

; this ones a file, so increment count & size

do_file:	addq.l	#1,r_files
		add.l	fib_Size(r_finfo),r_size
		add.l	fib_NumBlocks(r_finfo),r_blocks

; find next file

find_next:	move.b	r_flags,ap_Flags(r_anchor)   ; set directory handling

		move.l	r_anchor,a0
		CALL	FindNext
		tst.l	d0
		beq.s	du_loop 		; if zero then got something

; directory exhausted

		bsr.s	free_anchor		; free mem

; print out results

print:		movem.l r_files/r_dirs/r_size/r_blocks,files	 ; flush results

		move.l	(r_current_arg)+,a0     ; print directory name
		CALL	Printf
		lea	fmt(pc),a0		; format string
		lea	files(pc),a1		; address ptrs to args
		CALL	Printf			; print results

; and do it all again

end_loop:	subq.l	#1,r_num_arg		; decrement arg count
		bra.s	main_loop		; and do next arg

;********************************************************************
; handle case when directory/file doesn't exist...

no_files:	move.l	(r_current_arg)+,a0
		CALL	Printf
		lea	not_exist(pc),a1
		CALL	Puts
		bsr.s	free_anchor		; free mem
		bra.s   end_loop

;********************************************************************
; called if CNTL-C detected
; NB: 1	- call to CheckAbort sets up a1 to point to break string
;     2 - drop through to end of program

break_pressed:	CALL	Puts			; output "***BREAK"
		bsr.s	free_anchor		; free mem

;*******************************************************************
; exit program - close ARP & return to DOS - call frees resources

closearp:	move.l	a6,a1
		move.l	4.w,a6
		CALL	CloseLibrary

exit:		move.l	r_zero,d0
		rts

;********************************************************************
; free anchorpath

free_anchor:	move.l	r_anchor,a0		; free anchor
		jmp	_LVOFreeAnchorChain(a6)

;********************************************************************
; data

files		dc.l	0
dirs		dc.l	0
size		dc.l	0
blocks		dc.l	0
		even
fmt		dc.b	" -- %ld files, %ld directories : %ld bytes (%ld blocks)",$0a,0
		even
arplib		dc.b	"arp.library",0
		even
args		dc.l	0			; char *args[]
		even
help		dc.b	"<directory name> [...]",0
		even
tplate		dc.b	"DIR/...",0
		even
not_exist	dc.b	" -- directory does not exist",0
		end

