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 returnlf equ 0ah ;ASCII line feedblank equ 20h ;ASCII space codeeom 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 05chfcb label byte ;default file control block org 080hcommand label byte ;default command bufferpsp endscseg segment para public 'CODE' assume cs:cseg,ds:psp,es:data,ss:stackget_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 it mov 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. retget_drive endpfree 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 free4free1: 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 errorfree4: 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,0bin1: ;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:quotient2div1: ret ; BX = remainder2divide endpcseg endsdata segment para public 'DATA'output db cr,lfoutputa db 10 dup (blank) db ' bytes free on drive 'outputb db 'x:',cr,lf,eommsg1 db cr,lf db 'That disk drive does not exist.' db cr,lf,eommsg2 db cr,lf db 'Requires DOS version 2 or greater.' db cr,lf,eomdata ends stack segment para stack 'STACK' db 64 dup (?)stack ends end free  
|