cosmopolitan/third_party/f2c/fmt.c

478 lines
9.6 KiB
C

#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "third_party/f2c/f2c.h"
#include "third_party/f2c/fio.h"
#include "third_party/f2c/fmt.h"
#define SYLMX 300
#define GLITCH '\2'
#define Const const
#define STKSZ 10
#define skip(s) \
while (*s == ' ') s++
/* special quote character for stu */
static struct syl f__syl[SYLMX];
int f__parenlvl, f__pc, f__revloc;
int f__cnt[STKSZ], f__ret[STKSZ], f__cp, f__rp;
flag f__workdone, f__nonl;
static const char *ap_end(const char *s) {
char quote;
quote = *s++;
for (; *s; s++) {
if (*s != quote) continue;
if (*++s != quote) return (s);
}
if (f__elist->cierr) {
errno = 100;
return (NULL);
}
f__fatal(100, "bad string");
/*NOTREACHED*/ return 0;
}
static int op_gen(int a, int b, int c, int d) {
struct syl *p = &f__syl[f__pc];
if (f__pc >= SYLMX) {
fprintf(stderr, "format too complicated:\n");
sig_die(f__fmtbuf, 1);
}
p->op = a;
p->p1 = b;
p->p2.i[0] = c;
p->p2.i[1] = d;
return (f__pc++);
}
static const char *f_list(const char *);
static const char *gt_num(const char *s, int *n, int n1) {
int m = 0, f__cnt = 0;
char c;
for (c = *s;; c = *s) {
if (c == ' ') {
s++;
continue;
}
if (c > '9' || c < '0') break;
m = 10 * m + c - '0';
f__cnt++;
s++;
}
if (f__cnt == 0) {
if (!n1) s = 0;
*n = n1;
} else
*n = m;
return (s);
}
static const char *f_s(const char *s, int curloc) {
skip(s);
if (*s++ != '(') {
return (NULL);
}
if (f__parenlvl++ == 1) f__revloc = curloc;
if (op_gen(RET1, curloc, 0, 0) < 0 || (s = f_list(s)) == NULL) {
return (NULL);
}
skip(s);
return (s);
}
static int ne_d(const char *s, const char **p) {
int n, x, sign = 0;
struct syl *sp;
switch (*s) {
default:
return (0);
case ':':
(void)op_gen(COLON, 0, 0, 0);
break;
case '$':
(void)op_gen(NONL, 0, 0, 0);
break;
case 'B':
case 'b':
if (*++s == 'z' || *s == 'Z')
(void)op_gen(BZ, 0, 0, 0);
else
(void)op_gen(BN, 0, 0, 0);
break;
case 'S':
case 's':
if (*(s + 1) == 's' || *(s + 1) == 'S') {
x = SS;
s++;
} else if (*(s + 1) == 'p' || *(s + 1) == 'P') {
x = SP;
s++;
} else
x = S;
(void)op_gen(x, 0, 0, 0);
break;
case '/':
(void)op_gen(SLASH, 0, 0, 0);
break;
case '-':
sign = 1;
case '+':
s++; /*OUTRAGEOUS CODING TRICK*/
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (!(s = gt_num(s, &n, 0))) {
bad:
*p = 0;
return 1;
}
switch (*s) {
default:
return (0);
case 'P':
case 'p':
if (sign) n = -n;
(void)op_gen(P, n, 0, 0);
break;
case 'X':
case 'x':
(void)op_gen(X, n, 0, 0);
break;
case 'H':
case 'h':
sp = &f__syl[op_gen(H, n, 0, 0)];
sp->p2.s = (char *)s + 1;
s += n;
break;
}
break;
case GLITCH:
case '"':
case '\'':
sp = &f__syl[op_gen(APOS, 0, 0, 0)];
sp->p2.s = (char *)s;
if ((*p = ap_end(s)) == NULL) return (0);
return (1);
case 'T':
case 't':
if (*(s + 1) == 'l' || *(s + 1) == 'L') {
x = TL;
s++;
} else if (*(s + 1) == 'r' || *(s + 1) == 'R') {
x = TR;
s++;
} else
x = T;
if (!(s = gt_num(s + 1, &n, 0))) goto bad;
s--;
(void)op_gen(x, n, 0, 0);
break;
case 'X':
case 'x':
(void)op_gen(X, 1, 0, 0);
break;
case 'P':
case 'p':
(void)op_gen(P, 1, 0, 0);
break;
}
s++;
*p = s;
return (1);
}
static int e_d(const char *s, const char **p) {
int i, im, n, w, d, e, found = 0, x = 0;
Const char *sv = s;
s = gt_num(s, &n, 1);
(void)op_gen(STACK, n, 0, 0);
switch (*s++) {
default:
break;
case 'E':
case 'e':
x = 1;
case 'G':
case 'g':
found = 1;
if (!(s = gt_num(s, &w, 0))) {
bad:
*p = 0;
return 1;
}
if (w == 0) break;
if (*s == '.') {
if (!(s = gt_num(s + 1, &d, 0))) goto bad;
} else
d = 0;
if (*s != 'E' && *s != 'e')
(void)op_gen(x == 1 ? E : G, w, d, 0); /* default is Ew.dE2 */
else {
if (!(s = gt_num(s + 1, &e, 0))) goto bad;
(void)op_gen(x == 1 ? EE : GE, w, d, e);
}
break;
case 'O':
case 'o':
i = O;
im = OM;
goto finish_I;
case 'Z':
case 'z':
i = Z;
im = ZM;
goto finish_I;
case 'L':
case 'l':
found = 1;
if (!(s = gt_num(s, &w, 0))) goto bad;
if (w == 0) break;
(void)op_gen(L, w, 0, 0);
break;
case 'A':
case 'a':
found = 1;
skip(s);
if (*s >= '0' && *s <= '9') {
s = gt_num(s, &w, 1);
if (w == 0) break;
(void)op_gen(AW, w, 0, 0);
break;
}
(void)op_gen(A, 0, 0, 0);
break;
case 'F':
case 'f':
if (!(s = gt_num(s, &w, 0))) goto bad;
found = 1;
if (w == 0) break;
if (*s == '.') {
if (!(s = gt_num(s + 1, &d, 0))) goto bad;
} else
d = 0;
(void)op_gen(F, w, d, 0);
break;
case 'D':
case 'd':
found = 1;
if (!(s = gt_num(s, &w, 0))) goto bad;
if (w == 0) break;
if (*s == '.') {
if (!(s = gt_num(s + 1, &d, 0))) goto bad;
} else
d = 0;
(void)op_gen(D, w, d, 0);
break;
case 'I':
case 'i':
i = I;
im = IM;
finish_I:
if (!(s = gt_num(s, &w, 0))) goto bad;
found = 1;
if (w == 0) break;
if (*s != '.') {
(void)op_gen(i, w, 0, 0);
break;
}
if (!(s = gt_num(s + 1, &d, 0))) goto bad;
(void)op_gen(im, w, d, 0);
break;
}
if (found == 0) {
f__pc--; /*unSTACK*/
*p = sv;
return (0);
}
*p = s;
return (1);
}
static const char *i_tem(const char *s) {
const char *t;
int n, curloc;
if (*s == ')') return (s);
if (ne_d(s, &t)) return (t);
if (e_d(s, &t)) return (t);
s = gt_num(s, &n, 1);
if ((curloc = op_gen(STACK, n, 0, 0)) < 0) return (NULL);
return (f_s(s, curloc));
}
static const char *f_list(const char *s) {
for (; *s != 0;) {
skip(s);
if ((s = i_tem(s)) == NULL) return (NULL);
skip(s);
if (*s == ',')
s++;
else if (*s == ')') {
if (--f__parenlvl == 0) {
(void)op_gen(REVERT, f__revloc, 0, 0);
return (++s);
}
(void)op_gen(GOTO, 0, 0, 0);
return (++s);
}
}
return (NULL);
}
int pars_f(const char *s) {
f__parenlvl = f__revloc = f__pc = 0;
if (f_s(s, 0) == NULL) {
return (-1);
}
return (0);
}
static int type_f(int n) {
switch (n) {
default:
return (n);
case RET1:
return (RET1);
case REVERT:
return (REVERT);
case GOTO:
return (GOTO);
case STACK:
return (STACK);
case X:
case SLASH:
case APOS:
case H:
case T:
case TL:
case TR:
return (NED);
case F:
case I:
case IM:
case A:
case AW:
case O:
case OM:
case L:
case E:
case EE:
case D:
case G:
case GE:
case Z:
case ZM:
return (ED);
}
}
#ifdef KR_headers
integer do_fio(number, ptr, len) ftnint *number;
ftnlen len;
char *ptr;
#else
integer do_fio(ftnint *number, char *ptr, ftnlen len)
#endif
{
struct syl *p;
int n, i;
for (i = 0; i < *number; i++, ptr += len) {
loop:
switch (type_f((p = &f__syl[f__pc])->op)) {
default:
fprintf(stderr, "unknown code in do_fio: %d\n%s\n", p->op, f__fmtbuf);
err(f__elist->cierr, 100, "do_fio");
case NED:
if ((*f__doned)(p)) {
f__pc++;
goto loop;
}
f__pc++;
continue;
case ED:
if (f__cnt[f__cp] <= 0) {
f__cp--;
f__pc++;
goto loop;
}
if (ptr == NULL) return ((*f__doend)());
f__cnt[f__cp]--;
f__workdone = 1;
if ((n = (*f__doed)(p, ptr, len)) > 0)
errfl(f__elist->cierr, errno, "fmt");
if (n < 0) err(f__elist->ciend, (EOF), "fmt");
continue;
case STACK:
f__cnt[++f__cp] = p->p1;
f__pc++;
goto loop;
case RET1:
f__ret[++f__rp] = p->p1;
f__pc++;
goto loop;
case GOTO:
if (--f__cnt[f__cp] <= 0) {
f__cp--;
f__rp--;
f__pc++;
goto loop;
}
f__pc = 1 + f__ret[f__rp--];
goto loop;
case REVERT:
f__rp = f__cp = 0;
f__pc = p->p1;
if (ptr == NULL) return ((*f__doend)());
if (!f__workdone) return (0);
if ((n = (*f__dorevert)()) != 0) return (n);
goto loop;
case COLON:
if (ptr == NULL) return ((*f__doend)());
f__pc++;
goto loop;
case NONL:
f__nonl = 1;
f__pc++;
goto loop;
case S:
case SS:
f__cplus = 0;
f__pc++;
goto loop;
case SP:
f__cplus = 1;
f__pc++;
goto loop;
case P:
f__scale = p->p1;
f__pc++;
goto loop;
case BN:
f__cblank = 0;
f__pc++;
goto loop;
case BZ:
f__cblank = 1;
f__pc++;
goto loop;
}
}
return (0);
}
int en_fio(Void) {
ftnint one = 1;
return (do_fio(&one, (char *)NULL, (ftnint)0));
}
VOID fmt_bg(Void) {
f__workdone = f__cp = f__rp = f__pc = f__cursor = 0;
f__cnt[0] = f__ret[0] = 0;
}