kvisc/ka/crt/fmt/_doprnt.k

237 lines
3.9 KiB
Plaintext

; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
_doprnt_test:
mov ax0, .fmt
sub rsp, 128
mov q[rsp+40], 0x7FE
mov q[rsp+32], -2
mov q[rsp+24], 666
mov q[rsp+16], 0x112233DDAA6677BB
mov q[rsp+8], 'K'
mov q[rsp], .str
call printf
add rsp, 128
ret
.fmt = "%% Hello World %s - %c - %p - %d - %d - %b"
.str = "(cc)"
;
; typedef int (*PUTC)(int ch)
; int _doprnt(PUTC putc, int n, const char *fmt, va_list ap)
;
_doprnt:
enter 8
mov q[rbp-8], rbx
mov q[rbp-16], nx0
mov q[rbp-24], nx1
mov q[rbp-32], nx2
mov q[rbp-40], rdi
mov q[rbp-48], rsi
mov q[rbp-56], nx3
mov rbx, ax2 ; fmt
mov nx3, ax0 ; putc
mov nx0, ax1 ; n
xor nx1, nx1 ; return value
xor nx2, nx2 ; index in va_list
mov rsi, ax3 ; ap
.main_loop:
; find '%' or null-terminator
mov rcx, STRLEN_MAX
mov rdi, rbx
scasb.rep.nz rdi, '%'
.print_regular:
; everything below rdi is a regular character; print it
cmp rbx, rdi
j.z .check_modf
mov ax0, b[rbx]
call .doput
inc rbx
jmp .print_regular
.check_modf:
; did we find a '%' ?
cmp b[rbx], '%'
j.nz .epilogue ; no, we found fmt's null-terminator; we're done
; we did find a modifier / '%'
mov rax, b[rbx+1]
add rbx, 2
cmp rax, 's'
j.z .modf_s
cmp rax, 'c'
j.z .modf_c
cmp rax, 'p'
j.z .modf_p
cmp rax, 'x'
j.z .modf_x
cmp rax, 'u'
j.z .modf_u
cmp rax, 'd'
j.z .modf_d
cmp rax, 'o'
j.z .modf_o
cmp rax, 'b'
j.z .modf_b
cmp rax, '%'
j.z .modf_percent
; unrecognized
jmp .bad_modifier
.modf_s:
; get string address
mov rdi, q[rsi + nx2 * 8]
inc nx2
test rdi, rdi
j.z .nullstring
.print_string:
mov ax0, b[rdi]
test ax0, ax0
j.z .main_loop
inc rdi
call .doput
jmp .print_string
.modf_c:
mov ax0, q[rsi + nx2 * 8]
inc nx2
call .doput
jmp .main_loop
.modf_p:
mov ax0, '0'
call .doput
mov ax0, 'x'
call .doput
; Fallthrough
.modf_x:
mov ax2, 16
mov ax3, 1
jmp .print_number
.modf_u:
mov ax2, 10
mov ax3, 1
jmp .print_number
.modf_d:
mov ax2, 10
xor ax3, ax3
jmp .print_number
.modf_o:
mov ax2, 8
mov ax3, 1
jmp .print_number
.modf_b:
mov ax2, 2
mov ax3, 1
jmp .print_number
.print_number:
; allocate itoa convertion buffer
sub rsp, 80
mov rdi, rsp
; assume modifier already set up ax2 and ax3
mov ax0, rsp
mov ax1, q[rsi + nx2 * 8]
inc nx2
call _itoa
.print_itoa_buf:
mov ax0, b[rdi]
test ax0, ax0
add.z rsp, 80
j.z .main_loop
inc rdi
call .doput
jmp .print_itoa_buf
.modf_percent:
mov ax0, '%'
call .doput
jmp .main_loop
.bad_modifier:
; print "%?" to clearly indicate that something is wrong
mov ax0, '$'
call .doput
mov ax0, '?'
call .doput
jmp .main_loop
.nullstring:
; %s was passed a NULL
mov ax0, '('
call .doput
mov ax0, 'n'
call .doput
mov ax0, 'u'
call .doput
mov ax0, 'l'
call .doput
mov ax0, 'l'
call .doput
mov ax0, ')'
call .doput
jmp .main_loop
.epilogue:
mov rax, nx1
mov rbx, q[rbp-8]
mov nx0, q[rbp-16]
mov nx1, q[rbp-24]
mov nx2, q[rbp-32]
mov rdi, q[rbp-40]
mov rsi, q[rbp-48]
mov nx3, q[rbp-56]
leave
ret
;
; prints ax0
;
.doput:
; update print count
inc nx1
; if n==0, don't print
; we follow the C convention that sprintf()-like functions
; should return the number of characters that would have
; been printed/written if 'n' were big enough
test nx0, nx0
ret.z
; if n>0, decrement n and print
dec nx0
call nx3
; did putc fail?
cmp rax, 0
xor.nz nx0, nx0 ; yes, so artificially set n=0
ret