#include "config.h" #include "f2c.h" #include "fio.h" #include "fmt.h" #define skip(s) while(*s==' ') s++ #ifdef interdata #define SYLMX 300 #endif #ifdef pdp11 #define SYLMX 300 #endif #ifdef vax #define SYLMX 300 #endif #ifndef SYLMX #define SYLMX 300 #endif #define GLITCH '\2' /* special quote character for stu */ extern int f__cursor, f__scale; extern flag f__cblank, f__cplus; /*blanks in I and compulsory plus */ static struct syl f__syl[SYLMX]; int f__parenlvl, f__pc, f__revloc; static char * ap_end (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 char *f_list (char *); static char * gt_num (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 char * f_s (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); } return (s); } static int ne_d (char *s, 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 = s + 1; s += n; break; } break; case GLITCH: case '"': case '\'': sp = &f__syl[op_gen (APOS, 0, 0, 0)]; sp->p2.s = 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 (char *s, char **p) { int i, im, n, w, d, e, found = 0, x = 0; 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 char * i_tem (char *s) { 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 char * f_list (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 (char *s) { char *e; f__parenlvl = f__revloc = f__pc = 0; if ((e = f_s (s, 0)) == NULL) { /* Try and delimit the format string. Parens within hollerith and quoted strings have to match for this to work, but it's probably adequate for most needs. Note that this is needed because a valid CHARACTER variable passed for FMT= can contain '(I)garbage', where `garbage' is billions and billions of junk characters, and it's up to the run-time library to know where the format string ends by counting parens. Meanwhile, still treat NUL byte as "hard stop", since f2c still appends that at end of FORMAT-statement strings. */ int level = 0; for (f__fmtlen = 0; ((*s != ')') || (--level > 0)) && (*s != '\0') && (f__fmtlen < 80); ++s, ++f__fmtlen) { if (*s == '(') ++level; } if (*s == ')') ++f__fmtlen; return (-1); } f__fmtlen = e - s; return (0); } #define STKSZ 10 int f__cnt[STKSZ], f__ret[STKSZ], f__cp, f__rp; flag f__workdone, f__nonl; 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); } } integer do_fio (ftnint * number, char *ptr, ftnlen len) { 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__fmtlen, 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; }