在無圖形介面的 DOS 環境,查詢磁碟剩餘空間是批次檔、安裝程式、備份工具的常見需求。FREESPACE.ASM (Ray Duncan, 1984) 實作一個獨立 `.COM` 程式:接受命令列參數指定磁碟機 (如 `FREESPACE C:`),呼叫 INT 21h, AH=36h 取得幾何資訊,計算並以位元組為單位顯示剩餘空間。程式展示了命令列解析、DOS 版本檢查、32 位元無號除法、二進位轉十進位 ASCII、錯誤處理等核心系統工具技巧。
INT 21h, AH=30h 取得 DOS 版本,需 ≥ 2.0 (支援 36h)。INT 21h, AH=19h 取得當前磁碟機。INT 21h, AH=36h, DL=驅動器代號,回傳:
AX = 每叢集扇區數BX = 可用叢集數CX = 每扇區位元組數DX = 總叢集數AX = -1 (0xFFFF) 表示無效驅動器FreeBytes = AX * CX * BX (扇區/叢集 × 位元組/扇區 × 可用叢集)。以 32 位元無號整數 (DX:AX) 儲存結果。bin_to_asc 將 DX:AX 轉 ASCII,填入輸出緩衝區,INT 21h, AH=09h 列印。divide 子程式實現 DX:AX / CX → DX:AX = 商, BX = 餘數:
divide proc near
jcxz div1 ; 除數為 0 → 直接返回
push ax ; 保存低 16 位
mov ax, dx ; 高 16 位 → AX
xor dx, dx
div cx ; DX:AX / CX → AX=商1, DX=餘1
mov bx, ax ; BX = 商1
pop ax ; 恢復低 16 位
div cx ; 餘1:AX / CX → AX=商2, DX=餘2
xchg bx, dx ; DX:AX = 商1:商2, BX = 餘2
div1: ret
利用兩次 16 位元除法合成 32 位元除法,避免商溢位 (如 100,000 / 2)。
bin_to_asc proc near
mov byte ptr [si], '0' ; 至少輸出一位
or dx, dx
pushf ; 保存符號
jns bin1
not dx ; 負數 → 取二補數
not ax
add ax, 1
adc dx, 0
bin1:
mov bx, ax
or bx, dx
jz bin3 ; 值為 0 → 結束
call divide ; 除以基數 (CX=10)
add bl, '0' ; 餘數轉 ASCII
cmp bl, '9'
jle bin2
add bl, 'A'-'9'-1 ; 支援 16 進位 (A-F)
bin2:
mov [si], bl
dec si
jmp bin1
bin3:
popf
jns bin4
mov byte ptr [si], '-' ; 負號
bin4: ret
支援有號 32 位元整數、任意基數 (預設 10)、最小寬度保證、緩衝區反向填充 (SI 從尾部遞減)。
name free
page 60,132
title 'FREE --- Report free space on disk'
cr equ 0dh
lf equ 0ah
blank equ 20h
eom equ '$'
psp segment para public 'PSP'
org 05ch
fcb label byte
org 080h
command label byte
psp ends
cseg segment para public 'CODE'
assume cs:cseg,ds:psp,es:data,ss:stack
get_drive proc near
mov al, fcb
or al, al
jnz get_drive1
mov ah, 19h
int 21h
inc al
get_drive1: ret
get_drive endp
free proc far
push ds
xor ax, ax
push ax
mov ax, data
mov es, ax
mov ah, 30h
int 21h
cmp al, 2
jae free1
mov dx, offset msg2
mov ax, es
mov ds, ax
jmp free4
free1: call get_drive
push es
pop ds
assume ds:data
mov dl, al
add al, 'A'-1
mov outputb, al
mov ah, 36h
int 21h
cmp ax, -1
je free3
mul cx
mul bx
mov si, offset (outputa+9)
mov cx, 10
call bin_to_asc
mov dx, offset output
jmp free4
free3: mov dx, offset msg1
free4: mov ah, 9
int 21h
ret
free endp
bin_to_asc proc near ... endp
divide proc near ... 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,'That disk drive does not exist.',cr,lf,eom
msg2 db cr,lf,'Requires DOS version 2 or greater.',cr,lf,eom
data ends
stack segment para stack 'STACK'
db 64 dup (?)\n />stack ends\n />end free
INT 21h, AH=30h 確保 API 可用性,良好的相容性實踐。divide 以雙重 16 位除法合成 32 位除法,bin_to_asc 反覆呼叫其轉換進制 — 8086 無 32 位乘除指令時的標準技巧。free4 列印訊息並退出,結構清晰。FREE.ASM 以約 150 行程式碼,實作了專業級磁碟空間查詢工具,其「參數解析 → 系統查詢 → 多精度計算 → 格式化輸出 → 錯誤處理」完整流程,是 DOS 系統工具開發的教科書級範例,亦為現代 CLI 工具開發 (參數解析、系統呼叫、單位轉換、人類可讀輸出) 提供永恆的設計參考。