PC技術(shù)指導(dǎo):匯編源碼free

字號:

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