home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
700-799
/
ff701.lha
/
du
/
Du.a
< prev
next >
Wrap
Text File
|
1992-08-03
|
12KB
|
515 lines
;**************************************************************************
;
; NAME : Du v2.5
;
; TEMPLATE : Du <dir/filename>,... [FILES] [DIRS] [NOHEAD] [NOTOTAL]
;
; DESCRIPTION : print disk usage for a given set of directories/files.
; If no directory specified then use current dir.
;
; AUTHOR : Stuart Mitchell
; (email: stuart@minster.york.ac.uk)
;
; DATE : 12-Jul-92
;
; NOTES : v1.0 - Initial coding
; v2.0 - Accepts wildcards and files/dirs switches
; v2.1 - Code tidied up
; v2.2 - New tabular output
; v2.3 - Can now be made resident (uses the LINK
; instruction to grab workspace).
; Prints totals if more than 1 arg or
; an argument contains a wildcard.
; v2.4 - If Lock on current dir is NULL then
; uses "sys:"
; v2.5 - Now uses DOS 2.0 functions instead of ARP
; Added NOHEAD and NOTOTAL switches
; Added WB2.0 version string
;
;**************************************************************************
section du,code
include "dos/dos.i"
include "dos/dosextens.i"
include "dos/dosasl.i"
include "exec/memory.i"
include "exec/execbase.i"
_LVOOpenLibrary equ -$228
_LVOCloseLibrary equ -$19e
_LVOFreeMem equ -$d2
_LVOAllocMem equ -$c6
_LVOAllocDosObject equ -$e4
_LVOReadArgs equ -$31e
_LVOFreeArgs equ -$35a
_LVOPutStr equ -$3b4
_LVOMatchFirst equ -$336
_LVOMatchNext equ -$33c
_LVOMatchEnd equ -$342
_LVOVPrintf equ -$3ba
_LVOPrintFault equ -$1da
_LVOGetCurrentDirName equ -$234
CALL macro (name)
jsr _LVO\1(a6)
endm
r_current_arg equr a2
r_anchor equr a3
r_dosbase equr a4
r_var_base equr a5
r_files equr d2
r_dirs equr d3 ; note multiple use
r_options equr d3 ; this IS OK
r_bytes equr d4
r_blocks equr d5
r_total_flag equr d6
r_rdaargs equr d7
;; bitdefs for dir scan - should really be picked up from dosasl.i ...
DIDDIR equ 3
DODIR equ 2
ITSWILD equ 1
;; define offsets into space reserved on the stack by link instruction
LINK_SIZE equ 56 ; size of reserved area
;; running totals
TFILES equ -56 ; must be in this order!
TDIRS equ -52
TBYTES equ -48
TBLOCKS equ -44
;; arguments for VPrintf()
P_ARG0 equ -40 ; must be in this order
P_ARG1 equ -36 ;
P_ARG2 equ -32 ;
P_ARG3 equ -28 ;
P_ARG4 equ -24 ;
;; vars returned by call to ReadArgs()
ARGS equ -20 ; char *args[]
DIR_FLAG equ -16
FILE_FLAG equ -12
HEADER_FLAG equ -8
TOTAL_FLAG equ -4
;; *********************************************************************
start: link r_var_base,#-LINK_SIZE ; reserve 56 bytes on stack
;; open DOS library
open_lib: move.l (4).w,a6
lea doslib(pc),a1
moveq.l #37,d0 ; 2.04 +
CALL OpenLibrary
tst.l d0
beq exit
move.l d0,a6
move.l d0,r_dosbase
;; clear argument array and global vars
moveq.l #(LINK_SIZE-4)/4,d0 ; loop count
moveq.l #0,d3
lea -LINK_SIZE(r_var_base),a0
clr_loop: move.l d3,(a0)+
dbra d0,clr_loop
;; parse command line
;; (d3 already set to NULL)
parse_args: lea ARGS(r_var_base),a0 ; pointer to arg array
move.l a0,d2
lea tplate(pc),a0
move.l a0,d1
CALL ReadArgs
move.l d0,r_rdaargs
beq closedos
;; output header line
tst.l HEADER_FLAG(r_var_base)
bne.s 1$ ; skip if flag specified
lea header_bar(pc),a0
move.l a0,d1
CALL PutStr
;; total flag is incremented for each arg, thus if more than one arg
;; is present then total flag will end up non-zero...
1$ moveq.l #-1,r_total_flag
moveq.l #0,r_options
set_file_flag: move.l FILE_FLAG(r_var_base),d0
beq.s set_dir_flag ; if zero then option not specified
moveq.l #-1,r_options
set_dir_flag: move.l DIR_FLAG(r_var_base),d0
beq.s test_num_args
moveq.l #1,r_options
;; test if any directories/files specified on the command line - if none
;; then do current directory
test_num_args: tst.l ARGS(r_var_base)
beq do_curr_dir
;; allocate memory for AnchorPath structure
bsr alloc_anchor
;; main loop -
;; for each arg:
;; while (matching entry found)
;; if (file)
;; print info;
;; else
;; scan dir & print info;
move.l ARGS(r_var_base),r_current_arg
main_loop: move.l (r_current_arg)+,d1
beq print_total ; no args left (last arg NULL)
addq.l #1,r_total_flag ; increment totals count
findfirst: move.l r_anchor,d2
CALL MatchFirst
tst.l d0
bne does_not_exist
;; if arg is wildcard then force totals at the end
;; ( ITSWILD bit is set by the call to MatchFirst )
move.b ap_Flags(r_anchor),d0
btst #ITSWILD,d0 ; bit's status --> Z flag
beq.s inner_loop ; if bit clear then continue
moveq.l #1,r_total_flag ; make sure totals are printed
inner_loop: move.l fib_DirEntryType+ap_Info(r_anchor),d0
blt.s do_file
do_dir: cmp.l #ST_LINKDIR,d0 ; if this a (hard) link
beq.s skip ; if so ignore it
cmp.l #ST_SOFTLINK,d0 ; soft link (file OR dir)
beq.s skip
tst.l r_options ; if r_options is negative
blt.s skip ; then files only required
lea ap_Buf(r_anchor),a0
bsr du
tst.l d0
bne.s break_pressed ; error - break pressed
bra.s skip
do_file: cmp.l #ST_LINKFILE,d0 ; file link?
beq.s skip
tst.l r_options ; if r_options is positive
bgt.s skip ; then only dirs to be shown
move.l fib_Size+ap_Info(r_anchor),d0
move.l d0,P_ARG0(r_var_base)
add.l d0,TBYTES(r_var_base)
move.l fib_NumBlocks+ap_Info(r_anchor),d0
addq.l #1,d0 ; correct block count to
move.l d0,P_ARG1(r_var_base) ; include file header block
add.l d0,TBLOCKS(r_var_base)
lea fib_FileName+ap_Info(r_anchor),a0
move.l a0,P_ARG2(r_var_base)
lea P_ARG0(r_var_base),a0
move.l a0,d2
lea file_fmt(pc),a0
move.l a0,d1
CALL VPrintf
skip: move.l r_anchor,d1
CALL MatchNext
cmpi.l #ERROR_BREAK,d0
beq.s break_pressed
tst.l d0
beq.s inner_loop
bra main_loop
print_total: tst.l r_total_flag ; only print totals if
ble.s free_rda ; flag is >0
tst.l TOTAL_FLAG(r_var_base) ; skip totals if NOTOTAL flag
bne.s free_rda ; specified on command line
lea total_fmt(pc),a0
move.l a0,d1
lea TFILES(r_var_base),a0
move.l a0,d2
CALL VPrintf
bra.s free_rda
;; ********************************************************************
;; Output "**BREAK" - Called if CNTL-C detected
;; Note: drop through to end of program
break_pressed: move.l #break_str,d1
CALL PutStr
;; ********************************************************************
free_rda: move.l r_rdaargs,d1
CALL FreeArgs
bsr free_asl
closedos: move.l r_dosbase,a1
move.l (4).w,a6
CALL CloseLibrary
exit: unlk r_var_base
moveq.l #0,d0
rts
;; **********************************************************************
;; Print error message if object does not exist
;;
;; IN: d0 - error code from MatchFirst() call (i.e. IoErr() code)
;; a6 - DosBase
;; OUT: <none>
does_not_exist: move.l d0,d1
move.l -4(r_current_arg),d2 ; r_current_arg has been advanced already
CALL PrintFault
bra main_loop ; try next arg...
;; **********************************************************************
;; Scan directory and print info on directory
;;
;; IN: a0 - full pathname of required directory
;; r_var_base - pointer to top of allocated workspace
;; a6 - DosBase
;; OUT: d0 - 0 on success, 1 if interrupted by ^C
du: movem.l d2-d7/a2-a4,-(sp)
move.l a0,a2
move.l a0,P_ARG4(r_var_base) ; save name to print later
bsr alloc_anchor
move.l r_anchor,d2
beq exit_du ; no memory
;; main loop
;; find first file/directory
move.l a2,d1 ; move pathname
CALL MatchFirst
tst.l d0
bne.s finished ; should never happen...
init_regs: moveq.l #0,r_files ; zero results
moveq.l #0,r_dirs
moveq.l #0,r_bytes
moveq.l #0,r_blocks
;; loop around in directory until all subdirectories/files exhausted
du_loop: move.b ap_Flags(r_anchor),d1
;; if DirEntryType <0 then we have a file
move.l fib_DirEntryType+ap_Info(r_anchor),d0
blt.s du_do_file
du_do_dir: btst #DIDDIR,d1 ; DIDDIR bit set
beq.s du_enter_dir ; no ... enter dir
;; have just popped out of a directory, mark as finished & increment count
du_exit_dir: bclr #DIDDIR,d1
addq.l #1,r_dirs ; bump dir count
bra.s du_find_next
;; found a new directory, so enter it at next FindNext
du_enter_dir: bset #DODIR,d1
bra.s du_find_next
;; this ones a file, so increment count & bytes
du_do_file: addq.l #1,r_files
add.l fib_Size+ap_Info(r_anchor),r_bytes
add.l fib_NumBlocks+ap_Info(r_anchor),r_blocks
addq.l #1,r_blocks ; take account of file header block
;; find next file/dir
du_find_next: move.b d1,ap_Flags(r_anchor) ; set directory handling
move.l r_anchor,d1
CALL MatchNext
cmpi.l #ERROR_BREAK,d0 ; ^C pressed ?
beq.s du_break
tst.l d0 ; if zero then got something
beq.s du_loop
;; print out results (dirname already put in place at start of subroutine)
print_dir: movem.l r_files/r_dirs/r_bytes/r_blocks,P_ARG0(r_var_base) ; flush results
add.l r_bytes,TBYTES(r_var_base)
add.l r_files,TFILES(r_var_base)
add.l r_blocks,TBLOCKS(r_var_base)
add.l r_dirs,TDIRS(r_var_base)
lea dir_fmt(pc),a0 ; format string
move.l a0,d1
lea P_ARG0(r_var_base),a0 ; address of ptrs to args
move.l a0,d2
CALL VPrintf ; print results
finished: bsr.s free_asl
moveq.l #0,d0 ; set error code
exit_du: movem.l (sp)+,d2-d7/a2-a4
rts
du_break: bsr.s free_asl
moveq.l #1,d0 ; error return code
bra.s exit_du
;; **********************************************************************
;; Allocate an ASL AnchorPath structure & extra string storage space
;;
;; IN: <none>
;; OUT: d0 - pointer to anchorpath structure, or NULL on failiure
alloc_anchor: move.l a6,-(sp)
move.l #ap_SIZEOF+256,d0 ; allow room for full pathname
moveq.l #MEMF_PUBLIC,d1
move.l (4).w,a6
CALL AllocMem ;
move.l d0,r_anchor ; save it
;; set up required fields in structure
move.b #%00100001,ap_Flags(r_anchor) ; DOWILD|DODOT
move.w #256,ap_Strlen(r_anchor) ; for full path
;; set bits we can break on (^C only)
move.l #$00001000,ap_BreakBits(r_anchor)
move.l (sp)+,a6
rts
;; **********************************************************************
;; Free ASL Anchor Chain
;;
;; IN: a6 - DosBase
;; OUT: <none>
free_asl: move.l r_anchor,d1 ; free any memory allocated
beq.s null_anchor ; by dos routines
CALL MatchEnd
move.l a6,-(sp) ; save DosBase
move.l r_anchor,a1
move.l #ap_SIZEOF+256,d0
move.l (4).w,a6
CALL FreeMem ; free AnchorPath struct
sub.l r_anchor,r_anchor ; clear register
move.l (sp)+,a6
null_anchor: rts
;; **********************************************************************
;; find name of current directory and use that
;;
;; IN: a6 - DosBase
;; OUT: <none>
do_curr_dir: move.l r_rdaargs,d1 ; finished with args
CALL FreeArgs
move.l (4).w,a6
moveq.l #MEMF_PUBLIC,d1
move.l #1024,d0 ; get memory to store
CALL AllocMem ; full path of current dir
tst.l d0
beq closedos
move.l d0,a2 ; store address
move.l r_dosbase,a6
move.l d0,d1
move.l #1024,d2
CALL GetCurrentDirName
beq.s use_sys ; failed...
tst.b (a2) ; empty buffer?
beq.s use_sys ; use "sys:"
move.l a2,a0 ; get ptr path name
bra.s do_cd ; and do it
use_sys: lea sys(pc),a0
do_cd: bsr du
free_buffer: move.l a2,a1 ; move buffer address
move.l d2,d0 ; buffer length
move.l (4).w,a6 ; get ExecBase
CALL FreeMem
bra closedos ; exit program
;; ************************************************************************
even
ver_str: dc.b 0,"$VER: Du 2.5 (12.7.92)",0
even
doslib: dc.b "dos.library",0
even
tplate: dc.b "NAME/M,DIRS/S,FILES/S,NOHEAD/S,NOTOTAL/S",0
even
sys: dc.b "sys:",0
even
break_str dc.b "***Break",$a,0
even
total_fmt dc.b "----- ----- -------- ------",$a
dc.b "%5ld%6ld%9ld%7ld",$a,0
even
header_bar dc.b "Files Dirs Bytes Blocks",$a,0
even
file_fmt dc.b "%20ld%7ld %s",$0a,$0 ; uses %20ld for extra space
even
dir_fmt dc.b "%5ld%6ld%9ld%7ld ",$1b,"[33m","%s",$1b,"[31m",$0a,0
end