#include <ctype.h> #include <string.h> #define CAPS (1<<0) #define ALLCAPS (1<<1) #define RJUST (1<<2) #define LDEL (1<<3) #define RDEL (1<<4) #define SUBST 1 #define LMARK 2 #define RMARK 3 #define FLAGS 0 #define WIDTH 1 #define PREC 2 #define VAR 3 #define PSIZE 4 fmtcomp(prog, fmt, vars) register char *prog, *fmt; char *vars[]; { register char c, b; register char *p; int nl = 1, curly, i; vars[0] = 0; while (c = *fmt++) top: switch (c) { case '%': *prog++ = SUBST; prog[FLAGS] = prog[WIDTH] = prog[PREC] = 0; p = &prog[WIDTH]; curly = 0; while (c = *fmt++) switch (c) { case '^': prog[FLAGS] |= CAPS; break; case '+': prog[FLAGS] |= ALLCAPS; break; case '-': prog[FLAGS] |= RJUST; break; case '<': prog[FLAGS] |= LDEL; break; case '>': prog[FLAGS] |= RDEL; break; case '.': p = &prog[PREC]; break; case '{': curly++; c = *fmt++; /* fall thru */ default: if (isdigit(c)) { *p = (*p * 10) + (c - '0'); break; } p = --fmt; while (isalnum(c)) c = *++fmt; if (p == fmt) { prog--; goto brake; } if (c) *fmt++ = 0; for (i = 0; vars[i] && strcmp(vars[i], p); i++); prog[VAR] = i; prog += PSIZE; if (!vars[i]) { vars[i] = p; vars[++i] = 0; } if (c && !curly) goto top; goto brake; } prog--; fmt--; brake: break; case '\\': switch (c = *fmt++) { case '<': c = LMARK; break; case '>': c = RMARK; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'b': c = '\b'; break; case 'f': c = '\f'; break; case 'v': c = '\v'; break; case 0: c = '\\',fmt--; break; case 'c': nl = 0; continue; default: for (i = b = 0; i < 3 && isdigit(c); i++) { b = (b * 010) + (c - '0'); c = *fmt++; } if (i > 0) { c = b; fmt--; } } /* fall thru */ default: *prog++ = c; } if (nl) { *prog++ = RMARK; *prog++ = '\n'; } *prog = 0; } fmtexec(out, prog, vals) register char *out, *prog; char *vals[]; { register int len, spaces; register char c, prev; register char *val; char *mark = out; while (c = *prog++) switch (c) { case SUBST: c = prog[FLAGS]; val = vals[prog[VAR]]; if ((len = strlen(val)) == 0 && c & (LDEL|RDEL)) { prog += PSIZE; if (c & LDEL) out = mark; if (c & RDEL) while (*prog && *prog != RMARK) if (*prog++ == SUBST) prog += PSIZE; break; } if (prog[PREC] > 0 && prog[PREC] < len) len = prog[PREC]; spaces = prog[WIDTH] - len; if (spaces > 0 && c & RJUST) while (spaces--) *out++ = ' '; prev = 0; while (len--) *out++ = prev = c & ALLCAPS || (c & CAPS && !isalnum(prev)) ? toupper(*val++) : *val++; if (spaces > 0 && !(c & RJUST)) while (spaces--) *out++ = ' '; prog += PSIZE; break; case LMARK: mark = out; break; case RMARK: break; default: *out++ = c; } *out = 0; }