|
|
1.1 root 1: /*
2: * n1.c
3: *
4: * consume options, initialization, main loop,
5: * input routines, escape function calling
6: */
7:
8: #include "tdef.h"
9: #include "fns.h"
10: #include "ext.h"
11:
12: #include <setjmp.h>
13: #include <time.h>
14:
15: char *Version = "Dec 1, 1992";
16:
17: int TROFF = 1; /* assume we started in troff... */
18:
19: jmp_buf sjbuf;
20: Offset ipl[NSO];
21:
22: static FILE *ifile = stdin;
23: static FILE *ifl[NSO]; /* open input file pointers */
24: char cfname[NSO+1][NS] = { "stdin" }; /* file name stack */
25: int cfline[NSO]; /* input line count stack */
26: char *progname; /* program name (troff or nroff) */
27:
28: int trace = 0; /* tracing flag */
29: #define TRMAC 01 /* trace macros */
30: #define TRREQ 02 /* trace requests */
31:
32: main(int argc, char *argv[])
33: {
34: char *p;
35: int j;
36: Tchar i;
37: int eileenct; /* count to test for "Eileen's loop" */
38: char buf[100];
39:
40: progname = argv[0];
41: if ((p = strrchr(progname, '/')) == NULL)
42: p = progname;
43: else
44: p++;
45: if (strcmp(p, "nroff") == 0)
46: TROFF = 0;
47: if ((p = getenv("TYPESETTER")) != 0)
48: strcpy(devname, p);
49: mrehash();
50: nrehash();
51: numtab[NL].val = -1;
52:
53: while (--argc > 0 && (++argv)[0][0] == '-')
54: switch (argv[0][1]) {
55:
56: case 'N': /* ought to be used first... */
57: TROFF = 0;
58: break;
59: case 'd':
60: fprintf(stderr, "troff/nroff version %s\n", Version);
61: break;
62: case 'F': /* switch font tables from default */
63: if (argv[0][2] != '\0') {
64: strcpy(termtab, &argv[0][2]);
65: strcpy(fontdir, &argv[0][2]);
66: } else {
67: argv++; argc--;
68: strcpy(termtab, argv[0]);
69: strcpy(fontdir, argv[0]);
70: }
71: break;
72: case 0:
73: goto start;
74: case 'i':
75: stdi++;
76: break;
77: case 'n':
78: npn = atoi(&argv[0][2]);
79: break;
80: case 'u': /* set emboldening amount */
81: bdtab[3] = atoi(&argv[0][2]);
82: if (bdtab[3] < 0 || bdtab[3] > 50)
83: bdtab[3] = 0;
84: break;
85: case 's':
86: if (!(stop = atoi(&argv[0][2])))
87: stop++;
88: break;
89: case 'r':
90: sprintf(buf + strlen(buf), ".nr %c %s\n",
91: argv[0][2], &argv[0][3]);
92: cpushback(buf);
93: /* dotnr(&argv[0][2], &argv[0][3]); */
94: break;
95: case 'm':
96: if (mflg++ >= NMF) {
97: ERROR "Too many macro packages: %s", argv[0] WARN;
98: break;
99: }
100: strcpy(mfiles[nmfi], nextf);
101: strcat(mfiles[nmfi++], &argv[0][2]);
102: break;
103: case 'o':
104: getpn(&argv[0][2]);
105: break;
106: case 'T':
107: strcpy(devname, &argv[0][2]);
108: dotT++;
109: break;
110: case 'a':
111: ascii = 1;
112: break;
113: case 'h':
114: hflg++;
115: break;
116: case 'e':
117: eqflg++;
118: break;
119: case 'q':
120: quiet++;
121: save_tty();
122: break;
123: default:
124: ERROR "unknown option %s", argv[0] WARN;
125: done(02);
126: }
127:
128: start:
129: argp = argv;
130: rargc = argc;
131: nmfi = 0;
132: init2();
133: setjmp(sjbuf);
134: eileenct = 0; /*reset count for "Eileen's loop"*/
135: /* this is a really sick bit of code */
136: /* but i've never been able to figure out */
137: /* how to fix it. */
138: loop:
139: copyf = lgf = nb = nflush = nlflg = 0;
140: if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl) {
141: nflush++;
142: trap = 0;
143: eject((Stack *)0);
144: if (eileenct > 20) {
145: ERROR "job looping; check abuse of macros" WARN;
146: ejf = 0; /* try to break Eileen's loop */
147: eileenct = 0;
148: } else
149: eileenct++;
150: goto loop;
151: }
152: eileenct = 0; /*reset count for "Eileen's loop"*/
153: i = getch();
154: if (pendt)
155: goto Lt;
156: if ((j = cbits(i)) == XPAR) {
157: copyf++;
158: tflg++;
159: while (cbits(i) != '\n')
160: pchar(i = getch());
161: tflg = 0;
162: copyf--;
163: goto loop;
164: }
165: if (j == cc || j == c2) {
166: if (j == c2)
167: nb++;
168: copyf++;
169: while ((j = cbits(i = getch())) == ' ' || j == '\t')
170: ;
171: ch = i;
172: copyf--;
173: control(getrq(), 1);
174: flushi();
175: goto loop;
176: }
177: Lt:
178: ch = i;
179: text();
180: if (nlflg)
181: numtab[HP].val = 0;
182: goto loop;
183: }
184:
185:
186:
187: void init2(void)
188: {
189: int i;
190: char buf[100];
191:
192: for (i = NTRTAB; --i; )
193: trtab[i] = i;
194: trtab[UNPAD] = ' ';
195: iflg = 0;
196: obufp = obuf;
197: if (TROFF)
198: t_ptinit();
199: else
200: n_ptinit();
201: mchbits();
202: cvtime();
203: numtab[PID].val = getpid();
204: olinep = oline;
205: numtab[HP].val = init = 0;
206: numtab[NL].val = -1;
207: nfo = 0;
208: copyf = raw = 0;
209: sprintf(buf, ".ds .T %s\n", devname);
210: cpushback(buf);
211: numtab[CD].val = -1; /* compensation */
212: nx = mflg;
213: frame = stk = (Stack *)setbrk(STACKSIZE);
214: dip = &d[0];
215: nxf = frame + 1;
216: for (i = 1; i < NEV; i++) /* propagate the environment */
217: envcopy(&env[i], &env[0]);
218: blockinit();
219: }
220:
221: void cvtime(void)
222: {
223: long tt;
224: struct tm *ltime;
225:
226: time(&tt);
227: ltime = localtime(&tt);
228: numtab[YR].val = ltime->tm_year;
229: numtab[MO].val = ltime->tm_mon + 1; /* troff uses 1..12 */
230: numtab[DY].val = ltime->tm_mday;
231: numtab[DW].val = ltime->tm_wday + 1; /* troff uses 1..7 */
232: }
233:
234:
235:
236: char errbuf[200];
237:
238: void errprint(void) /* error message printer */
239: {
240: fprintf(stderr, "%s: ", progname);
241: fputs(errbuf, stderr);
242: if (numtab[CD].val > 0)
243: fprintf(stderr, "; line %d, file %s", numtab[CD].val, cfname[ifi]);
244: fputs("\n", stderr);
245: stackdump();
246: }
247:
248:
249: int control(int a, int b)
250: {
251: int j;
252:
253: if (a == 0 || (j = findmn(a)) == -1)
254: return(0);
255: if (contab[j].f == 0) {
256: if (trace & TRMAC)
257: fprintf(stderr, "invoke macro %s\n", unpair(a));
258: nxf->nargs = 0;
259: if (b)
260: collect();
261: flushi();
262: return pushi(contab[j].mx, a); /* BUG??? all that matters is 0/!0 */
263: }
264: if (b) {
265: if (trace & TRREQ)
266: fprintf(stderr, "invoke request %s\n", unpair(a));
267: (*contab[j].f)();
268: }
269: return(0);
270: }
271:
272: void casept(void)
273: {
274: skip();
275: noscale++;
276: trace = atoi0();
277: noscale = 0;
278: }
279:
280:
281: int getrq(void)
282: {
283: int i, j;
284:
285: if ((i = getach()) == 0 || (j = getach()) == 0)
286: goto rtn;
287: i = PAIR(i, j);
288: rtn:
289: return(i);
290: }
291:
292: /*
293: * table encodes some special characters, to speed up tests
294: * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
295: */
296:
297: char gchtab[NCHARS] = {
298: 000,004,000,000,010,000,000,000, /* fc, ldr */
299: 001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
300: 000,000,000,000,000,000,000,000,
301: 000,001,000,001,000,000,000,000, /* FLSS, ESC */
302: 000,000,000,000,000,000,000,000,
303: 000,000,000,000,000,000,000,000,
304: 000,000,000,000,000,000,000,000,
305: 000,000,000,000,000,000,000,000,
306: 000,000,000,000,000,000,000,000,
307: 000,000,000,000,000,000,000,000,
308: 000,000,000,000,000,000,000,000,
309: 000,000,000,000,000,000,000,000,
310: 000,000,000,000,000,000,001,000, /* f */
311: 000,000,000,000,000,000,000,000,
312: 000,000,000,000,000,000,000,000,
313: 000,000,000,000,000,000,000,000,
314: };
315:
316: int realcbits(Tchar c) /* return character bits, or MOTCH if motion */
317: {
318: if (ismot(c))
319: return MOTCH;
320: else
321: return c & 0xFFFF;
322: }
323:
324: Tchar getch(void)
325: {
326: int k;
327: Tchar i, j;
328:
329: g0:
330: if (ch) {
331: i = ch;
332: if (cbits(i) == '\n')
333: nlflg++;
334: ch = 0;
335: return(i);
336: }
337:
338: if (nlflg)
339: return('\n');
340: i = getch0();
341: if (ismot(i))
342: return(i);
343: k = cbits(i);
344: if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0) /* nothing special */
345: return(i);
346: if (k != ESC) {
347: if (k == '\n') {
348: nlflg++;
349: if (ip == 0)
350: numtab[CD].val++; /* line number */
351: return(k);
352: }
353: if (k == FLSS) {
354: copyf++;
355: raw++;
356: i = getch0();
357: if (!fi)
358: flss = i;
359: copyf--;
360: raw--;
361: goto g0;
362: }
363: if (k == RPT) {
364: setrpt();
365: goto g0;
366: }
367: if (!copyf) {
368: if (k == 'f' && lg && !lgf) {
369: i = getlg(i);
370: return(i);
371: }
372: if (k == fc || k == tabch || k == ldrch) {
373: if ((i = setfield(k)) == 0)
374: goto g0;
375: else
376: return(i);
377: }
378: if (k == '\b') {
379: i = makem(-width(' ' | chbits));
380: return(i);
381: }
382: }
383: return(i);
384: }
385:
386: k = cbits(j = getch0());
387: if (ismot(j))
388: return(j);
389:
390: switch (k) {
391: case 'n': /* number register */
392: setn();
393: goto g0;
394: case '$': /* argument indicator */
395: seta();
396: goto g0;
397: case '*': /* string indicator */
398: setstr();
399: goto g0;
400: case '{': /* LEFT */
401: i = LEFT;
402: goto gx;
403: case '}': /* RIGHT */
404: i = RIGHT;
405: goto gx;
406: case '"': /* comment */
407: while (cbits(i = getch0()) != '\n')
408: ;
409: nlflg++;
410: if (ip == 0)
411: numtab[CD].val++;
412: return(i);
413:
414: /* experiment: put it here instead of copy mode */
415: case '(': /* special char name \(xx */
416: case 'C': /* \C'...' */
417: if ((i = setch(k)) == 0)
418: goto g0;
419: goto gx;
420:
421: case ESC: /* double backslash */
422: i = eschar;
423: goto gx;
424: case 'e': /* printable version of current eschar */
425: i = PRESC;
426: goto gx;
427: case '\n': /* concealed newline */
428: goto g0;
429: case ' ': /* unpaddable space */
430: i = UNPAD;
431: goto gx;
432: case '\'': /* \(aa */
433: i = ACUTE;
434: goto gx;
435: case '`': /* \(ga */
436: i = GRAVE;
437: goto gx;
438: case '_': /* \(ul */
439: i = UNDERLINE;
440: goto gx;
441: case '-': /* current font minus */
442: i = MINUS;
443: goto gx;
444: case '&': /* filler */
445: i = FILLER;
446: goto gx;
447: case 'c': /* to be continued */
448: i = CONT;
449: goto gx;
450: case '!': /* transparent indicator */
451: i = XPAR;
452: goto gx;
453: case 't': /* tab */
454: i = '\t';
455: return(i);
456: case 'a': /* leader (SOH) */
457: /* old: *pbp++ = LEADER; goto g0; */
458: i = LEADER;
459: return i;
460: case '%': /* ohc */
461: i = OHC;
462: return(i);
463: case 'g': /* return format of a number register */
464: setaf(); /* should this really be in copy mode??? */
465: goto g0;
466: case '.': /* . */
467: i = '.';
468: gx:
469: setsfbits(i, sfbits(j));
470: return(i);
471: }
472: if (copyf) {
473: *pbp++ = j;
474: return(eschar);
475: }
476: switch (k) {
477:
478: case 'f': /* font indicator */
479: setfont(0);
480: goto g0;
481: case 's': /* size indicator */
482: setps();
483: goto g0;
484: case 'v': /* vert mot */
485: if (i = vmot()) {
486: return(i);
487: }
488: goto g0;
489: case 'h': /* horiz mot */
490: if (i = hmot())
491: return(i);
492: goto g0;
493: case '|': /* narrow space */
494: if (NROFF)
495: goto g0;
496: return(makem((int)(EM)/6));
497: case '^': /* half narrow space */
498: if (NROFF)
499: goto g0;
500: return(makem((int)(EM)/12));
501: case 'w': /* width function */
502: setwd();
503: goto g0;
504: case 'p': /* spread */
505: spread++;
506: goto g0;
507: case 'N': /* absolute character number */
508: if ((i = setabs()) == 0)
509: goto g0;
510: return i;
511: case 'H': /* character height */
512: return(setht());
513: case 'S': /* slant */
514: return(setslant());
515: case 'z': /* zero with char */
516: return(setz());
517: case 'l': /* hor line */
518: setline();
519: goto g0;
520: case 'L': /* vert line */
521: setvline();
522: goto g0;
523: case 'D': /* drawing function */
524: setdraw();
525: goto g0;
526: case 'X': /* \X'...' for copy through */
527: setxon();
528: goto g0;
529: case 'b': /* bracket */
530: setbra();
531: goto g0;
532: case 'o': /* overstrike */
533: setov();
534: goto g0;
535: case 'k': /* mark hor place */
536: if ((k = findr(getsn())) != -1) {
537: numtab[k].val = numtab[HP].val;
538: }
539: goto g0;
540: case '0': /* number space */
541: return(makem(width('0' | chbits)));
542: case 'x': /* extra line space */
543: if (i = xlss())
544: return(i);
545: goto g0;
546: case 'u': /* half em up */
547: case 'r': /* full em up */
548: case 'd': /* half em down */
549: return(sethl(k));
550: default:
551: return(j);
552: }
553: /* NOTREACHED */
554: }
555:
556: void setxon(void) /* \X'...' for copy through */
557: {
558: Tchar xbuf[NC];
559: Tchar *i;
560: Tchar c;
561: int delim, k;
562:
563: if (ismot(c = getch()))
564: return;
565: delim = cbits(c);
566: i = xbuf;
567: *i++ = XON | chbits;
568: while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
569: if (k == ' ')
570: setcbits(c, WORDSP);
571: *i++ = c | ZBIT;
572: }
573: *i++ = XOFF | chbits;
574: *i = 0;
575: pushback(xbuf);
576: }
577:
578:
579: char ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 };
580:
581: Tchar getch0(void)
582: {
583: int j;
584: Tchar i;
585:
586: again:
587: if (pbp > lastpbp)
588: i = *--pbp;
589: else if (ip) {
590: /* i = rbf(); */
591: i = rbf0(ip);
592: if (i == 0)
593: i = rbf();
594: else {
595: ++ip;
596: if (pastend(ip)) {
597: --ip;
598: rbf();
599: }
600: }
601: } else {
602: if (donef || ndone)
603: done(0);
604: if (nx || 1) { /* BUG: was ibufp >= eibuf, so EOF test is wrong */
605: if (nfo < 0)
606: ERROR "in getch0, nfo = %d", nfo WARN;
607: if (nfo == 0) {
608: g0:
609: if (nextfile()) {
610: if (ip)
611: goto again;
612: }
613: }
614: nx = 0;
615: if ((i = getc(ifile)) == EOF)
616: goto g0;
617: if (ip)
618: goto again;
619: }
620: g2:
621: if (i >= 040) /* zapped: && i < 0177 */
622: goto g4;
623: i = ifilt[i];
624: }
625: if (cbits(i) == IMP && !raw)
626: goto again;
627: if (i == 0 && !init && !raw) { /* zapped: || i == 0177 */
628: goto again;
629: }
630: g4:
631: if (ismot(i))
632: return i;
633: if (copyf == 0 && sfbits(i) == 0)
634: i |= chbits;
635: if (cbits(i) == eschar && !raw)
636: setcbits(i, ESC);
637: return(i);
638: }
639:
640: void pushback(Tchar *b)
641: {
642: Tchar *ob = b;
643:
644: while (*b++)
645: ;
646: b--;
647: while (b > ob && pbp < &pbbuf[NC-3])
648: *pbp++ = *--b;
649: if (pbp >= &pbbuf[NC-3]) {
650: ERROR "pushback overflow" WARN;
651: done(2);
652: }
653: }
654:
655: void cpushback(char *b)
656: {
657: char *ob = b;
658:
659: while (*b++)
660: ;
661: b--;
662: while (b > ob && pbp < &pbbuf[NC-3])
663: *pbp++ = *--b;
664: if (pbp >= &pbbuf[NC-3]) {
665: ERROR "cpushback overflow" WARN;
666: done(2);
667: }
668: }
669:
670: int nextfile(void)
671: {
672: char *p;
673:
674: n0:
675: if (ifile != stdin)
676: fclose(ifile);
677: if (ifi > 0 && !nx) {
678: if (popf())
679: goto n0; /* popf error */
680: return(1); /* popf ok */
681: }
682: if (nx || nmfi < mflg) {
683: p = mfiles[nmfi++];
684: if (*p != 0)
685: goto n1;
686: }
687: if (rargc-- <= 0) {
688: if ((nfo -= mflg) && !stdi) {
689: done(0);
690: }
691: nfo++;
692: numtab[CD].val = stdi = mflg = 0;
693: ifile = stdin;
694: strcpy(cfname[ifi], "stdin");
695: return(0);
696: }
697: p = (argp++)[0];
698: n1:
699: numtab[CD].val = 0;
700: if (p[0] == '-' && p[1] == 0) {
701: ifile = stdin;
702: strcpy(cfname[ifi], "stdin");
703: } else if ((ifile = fopen(p, "r")) == NULL) {
704: ERROR "cannot open file %s", p WARN;
705: nfo -= mflg;
706: done(02);
707: } else
708: strcpy(cfname[ifi],p);
709: nfo++;
710: return(0);
711: }
712:
713:
714: popf(void)
715: {
716: --ifi;
717: if (ifi < 0) {
718: ERROR "popf went negative" WARN;
719: return 1;
720: }
721: numtab[CD].val = cfline[ifi]; /* restore line counter */
722: ip = ipl[ifi]; /* input pointer */
723: ifile = ifl[ifi]; /* input FILE * */
724: return(0);
725: }
726:
727:
728: void flushi(void)
729: {
730: if (nflush)
731: return;
732: ch = 0;
733: copyf++;
734: while (!nlflg) {
735: if (donef && frame == stk)
736: break;
737: getch();
738: }
739: copyf--;
740: }
741:
742:
743: getach(void) /* return ascii/alphabetic character */
744: {
745: Tchar i;
746: int j;
747:
748: lgf++;
749: j = cbits(i = getch());
750: if (ismot(i) || !isgraph(j)) {
751: ch = i;
752: j = 0;
753: }
754: lgf--;
755: return j;
756: }
757:
758:
759: void casenx(void)
760: {
761: lgf++;
762: skip();
763: getname();
764: nx++;
765: if (nmfi > 0)
766: nmfi--;
767: strcpy(mfiles[nmfi], nextf);
768: nextfile();
769: nlflg++;
770: ip = 0;
771: pendt = 0;
772: frame = stk;
773: nxf = frame + 1;
774: }
775:
776:
777: getname(void)
778: {
779: int j, k;
780: Tchar i;
781:
782: lgf++;
783: for (k = 0; k < NS - 1; k++) {
784: j = getach();
785: if (!j)
786: break;
787: nextf[k] = j;
788: }
789: nextf[k] = 0;
790: lgf--;
791: return(nextf[0]);
792: }
793:
794:
795: void caseso(void)
796: {
797: FILE *fp;
798: char *p, *q;
799:
800: lgf++;
801: nextf[0] = 0;
802: if (skip() || !getname() || (fp = fopen(nextf, "r")) == NULL || ifi >= NSO) {
803: ERROR "can't open file %s", nextf WARN;
804: done(02);
805: }
806: strcpy(cfname[ifi+1], nextf);
807: cfline[ifi] = numtab[CD].val; /*hold line counter*/
808: numtab[CD].val = 0;
809: flushi();
810: ifl[ifi] = ifile;
811: ifile = fp;
812: ipl[ifi] = ip;
813: ip = 0;
814: nx++;
815: nflush++;
816: ifi++;
817: }
818:
819: void caself(void) /* set line number and file */
820: {
821: int n;
822:
823: if (skip())
824: return;
825: n = atoi0();
826: cfline[ifi] = numtab[CD].val = n - 2;
827: if (skip())
828: return;
829: if (getname())
830: strcpy(cfname[ifi], nextf);
831: }
832:
833:
834: void casecf(void)
835: { /* copy file without change */
836: int fd, n;
837: char buf[1024];
838: extern int hpos, esc, po;
839:
840: /* this may not make much sense in nroff... */
841:
842: lgf++;
843: nextf[0] = 0;
844: if (skip() || !getname() || (fd = open(nextf, 0)) < 0) {
845: ERROR "can't open file %s", nextf WARN;
846: done(02);
847: }
848: lgf--;
849:
850: /* make it into a clean state, be sure that everything is out */
851: tbreak();
852: hpos = po;
853: esc = 0;
854: ptesc(); /* to left margin */
855: esc = un;
856: ptesc();
857: ptlead();
858: ptps();
859: ptfont();
860: flusho();
861: while ((n = read(fd, buf, sizeof buf)) > 0)
862: fwrite(buf, n, 1, ptid);
863: close(fd);
864: ptps();
865: ptfont();
866: }
867:
868: void getline(char *s, int n) /* get rest of input line into s */
869: {
870: int i;
871:
872: lgf++;
873: copyf++;
874: skip();
875: for (i = 0; i < n-1; i++)
876: if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT)
877: break;
878: s[i] = 0;
879: copyf--;
880: lgf--;
881: }
882:
883: void casesy(void) /* call system */
884: {
885: char sybuf[NTM];
886:
887: getline(sybuf, NTM);
888: system(sybuf);
889: }
890:
891:
892: void getpn(char *a)
893: {
894: int n, neg;
895:
896: if (*a == 0)
897: return;
898: neg = 0;
899: for ( ; *a; a++)
900: switch (*a) {
901: case '+':
902: case ',':
903: continue;
904: case '-':
905: neg = 1;
906: continue;
907: default:
908: n = 0;
909: if (isdigit(*a)) {
910: do
911: n = 10 * n + *a++ - '0';
912: while (isdigit(*a));
913: a--;
914: } else
915: n = 9999;
916: *pnp++ = neg ? -n : n;
917: neg = 0;
918: if (pnp >= &pnlist[NPN-2]) {
919: ERROR "too many page numbers" WARN;
920: done3(-3);
921: }
922: }
923: if (neg)
924: *pnp++ = -9999;
925: *pnp = -INT_MAX;
926: print = 0;
927: pnp = pnlist;
928: if (*pnp != -INT_MAX)
929: chkpn();
930: }
931:
932:
933: void setrpt(void)
934: {
935: Tchar i, j;
936:
937: copyf++;
938: raw++;
939: i = getch0();
940: copyf--;
941: raw--;
942: if ((long) i < 0 || cbits(j = getch0()) == RPT)
943: return;
944: while (i > 0 && pbp < &pbbuf[NC-3]) {
945: i--;
946: *pbp++ = j;
947: }
948: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.