name free
page 60,132
title 'free --- report free space on disk'
; free --- a utility to report free space on
; the default or selected disk drive.
;
; requires pc-dos or ms-dos 2.0.
;
; used in the form:
; a> free [unit:]
; (item in square brackets is optional)
;
; version 1.0 july 4, 1984
; copyright (c) 1984 by ray duncan
; may be freely reproduced for non-commercial use.
cr equ 0dh ;ascii carriage return
lf equ 0ah ;ascii line feed
blank equ 20h ;ascii space code
eom equ '$' ;end of string marker
; here we define a dummy segment containing labels
; for the default file control block and the command tail buffer,
; so that the main program can access those locations.
;
psp segment para public 'psp'
org 05ch
fcb label byte ;default file control block
org 080h
command label byte ;default command buffer
psp ends
cseg segment para public 'code'
assume cs:cseg,ds:psp,es:data,ss:stack
get_drive proc near ;get drive selection, if any,
;otherwise obtain the identity
;of the current disk drive.
;return drive (1=a, 2=b, etc) in al.
;
mov al,fcb ;pick up the drive code, parsed
;by dos into the default file
;control block.
or al,al ;is it the default?
jnz get_drive1 ;no, use itmov ah,19h ;yes, get the actual current
int 21h ;drive from pc-dos.
inc al ;increment to match fcb code.
get_drive1: ;return drive code in al.
ret
get_drive endp
free proc far ;entry point from pc-dos
push ds ;save ds:0000 for final
xor ax,ax ;return to pc-dos
push ax
mov ax,data ;make our data segment
mov es,ax ;addressable via es register.
mov ah,30h ;check version of pc-dos.
int 21h
cmp al,2
jae free1 ;proceed, dos 2.0 or greater.
mov dx,offset msg2 ;dos 1.x --- print error message
mov ax,es ;and exit. first fix up ds register
mov ds,ax ;so error message is addressable.
jmp free4
free1: call get_drive ;get drive selection into dl.
push es ;copy es to ds for remainder
pop ds ;of the program...
assume ds:data ;and tell assembler about it.
mov dl,al
add al,'a'-1 ;form drive letter from drive code,
mov outputb,al ;and put it into the output string.
mov ah,36h ;now call dos to get free disk space.
int 21h
cmp ax,-1 ;was drive invalid?
je free3 ;yes,go print error message
;drive was ok, so now registers are...
;ax=number of sectors per cluster
;bx=available clusters,
;cx=number of bytes per sector,
;dx=total clusters per drive.
;calculate free space:
mul cx ;sectors per cluster * bytes per sector
;(we assume this won't overflow into dx)
mul bx ;then * available clusters
;dx:ax now contains free space in bytes.
;si = last byte address for converted string.
mov si,offset (outputa+9)
mov cx,10 ;cx = 10, radix for conversion
call bin_to_asc ;convert free space value to ascii,
mov dx,offset output
jmp free4 ;and print it out.
free3: mov dx,offset msg1 ;illegal drive, print error
free4: mov ah,9 ;print the string whose address
int 21h ;is in dx.
ret ;then return to dos.
free endp
; convert 32 bit binary value to ascii string.
;
; call with dx:ax = signed 32 bit value
; cx = radix
; si = last byte of area to store resulting string
; (make sure enough room is available to store
; the string in the radix you have selected.);
; destroys ax, bx, cx, dx, and si.
;
bin_to_asc proc near ;convert dx:ax to ascii.
;force storage of at least 1 digit.
mov byte ptr [si],'0'
or dx,dx ;test sign of 32 bit value,
pushf ;and save sign on stack.
jns bin1 ;jump if it was positive.
not dx ;it was negative, take 2's complement
not ax ;of the value.
add ax,1
adc dx,0
bin1: ;divide the 32 bit value by the radix
;to extract the next digit for the
;forming string.
mov bx,ax ;is the value zero yet?
or bx,dx
jz bin3 ;yes, we are done converting.
call divide ;no, divide by radix.
add bl,'0' ;convert the remainder to an ascii digit.
cmp bl,'9' ;we might be converting to hex ascii,
jle bin2 ;jump if in range 0-9,
add bl,'a'-'9'-1 ;correct it if in range a-f.
bin2: mov [si],bl ;store this character into string.
dec si ;back up through string,
jmp bin1 ;and do it again.
bin3: ;restore sign flag,
popf ;was original value negative?
jns bin4 ;no, jump
;yes,store sign into output string.
mov byte ptr [si],'-'
bin4: ret ;back to caller.
bin_to_asc endp
; general purpose 32 bit by 16 bit unsigned divide.
; this must be used instead of the plain machine unsigned divide
; for cases where the quotient may overflow 16 bits (for example,
; dividing 100,000 by 2). if called with a zero divisor, this
; routine returns the dividend unchanged and gives no warning.
;
; call with dx:ax = 32 bit dividend
; cx = divisor
;
; returns dx:ax = quotient
; bx = remainder
; cx = divisor (unchanged)
;
divide proc near ; divide dx:ax by cx
jcxz div1 ; exit if divide by zero
push ax ; 0:dividend_upper/divisor
mov ax,dx
xor dx,dx
div cx
mov bx,ax ; bx = quotient1
pop ax ; remainder1:dividend_lower/divisor
div cx
xchg bx,dx ; dx:ax = quotient1:quotient2
div1: ret ; bx = remainder2
divide endp
cseg ends
data segment para public 'data'
output db cr,lf
outputa db 10 dup (blank)db ' bytes free on drive '
outputb db 'x:',cr,lf,eom
msg1 db cr,lf
db 'that disk drive does not exist.'
db cr,lf,eom
msg2 db cr,lf
db 'requires dos version 2 or greater.'
db cr,lf,eom
data ends
stack segment para stack 'stack'
db 64 dup (?)
stack ends
end free
page 60,132
title 'free --- report free space on disk'
; free --- a utility to report free space on
; the default or selected disk drive.
;
; requires pc-dos or ms-dos 2.0.
;
; used in the form:
; a> free [unit:]
; (item in square brackets is optional)
;
; version 1.0 july 4, 1984
; copyright (c) 1984 by ray duncan
; may be freely reproduced for non-commercial use.
cr equ 0dh ;ascii carriage return
lf equ 0ah ;ascii line feed
blank equ 20h ;ascii space code
eom equ '$' ;end of string marker
; here we define a dummy segment containing labels
; for the default file control block and the command tail buffer,
; so that the main program can access those locations.
;
psp segment para public 'psp'
org 05ch
fcb label byte ;default file control block
org 080h
command label byte ;default command buffer
psp ends
cseg segment para public 'code'
assume cs:cseg,ds:psp,es:data,ss:stack
get_drive proc near ;get drive selection, if any,
;otherwise obtain the identity
;of the current disk drive.
;return drive (1=a, 2=b, etc) in al.
;
mov al,fcb ;pick up the drive code, parsed
;by dos into the default file
;control block.
or al,al ;is it the default?
jnz get_drive1 ;no, use itmov ah,19h ;yes, get the actual current
int 21h ;drive from pc-dos.
inc al ;increment to match fcb code.
get_drive1: ;return drive code in al.
ret
get_drive endp
free proc far ;entry point from pc-dos
push ds ;save ds:0000 for final
xor ax,ax ;return to pc-dos
push ax
mov ax,data ;make our data segment
mov es,ax ;addressable via es register.
mov ah,30h ;check version of pc-dos.
int 21h
cmp al,2
jae free1 ;proceed, dos 2.0 or greater.
mov dx,offset msg2 ;dos 1.x --- print error message
mov ax,es ;and exit. first fix up ds register
mov ds,ax ;so error message is addressable.
jmp free4
free1: call get_drive ;get drive selection into dl.
push es ;copy es to ds for remainder
pop ds ;of the program...
assume ds:data ;and tell assembler about it.
mov dl,al
add al,'a'-1 ;form drive letter from drive code,
mov outputb,al ;and put it into the output string.
mov ah,36h ;now call dos to get free disk space.
int 21h
cmp ax,-1 ;was drive invalid?
je free3 ;yes,go print error message
;drive was ok, so now registers are...
;ax=number of sectors per cluster
;bx=available clusters,
;cx=number of bytes per sector,
;dx=total clusters per drive.
;calculate free space:
mul cx ;sectors per cluster * bytes per sector
;(we assume this won't overflow into dx)
mul bx ;then * available clusters
;dx:ax now contains free space in bytes.
;si = last byte address for converted string.
mov si,offset (outputa+9)
mov cx,10 ;cx = 10, radix for conversion
call bin_to_asc ;convert free space value to ascii,
mov dx,offset output
jmp free4 ;and print it out.
free3: mov dx,offset msg1 ;illegal drive, print error
free4: mov ah,9 ;print the string whose address
int 21h ;is in dx.
ret ;then return to dos.
free endp
; convert 32 bit binary value to ascii string.
;
; call with dx:ax = signed 32 bit value
; cx = radix
; si = last byte of area to store resulting string
; (make sure enough room is available to store
; the string in the radix you have selected.);
; destroys ax, bx, cx, dx, and si.
;
bin_to_asc proc near ;convert dx:ax to ascii.
;force storage of at least 1 digit.
mov byte ptr [si],'0'
or dx,dx ;test sign of 32 bit value,
pushf ;and save sign on stack.
jns bin1 ;jump if it was positive.
not dx ;it was negative, take 2's complement
not ax ;of the value.
add ax,1
adc dx,0
bin1: ;divide the 32 bit value by the radix
;to extract the next digit for the
;forming string.
mov bx,ax ;is the value zero yet?
or bx,dx
jz bin3 ;yes, we are done converting.
call divide ;no, divide by radix.
add bl,'0' ;convert the remainder to an ascii digit.
cmp bl,'9' ;we might be converting to hex ascii,
jle bin2 ;jump if in range 0-9,
add bl,'a'-'9'-1 ;correct it if in range a-f.
bin2: mov [si],bl ;store this character into string.
dec si ;back up through string,
jmp bin1 ;and do it again.
bin3: ;restore sign flag,
popf ;was original value negative?
jns bin4 ;no, jump
;yes,store sign into output string.
mov byte ptr [si],'-'
bin4: ret ;back to caller.
bin_to_asc endp
; general purpose 32 bit by 16 bit unsigned divide.
; this must be used instead of the plain machine unsigned divide
; for cases where the quotient may overflow 16 bits (for example,
; dividing 100,000 by 2). if called with a zero divisor, this
; routine returns the dividend unchanged and gives no warning.
;
; call with dx:ax = 32 bit dividend
; cx = divisor
;
; returns dx:ax = quotient
; bx = remainder
; cx = divisor (unchanged)
;
divide proc near ; divide dx:ax by cx
jcxz div1 ; exit if divide by zero
push ax ; 0:dividend_upper/divisor
mov ax,dx
xor dx,dx
div cx
mov bx,ax ; bx = quotient1
pop ax ; remainder1:dividend_lower/divisor
div cx
xchg bx,dx ; dx:ax = quotient1:quotient2
div1: ret ; bx = remainder2
divide endp
cseg ends
data segment para public 'data'
output db cr,lf
outputa db 10 dup (blank)db ' bytes free on drive '
outputb db 'x:',cr,lf,eom
msg1 db cr,lf
db 'that disk drive does not exist.'
db cr,lf,eom
msg2 db cr,lf
db 'requires dos version 2 or greater.'
db cr,lf,eom
data ends
stack segment para stack 'stack'
db 64 dup (?)
stack ends
end free