#include #include typedef void (*putc_func)(void *data, char c); void int_itoa(char *buf, char base, uintptr_t value, char zero_pad, int precision, int size_mod, char big, int alternate_form, int neg, char sign) { int length = 0; do { char c = value % base; if (c >= 10) { if (big) c += 'A'-10; else c += 'a'-10; } else c += '0'; value = value / base; buf[length++] = c; } while(value != 0); if (precision != 0) { while (length < precision) buf[length++] = '0'; } else if (size_mod != 0 && zero_pad) { int sz_mod = size_mod; if (alternate_form) { if (base == 16) sz_mod -= 2; else if (base == 8) sz_mod -= 1; } if (neg) sz_mod -= 1; while (length < sz_mod) buf[length++] = '0'; } if (alternate_form) { if (base == 8) buf[length++] = '0'; if (base == 16) { buf[length++] = big ? 'X' : 'x'; buf[length++] = '0'; } } if (neg) buf[length++] = '-'; else { if (sign == '+') buf[length++] = '+'; else if (sign == ' ') buf[length++] = ' '; } for (int i=0; i < length/2; i++) { char tmp = buf[i]; buf[i] = buf[length - i - 1]; buf[length - i - 1] = tmp; } buf[length] = 0; } int int_strlen(char *buf) { int len = 0; if (buf) while(*buf++) len++; return len; } void vkprintf_pc(putc_func putc_f, void *putc_data, const char * restrict format, va_list args) { char tmpbuf[32]; while(*format) { char c; char alternate_form = 0; int size_mod = 0; int length_mod = 0; int precision = 0; char zero_pad = 0; char *str; char sign = 0; char leftalign = 0; uintptr_t value = 0; intptr_t ivalue = 0; char big = 0; c = *format++; if (c != '%') { putc_f(putc_data, c); } else { c = *format++; if (c == '#') { alternate_form = 1; c = *format++; } if (c == '-') { leftalign = 1; c = *format++; } if (c == ' ' || c == '+') { sign = c; c = *format++; } if (c == '0') { zero_pad = 1; c = *format++; } while(c >= '0' && c <= '9') { size_mod = size_mod * 10; size_mod = size_mod + c - '0'; c = *format++; } if (c == '.') { c = *format++; while(c >= '0' && c <= '9') { precision = precision * 10; precision = precision + c - '0'; c = *format++; } } big = 0; if (c == 'h') { c = *format++; if (c == 'h') { c = *format++; length_mod = 1; } else length_mod = 2; } else if (c == 'l') { c = *format++; if (c == 'l') { c = *format++; length_mod = 8; } else length_mod = 4; } else if (c == 'j') { c = *format++; length_mod = 9; } else if (c == 't') { c = *format++; length_mod = 10; } else if (c == 'z') { c = *format++; length_mod = 11; } switch (c) { case 0: return; case '%': putc_f(putc_data, '%'); break; case 'X': big = 1; /* fallthrough */ case 'x': switch (length_mod) { case 8: value = va_arg(args, uint64_t); break; case 9: value = va_arg(args, uintmax_t); break; case 10: value = va_arg(args, uintptr_t); break; case 11: value = va_arg(args, uintptr_t); break; default: value = va_arg(args, unsigned int); break; } int_itoa(tmpbuf, 16, value, zero_pad, precision, size_mod, big, alternate_form, 0, sign); str = tmpbuf; size_mod -= int_strlen(str); if (!leftalign) while(size_mod-- > 0) putc_f(putc_data, ' '); do { putc_f(putc_data, *str); } while(*str++); if (leftalign) while(size_mod-- > 0) putc_f(putc_data, ' '); break; case 'u': switch (length_mod) { case 8: value = va_arg(args, uint64_t); break; case 9: value = va_arg(args, uintmax_t); break; case 10: value = va_arg(args, uintptr_t); break; case 11: value = va_arg(args, uintptr_t); break; default: value = va_arg(args, unsigned int); break; } int_itoa(tmpbuf, 10, value, zero_pad, precision, size_mod, 0, alternate_form, 0, sign); str = tmpbuf; size_mod -= int_strlen(str); if (!leftalign) while(size_mod-- > 0) putc_f(putc_data, ' '); do { putc_f(putc_data, *str); } while(*str++); if (leftalign) while(size_mod-- > 0) putc_f(putc_data, ' '); break; case 'd': case 'i': switch (length_mod) { case 8: ivalue = va_arg(args, int64_t); break; case 9: ivalue = va_arg(args, intmax_t); break; case 10: ivalue = va_arg(args, intptr_t); break; case 11: ivalue = va_arg(args, uintptr_t); break; default: ivalue = va_arg(args, int); break; } if (ivalue < 0) int_itoa(tmpbuf, 10, -ivalue, zero_pad, precision, size_mod, 0, alternate_form, 1, sign); else int_itoa(tmpbuf, 10, ivalue, zero_pad, precision, size_mod, 0, alternate_form, 0, sign); str = tmpbuf; size_mod -= int_strlen(str); if (!leftalign) while(size_mod-- > 0) putc_f(putc_data, ' '); do { putc_f(putc_data, *str); } while(*str++); if (leftalign) while(size_mod-- > 0) putc_f(putc_data, ' '); break; case 'o': switch (length_mod) { case 8: value = va_arg(args, uint64_t); break; case 9: value = va_arg(args, uintmax_t); break; case 10: value = va_arg(args, uintptr_t); break; case 11: value = va_arg(args, uintptr_t); break; default: value = va_arg(args, uint32_t); break; } int_itoa(tmpbuf, 8, value, zero_pad, precision, size_mod, 0, alternate_form, 0, sign); str = tmpbuf; size_mod -= int_strlen(str); if (!leftalign) while(size_mod-- > 0) putc_f(putc_data, ' '); do { putc_f(putc_data, *str); } while(*str++); if (leftalign) while(size_mod-- > 0) putc_f(putc_data, ' '); break; case 'c': putc_f(putc_data, va_arg(args, int)); break; case 's': { str = va_arg(args, char *); do { if (*str == 0) break; else putc_f(putc_data, *str); } while(*str++ && --precision); } break; default: putc_f(putc_data, c); break; } } } } #define ARM_PERIIOBASE ((uint32_t)io_base) void putByte(void *io_base, char chr) { (void*)io_base; *(uint8_t*)0xdeadbeef = chr; } void kprintf_pc(putc_func putc_f, void *putc_data, const char * restrict format, ...) { va_list v; va_start(v, format); vkprintf_pc(putc_f, putc_data, format, v); va_end(v); } void bug(const char * restrict format, ...) { va_list v; va_start(v, format); vkprintf_pc(putByte, (void*)0xf2000000, format, v); va_end(v); }