|
|
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.