; 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, r13, r14 push r15, r16, r17 mov r12, ax2 ; fmt mov r14, ax3 ; va_list mov r15, ax1 ; n mov r17, ax0 ; putc nul r16 ; return value .main_loop: ; find '%' or null-terminator mov rcx, STRLEN_MAX mov r13, r12 scasb r13, '%' ; everything below r13 is a regular character; print it .print_regular: beq 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 bne b[r12], '%', .epilogue ; we did find a modifier / '%' mov rax, b[r12+1] inc r12, 2 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 ; unrecognized jmp .bad_modifier .modf_s: ; get string address mov r13, q[r14] inc r14, 8 bzr r13, .nullstring .print_string: movzx ax0, b[r13] bzr ax0, .main_loop inc r13 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 sub rsp, 80 mov r13, rsp ; assume modifier already set up ax2 call itoa, rsp, q[r14] inc r14, 8 .print_itoa_buf: movzx ax0, b[r13] bzr ax0, .pib_end_loop inc r13 call .doput jmp .print_itoa_buf .pib_end_loop: inc rsp, 80 jmp .main_loop .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, r16 pop r15, r14 pop r13, r12 leave ret ; ; prints ax0 ; .doput: ; update print count inc r16 ; 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 bzr r15, .r ; decrement n and print dec r15 call r17 ; did putc fail? jraxz .r ; yes, so artificially set n=0 nul r15 .r: ret