|
|
1.1 root 1: #include <sys/types.h>
2: #include <sys/stat.h>
3: #include "tdef.h"
4: extern
5: #include "d.h"
6: extern
7: #include "v.h"
8: #ifdef NROFF
9: extern
10: #include "tw.h"
11: #endif
12: #include "s.h"
13: #include <setjmp.h>
14: jmp_buf sjbuf;
15: #include <sgtty.h>
16: /*
17: troff1.c
18:
19: consume options, initialization, main loop,
20: input routines, escape function calling
21: */
22:
23: extern struct s *frame, *stk, *nxf;
24: extern struct s *ejl, *litlev;
25: extern filep ip;
26: extern filep offset;
27: extern filep nextb;
28:
29:
30: extern int stdi;
31: extern int waitf;
32: extern int nofeed;
33: extern int quiet;
34: extern int ptid;
35: extern int ascii;
36: extern int npn;
37: extern int xflg;
38: extern int stop;
39: extern char ibuf[IBUFSZ];
40: extern char xbuf[IBUFSZ];
41: extern char *ibufp;
42: extern char *xbufp;
43: extern char *eibuf;
44: extern char *xeibuf;
45: extern int cbuf[NC];
46: extern int *cp;
47: extern int *vlist;
48: extern int nx;
49: extern int mflg;
50: extern int ch;
51: extern int pto;
52: extern int pfrom;
53: extern int cps;
54: extern int chbits;
55: extern int ibf;
56: extern int ttyod;
57: extern struct sgttyb ttys;
58: extern int iflg;
59: extern int init;
60: extern int rargc;
61: extern char **argp;
62: extern char trtab[256];
63: extern int lgf;
64: extern int copyf;
65: extern int eschar;
66: extern int ch0;
67: extern int cwidth;
68: extern int nlflg;
69: extern int *ap;
70: extern int donef;
71: extern int nflush;
72: extern int nchar;
73: extern int rchar;
74: extern int nfo;
75: extern int ifile;
76: extern int fc;
77: extern int padc;
78: extern int tabc;
79: extern int dotc;
80: extern int raw;
81: extern int tabtab[NTAB];
82: extern char nextf[];
83: extern int nfi;
84: #ifdef NROFF
85: extern char termtab[];
86: extern int tti;
87: #endif
88: extern int ifl[NSO];
89: extern int ifi;
90: extern int pendt;
91: extern int flss;
92: extern int fi;
93: extern int lg;
94: extern char ptname[];
95: extern int print;
96: extern int nonumb;
97: extern int pnlist[];
98: extern int *pnp;
99: extern int nb;
100: extern int trap;
101: extern int tflg;
102: extern int ejf;
103: extern int lit;
104: extern int cc;
105: extern int c2;
106: extern int spread;
107: extern int gflag;
108: extern int oline[];
109: extern int *olinep;
110: extern int dpn;
111: extern int noscale;
112: extern char *unlkp;
113: extern int pts;
114: extern int level;
115: extern int ttysave;
116: extern int tdelim;
117: extern int dotT;
118: extern int tabch, ldrch;
119: extern int eqflg;
120: extern no_out;
121: extern int hflg;
122: #ifndef NROFF
123: extern char codetab[];
124: extern int spbits;
125: #endif
126: extern int xxx;
127: int stopmesg;
128: filep ipl[NSO];
129: long offl[NSO];
130: long ioff;
131: char *ttyp;
132: extern struct contab {
133: int rq;
134: union {
135: int (*f)();
136: unsigned mx;
137: }x;
138: }contab[NM];
139: int ms[] = {31,28,31,30,31,30,31,31,30,31,30,31};
140: #ifndef NROFF
141: int acctf;
142: #endif
143:
144: main(argc,argv)
145: int argc;
146: char **argv;
147: {
148: char *p, *q;
149: register i, j;
150: extern catch(), fpecatch(), kcatch();
151:
152: signal(SIGHUP,catch);
153: if(signal(SIGINT,catch) == SIG_IGN){
154: signal(SIGHUP,SIG_IGN);
155: signal(SIGINT,SIG_IGN);
156: signal(SIGQUIT,SIG_IGN);
157: }
158: signal(SIGFPE,fpecatch);
159: signal(SIGPIPE,catch);
160: signal(SIGTERM,kcatch);
161: init1(argv[0][0]);
162: options:
163: while(--argc > 0 && (++argv)[0][0]=='-')
164: switch(argv[0][1]){
165:
166: case 0:
167: goto start;
168: case 'i':
169: stdi++;
170: continue;
171: case 'q':
172: quiet++;
173: if(gtty(0, &ttys) >= 0)
174: ttysave = ttys.sg_flags;
175: continue;
176: case 'n':
177: npn = cnum(&argv[0][2]);
178: continue;
179: case 'p':
180: xflg = 0;
181: cps = cnum(&argv[0][2]);
182: continue;
183: case 'S':
184: stopmesg++;
185: continue;
186: case 's':
187: if(!(stop = cnum(&argv[0][2])))stop++;
188: continue;
189: case 'r':
190: vlist[findr(argv[0][2])] = cnum(&argv[0][3]);
191: continue;
192: case 'm':
193: p = &nextf[nfi];
194: q = &argv[0][2];
195: while((*p++ = *q++) != 0);
196: mflg++;
197: continue;
198: case 'o':
199: getpn(&argv[0][2]);
200: continue;
201: #ifdef NROFF
202: case 'h':
203: hflg++;
204: continue;
205: case 'z':
206: no_out++;
207: continue;
208: case 'e':
209: eqflg++;
210: continue;
211: case 'T':
212: p = &termtab[tti];
213: q = &argv[0][2];
214: if(!((*q) & 0177))continue;
215: while((*p++ = *q++) != 0);
216: dotT++;
217: continue;
218: #endif
219: #ifndef NROFF
220: case 'z':
221: no_out++;
222: case 'a':
223: ascii = 1;
224: nofeed++;
225: case 't':
226: ptid = 1;
227: continue;
228: case 'w':
229: waitf = 1;
230: continue;
231: case 'f':
232: nofeed++;
233: continue;
234: case 'x':
235: xflg = 0;
236: continue;
237: case 'b':
238: if(open(ptname,1) < 0)prstr("Busy.\n");
239: else prstr("Available.\n");
240: done3(0);
241: case 'g':
242: stop = ptid = gflag = 1;
243: dpn = 0;
244: continue;
245: #endif
246: default:
247: pto = cnum(&argv[0][1]);
248: continue;
249: }
250:
251: if(argv[0][0] == '+'){
252: pfrom = cnum(&argv[0][1]);
253: print = 0;
254: if(argc > 0)goto options;
255: }
256:
257: start:
258: argp = argv;
259: rargc = argc;
260: init2();
261: setjmp(sjbuf);
262: loop:
263: copyf = lgf = nb = nflush = nlflg = 0;
264: if(ip && (rbf0(ip)==0) && ejf && (frame->pframe <= ejl)){
265: nflush++;
266: trap = 0;
267: eject((struct s *)0);
268: goto loop;
269: }
270: i = getch();
271: if(pendt)goto lt;
272: if(lit && (frame <= litlev)){
273: lit--;
274: goto lt;
275: }
276: if((j = (i & CMASK)) == XPAR){
277: copyf++;
278: tflg++;
279: for(;(i & CMASK) != '\n';)pchar(i = getch());
280: tflg = 0;
281: copyf--;
282: goto loop;
283: }
284: if((j == cc) || (j == c2)){
285: if(j == c2)nb++;
286: copyf++;
287: while(((j=((i=getch()) & CMASK)) == ' ') ||
288: (j == '\t'));
289: ch = i;
290: copyf--;
291: control(getrq(),1);
292: flushi();
293: goto loop;
294: }
295: lt:
296: ch = i;
297: text();
298: goto loop;
299: }
300: catch(){
301: /*
302: prstr("Interrupt\n");
303: */
304: done3(01);
305: }
306: fpecatch(){
307: prstrfl("Floating Exception.\n");
308: signal(SIGFPE,fpecatch);
309: }
310: kcatch(){
311: signal(SIGTERM,SIG_IGN);
312: done3(01);
313: }
314: #ifndef NROFF
315: acctg() {
316: static char *acct_file = "/usr/adm/tracct";
317: acctf = open(acct_file,1);
318: setuid(getuid());
319: }
320: #endif
321: init1(a)
322: char a;
323: {
324: register char *p;
325: char *mktemp();
326: register i;
327:
328: #ifndef NROFF
329: acctg();/*open troff actg file while mode 4755*/
330: #endif
331: p = mktemp("/tmp/taXXXXX");
332: if(a == 'a')p = &p[5];
333: if((close(creat(p, 0600))) < 0){
334: prstr("Cannot create temp file.\n");
335: exit(-1);
336: }
337: ibf = open(p, 2);
338: for(i=256; --i;)trtab[i]=i;
339: trtab[UNPAD] = ' ';
340: mchbits();
341: if(a != 'a')unlkp = p;
342: }
343: init2()
344: {
345: register i,j;
346: extern int block;
347: extern char *setbrk();
348: extern char *ttyname();
349:
350: ttyod = 2;
351: if(((ttyp=ttyname(j=0)) != (char *)0) ||
352: ((ttyp=ttyname(j=1)) != (char *)0) ||
353: ((ttyp=ttyname(j=2)) != (char *)0)
354: );else ttyp = "notty";
355: iflg = j;
356: if(ascii)mesg(0);
357:
358: if((!ptid) && (!waitf)){
359: if((ptid = open(ptname,1)) < 0){
360: prstr("Typesetter busy.\n");
361: done3(-2);
362: }
363: }
364: ptinit();
365: for(i=NEV; i--;)write(ibf, (char *)&block, EVS*sizeof(int));
366: olinep = oline;
367: ibufp = eibuf = ibuf;
368: v.hp = init = 0;
369: ioff = 0;
370: v.nl = -1;
371: cvtime();
372: frame = stk = (struct s *)setbrk(DELTA);
373: dip = &d[0];
374: nxf = frame + 1;
375: nx = mflg;
376: }
377: cvtime(){
378:
379: long tt;
380: register i;
381:
382: time(&tt);
383: tt -= 3600*ZONE; /*5hrs for EST*/
384: v.dy = (tt/86400L) + 1;
385: v.dw = (v.dy + 3)%7 + 1;
386: for(v.yr=70;; v.yr++){
387: if((v.yr)%4)ms[1]=28;else ms[1]=29;
388: for(i=0;i<12;){
389: if(v.dy<=ms[i]){
390: v.mo = i+1;
391: return;
392: }
393: v.dy -= ms[i++];
394: }
395: }
396: }
397: cnum(a)
398: char *a;
399: {
400: register i;
401:
402: ibufp = a;
403: eibuf = MAXPTR;
404: i = atoi();
405: ch = 0;
406: return(i);
407: }
408: mesg(f)
409: int f;
410: {
411: static int mode;
412:
413: if(!f){
414: stat(ttyp,cbuf);
415: mode = ((struct stat *)(cbuf))->st_mode;
416: chmod(ttyp,mode & ~022);
417: }else{
418: chmod(ttyp,mode);
419: }
420: }
421: prstrfl(s)
422: char *s;
423: {
424: flusho();
425: prstr(s);
426: }
427: prstr(s)
428: char *s;
429: {
430: register i;
431: register char *j;
432:
433: j = s;
434: for(i=0;*s;i++)s++;
435: write(ttyod,j,i);
436: }
437: control(a,b)
438: int a,b;
439: {
440: register i,j;
441: extern filep boff();
442:
443: i = a;
444: if((i == 0) || ((j = findmn(i)) == -1))return(0);
445: if(contab[j].rq & MMASK){
446: nxf->nargs = 0;
447: if(b)collect();
448: flushi();
449: return(pushi(((filep)contab[j].x.mx)<<BLKBITS));
450: }else{
451: if(!b)return(0);
452: return((*contab[j].x.f)(0));
453: }
454: }
455:
456: getrq(){
457: register i,j;
458:
459: if(((i=getach()) == 0) ||
460: ((j=getach()) == 0))goto rtn;
461: i = PAIR(i,j);
462: rtn:
463: return(i);
464: }
465: getch(){
466: register int i, j, k;
467:
468: level++;
469: g0:
470: if(ch){
471: if(((i = ch) & CMASK) == '\n')nlflg++;
472: ch = 0;
473: level--;
474: return(i);
475: }
476:
477: if(nlflg){
478: level--;
479: return('\n');
480: }
481:
482: if((k = (i = getch0()) & CMASK) != ESC){
483: if(i & MOT)goto g2;
484: if(k == FLSS){
485: copyf++; raw++;
486: i = getch0();
487: if(!fi)flss = i;
488: copyf--; raw--;
489: goto g0;
490: }
491: if(k == RPT){
492: setrpt();
493: goto g0;
494: }
495: if(!copyf){
496: if((k == 'f') && lg && !lgf){
497: i = getlg(i);
498: goto g2;
499: }
500: if((k == fc) || (k == tabch) || (k == ldrch)){
501: if((i=setfield(k)) == 0)goto g0; else goto g2;
502: }
503: if(k == 010){
504: i = makem(-width(' ' | chbits));
505: goto g2;
506: }
507: }
508: goto g2;
509: }
510: k = (j = getch0()) & CMASK;
511: if(j & MOT){
512: i = j;
513: goto g2;
514: }
515: /*
516: if(k == tdelim){
517: i = TDELIM;
518: tdelim = IMP;
519: goto g2;
520: }
521: */
522: switch(k){
523:
524: case '\n': /*concealed newline*/
525: goto g0;
526: case 'n': /*number register*/
527: setn();
528: goto g0;
529: case '*': /*string indicator*/
530: setstr();
531: goto g0;
532: case '$': /*argument indicator*/
533: seta();
534: goto g0;
535: case '{': /*LEFT*/
536: i = LEFT;
537: goto gx;
538: case '}': /*RIGHT*/
539: i = RIGHT;
540: goto gx;
541: case '"': /*comment*/
542: while(((i=getch0()) & CMASK ) != '\n');
543: goto g2;
544: case ESC: /*double backslash*/
545: i = eschar;
546: goto gx;
547: case 'e': /*printable version of current eschar*/
548: i = PRESC;
549: goto gx;
550: case ' ': /*unpaddable space*/
551: i = UNPAD;
552: goto gx;
553: case '|': /*narrow space*/
554: i = NARSP;
555: goto gx;
556: case '^': /*half of narrow space*/
557: i = HNSP;
558: goto gx;
559: case '\'': /*\(aa*/
560: i = 0222;
561: goto gx;
562: case '`': /*\(ga*/
563: i = 0223;
564: goto gx;
565: case '_': /*\(ul*/
566: i = 0224;
567: goto gx;
568: case '-': /*current font minus*/
569: i = 0210;
570: goto gx;
571: case '&': /*filler*/
572: i = FILLER;
573: goto gx;
574: case 'c': /*to be continued*/
575: i = CONT;
576: goto gx;
577: case ':': /*lem's char*/
578: i = COLON;
579: goto gx;
580: case '!': /*transparent indicator*/
581: i = XPAR;
582: goto gx;
583: case 't': /*tab*/
584: i = '\t';
585: goto g2;
586: case 'a': /*leader (SOH)*/
587: i = LEADER;
588: goto g2;
589: case '%': /*ohc*/
590: i = OHC;
591: goto g2;
592: case '.': /*.*/
593: i = '.';
594: gx:
595: i = (j & ~CMASK) | i;
596: goto g2;
597: }
598: if(!copyf)
599: switch(k){
600:
601: case 'p': /*spread*/
602: spread++;
603: goto g0;
604: case '(': /*special char name*/
605: if((i=setch()) == 0)goto g0;
606: break;
607: case 's': /*size indicator*/
608: setps();
609: goto g0;
610: case 'f': /*font indicator*/
611: setfont(0);
612: goto g0;
613: case 'w': /*width function*/
614: setwd();
615: goto g0;
616: case 'v': /*vert mot*/
617: if(i = vmot())break;
618: goto g0;
619: case 'h': /*horiz mot*/
620: if(i = hmot())break;
621: goto g0;
622: case 'z': /*zero with char*/
623: i = setz();
624: break;
625: case 'l': /*hor line*/
626: setline();
627: goto g0;
628: case 'L': /*vert line*/
629: setvline();
630: goto g0;
631: case 'b': /*bracket*/
632: setbra();
633: goto g0;
634: case 'o': /*overstrike*/
635: setov();
636: goto g0;
637: case 'k': /*mark hor place*/
638: if((i=findr(getsn())) == -1)goto g0;
639: vlist[i] = v.hp;
640: goto g0;
641: case 'j': /*mark output hor place*/
642: if(!(i=getach()))goto g0;
643: i = (i<<BYTE) | JREG;
644: break;
645: case '0': /*number space*/
646: i = makem(width('0' | chbits));
647: break;
648: case 'x': /*extra line space*/
649: if(i = xlss())break;
650: goto g0;
651: case 'u': /*half em up*/
652: case 'r': /*full em up*/
653: case 'd': /*half em down*/
654: i = sethl(k);
655: break;
656: default:
657: i = j;
658: }
659: else{
660: ch0 = j;
661: i = eschar;
662: }
663: g2:
664: if((i & CMASK) == '\n'){
665: nlflg++;
666: v.hp = 0;
667: if(ip == 0)v.cd++;
668: }
669: if(!--level){
670: j = width(i);
671: v.hp += j;
672: cwidth = j;
673: }
674: return(i);
675: }
676: char ifilt[32] = {0,001,002,003,0,005,006,007,010,011,012};
677: getch0(){
678: register int i, j;
679:
680: if(ch0){i=ch0; ch0=0; return(i);}
681: if(nchar){nchar--; return(rchar);}
682:
683: again:
684: if(cp){
685: if((i = *cp++) == 0){
686: cp = 0;
687: goto again;
688: }
689: }else if(ap){
690: if((i = *ap++) == 0){
691: ap = 0;
692: goto again;
693: }
694: }else if(ip){
695: if(ip == -1)i = rdtty();
696: else i = rbf();
697: }else{
698: if(donef)done(0);
699: if(nx || ((ibufp >= eibuf) && (ibufp != MAXPTR))){
700: if(nfo)goto g1;
701: g0:
702: if(nextfile()){
703: if(ip)goto again;
704: if(ibufp < eibuf)goto g2;
705: }
706: g1:
707: nx = 0;
708: if((j=read(ifile,ibuf,IBUFSZ)) <= 0)goto g0;
709: ibufp = ibuf;
710: eibuf = ibuf + j;
711: if(ip)goto again;
712: }
713: g2:
714: i = *ibufp++ & 0177;
715: ioff++;
716: if(i >= 040)goto g4; else i = ifilt[i];
717: }
718: if(raw)return(i);
719: if((j = i & CMASK) == IMP)goto again;
720: if((i == 0) && !init)goto again;
721: g4:
722: if((copyf == 0) && ((i & ~BMASK) == 0) && ((i & CMASK) < 0370))
723: #ifndef NROFF
724: if(spbits && (i>31) && ((codetab[i-32] & 0200))) i |= spbits;
725: else
726: #endif
727: i |= chbits;
728: if((i & CMASK) == eschar)i = (i & ~CMASK) | ESC;
729: return(i);
730: }
731: nextfile(){
732: register char *p;
733:
734: n0:
735: if(ifile)close(ifile);
736: if(nx){
737: p = nextf;
738: if(*p != 0)goto n1;
739: }
740: if(ifi > 0){
741: if(popf())goto n0; /*popf error*/
742: return(1); /*popf ok*/
743: }
744: if(rargc-- <= 0)goto n2;
745: p = (argp++)[0];
746: n1:
747: if((p[0] == '-') && (p[1] == 0)){
748: ifile = 0;
749: }else if((ifile=open(p,0)) < 0){
750: prstr("Cannot open ");
751: prstr(p);
752: prstr("\n");
753: nfo -= mflg;
754: done(02);
755: }
756: nfo++;
757: v.cd = 0;
758: ioff = 0;
759: return(0);
760: n2:
761: if((nfo -= mflg) && !stdi)done(0);
762: nfo++;
763: v.cd = ifile = stdi = mflg = 0;
764: ioff = 0;
765: return(0);
766: }
767: popf(){
768: register i;
769: register char *p, *q;
770: extern char *ttyname();
771:
772: ioff = offl[--ifi];
773: ip = ipl[ifi];
774: if((ifile = ifl[ifi]) == 0){
775: p = xbuf;
776: q = ibuf;
777: ibufp = xbufp;
778: eibuf = xeibuf;
779: while(q < eibuf)*q++ = *p++;
780: return(0);
781: }
782: if((lseek(ifile,(long)(ioff & ~(IBUFSZ-1)),0) < 0) ||
783: ((i = read(ifile,ibuf,IBUFSZ)) < 0))return(1);
784: eibuf = ibuf + i;
785: ibufp = ibuf;
786: if(ttyname(ifile) == (char *)0)
787: if((ibufp = ibuf + (int)(ioff & (IBUFSZ-1))) >= eibuf)return(1);
788: return(0);
789: }
790: flushi(){
791: if(nflush)return;
792: ch = 0;
793: if((ch0 & CMASK) == '\n')nlflg++;
794: ch0 = 0;
795: copyf++;
796: while(!nlflg){
797: if(donef && (frame == stk))break;
798: getch();
799: }
800: copyf--;
801: v.hp = 0;
802: }
803: getach(){
804: register i;
805:
806: lgf++;
807: if(((i = getch()) & MOT) ||
808: ((i&CMASK) == ' ') ||
809: ((i&CMASK) == '\n')||
810: (i & 0200)){
811: ch = i;
812: i = 0;
813: }
814: lgf--;
815: return(i & 0177);
816: }
817: casenx(){
818: lgf++;
819: skip();
820: getname();
821: nx++;
822: nextfile();
823: nlflg++;
824: ip = 0;
825: ap = 0;
826: nchar = pendt = 0;
827: frame = stk;
828: nxf = frame + 1;
829: }
830: getname(){
831: register int i, j, k;
832:
833: lgf++;
834: for(k=0; k < (NS-1); k++){
835: if(((j=(i=getch()) & CMASK) <= ' ') ||
836: (j > 0176))break;
837: nextf[k] = j;
838: }
839: nextf[k] = 0;
840: ch = i;
841: lgf--;
842: return(nextf[0]);
843: }
844: caseso(){
845: register i;
846: register char *p, *q;
847:
848: lgf++;
849: nextf[0] = 0;
850: if(skip() || !getname() || ((i=open(nextf,0)) <0) || (ifi >= NSO)) {
851: prstr("can't open file ");
852: prstr(nextf);
853: prstr("\n");
854: done(02);
855: }
856: flushi();
857: ifl[ifi] = ifile;
858: ifile = i;
859: offl[ifi] = ioff;
860: ioff = 0;
861: ipl[ifi] = ip;
862: ip = 0;
863: nx++;
864: nflush++;
865: if(!ifl[ifi++]){
866: p = ibuf;
867: q = xbuf;
868: xbufp = ibufp;
869: xeibuf = eibuf;
870: while(p < eibuf)*q++ = *p++;
871: }
872: }
873:
874: casecf(){ /* copy file without change */
875: int fd, i, n;
876: char buf[OBUFSZ];
877:
878: flusho();
879: lgf++;
880: nextf[0] = 0;
881: if(skip() || !getname() || ((fd=open(nextf,0)) <0) || (ifi >= NSO)) {
882: prstr("can't open file ");
883: prstr(nextf);
884: prstr("\n");
885: done(02);
886: }
887: while ((n = read(fd, buf, OBUFSZ)) > 0)
888: for (i = 0; i < n; i++)
889: oput(buf[i]);
890: flusho();
891: close(fd);
892: }
893: getpn(a)
894: char *a;
895: {
896: register i, neg;
897: long atoi1();
898:
899: if((*a & 0177) == 0)return;
900: neg = 0;
901: ibufp = a;
902: eibuf = MAXPTR;
903: noscale++;
904: while((i = getch() & CMASK) != 0)switch(i){
905: case '+':
906: case ',':
907: continue;
908: case '-':
909: neg = MOT;
910: goto d2;
911: default:
912: ch = i;
913: d2:
914: i = atoi1();
915: if(nonumb)goto fini;
916: else{
917: *pnp++ = i | neg;
918: neg = 0;
919: if(pnp >= &pnlist[NPN-2]){
920: prstr("Too many page numbers\n");
921: done3(-3);
922: }
923: }
924: }
925: fini:
926: if(neg)*pnp++ = -2;
927: *pnp = -1;
928: ch = noscale = print = 0;
929: pnp = pnlist;
930: if(*pnp != -1)chkpn();
931: }
932: setrpt(){
933: register i, j;
934:
935: copyf++;raw++;
936: i = getch0();
937: copyf--;raw--;
938: if((i < 0) ||
939: (((j = getch0()) & CMASK) == RPT))return;
940: rchar = j;
941: nchar = i & BMASK;
942: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.