#include "printf.h" #include "string.h" #include "init.h" #include "hal/obj.h" #include int kprintf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); int r = kvprintf(fmt, ap); va_end(ap); return r; } #define SPRINTF_PUTC(str, size, i, c) \ if(str && i < size) str[i] = (c); \ i++ struct print_flags { char flg_alt, flg_zeropad, flg_ladjust, flg_showsign, flg_signspace; int fieldw, precision; int lenmod, lenspec, radix, unsign; }; static int convert_as_int( char *str, size_t size, int stri, uintmax_t value, int radix, int unsign) { unsigned digits = 0; int ostri = stri; if((intmax_t)value < 0 && !unsign) { SPRINTF_PUTC(str, size, stri, '-'); value = 0 - (intmax_t)value; } for(uintmax_t i = value; i != 0; i /= radix) digits++; if(value == 0) digits++; for(uintmax_t i = value, digiti = 0; digiti < digits; i /= radix) { char i_mod = (char)(i % radix); int stri_digiti = stri + (digits - digiti) - 1; SPRINTF_PUTC(str, size, stri_digiti, (i_mod > 9 ? (i_mod + 'a' - 10) : (i_mod + '0'))); digiti++; } return digits; } enum printf_state { FSTATE_DIRECT = 0, FSTATE_FLAG, FSTATE_FIELDWIDTH, FSTATE_PRECISION, FSTATE_LENMOD, FSTATE_CONVERT }; static int s_convert_string(char *str, size_t size, va_list ap, size_t stri, struct print_flags flags) { const char *strarg = va_arg(ap, const char*); if((uintptr_t)strarg < 0xFFFF800000000000ULL) return stri; int arglen = flags.precision == 0 ? strlen(strarg) : flags.precision; int minlen = flags.fieldw; char padc = flags.flg_zeropad ? '0' : ' '; for(int i = 0; i < minlen - arglen; i++) { SPRINTF_PUTC(str, size, stri, padc); } for(int i = 0; i < arglen; i++) { SPRINTF_PUTC(str, size, stri, strarg[i]); } return stri; } static int s_convert_int(char *str, size_t size, va_list ap, size_t stri, struct print_flags flags) { char num_buf[64]; uintmax_t value = 0; switch(flags.lenspec) { case 1: value = (uintmax_t)(int8_t)va_arg(ap, int); break; case 2: value = (uintmax_t)(int16_t)va_arg(ap, int); break; default: case 4: value = (uintmax_t)va_arg(ap, unsigned int); break; case 8: value = (uintmax_t)va_arg(ap, uintmax_t); break; } size_t pad_stri = stri; int advance = convert_as_int(num_buf, 64, 0, value, flags.radix, flags.unsign); if(flags.flg_alt) { for(int i = 0; i < advance; i++) { num_buf[i] = c_toupper(num_buf[i]); } } int pad_diff = flags.fieldw - advance; char padchar = flags.flg_zeropad ? '0' : ' '; for(int i = 0; i < pad_diff; i++) { SPRINTF_PUTC(str, size, stri, padchar); } for(int i = 0; i < advance; i++) { SPRINTF_PUTC(str, size, stri, num_buf[i]); } return stri; } int s_convert_path(char *str, size_t size, va_list ap, size_t stri) { uint16_t *obj_path = va_arg(ap, uint16_t*); size_t obj_pathlen = va_arg(ap, size_t); for(size_t i = 0; i < obj_pathlen; i++) { uint16_t subdir = obj_path[i]; int advance = convert_as_int(str, size, stri, subdir, 10, 1); stri += advance; SPRINTF_PUTC(str, size, stri, '/'); } return stri; } int vsnprintf( char *str, size_t size, const char *fmt, va_list ap) { int stri = 0; int state = FSTATE_DIRECT; struct print_flags flags = { 0 }; flags.lenspec = 4; for(const char *fmtc = fmt; *fmtc; fmtc++) { if(state == FSTATE_DIRECT) { if(*fmtc == '%') { state++; continue; } SPRINTF_PUTC(str, size, stri, *fmtc); }else if(state == FSTATE_FLAG) { switch(*fmtc) { case '#': flags.flg_alt = 1; break; case '0': flags.flg_zeropad = 1; break; case '-': flags.flg_ladjust = 1; break; case ' ': flags.flg_signspace = 1; break; case '+': flags.flg_showsign = 1; break; default: state++; fmtc--; break; } }else if(state == FSTATE_FIELDWIDTH) { if(*fmtc > '0' && *fmtc <= '9') { do { flags.fieldw *= 10; flags.fieldw += *fmtc - '0'; fmtc++; } while(*fmtc >= '0' && *fmtc <= '9'); } fmtc--; state++; }else if(state == FSTATE_PRECISION) { if(*fmtc == '.') { fmtc++; while(*fmtc >= '0' && *fmtc <= '9') { flags.precision *= 10; flags.precision += *fmtc - '0'; fmtc++; } } fmtc--; state++; }else if(state == FSTATE_LENMOD) { switch(*fmtc) { case 'l': flags.lenmod = flags.lenmod == 'l' ? 'L' : 'l'; break; default: fmtc--; state++; break; } }else if(state == FSTATE_CONVERT) { switch(*fmtc) { case 's': stri = s_convert_string(str, size, ap, stri, flags); break; case 'b': flags.radix = 2; stri = s_convert_int(str, size, ap, stri, flags); break; case 'o': flags.radix = 8; stri = s_convert_int(str, size, ap, stri, flags); break; case 'p': flags.lenspec = sizeof(uintptr_t); flags.fieldw = flags.lenspec * 2; flags.flg_zeropad = 1; flags.flg_alt = 1; case 'X': flags.flg_alt = 1; case 'x': flags.unsign = 1; flags.radix = 16; stri = s_convert_int(str, size, ap, stri, flags); break; case 'u': flags.unsign = 1; case 'd': case 'i': flags.radix = 10; stri = s_convert_int(str, size, ap, stri, flags); break; /*custom formatters for jove.*/ case 'P': stri = s_convert_path(str, size, ap, stri); break; } flags = (struct print_flags) { 0 }; state = FSTATE_DIRECT; } } if(str && stri < size) str[stri] = 0; return stri; }