|
|
1.1 ! root 1: /* ! 2: * getf.c ! 3: * Nroff/Troff. ! 4: * Input handling. ! 5: */ ! 6: ! 7: #include <ctype.h> ! 8: #include "roff.h" ! 9: ! 10: #define ok_name(name) ((name[0]>0 && name[0]<128) && (name[1]>=0 && name[1]<128)) ! 11: ! 12: /* ! 13: * Get a character handling escapes. ! 14: * Flag bit 0: 0 means die if EOF seen, 1 means return EOF. ! 15: * Flag bit 1: 2 means copy mode. ! 16: * If character is escaped but not recognized as a special escape sequence, ! 17: * set escflag and return character unchanged. ! 18: */ ! 19: getf(flags) int flags; ! 20: { ! 21: register REG *rp; ! 22: register int c, n; ! 23: SPECIAL *sp; ! 24: char charbuf[CBFSIZE], name[2]; ! 25: ! 26: escflag = 0; ! 27: for (;;) { ! 28: if ((c = getl(flags&1)) == esc) { ! 29: if ((c = getl(flags&1)) == EOF) ! 30: return c; ! 31: if (c >= ASCSIZE || esctab[c] == ENUL) { ! 32: escflag = 1; ! 33: return c; ! 34: } ! 35: c = esctab[c] & 0377; ! 36: } ! 37: switch (c) { ! 38: case EIGN: ! 39: continue; ! 40: case ECOM: ! 41: while ((c=getl(0)) != '\n') ! 42: ; ! 43: return c; ! 44: case EARG: ! 45: c = getf(0); ! 46: if (!isdigit(c)) { ! 47: printe("bad argument reference"); ! 48: break; ! 49: } ! 50: if (strp->x1.s_argp[c-='0']) ! 51: adscore(strp->x1.s_argp[c]); ! 52: continue; ! 53: case ESTR: ! 54: if ((c=getf(0)) != '(') { ! 55: name[0] = c; ! 56: name[1] = '\0'; ! 57: } else { ! 58: name[0] = getf(0); ! 59: name[1] = getf(0); ! 60: } ! 61: if (!ok_name(name)) { ! 62: printe("illegal string name"); ! 63: break; ! 64: } else if ((rp=findreg(name, RTEXT))) ! 65: adstreg(rp); ! 66: continue; ! 67: case ECHR: ! 68: name[0] = getf(0); ! 69: name[1] = getf(0); ! 70: if (!ok_name(name)) { ! 71: printe("illegal special character name"); ! 72: break; ! 73: } else if ((sp = spc_find(name)) != NULL) ! 74: adscore(sp->spc_val); ! 75: continue; ! 76: case ENUM: ! 77: n = 0; ! 78: if ((c=getf(0)) == '+') { ! 79: n = 1; ! 80: c = getf(0); ! 81: } else if (c == '-') { ! 82: n = -1; ! 83: c = getf(0); ! 84: } ! 85: if (c != '(') { ! 86: name[0] = c; ! 87: name[1] = '\0'; ! 88: } else { ! 89: name[0] = getf(0); ! 90: name[1] = getf(0); ! 91: } ! 92: if (!ok_name(name)) { ! 93: printe("illegal register name"); ! 94: break; ! 95: } else if ((rp=findreg(name, RNUMR)) == NULL) ! 96: spcnreg(name); ! 97: else { ! 98: rp->n_reg.r_nval += n*rp->n_reg.r_incr; ! 99: adsnval(rp->n_reg.r_nval, rp->n_reg.r_form); ! 100: } ! 101: continue; ! 102: case EWID: ! 103: if (flags&2) /* Copy mode */ ! 104: return c; ! 105: if (scandel(charbuf, CBFSIZE) == 0) ! 106: adsnval(0, '1'); ! 107: else ! 108: adsnval(getwidth(charbuf), '1'); ! 109: continue; ! 110: case EBEG: ! 111: if (flags&2) ! 112: return c; ! 113: ++bracelevel; ! 114: return c; ! 115: case EEND: ! 116: if (flags&2) ! 117: return c; ! 118: if (bracelevel == 0) ! 119: printe("\\} without matching \\{"); ! 120: else ! 121: --bracelevel; ! 122: return c; ! 123: case EHEX: ! 124: n = hexdigit(getf(0)) * 0x10; ! 125: n += hexdigit(getf(0)); ! 126: return n; ! 127: default: ! 128: return c; ! 129: } ! 130: } ! 131: } ! 132: ! 133: /* ! 134: * Get width of string by processing into temporary environment. ! 135: */ ! 136: int ! 137: getwidth(cp) char *cp; ! 138: { ! 139: int n; ! 140: ! 141: envsave(ENVWIDTH); ! 142: setline(); ! 143: ccc = ind = tif = fill = 0; ! 144: adscore(cp); ! 145: strp->x1.s_eoff = 1; ! 146: process(); ! 147: wordbreak(DNULL); ! 148: n = nlinsiz; ! 149: envload(ENVWIDTH); ! 150: return n; ! 151: } ! 152: ! 153: /* ! 154: * Like scandel(), except the delimiter is optional. ! 155: * Accepts digits with optional sign without delimiter. ! 156: * Currently called only for pointsize changes, e.g. "\s10" or "\s+1". ! 157: */ ! 158: scanoptdel(cp, n) register char *cp; int n; ! 159: { ! 160: register int c, retval; ! 161: static char buf[2]; ! 162: ! 163: c = getf(0); ! 164: if (c != '-' && c != '+' && !isdigit(c)) { ! 165: buf[0] = c; ! 166: adscore(buf); /* push back c */ ! 167: return scandel(cp, n); /* and use scandel() */ ! 168: } ! 169: retval = 1; ! 170: do { ! 171: if (--n == 0) { ! 172: printe("delimiter argument too large"); ! 173: retval = 0; ! 174: } else ! 175: *cp++ = c; ! 176: c = getf(0); ! 177: } while (isdigit(c)); ! 178: buf[0] = c; ! 179: adscore(buf); /* push back nondigit */ ! 180: return retval; ! 181: } ! 182: ! 183: /* ! 184: * Given a buffer pointer, 'bp', and the size of the buffer, 'n', ! 185: * get an argument surrounded by delimiters and store it in the buffer. ! 186: */ ! 187: scandel(cp, n) register char *cp; int n; ! 188: { ! 189: int retval; ! 190: register int c; ! 191: register int endc; ! 192: ! 193: retval = 1; ! 194: endc = getf(0); ! 195: while ((c=getf(0)) != endc) { ! 196: if (c == '\n') { ! 197: printe("syntax error"); ! 198: return 0; ! 199: } ! 200: if (--n == 0) { ! 201: printe("delimiter argument too large"); ! 202: retval = 0; ! 203: } else if (n > 0) ! 204: *cp++ = c; ! 205: } ! 206: *cp++ = '\0'; ! 207: return retval; ! 208: } ! 209: ! 210: /* ! 211: * Get a character from the current input source. ! 212: * If EOF is seen: return EOF if eofflag, die if !eofflag. ! 213: */ ! 214: getl(eofflag) int eofflag; ! 215: { ! 216: register STR *sp; ! 217: int n; ! 218: register int c; ! 219: register char *cp; ! 220: ! 221: sp = strp; ! 222: if (sp != NULL) ! 223: sp->x1.s_clnc = sp->x1.s_nlnc; ! 224: for (;;) { ! 225: if (sp == NULL) { ! 226: if (eofflag == 0) ! 227: panic("unexpected end of file"); ! 228: return EOF; ! 229: } ! 230: switch (sp->x1.s_type) { ! 231: case SSINP: ! 232: if ((c=getc(stdin)) == EOF) ! 233: break; ! 234: if (c == '\0') ! 235: break; ! 236: if (c == '\n') { ! 237: if ((c=getc(stdin)) == '\n') ! 238: c = '\0'; ! 239: ungetc(c, stdin); ! 240: c = '\n'; ! 241: } ! 242: goto ret; ! 243: case SFILE: ! 244: if ((c=getc(sp->x2.s_fp)) == EOF) { ! 245: fclose(sp->x2.s_fp); ! 246: nfree(sp->x2.s_fname); ! 247: break; ! 248: } ! 249: goto ret; ! 250: case SCORE: ! 251: if ((c = *sp->x3.s_cp++) == '\0') { ! 252: if (sp->x3.s_srel) ! 253: nfree(sp->x3.s_srel); ! 254: break; ! 255: } ! 256: goto ret; ! 257: case SCTEX: ! 258: if (sp->x4.s_disk && sp->x4.s_sp >= sp->x4.s_bufend) { ! 259: nread((long)sp->x4.s_seek, ! 260: (char *)sp->x4.s_bufp); ! 261: sp->x4.s_seek += DBFSIZE; ! 262: sp->x4.s_sp = sp->x4.s_bufp; ! 263: } ! 264: if ((c = *sp->x4.s_sp++) == '\0') { ! 265: if (strnext()) ! 266: continue; ! 267: nfree(sp->x4.s_bufp); ! 268: break; ! 269: } ! 270: goto ret; ! 271: case SCDIV: ! 272: if (sp->x4.s_n-- == 0) { ! 273: if (strnext()) ! 274: continue; ! 275: nfree(sp->x4.s_bufp); ! 276: break; ! 277: } ! 278: n = sizeof (CODE); ! 279: cp = (char *) &codeval; ! 280: while (n--) ! 281: *cp++ = geth(); ! 282: return ECOD; ! 283: } ! 284: if (sp->x4.s_abuf) ! 285: nfree(sp->x4.s_abuf); ! 286: n = sp->x4.s_eoff; ! 287: strp = strp->x4.s_next; ! 288: nfree((char *)sp); ! 289: sp = strp; ! 290: if (n) { ! 291: if (eofflag == 0) ! 292: panic("incomplete macro in trap"); ! 293: return EOF; ! 294: } ! 295: } ! 296: ret: ! 297: if ((c&=0377) == '\n') ! 298: sp->x4.s_nlnc++; ! 299: return c; ! 300: } ! 301: ! 302: /* ! 303: * In a chained macro, set up input stack to point to next element in chain. ! 304: */ ! 305: strnext() ! 306: { ! 307: register STR *sp; ! 308: register MAC *mp; ! 309: ! 310: sp = strp; ! 311: if ((mp=sp->x4.s_macp) == NULL) ! 312: return 0; ! 313: sp->x4.s_macp = mp->t_div.m_next; ! 314: switch (mp->t_div.m_type) { ! 315: case MTEXT: ! 316: sp->x1.s_type = SCTEX; ! 317: break; ! 318: case MDIVN: ! 319: sp->x4.s_type = SCDIV; ! 320: if ((sp->x4.s_n=mp->t_div.m_size) == 0) ! 321: return strnext(); ! 322: break; ! 323: } ! 324: if (mp->t_div.m_core) { ! 325: sp->x4.s_disk = 0; ! 326: sp->x4.s_sp = mp->t_div.m_core; ! 327: } else { ! 328: sp->x4.s_disk = 1; ! 329: sp->x4.s_seek = mp->t_div.m_seek/DBFSIZE * DBFSIZE; ! 330: sp->x4.s_sp = &(sp->x4.s_bufp[mp->t_div.m_seek%DBFSIZE]); ! 331: nread((long)sp->x4.s_seek,(char *)sp->x4.s_bufp); ! 332: sp->x4.s_seek += DBFSIZE; ! 333: } ! 334: return 1; ! 335: } ! 336: ! 337: /* ! 338: * Get a single character assuming the stack has been set up ! 339: * for chained I/O. ! 340: */ ! 341: geth() ! 342: { ! 343: if (strp->x4.s_disk && strp->x4.s_sp >= strp->x4.s_bufend) { ! 344: nread((long)strp->x4.s_seek,(char *)strp->x4.s_bufp); ! 345: strp->x4.s_seek += DBFSIZE; ! 346: strp->x4.s_sp = strp->x4.s_bufp; ! 347: } ! 348: return (*strp->x4.s_sp++); ! 349: } ! 350: ! 351: /* ! 352: * Push down input stack and add the given file on top. ! 353: */ ! 354: adsfile(file) ! 355: char *file; ! 356: { ! 357: register STR *sp; ! 358: register FILE *fp; ! 359: ! 360: if ((fp = fopen(file, "r")) == NULL) { ! 361: printe("cannot open file \"%s\"", file); ! 362: return 0; ! 363: } ! 364: sp = allstr(SFILE); ! 365: sp->x2.s_fname = duplstr(file); ! 366: sp->x2.s_fp = fp; ! 367: return 1; ! 368: } ! 369: ! 370: /* ! 371: * Push down input stack and add the given FILE. ! 372: */ ! 373: adsunit(fp) FILE *fp; ! 374: { ! 375: register STR *sp; ! 376: ! 377: sp = allstr(SFILE); ! 378: sp->x2.s_fname = duplstr("<stdin>"); ! 379: sp->x2.s_fp = fp; ! 380: } ! 381: ! 382: /* ! 383: * Push down input stack and add the given register. ! 384: */ ! 385: adstreg(rp) ! 386: register REG *rp; ! 387: { ! 388: register STR *sp; ! 389: ! 390: if (rp->t_reg.r_macd.t_div.m_type == MREQS) ! 391: return 1; /* return had been random, 1 is guess by cef */ ! 392: sp = allstr(0); ! 393: sp->x4.s_bufp = nalloc(DBFSIZE); ! 394: sp->x4.s_bufend = &sp->x4.s_bufp[DBFSIZE]; ! 395: sp->x4.s_macp = &rp->t_reg.r_macd; ! 396: if (strnext() == 0) { ! 397: strp = strp->x4.s_next; ! 398: nfree(sp->x4.s_bufp); ! 399: nfree((char *)sp); ! 400: return 0; ! 401: } ! 402: return 1; ! 403: } ! 404: ! 405: /* ! 406: * Given the name of a special number register, expand it and ! 407: * add it onto the input stack. ! 408: */ ! 409: spcnreg(name) ! 410: char name[2]; ! 411: { ! 412: register STR *sp; ! 413: register int n; ! 414: register char *cp; ! 415: ! 416: n = 0; ! 417: if (name[0] == '.') { ! 418: switch (name[1]) { ! 419: case '$': ! 420: if ((n=strp->x1.s_argc) > 0) ! 421: --n; ! 422: break; ! 423: case 'A': n = A_reg; break; ! 424: case 'F': /* Filename, not in V7. */ ! 425: for (sp=strp; sp; sp=sp->x1.s_next) { ! 426: if (sp->x1.s_type == SFILE) { ! 427: adscore(sp->x2.s_fname); ! 428: return; ! 429: } ! 430: } ! 431: return; ! 432: case 'H': n = unit(SMHRES, SDHRES); break; ! 433: /* case 'L': TO_DO */ ! 434: /* case 'P': TO_DO */ ! 435: case 'T': n = T_reg; break; ! 436: case 'V': n = unit(SMVRES, SDVRES); break; ! 437: case 'a': n = a_reg; break; ! 438: case 'c': ! 439: n = 0; ! 440: for (sp=strp; sp; sp=sp->x1.s_next) { ! 441: if (sp->x1.s_type == SFILE) { ! 442: n = sp->x1.s_clnc; ! 443: break; ! 444: } ! 445: } ! 446: break; ! 447: case 'd': n = cdivp->d_rpos; break; ! 448: case 'f': n = 0; break; ! 449: case 'h': n = cdivp->d_maxh; break; ! 450: case 'i': n = ind; break; ! 451: /* case 'j': TO_DO */ ! 452: /* case 'k': TO_DO */ ! 453: case 'l': n = lln; break; ! 454: case 'n': n = n_reg; break; ! 455: case 'o': n = pof; break; ! 456: case 'p': n = pgl; break; ! 457: case 's': n = unit(psz*SDPOIN, SMPOIN); break; ! 458: case 't': ! 459: n = cdivp->d_ctpp ? cdivp->d_ctpp->t_apos : pgl; ! 460: if (n > pgl) ! 461: n = pgl; ! 462: n -= cdivp->d_rpos; ! 463: break; ! 464: case 'u': n = fill; break; ! 465: case 'v': n = vls; break; ! 466: case 'w': n = 0; break; ! 467: case 'x': n = 0; break; ! 468: case 'y': n = 0; break; ! 469: case 'z': ! 470: cp = nalloc(3); ! 471: cp[0] = cdivp->d_name[0]; ! 472: cp[1] = cdivp->d_name[1]; ! 473: cp[2] = '\0'; ! 474: adscore(cp); ! 475: strp->x3.s_srel = cp; ! 476: return; ! 477: } ! 478: } ! 479: adsnval(n, '1'); ! 480: } ! 481: ! 482: /* ! 483: * Given a value and a format, expand out the value to the ! 484: * particular format and add it onto the top of the stack. ! 485: */ ! 486: adsnval(val, f) int val, f; ! 487: { ! 488: register ROM *op; ! 489: int w; ! 490: register int n; ! 491: char charbuf[CBFSIZE], *str, *cp2; ! 492: register char *cp1; ! 493: ! 494: n = val; ! 495: if (n <= 0) { ! 496: if ((n = -n) <= 0) { ! 497: n = 0; ! 498: if (!isdigit(f)) ! 499: f = '0'; ! 500: } ! 501: } ! 502: cp1 = charbuf; ! 503: switch (f) { ! 504: case 'a': ! 505: case 'A': ! 506: while (n) { ! 507: n--; ! 508: *cp1++ = 'a' + n%26; ! 509: n /= 26; ! 510: } ! 511: break; ! 512: case 'i': ! 513: case 'I': ! 514: for (cp2="ivxlcdm"; *cp2!='m'; cp2+=2) { ! 515: op = &romtab[n%10]; ! 516: n /= 10; ! 517: while (op != &romtab[0]) { ! 518: *cp1++ = cp2[op->o_digit]; ! 519: op = &romtab[op->o_state]; ! 520: } ! 521: } ! 522: if (cp1+n >= &charbuf[CBFSIZE]) { ! 523: *cp1++ = '*'; ! 524: break; ! 525: } ! 526: while (n--) ! 527: *cp1++ = 'm'; ! 528: break; ! 529: default: ! 530: w = f - '0'; ! 531: while (n) { ! 532: --w; ! 533: *cp1++ = n%10 + '0'; ! 534: n /= 10; ! 535: } ! 536: while (w-- > 0) ! 537: *cp1++ = '0'; ! 538: if (val < 0) ! 539: *cp1++ = '-'; ! 540: } ! 541: cp2 = str = nalloc(cp1-charbuf + 1); ! 542: if (isupper(f)) { ! 543: while (cp1 > charbuf) ! 544: if (islower(*--cp1)) ! 545: *cp2++ = toupper(*cp1); ! 546: else *cp2++ = *cp1; ! 547: } else { ! 548: while (cp1 > charbuf) ! 549: *cp2++ = *--cp1; ! 550: } ! 551: *cp2 = '\0'; ! 552: adscore(str); ! 553: strp->x3.s_srel = str; ! 554: } ! 555: ! 556: /* ! 557: * Divert input to the given string. ! 558: */ ! 559: adscore(cp) char *cp; ! 560: { ! 561: register STR *sp; ! 562: ! 563: sp = allstr(SCORE); ! 564: sp->x3.s_cp = cp; ! 565: sp->x3.s_srel = NULL; ! 566: } ! 567: ! 568: /* ! 569: * Allocate an entry and add it to the input stack. ! 570: */ ! 571: STR * ! 572: allstr(type) ! 573: { ! 574: register STR *sp; ! 575: register int i; ! 576: ! 577: sp = (STR *) nalloc(sizeof *sp); ! 578: sp->x1.s_next = strp; ! 579: strp = sp; ! 580: sp->x1.s_type = type; ! 581: sp->x1.s_eoff = 0; ! 582: sp->x1.s_clnc = 1; ! 583: sp->x1.s_nlnc = 1; ! 584: sp->x1.s_argc = 0; ! 585: for (i = 0; i < ARGSIZE; i++) ! 586: sp->x1.s_argp[i] = ""; ! 587: sp->x1.s_abuf = NULL; ! 588: return sp; ! 589: } ! 590: ! 591: hexdigit(c) register int c; ! 592: { ! 593: if (isdigit(c)) ! 594: return c - '0'; ! 595: else if (c >= 'A' && c <= 'F') ! 596: return c - 'A' + 10; ! 597: else if (c >= 'a' && c <= 'f') ! 598: return c - 'a' + 10; ! 599: printe("illegal hex digit"); ! 600: return 0; ! 601: } ! 602: ! 603: ! 604: /* end of getf.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.