kvisc/ka/crt/fmt/doprnt.k

203 lines
3.4 KiB
Plaintext
Raw Normal View History

2019-06-17 20:59:30 +02:00
; 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)
2019-06-19 13:50:53 +02:00
; int doprnt(PUTC putc, int n, const char *fmt, va_list ap)
2019-06-17 20:59:30 +02:00
;
2019-06-19 13:50:53 +02:00
doprnt:
2019-06-17 20:59:30 +02:00
enter 8
2019-07-04 20:33:49 +02:00
2019-06-17 20:59:30 +02:00
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, '%'
; everything below rdi is a regular character; print it
2019-07-15 20:46:00 +02:00
.print_regular:
b.z rbx, rdi, .check_modf
2019-06-17 20:59:30 +02:00
mov ax0, b[rbx]
call .doput
inc rbx
jmp .print_regular
.check_modf:
; did we find a '%' ?
2019-07-02 20:13:05 +02:00
; if not, then we found fmt's null-terminator; we're done
b.nz b[rbx], '%', .epilogue
2019-06-17 20:59:30 +02:00
; we did find a modifier / '%'
mov rax, b[rbx+1]
add rbx, 2
2019-07-15 20:46:00 +02:00
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
2019-07-02 20:13:05 +02:00
2019-06-17 20:59:30 +02:00
; unrecognized
jmp .bad_modifier
.modf_s:
; get string address
2019-06-21 12:13:09 +02:00
mov rdi, q[rsi+nx2*8]
2019-06-17 20:59:30 +02:00
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:
2019-06-21 12:13:09 +02:00
mov ax0, q[rsi+nx2*8]
2019-06-17 20:59:30 +02:00
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
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:
2019-06-18 12:58:26 +02:00
; allocate itoa conversion buffer
2019-06-17 20:59:30 +02:00
sub rsp, 80
mov rdi, rsp
2019-06-20 12:31:36 +02:00
; assume modifier already set up ax2
2019-06-17 20:59:30 +02:00
mov ax0, rsp
2019-06-21 12:13:09 +02:00
mov ax1, q[rsi+nx2*8]
2019-06-20 12:31:36 +02:00
call itoa
2019-06-18 12:58:26 +02:00
inc nx2
2019-06-17 20:59:30 +02:00
.print_itoa_buf:
mov ax0, b[rdi]
2019-07-04 20:33:49 +02:00
2019-06-17 20:59:30 +02:00
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
2019-06-27 23:00:35 +02:00
mov ax0, '%'
2019-06-17 20:59:30 +02:00
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
2019-06-27 23:00:35 +02:00
2019-06-17 20:59:30 +02:00
; if n>0, decrement n and print
dec nx0
call nx3
; did putc fail?
2019-07-05 14:06:14 +02:00
test rax, rax
2019-06-17 20:59:30 +02:00
xor.nz nx0, nx0 ; yes, so artificially set n=0
ret