478 lines
9.6 KiB
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;
|
|
}
|