CNC Programming

CNC | C | C++ | Assembly | Python | R | Rust | Arduino | Solidworks | Embedded Systems

A utility to report free space on the default or selected disk drive

        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)

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 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.
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



No comments:

Post a Comment