#include "printf.h" enum PRINTF_TYPE { PRINTF_TYPE_STRING = 0, PRINTF_TYPE_INT = 1, PRINTF_TYPE_PERCENT = 2, PRINTF_TYPE_UNKNOWN = 999 }; static enum PRINTF_TYPE get_printf_type(const char* cur) { while (*cur >= 0x30 && *cur < 0x3a) ++ cur; if (*cur == 's') { return PRINTF_TYPE_STRING; } else if (*cur == 'd' || *cur == 'x' || *cur == 'X' || *cur == 'u') { return PRINTF_TYPE_INT; } return PRINTF_TYPE_UNKNOWN; } static const char* printf_handle_string( const char* fmt, const char* next, printf_callback_t callback, volatile void* closure) { const char* cur = next; for (; *cur != 0; ++ cur) { callback(closure, *cur); } return fmt; } static char printf_toupper(char ch) { if (ch <= 0x7a && ch > 0x60) { return ch - 0x20; } return ch; } static const char* parse_fmt( const char* fmt, int* out_padding, char* out_pad_char) { if (*fmt == '0') { *out_pad_char = '0'; ++ fmt; } else { *out_pad_char = ' '; } int padding = 0; while (*fmt < 0x3a && *fmt >= 0x30) { padding *= 10; padding += (*fmt ++) - 0x30; } *out_padding = padding; return fmt; } static const char* mapping = "0123456789abcdef"; static const char* printf_handle_int( const char* fmt, unsigned int next, printf_callback_t callback, volatile void* closure) { int base = 10; char chars[32]; int pos = 31; int upper = 0; char pad_char; int padding; int is_unsigned = 0; fmt = parse_fmt(fmt, &padding, &pad_char); if (*fmt == 'x' || *fmt == 'X') { base = 16; is_unsigned = 1; } else if (*fmt == 'u') { is_unsigned = 1; } upper = *fmt == 'X'; int next_i = (int) next; if (next_i < 0 && !is_unsigned) { callback(closure, '-'); next_i *= -1; next = (unsigned) next_i; } if (next == 0) { callback(closure, '0'); } else { while (next > 0) { char next_ch = mapping[next % base]; if (upper) next_ch = printf_toupper(next_ch); chars[pos --] = next_ch; padding --; next /= base; } while ((padding--) > 0) { chars[pos --] = pad_char; } for (++ pos; pos < 32; ++ pos) { callback(closure, chars[pos]); } } return fmt; } void printf_format( const char* fmt, printf_callback_t callback, volatile void* closure, va_list ap) { const char* cur = fmt; const char* next_string; int next_int; for (; *cur != 0; ++ cur) { if (*cur == '%') { // Handle the formatting here. ++ cur; enum PRINTF_TYPE printf_type = get_printf_type(cur); switch (printf_type) { case PRINTF_TYPE_PERCENT: callback(closure, '%'); break; case PRINTF_TYPE_STRING: next_string = va_arg(ap, const char*); cur = printf_handle_string(cur, next_string, callback, closure); break; case PRINTF_TYPE_INT: next_int = va_arg(ap, int); cur = printf_handle_int(cur, next_int, callback, closure); } } else { callback(closure, *cur); } } }