; 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: push rbp mov rbp, rsp push r12 push r13 push r14 push r15 push r16 push r17 mov r12, ax2 ; fmt mov r14, ax3 ; va_list mov r15, ax1 ; n mov r16, zero ; return value mov r17, ax0 ; putc .main_loop: ; find '%' or null-terminator mov rcx, STRLEN_MAX mov r13, r12 scasb.rep.nz r13, '%' ; everything below r13 is a regular character; print it .print_regular: b.z r12, r13, .check_modf call .doput, b[r12] inc r12, 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[r12], '%', .epilogue ; we did find a modifier / '%' mov rax, b[r12+1] inc r12, 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 r13, q[r14] inc r14, 8 b.z r13, zero, .nullstring .print_string: mov ax0, b[r13] b.z ax0, zero, .main_loop inc r13, 1 call .doput jmp .print_string .modf_c: call .doput, q[r14] inc r14, 8 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 dec rsp, 80 mov r13, rsp ; assume modifier already set up ax2 call itoa, rsp, q[r14] inc r14, 8 .print_itoa_buf: mov ax0, b[r13] cmp ax0, zero inc.z rsp, 80 jmp.z .main_loop inc r13, 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, r16 pop r17 pop r16 pop r15 pop r14 pop r13 pop r12 leave ret ; ; prints ax0 ; .doput: ; update print count inc r16, 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 r15, zero ret.z ; if n>0, decrement n and print dec r15, 1 call r17 ; did putc fail? mov.axnz r15, zero ; yes, so artificially set n=0 ret