kvisc/ka/crt/fmt/doprnt.k

200 lines
3.3 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.
;
; 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], rdi
mov q[rbp-40], rsi
mov q[rbp-48], nx3
mov rbx, ax2 ; fmt
mov nx3, ax0 ; putc
mov nx0, ax1 ; n
mov rsi, ax3 ; va_list
mov nx1, zero ; return value
.main_loop:
; find '%' or null-terminator
mov rcx, STRLEN_MAX
mov rdi, rbx
scasb.rep.nz rdi, '%'
; everything below rdi is a regular character; print it
.print_regular:
b.z rbx, rdi, .check_modf
mov ax0, b[rbx]
call .doput
inc rbx
jmp .print_regular
.check_modf:
; did we find a '%' ?
; if not, then we found fmt's null-terminator; we're done
b.nz b[rbx], '%', .epilogue
; we did find a modifier / '%'
mov rax, b[rbx+1]
add rbx, rbx, 2
b.z rax, 's', .modf_s
b.z rax, 'c', .modf_c
b.z rax, 'p', .modf_p
b.z rax, 'x', .modf_x
b.z rax, 'd', .modf_d
b.z rax, 'o', .modf_o
b.z rax, 'b', .modf_b
b.z rax, '%', .modf_percent
; unrecognized
jmp .bad_modifier
.modf_s:
; get string address
mov rdi, q[rsi]
add rsi, rsi, 8
cmp rdi, zero
jmp.z .nullstring
.print_string:
mov ax0, b[rdi]
cmp ax0, zero
jmp.z .main_loop
inc rdi
call .doput
jmp .print_string
.modf_c:
mov ax0, q[rsi]
add rsi, rsi, 8
call .doput
jmp .main_loop
.modf_p:
mov ax0, '0'
call .doput
mov ax0, 'x'
call .doput
; Fallthrough
.modf_x:
mov ax2, 16
jmp .print_number
.modf_d:
mov ax2, 10
jmp .print_number
.modf_o:
mov ax2, 8
jmp .print_number
.modf_b:
mov ax2, 2
jmp .print_number
.print_number:
; allocate itoa conversion buffer
sub rsp, rsp, 80
mov rdi, rsp
; assume modifier already set up ax2
mov ax0, rsp
mov ax1, q[rsi]
call itoa
add rsi, rsi, 8
.print_itoa_buf:
mov ax0, b[rdi]
cmp ax0, zero
add.z rsp, rsp, 80
jmp.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 rdi, q[rbp-32]
mov rsi, q[rbp-40]
mov nx3, q[rbp-48]
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
cmp nx0, zero
ret.z
; if n>0, decrement n and print
dec nx0
call nx3
; did putc fail?
cmp rax, zero
mov.nz nx0, zero ; yes, so artificially set n=0
ret