; 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 ebp mov ebp, esp push nx0, nx1, nx2 push nx3, nx4, nx5 mov nx0, ax2 ; fmt mov nx2, ax3 ; va_list mov nx3, ax1 ; n mov nx5, ax0 ; putc nul nx4 ; return value .main_loop: ; find '%' or null-terminator mov ecx, STRLEN_MAX mov nx1, nx0 scasb nx1, '%' ; everything below nx1 is a regular character; print it .print_regular: beq nx0, nx1, .check_modf call .doput, b[nx0] inc nx0 jmp .print_regular .check_modf: ; did we find a '%' ? ; if not, then we found fmt's null-terminator; we're done bne b[nx0], '%', .epilogue ; we did find a modifier / '%' mov eax, b[nx0+1] add nx0, 2 beq eax, 's', .modf_s beq eax, 'c', .modf_c beq eax, 'p', .modf_p beq eax, 'x', .modf_x beq eax, 'd', .modf_d beq eax, 'o', .modf_o beq eax, 'b', .modf_b beq eax, '%', .modf_percent ; unrecognized jmp .bad_modifier .modf_s: ; get string address mov nx1, q[nx2] add nx2, 8 bzr nx1, .nullstring .print_string: movzx ax0, b[nx1] bzr ax0, .main_loop inc nx1 call .doput jmp .print_string .modf_c: call .doput, q[nx2] add nx2, 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 esp, 80 mov nx1, esp ; assume modifier already set up ax2 call itoa, esp, q[nx2] add nx2, 8 .print_itoa_buf: movzx ax0, b[nx1] bzr ax0, .pib_end_loop inc nx1 call .doput jmp .print_itoa_buf .pib_end_loop: add esp, 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 eax, nx4 pop nx5, nx4 pop nx3, nx2 pop nx1, nx0 leave ret ; ; prints ax0 ; .doput: ; update print count inc nx4 ; 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 nx3, .r ; decrement n and print dec nx3 call nx5 ; did putc fail? jeaxz .r ; yes, so artificially set n=0 nul nx3 .r: ret