#include #include #include #include #include #include "printxf.h" struct printxf printxf_default; /* allow domains an easy way to defer standard specifiers to the * system's implementation. */ int printxf_vfprintf(struct printxf *pxf, FILE *fp, const char *spec, va_list ap) { return vfprintf(fp, spec, ap); } int __printxf_wsegment(FILE *fp, const char **fmt, size_t ssize, size_t *tsize) { size_t wsize; wsize = fwrite(*fmt, 1, ssize, fp); *tsize += wsize; *fmt += wsize; return (wsize < ssize) ? EOF : 0; } int vfprintxf(struct printxf *pxf, FILE *fp, const char *fmt, va_list ap) { size_t tsize = 0, wsize, ssize; vfprintxf_fn handler; char spec[16]; pxf = pxf ? : &printxf_default; if (!fmt) return 0; while (*fmt) { ssize = strcspn(fmt, "%"); /* leading segment containing no format specifiers. */ if (ssize && __printxf_wsegment(fp, &fmt, ssize, &tsize)) break; if (fmt[0] == '\0') { /* this was the last segment */ break; } else if ((fmt[0] == '%') && ((fmt[1] == '\0') || (fmt[1] == '%'))) { /* "%" or "%%", write "%" */ if (!fwrite("%", 1, 1, fp)) break; tsize++; fmt += fmt[1] ? 2 : 1; continue; } ssize = strspn(fmt + 1, " #$'*+,-.0123456789:;L_hjlqtvz") + 1; if (!fmt[ssize]) { /* corner case. fmt ends with an unterminated * format. e.g. "evilness: 100%" */ __printxf_wsegment(fp, &fmt, ssize, &tsize); break; } handler = pxf->vfprintxf[fmt[ssize] & 0x7f]; if (!handler) { /* unsupported specifier, write the entire * specifier unformatted to the output */ if (__printxf_wsegment(fp, &fmt, ssize + 1, &tsize)) break; continue; } ssize++; memset(spec, '\0', sizeof(spec)); strncpy(spec, fmt, (ssize >= sizeof(spec)) ? sizeof(spec) - 1 : ssize); fmt += ssize; tsize += handler(pxf, fp, spec, ap); } return tsize; } int fprintxf(struct printxf *pxf, FILE *fp, const char *fmt, ...) { va_list ap; int ret; va_start(ap, fmt); ret = vfprintxf(pxf, fp, fmt, ap); va_end(ap); return ret; } int vprintxf(struct printxf *pxf, const char *fmt, va_list ap) { return vfprintxf(pxf, stdout, fmt, ap); } int printxf(struct printxf *pxf, const char *fmt, ...) { va_list ap; int ret; va_start(ap, fmt); ret = vprintxf(pxf, fmt, ap); va_end(ap); return ret; } __attribute__((constructor)) static void printxf_init(void) { const char *std = "aAcdeEfFgGiosuxX"; for (; *std; std++) printxf_default.vfprintxf[(int)*std] = &printxf_vfprintf; }