本文收錄 CLEANF.ASM (Bob Taylor 改自 Ray Duncan 的 CLEAN),功能相同但改為標準輸入/輸出/錯誤過濾器:從 STDIN 讀取、過濾後寫入 STDOUT、錯誤訊息輸出 STDERR。支援管道重導向 (type file.txt | cleanf > clean.txt),體現 Unix 哲學「做一件事、做好、支援管道」。程式極精簡 (約 100 行),展示 DOS 2.0 預定義控制代碼、字元級管線處理、最小化資源佔用。
| 特性 | CLEAN | CLEANF |
|---|---|---|
| 檔案指定 | 命令列參數 | 標準串流 (STDIN/STDOUT/STDERR) |
| 檔案開啟/關閉 | 明確 3Ch/3Dh/3Eh | 無需開啟/關閉,繼承自父進程 |
| 緩衝區 | 1KB 區塊緩衝 | 單字元緩衝 (input_buffer/output_buffer db 0) |
| 錯誤輸出 | 螢幕訊息框 | STDERR (控制台) |
| 適用場景 | 獨立檔案處理 | 管道鏈結、腳本自動化 |
stdin equ 0000 ; 標準輸入
stdout equ 0001 ; 標準輸出
stderr equ 0002 ; 標準錯誤
stdaux equ 0003 ; 標準輔助
stdprn equ 0004 ; 標準列印
子進程繼承父進程的控制代碼,CLEANF 直接使用這些值呼叫 INT 21h AH=3Fh/40h,無需開啟檔案。
name cleanf
page 55,132
title 'CLEANF - Filter text file'
cr equ 0dh
lf equ 0ah
ff equ 0ch
eof equ 01ah
tab equ 09h
command equ 80h
stdin equ 0000
stdout equ 0001
stderr equ 0002
stdaux equ 0003
stdprn equ 0004
cseg segment para public 'CODE'
assume cs:cseg,ds:cseg
org 100H
clean proc far
push ds
xor ax,ax
push ax
clean3: call get_char
and al,7fh
cmp al,20h
jae clean4
cmp al,eof
je clean6
cmp al,tab
je clean5
cmp al,cr
je clean35
cmp al,lf
je clean35
cmp al,ff
jne clean3
clean35:
mov column,0
jmp clean45
clean4: inc column
clean45: call put_char
jnc clean3
mov bx,stderr
mov dx,offset err_msg
mov cx,err_msg_len
mov ah,40h
int 21h
ret
clean5: mov ax,column
cwd
mov cx,8
idiv cx
sub cx,dx
add column,cx
clean55: push cx
mov al,20h
call put_char
pop cx
loop clean55
jmp clean3
clean6: call put_char
ret
clean endp
get_char proc near
mov bx,stdin
mov cx,1
mov dx,offset input_buffer
mov ah,3fh
int 21h
or ax,ax
jz get_char1
mov al,input_buffer
ret
get_char1: mov al,eof; ret
get_char endp
put_char proc near
mov output_buffer,al
mov bx,stdout
mov cx,1
mov dx,offset output_buffer
mov ah,40h
int 21h
cmp ax,1
jne put_char1
clc; ret
put_char1: stc; ret
put_char endp
input_buffer db 0
output_buffer db 0
column dw 0
err_msg db cr,lf,'clean: Disk is full.',cr,lf
err_msg_len equ (this byte)-(offset err_msg)
cseg ends
end clean
clean3:呼叫 get_char → 去高位 (AND 7Fh) → 分類處理 → put_char → 檢查 CY (磁碟滿) → 循環。INT 21h AH=3Fh, BX=0 (STDIN), CX=1 讀 1 位元組。若 AX=0 (EOF) 返回 EOF (1Ah)。INT 21h AH=40h, BX=1 (STDOUT), CX=1 寫 1 位元組。成功清 CY,失敗置 CY。CLEAN,以 column 追蹤欄位,補空白至 8 的倍數。CR(0Dh)/LF(0Ah)/FF(0Ch) 寫入並歸零 column;其他控制碼捨棄。put_char 失敗 (磁碟滿) → 寫入 STDERR (BX=2) → 返回 DOS。C:\> type source.txt | cleanf > filtered.txt
C:\> cleanf < source.txt > filtered.txt
C:\> dir | cleanf | more
父進程 (CMD/COMMAND.COM) 建立管道,將左側程式 STDOUT 接管道寫端,右側程式 STDIN 接管道讀端。CLEANF 完全不知情,只操作標準控制代碼 0/1/2。
| CLEANF 概念 | 現代對應 |
|---|---|
| 標準串流過濾器 | Unix stdin/stdout/stderr、Windows 控制台控制代碼、System.Console |
| 管道組合 | Shell 管道 |、PowerShell 管道、subprocess.Popen、Node.js stream.pipe |
| 單字元無緩衝 I/O | 非緩衝 I/O、read(STDIN_FILENO, &c, 1)、getchar() |
| 錯誤輸出分離 | stderr 重導向、日誌框架、log.Error() |
| 最小化依賴 | 單一職責原則、微服務、Unix 哲學 |
CY 旗標傳遞、STDERR 輸出、立即退出get_char → filter → put_char 管線模式.COM 程式結構:ORG 100h、PUSH DS; XOR AX,AX; PUSH AX 返回 DOSCLEANF.ASM 是管道過濾器模式在 DOS 組合語言的純粹實現:100 行、零檔案操作、零命令列解析、專注字元轉換。它證明了「小而美、可組合、標準介面」的設計哲學在 1980 年代的 16 位實模式下同樣成立。今日我們在微服務、Serverless、資料管線中談論的「單一職責、標準輸入輸出、可組合性」,其靈魂早已在這段精簡代碼中完美呈現。