Skip to content

Instantly share code, notes, and snippets.

@LightningStalker
Last active December 19, 2025 22:13
Show Gist options
  • Select an option

  • Save LightningStalker/32b86c751114bafd6fb38ec744f29f0f to your computer and use it in GitHub Desktop.

Select an option

Save LightningStalker/32b86c751114bafd6fb38ec744f29f0f to your computer and use it in GitHub Desktop.
"wc" - wordcount in asm for DOS, 8086 +
name wc
title WC.COM--word count
;--- assemble: uasm -bin -Fo WC.COM WC.ASM
display_char macro character
mov dl, character
mov ah, 02h
int 21h
endm
display macro string
mov dx, offset string
mov ah, 09h
int 21h
endm
open_handle macro path, access
mov dx, offset path
mov al, access
mov ah, 3dh
int 21h
endm
read_handle macro handle, buffer, bytes
mov bx, handle
mov dx, offset buffer
mov cx, bytes
mov ah, 3fh
int 21h
endm
.model tiny
DEBUG equ 1
CR equ 13 ; carriage return
LF equ 10 ; linefeed char
BUFSIZE equ 256
ARGCOUNT equ 80h ; DOS area args count
FILENAME equ 82h ; ... argv[]
MAXARGS equ 77h
.code
org 100h
start:
mov cx, MAXARGS ; zero terminate args
mov di, FILENAME - 1 ; argv[] block
mov al, CR ; we gotta look
repne scasb
dec di ; went past
mov byte ptr [di], 0 ; maybe di - 1 is faster?
open_handle FILENAME, 0
mov handle, ax
jc errorOpen ; open error
xor dx, dx ; inWord = 0
mov bp, dx ; chars = 0
push dx ; align stack
readStream:
read_handle handle, buffer, BUFSIZE
jc errorRead ; error reading
; wc bp = lines, bx, mem = words, mem = chars
pop dx ; inWord = stack
mov si, offset buffer ; load at beginning
push ax ; save bytes read
mov cx, ax ; counter = nbytes read
add [charcount], ax ; add to 32-bit char count var
adc [charcount + 2], 0 ; ...
mov ah, ' ' ; white space we look for
xor bx, bx ; words = 0
countWords:
dec cx ; next byte
js EOB ; could be the end?
lodsb ; load a byte from buffer to al
cmp al, ah ; is a control char
jbe whitespace ; or whitespace?
test dl, dl ; already inside the word?
jnz countWords ; still inside
not dl ; whitespace/word boundary
inc bx ; words += 1
jmp countWords ; go get the next
whitespace:
jne notSpace ; not 20h
xor dl, dl ; end of word
jmp countWords ; ^next char^
notSpace: ; other whitespace or control ch
xor dl, dl ; dl = 0 = still not the word
cmp al, LF ; end
je EOL ; of line?
jmp countWords ; next byte
EOL: ; end the line
inc bp ; add to count
jmp countWords
EOB: ; end the buffer
add [wordcount], bx ; add to word count
adc [wordcount + 2], 0 ; ... 32-bit var
pop ax ; get bytes read from above
cmp ax, BUFSIZE ; smaller than buffer?
push dx ; stack = inWord
jae readStream
IF DEBUG
nop
ENDIF
; displayCounts
xor dx, dx ; dx = 0
mov ax, bp ; bp = lines
call optdecdw ; display
display_char ' ' ; space between
mov ax, [wordcount] ; mem = words
mov dx, [wordcount + 2] ; ...
call optdecdw ; display
display_char ' ' ; space again
mov ax, [charcount] ; mem = chars
mov dx, [charcount + 2] ; ...
call optdecdw ; disp
display crlf
; goodbye
mov ax, 4c00h
int 21h
errorOpen:
display errOpenMsg
display crlf
jmp badbye
errorRead:
display errReadMsg
display crlf
badbye:
mov ax, 4c01h
int 21h
IF DEBUG
nop ; debugs for the remove
nop
ENDIF
;--- 8086asm library code begin here
; written by hyan23
; 2016.10.24
; output the dword as the unsigned decimal string
; in: dx:ax
; ret: none
optdecdw: ; dword
push ax
push bx
push cx
push dx
xor cx, cx ; count
; - Project Crew - patch to handle in case of the zero
mov bx, cx ; 0
or bx, dx ; testing
or bx, ax ; ...
jnz optddw1 ; dx:ax > 0, decompose number
push cx ; 0 found, align stack
inc cx ; 1 char
jmp optddw2 ; print him
; - end patch
optddw0: ; /= 10
cmp dx, ax
jne optddw1
test ax, ax
jz optddw2
optddw1:
push cx
mov cx, 10
call div32 ; arith.inc
pop cx
add cx, 1
push bx
jmp optddw0
optddw2: ; print digit
pop ax
add ax, 30h
mov dl, al
mov ah, 02h
int 21h
loop optddw2
pop dx
pop cx
pop bx
pop ax
ret
IF DEBUG
nop
nop
ENDIF
; 00:dx / cx = q1 ... r1
; r1:ax / cx = q2 ... r2
; q1:q2 ... r2
; in: dx:ax / cx
; ret: dx:ax ... bx
div32: ; 32-bit division
mov bx, dx
; bx:ax / cx
; bx:ax ... dx
xchg ax, bx
xor dx, dx
div cx
xchg ax, bx
div cx
push dx
mov dx, bx
pop bx
ret
; ====================================== vars:
wordcount dw 0, 0 ; word count
charcount dw 0, 0 ; characters count
; strings:
crlf db 13, 10, '$' ; DOS line end
buffer db [BUFSIZE + 1] dup (?) ; you're gonna be our string
handle dw ? ; open handle
errOpenMsg db "File open error$" ; error msgs
errReadMsg db "File read error$" ; ...
end start
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment