kvisc/ka/crt/fmt/doprnt.k

179 lines
2.9 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-07-22 13:18:13 +02:00
push rbp
mov rbp, rsp
2019-08-08 18:39:12 +02:00
push r12, r13, r14
push r15, r16, r17
2019-07-22 13:18:13 +02:00
mov r12, ax2 ; fmt
mov r14, ax3 ; va_list
mov r15, ax1 ; n
mov r17, ax0 ; putc
2019-08-14 20:23:05 +02:00
nul r16 ; return value
2019-06-17 20:59:30 +02:00
.main_loop:
; find '%' or null-terminator
mov rcx, STRLEN_MAX
2019-07-22 13:18:13 +02:00
mov r13, r12
2019-08-14 20:23:05 +02:00
scasb r13, '%'
2019-06-17 20:59:30 +02:00
2019-07-22 13:18:13 +02:00
; everything below r13 is a regular character; print it
2019-07-15 20:46:00 +02:00
.print_regular:
2019-08-14 09:52:39 +02:00
beq r12, r13, .check_modf
2019-06-17 20:59:30 +02:00
2019-08-03 17:41:44 +02:00
call .doput, b[r12]
2019-06-17 20:59:30 +02:00
2019-08-03 17:41:44 +02:00
inc r12, 1
2019-06-17 20:59:30 +02:00
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
2019-08-14 09:52:39 +02:00
bne b[r12], '%', .epilogue
2019-06-17 20:59:30 +02:00
; we did find a modifier / '%'
2019-07-22 13:18:13 +02:00
mov rax, b[r12+1]
2019-08-03 17:41:44 +02:00
inc r12, 2
2019-06-17 20:59:30 +02:00
2019-08-14 09:52:39 +02:00
beq rax, 's', .modf_s
beq rax, 'c', .modf_c
beq rax, 'p', .modf_p
beq rax, 'x', .modf_x
beq rax, 'd', .modf_d
beq rax, 'o', .modf_o
beq rax, 'b', .modf_b
beq 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-07-22 13:18:13 +02:00
mov r13, q[r14]
2019-08-03 17:41:44 +02:00
inc r14, 8
2019-06-17 20:59:30 +02:00
2019-08-14 09:52:39 +02:00
bzr r13, .nullstring
2019-06-17 20:59:30 +02:00
.print_string:
2019-08-14 20:23:05 +02:00
movzx ax0, b[r13]
2019-08-14 09:52:39 +02:00
bzr ax0, .main_loop
2019-06-17 20:59:30 +02:00
2019-08-21 16:57:32 +02:00
inc r13
2019-06-17 20:59:30 +02:00
call .doput
2019-08-03 17:41:44 +02:00
2019-06-17 20:59:30 +02:00
jmp .print_string
.modf_c:
2019-08-03 17:41:44 +02:00
call .doput, q[r14]
inc r14, 8
2019-06-17 20:59:30 +02:00
jmp .main_loop
.modf_p:
2019-07-18 22:49:31 +02:00
call .doput, '0'
call .doput, 'x'
2019-06-17 20:59:30 +02:00
; 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-08-21 16:57:32 +02:00
sub rsp, 80
2019-07-22 13:18:13 +02:00
mov r13, rsp
2019-06-17 20:59:30 +02:00
2019-06-20 12:31:36 +02:00
; assume modifier already set up ax2
2019-08-03 17:41:44 +02:00
call itoa, rsp, q[r14]
inc r14, 8
2019-06-17 20:59:30 +02:00
.print_itoa_buf:
2019-08-14 20:23:05 +02:00
movzx ax0, b[r13]
2019-07-04 20:33:49 +02:00
2019-08-14 09:52:39 +02:00
bzr ax0, .pib_end_loop
2019-08-21 16:57:32 +02:00
inc r13
2019-08-14 09:52:39 +02:00
2019-06-17 20:59:30 +02:00
call .doput
jmp .print_itoa_buf
2019-08-14 09:52:39 +02:00
.pib_end_loop:
inc rsp, 80
jmp .main_loop
2019-06-17 20:59:30 +02:00
.modf_percent:
2019-07-18 22:49:31 +02:00
call .doput, '%'
2019-06-17 20:59:30 +02:00
jmp .main_loop
.bad_modifier:
; print "%?" to clearly indicate that something is wrong
2019-07-18 22:49:31 +02:00
call .doput, '%'
call .doput, '?'
2019-06-17 20:59:30 +02:00
jmp .main_loop
.nullstring:
; %s was passed a NULL
2019-07-18 22:49:31 +02:00
call .doput, '('
call .doput, 'n'
call .doput, 'u'
call .doput, 'l'
call .doput, 'l'
call .doput, ')'
2019-06-17 20:59:30 +02:00
jmp .main_loop
.epilogue:
2019-07-22 13:18:13 +02:00
mov rax, r16
2019-08-08 18:39:12 +02:00
2019-08-14 20:23:05 +02:00
pop r17, r16
pop r15, r14
pop r13, r12
2019-07-22 13:18:13 +02:00
2019-06-17 20:59:30 +02:00
leave
ret
;
; prints ax0
;
.doput:
; update print count
2019-08-21 16:57:32 +02:00
inc r16
2019-06-17 20:59:30 +02:00
; 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
2019-08-14 09:52:39 +02:00
bzr r15, .r
2019-06-27 23:00:35 +02:00
2019-08-03 19:01:12 +02:00
; decrement n and print
2019-08-21 16:57:32 +02:00
dec r15
2019-07-22 13:18:13 +02:00
call r17
2019-08-14 09:52:39 +02:00
2019-06-17 20:59:30 +02:00
; did putc fail?
2019-08-14 09:52:39 +02:00
jraxz .r
; yes, so artificially set n=0
2019-08-14 20:23:05 +02:00
nul r15
2019-06-17 20:59:30 +02:00
2019-08-14 09:52:39 +02:00
.r:
2019-06-17 20:59:30 +02:00
ret