mirror of
https://gitlab.os-k.eu/os-k-team/kvisc.git
synced 2023-08-25 14:05:46 +02:00
209 lines
3.5 KiB
Plaintext
209 lines
3.5 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], 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, '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
|
|
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, 80
|
|
mov rdi, rsp
|
|
|
|
; assume modifier already set up ax2
|
|
mov ax0, rsp
|
|
mov ax1, q[rsi+nx2*8]
|
|
call itoa
|
|
inc nx2
|
|
|
|
.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
|
|
|