This was originally an exercise in hand assembling machine code (4 hours).
;DumpHex.asm
;Translates bytes from STDIN to space
;separated two digit hexadecimal notion
;Ryan Kelly (codeFoil) 2012
;Nasm -f bin -o DumpHex.com DumpHex.asm
;Usage:
; commandx | DumpHex
;Or
; DumpHex < somefile.xxx
;Or
; DumpHex (use CTRL-C to terminate)
Org 0x100
ReadIn: MOV AH, 0x3F ; Read from handle
XOR BX, BX ; - STDIN = 0
MOV CX, 0x10 ; - 16 bytes
MOV DX, inBuff ; - Destination
INT 0x21
JS Exit ; Exit on error
OR AX, AX ; If no bytes read
JNZ Translate
Exit: MOV AH, 0x4C ; Terminate proccess
INT 0x21
Translate: MOV CX, AX ; Set loop counter to bytes in buffer
MOV [bytesRead], AX ; Save byte count
MOV DI, outBuff ; Initialize for string instruction
MOV SI, inBuff
Begin: MOV AL, 0x20 ; ASCII space
STOSb ; Store in output buffer
LODSb ; Load byte from input buffer
MOV AH, AL ; Duplicate
SHR AL, 0x04 ; High nibble to low sibble
AND AX, 0x0F0F ; Mask out high nibbles
; High nibble is now in low 4 of AL
; Low niblle is in low 4 of AH
OR AX, 0x3030 ; Shift code bank
CMP AL, 0x39 ; If high nibble > '9'
JBE Skip1
ADD AL, 0x07 ; adjust to alphabetic
Skip1: CMP AH, 0x39 ; If low nibble > '9'
JBE Skip2 ;
ADD AH, 0x07 ; adjust to alphabetic
Skip2: STOSw ; Save word in output buffer
LOOP Begin ; Repeat while bytes remain.
MOV AX, 0x0A0D ; carriage return, linefeed
STOSw ; terminate line
MOV AX, [bytesRead] ; Output buffer length is now
MOV CX, 0x0003 ; 3 * bytesRead + 2
MUL CX
ADD AX, 0x02
MOV CX, AX ; - byte count
MOV AH, 0x40 ; Write to handle
MOV BX, 0x0001 ; - STDOUT = 1
MOV DX, outBuff ; - source
INT 0x21
JMP ReadIn
Data Equ $
bytesRead: Equ Data
inBuff: Equ bytesRead + 0x02
outBuff: Equ inBuff + 0x10