; 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 add rbx, rbx, 1 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 add rdi, rdi, 1 call .doput jmp .print_string .modf_c: mov ax0, q[rsi] add rsi, rsi, 8 call .doput jmp .main_loop .modf_p: call .doput, '0' call .doput, 'x' ; 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 add rdi, rdi, 1 call .doput jmp .print_itoa_buf .modf_percent: call .doput, '%' jmp .main_loop .bad_modifier: ; print "%?" to clearly indicate that something is wrong call .doput, '%' call .doput, '?' jmp .main_loop .nullstring: ; %s was passed a NULL call .doput, '(' call .doput, 'n' call .doput, 'u' call .doput, 'l' call .doput, 'l' 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 add nx1, nx1, 1 ; 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 sub nx0, nx0, 1 call nx3 ; did putc fail? cmp rax, zero mov.nz nx0, zero ; yes, so artificially set n=0 ret