; 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 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, 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 inc rdi call .doput jmp .print_string .modf_c: mov ax0, q[rsi] add rsi, rsi, 8 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, 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 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 rdi, q[rbp-32] mov rsi, q[rbp-40] mov nx3, q[rbp-48] 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 cmp nx0, zero ret.z ; if n>0, decrement n and print dec nx0 call nx3 ; did putc fail? cmp rax, zero mov.nz nx0, zero ; yes, so artificially set n=0 ret