; FILESIZE.Z80 1k Utility ; vers equ 15 subvers equ 'a' ; ; Reports size of file in records, pages, kilobytes. ; ; USAGE: ; ; FILESIZE {dir:}{{afn}.aft} {{/}options} ; ; OPTIONS (as distributed): ; ; P Turn off screen paging. ; ; S Include system files. ; ; HISTORY (from limited information): ; ; Version 1.5a March 26, 1991 Gene Pizzetta ; - Corrected usage screen: effect of options was reversed. ; - Slight revision of CFG file. ; ; Version 1.5 March 24, 1991 Rob Friefeld ; - Type 4 version assembly option ; - Made file limit installable ; - Enhanced speed on small files by using record count from search ; - Default option report was reversed ; ; Version 1.4 March 20, 1991 Gene Pizzetta ; - handles up to 1024 files (more if re-assembled), and now ; actually checks to see if the file limit has been exceeded. ; If so, aborts with error message. ; - filters high bit of filenames for proper display on all terminals. ; - aborts with ^C any time, not just at page pause. ; - defaults to current directory if none is given. ; - automatic wildcarding if no filename is given. ; - automatic wildcarding if only filetype is given. ; - extra new line at end of display eliminated. ; - wipes out "more" message when continuing display. ; - under ZCPR3 gets number of screen lines from environment. ; - option P toggles screen paging on or off. ; - option S toggles inclusion or exclusion of system files. ; - options can be configured as defaults using ZCNFG. ; - intelligent usage screen shows current effect of options. ; - corrected bug that always chose user 0 under vanilla CP/M. ; - code somewhat re-organized for easier modification and maintenance. ; ; Version 1.3 Rob Friefeld, Long Beach, CA ; - issued with ZCPR33-only type-3 version. No changes. ; ; Version 1.2 July 1986 Rob Friefeld, Long Beach, CA ; - correctly reports very large file sizes ; - 0 length and non-extant files differentiated ; ; Version 1.1 Rob Friefeld, Long Beach, CA ; - accepts ambiguous file spec, up to 255 matches ; ; Addresses and BDOS functions ; bdos equ 5 fcb equ 5ch ; Default FCB recnt equ 7dh ; Random record count returned by BDOS cmdbuf equ 80h ; Default command buffer ; printc equ 2 ; Character E -> console readc equ 6 ; BIOS read character openf equ 15 ; Open file srchf equ 17 ; Search first srchn equ 18 ; Search next setusr equ 32 ; Set user filsz equ 35 ; Compute file length (returns record count) ; bel equ 7 tab equ 9 cr equ 13 lf equ 10 ctlc equ 'C'-'@' n equ 0 y equ not n ; ; A list of matched filenames is created, along with 4 bytes of directory ; info as returned by bdos search function. The list is then run through ; for file size calculations. If search didn't find the last extent, the ; bdos get end address function is called. (This can't be done on the fly, ; eliminating the need for any file list buffer, because you can't reliably ; interleave bdos search next with other file ops.) The buffer can overflow ; available memory. At 15 bytes/entry, 1000 entries uses about 15k. listsz equ 15 ; Directory list entry size (in SBUF) ; ; ----- Type 4 program header ; ; Any dynamic buffers must be set BELOW code origin for Type 4 ; Link ZML FILESZ15.COM/N,FILESZ15,T4LDR/P ; .accept "Type 4 assembly? (y/n) ",type4 if type4 public $memry endif ; ----- Program Header entry: jp start db 'Z3ENV' type: db 3 ; Type-3 (overwritten by T4LDR) z3eadr: dw 0 ; Filled in by Z33+ if type4 $memry: ds 2 ; Filled in by linker else dw entry ; Intended load address endif ;type 4 ; ; ----- Configuration Area ; db 'FILESZ' ; for ZCNFG db vers/10+'0',vers mod 10+'0' pagdft: db 0 ; FFh=no screen paging sysdft: db 0 ; FFh=include system files scrdft: db 24 ; default screen lines under CP/M buflmt: dw 1024 ; maximum files ; ; ----- Code Start ; start: ld (stack),sp ; Save stack pointer and set up local stack ld sp,stack ; Should be out of the way ; ;===================================== ; Initialize and process command line ;===================================== ; xor a ld (fnflg),a ld hl,(pagdft) ; get default paging and system flags ld (pagflg),hl ; ..and move them to program flags ld hl,(z3eadr) ; check for ZCPR3 ld a,h or l ld a,(scrdft) ; assume default lines jr z,setlns ; (not ZCPR3, set default lines) ld de,50 ; get screen lines from environment add hl,de ; add offset ld a,(hl) ; get lines setlns: ld (scrlns),a ; and store for program call getopt ld a,(fnflg) ; do we have a file mask? or a ld hl,fcb+1 ; prepare for '?' fill ld b,11 jr z,fillft ; (no, so match 'em all) gotfn: ld a,(hl) ; do we have a filename? cp ' ' jr nz,nofill ; (yes) ld b,8 fillfn: call fillq ld a,(hl) ; do we have a filetype? cp ' ' ld b,3 fillft: call z,fillq ; (no, fill it) nofill: ld a,(z3eadr+1) ; is this ZCPR3? or a jr z,search ; (no, just use default user) ld a,(fcb+13) ; Get the user code ld e,a ld c,setusr ; Select the new user code call bdos ; ;=============================== ; Main program ;=============================== ; ; Find matches for ambiguous file spec, save them, then cycle them ; through the file size routines. ; search: ld hl,0 ; Set up counter ld (snum),hl if type4 ld de,entry-1 ; Type 4 buffer goes down from entry point else ld de,sbuf ; Type 1/3 buffer goes up from end of code endif ld (sptr),de ld c,srchf jr z,sloop1 ; No match on first try sloop: call sfind ld c,srchn sloop1: ld de,fcb call bdos cp 0ffh jr nz,sloop ; Still matching ; ; Show sizes for file in fcb ; show: ld bc,(snum) ; # of files in BC ld a,b or c jr z,nofile if type4 ld hl,entry-listsz else ld hl,sbuf ; Point to buffer endif ld a,(scrlns) ; # of lines to display show1: ld (sptr),hl dec a call z,spage push af ld (cnum),bc ; save current file count push bc ; save file count on stack also ld de,fcb+1 ; Move first file name to FCB ld bc,11 ldir ld de,listsz-11 ; 4 extra bytes in entry add hl,de push hl ; Save pointer call pfn ; Print filename call print dc ' |' call fsize ; Print size info ld hl,(cnum) ; get current file count dec hl ; see if we need a new line ld a,h or l call nz,crlf call getchr cp ctlc jr z,abort pop hl ; Restore pointer if type4 ld de,-listsz*2 ; -30, back up to start of lower entry add hl,de endif pop bc ; Restore count dec bc ld a,b or c jr z,exit pop af ; Restore line count jr show1 ; ; exit to system ; exit: ld sp,(stack) ; restore stack ret ; and return to CCP ; ; Error exits ; nofile: call print dc 'No file' jr exit ; abort: call print dc cr,'Aborted' jr exit ; ;================================ ; Utility routines ;================================ ; ; Get filesize ; fsize: ld hl,0 ld (recnt),hl ; Init record count at end of fcb ld ix,(sptr) ; Pointer to first dir entry from search ld a,(ix+14) ; Look at record count ld (recnt),a ; May be info we need cp 80h jr z,fsize1 ; This entry full, can't trust it ld a,(ix+11) ; Check extent # or a jr z,fsize2 ; First and only extent fsize1: ld de,fcb ; Get file end address ld c,filsz call bdos ld a,(recnt+2) ; 8 meg file byte or a jp nz,fsz8m ; Special message for this case fsize2: ld hl,(recnt) ; Size is returned here ; ; Convert record count in hl to decimal and display call todec call print dc ' records |' ; Display records ; ; Convert record count to page count and display ld hl,(recnt) ; Get record count srl h ; Divide by 2 rr l jr nc,fsz02 ; If carry, count was odd inc hl ; so add a page fsz02: call todec call print dc ' pages |' ; Display pages ; ; Compute kbyte size (records / 8) and display ld hl,(recnt) ; Get record count ld e,0 ; E is a carry flag ld b,3 ; divide HL by 8 fsz03: srl h rr l jr nc,fsz04 ; If there is a carry, division has remainder ld e,1 ; and E is flagged fsz04: djnz fsz03 ld a,h ; Is result 0? or l jr z,fsz1k ; If so, we started at less than 1 k xor a ; Zero A cp e ; Check flag jr z,fsz05 ; Skip round up if no remainder inc hl ; Round size up fsz05: call todec call print dc 'k' ret ; ; Routine to convert HL to decimal number and display it ; todec: ld b,0 ; B holds leading zero suppression flag ld de,10000 call todec2 ld de,1000 call todec2 ld de,100 call todec2 ld de,10 call todec2 ld a,l add a,'0' jp pchar ; todec2: ld c,'0'-1 ; Count number of divisions by DE todec3: inc c xor a sbc hl,de jr nc,todec3 ; Keep subtracting until negative add hl,de ; then add one back ld a,c cp '1' jr nc,todec4 ; If '0', was it a leading 0? ld a,b ; Check flag at B or a ; Set the 0 flag if B was 0 ld a,c ; Put character back in C jr nz,todec5 ; If B NOT 0, this '0' is not leading ld a,' ' ; otherwise, print a blank instead jr todec5 todec4: ld b,0ffh ; Turn the leading 0 flag off todec5: jp pchar ; Print the number ; ; Special display for 8 megabyte files ; fsz8m: call print dc '> 8 MB' ret ; ; Special display for files less than 1 kilobyte ; fsz1k: call print dc ' < 1k' ret ; ; Print usage message ; fszhlp: call print db 'FILESIZE Version ' db vers/10+'0','.',vers mod 10+'0',subvers,cr,lf db 'Reports number of records, pages, kilobytes in file' db cr,lf db 'Usage:'cr,lf db ' FILESIZE {dir:}{{afn}.aft} {{/}options}',cr,lf db 'Options:',cr,lf db ' P Paging o',0 ld a,(pagdft) or a call nz,pron call z,proff call print db cr,lf dc ' S ' ld a,(sysdft) or a call nz,prex call z,prin call print dc 'clude System files' jp exit ; pron: ld a,'n' jp pchar ; proff: call print dc 'ff' ret ; prin: push af call print dc 'In' pop af ret ; prex: push af call print dc 'Ex' pop af ret ; ; Print character in A ; pchar: push hl push de push bc push af and 7fh ; get rid of high bit. Yuk! ld e,a ld c,printc call bdos pop af pop bc pop de pop hl ret ; ; Print string terminated by 0 ; print: ex (sp),hl ld a,(hl) inc hl ex (sp),hl or a ret z call pchar ret m jr print ; ; Print carriage return and line feed ; crlf: call print dc cr,lf ret ; ; Get a character ; getchr: ld e,0ffh ld c,readc jp bdos ; ; Print the file name in the FCB ; pfn: ld b,8 ; Print file name ld hl,fcb+1 call pfn0 ld a,'.' call pchar ld b,3 ; Print file type pfn0: ld a,(hl) inc hl call pchar djnz pfn0 ret ; ; When screen is full, pause until key is pressed ; spage: ld a,(pagflg) or a ret nz ; A = FF push hl push bc call print dc '[more] ' spage2: call getchr or a jr z,spage2 cp ctlc ; Permit ^C abort at pause jp z,abort call print dc cr ld a,(scrlns) ; restore screen limit dec a ; ..but make it one less pop bc pop hl ret ; ; Save a matching filename in buffer ; sfind: ld b,5 ; Save a match sfind1: add a,a ; A contains offset 20H / n djnz sfind1 add a,cmdbuf+1 ld l,a ld h,0 ; HL now -> beginning of matched filename ld a,(sysflg) ; are we excluding system files? or a jr nz,sfind2 ; (nope) push hl ; save filename pointer ld de,9 add hl,de ; point to system attribute bit 7,(hl) pop hl ; recover filename pointer ret nz ; (system file, ignore it) sfind2: ld de,(sptr) ld bc,listsz ; Move matched filename into sbuf if type4 add hl,bc ; Building buf downward dec hl lddr else ldir endif ld (sptr),de ; Save pointer ld hl,(snum) ; increment counter inc hl ld (snum),hl or a ld de,(buflmt) ex de,hl sbc hl,de ; Max files - count ret nc call print dc bel,'Too many files' jp exit ; ; get command line options, if any. ; getopt: ld hl,cmdbuf+1 oloop1: ld a,(hl) inc hl or a ret z cp ' ' jr z,oloop1 cp tab jr z,oloop1 cp '/' jr z,gotopt ld a,0ffh ld (fnflg),a nloop: ld a,(hl) inc hl or a ret z cp ' ' jr z,sloop2 cp tab jr z,sloop2 jr nloop ; sloop2: ld a,(hl) inc hl or a ret z cp ' ' jr z,sloop2 cp tab jr z,sloop2 cp '/' jr nz,gotop2 ; gotopt: ld a,(hl) inc hl or a ret z gotop2: cp '/' jp z,fszhlp cp 'P' jr nz,gotop3 ld a,(pagflg) cpl ld (pagflg),a jr gotopt gotop3: cp 'S' jr nz,gotop4 ld a,(sysflg) cpl ld (sysflg),a jr gotopt ; gotop4: call print dc bel,'Invalid option' jp exit ; ; Put number of "?"'s in B, beginning at HL. On return HL points to next. ; fillq: ld a,'?' fillp: ld (hl),a inc hl djnz fillp ret ; ;=============================== ; Uninitialized data storage ;=============================== ; if type4 dseg endif fnflg: ds 1 ; FFh=filespec exists pagflg: ds 1 ; FFh=no paging sysflg: ds 1 ; FFh=include system files scrlns: ds 1 ; number of screen lines ds 60 ; stack stack: ds 2 ; old stack pointer storage snum: ds 2 ; Number of matches found cnum: ds 2 ; Current file count sptr: ds 2 ; Pointer into sbuf sbuf ds 2 ; Matched filename buffer ; end