Reputation: 33956
I have variable like this one:
myVar db 'A','B',0
I need to embed 'A' and 'B' in the middle of a string that is printed on screen. Something like this:
CALL PTHIS
db 'first val is ', %1, ' second val is ', %2, 0
I think I saw something like this somewhere. How can this be done?
Upvotes: 0
Views: 251
Reputation: 14409
For the sake of an answer I wrote a very simple printf parser. It works like its big brother of C, but understands only the format specifier '%c' and '%s'. This can be expanded as well.
It's also a good example to explore the C calling convention.
Following program assembles in EMU8086, TASM, JWASM and MASM>=6.0:
.MODEL tiny ; For MASM 6 and TASM
.CODE ; For MASM 6 and TASM
.186 ; For MASM 6 (push immediates)
ORG 100h ; Origin for COM program
start:
; printf (&format, &myVar, myVar[0], myVar[1])
push WORD PTR myVar + 1 ; Forth argument (single character directly pushed)
push WORD PTR myVar + 0 ; Third argument (single character directly pushed)
push OFFSET myVar ; Second argument (address of null terminated string)
push OFFSET fmt ; First argument (address of null terminated format string)
call printf
add sp, 2 * 4 ; Adjust stack: 4 arguments a 2 bytes
lea dx, report
mov ah, 09h
int 21h
RET ; return to operating system.
printf PROC
push bp ; Prologue
mov bp, sp
sub sp, 2 * 3 ; Reserve local stack for three WORDs
mov [bp-2], bx ; Preserve BX (CCall calling convention)
mov [bp-4], si ; Preserve SI (CCall calling convention)
mov [bp-6], di ; Preserve DI (CCall calling convention)
mov di, 4 ; Counter to the arguments
mov si, [bp+di] ; Get the first argument
output:
mov ax, [si] ; Get two characters
cmp al, '%' ; First charcter == '%'
jnz J1 ; No, skip over the placeholder blocks
cmp ah, 'c' ; Second character == 'c'
jnz no_c ; No, skip over the '%c' placeholder block
inc si ; Adjust the index to format string
add di, 2 ; Point to the next argument on stack
mov al, BYTE PTR [bp+di] ; Get the argument (it is a directly pushed character)
jmp J1 ; and print it
no_c:
cmp ah, 's' ; Second character = 's'
jnz no_s ; No skip over the %s placeholder block
add si, 2 ; Adjust the index to format string
add di, 2 ; Point to the next argument on stack
mov bx, [bp+di] ; Get argument (it is an offset to an ASCIIZ string)
next:
mov al, [bx] ; Get character
test al, al ; character == 0
jz output ; Yes - this string is ready, turn back to format string
mov ah, 0Eh ; Teletype
int 10h ; BIOS
inc bx ; Point to next charcter
jmp next ; Repeat the output
no_s:
J1:
test al, al ; Character == 0?
jz ready ; Yes, format string is ready, print is done
doit:
mov ah, 0Eh ; Teletype
int 10h ; BIOS
inc si ; Point to next character
jmp output ; Repeat the bunch
ready:
mov bx, [bp-2] ; Restore BX (CCall calling convention)
mov si, [bp-4] ; Restore SI (CCall calling convention)
mov di, [bp-6] ; Restore DI (CCall calling convention)
mov sp, bp ; Epilogue
pop bp
ret
printf ENDP
fmt db "From the word %s is the first char %c and the second char %c",0
myVar db 'H','e','l','l','o',0
report db 13,10,13,10,"I'm back to the root",13, 10,'$'
END start ; Directive to stop the compiler.
Upvotes: 1