#include "string.h" #include "format.h" char* sfmt(char *s, size_t limit, const char *fmt, ...) { va_list ap; va_start(ap, fmt); s = svfmt(s, limit, fmt, ap); va_end(ap); return s; } char* svfmt(char *s, size_t limit, const char *fmt, va_list ap) { size_t fmtlen = strlen(fmt); size_t si = 0; for(size_t fmti = 0; fmti < fmtlen; fmti++) { if(si >= limit) break; if(fmt[fmti] != '%') { s[si++] = fmt[fmti]; continue; } // TODO: Format flags fmti++; bool alt = false; bool zpad = false; for(;;fmti++){ if(fmt[fmti] == '#') { alt = true; continue; } if(fmt[fmti] == '0') { zpad = true; continue; } break; } int fwidth = 0; if(fmt[fmti] >= '1' && fmt[fmti] <= '9') { for(;fmt[fmti] >= '0' && fmt[fmti] <= '9';fmti++) { fwidth *= 10; fwidth += fmt[fmti] - '0'; } } int precision = 0; if(fmt[fmti] == '.') { fmti++; for(;fmt[fmti] >= '0' && fmt[fmti] <= '9';fmti++) { precision *= 10; precision += fmt[fmti] - '0'; } } bool sgn = true; bool upper = false; int radix = 10; switch(fmt[fmti]) { case '%': s[si++] = '%'; break; case 'b': radix = 2; case 'X': upper = true; case 'x': if(radix == 10) radix = 16; case 'o': if(radix == 10) radix = 8; case 'u': sgn = false; case 'i': { if((radix == 8 || radix == 16) && alt) { s[si++] = '0'; if(radix == 16) { s[si++] = 'x'; } if(radix == 2) { s[si++] = 'b'; } } size_t osi = si; size_t nlen = ltostr(&s[si], limit - si, va_arg(ap, long), sgn, radix); if(upper) sntoupper(&s[si], nlen); si += nlen; int lpad = fwidth - (int)nlen; if(lpad > 0) { if(lpad + osi >= limit) lpad = (limit - osi - 1); memmove(&s[osi + lpad], &s[osi], nlen); memset(&s[osi], zpad ? '0' : ' ', lpad); si += lpad; } } break; case 's': { const char *str = va_arg(ap, char*); size_t slen = strlen(str); size_t wlen = slen > limit - si ? limit - si : slen; for(size_t i = 0; i < wlen; i++) s[si++] = str[i]; } break; } } s[si] = 0; return s; }