; 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: dump 0 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 b.e 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, 2 b.e rax, 's', .modf_s b.e rax, 'c', .modf_c b.e rax, 'p', .modf_p b.e rax, 'x', .modf_x b.e rax, 'd', .modf_d b.e rax, 'o', .modf_o b.e rax, 'b', .modf_b b.e rax, '%', .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 dump 1 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