|
|
1.1 root 1:
2:
3:
4:
5: #include "stdio.h"
6: #include <sgtty.h>
7:
8: /*
9: * tunables
10: */
11: #define NAV 20
12: #define NINVOKE 5
13: #define LBSIZE 256
14: #define HOTZONE 10
15: /*
16: */
17:
18: #define SCAT 0
19: #define NOSCAT (!SCAT)
20: #define not_a_tty (!is_a_tty)
21:
22: #define NUL '\0'
23: #define EOT '\4'
24: #define BS '\b'
25: #define HT '\t'
26: #define NL '\n'
27: #define FF '\f'
28: #define CR '\r'
29: #define ESC '\33'
30: #define SP ' '
31: #define DEL '\177'
32: #define ASC 0177
33:
34: /*
35: * Kludge around a bug in
36: * sgtty.h file
37: */
38: #define CR2 0
39: #define FF1 0
40:
41:
42: typedef char *arg_t; /* argument string */
43: typedef char **argp_t; /* pointer to the above */
44:
45:
46: /*
47: * The flags structure that stores the command options.
48: */
49: struct flags {
50: int f_modes; /* mode bits */
51: long f_seekoff; /* seek into file before scatting */
52: unsigned f_length, /* page length */
53: f_width; /* page width */
54: int f_lineoff, /* starting scatting at this line */
55: f_inset; /* shift display window right */
56: };
57:
58: /* f_modes
59: */
60: #define M_TRUNC 01 /* truncate lines */
61: #define M_CTL 02 /* display unambiguously: */
62: #define M_CTLSP 04 /* map spaces to '_' */
63: #define M_CTLHT 010 /* print literal tabs, not ^I */
64: #define M_SQUASH 020 /* squash empty lines */
65: #define M_XPAND 040 /* expand tabs */
66: #define M_REMOTE 0100 /* don't hold pages */
67: #define M_NUMBER 0200 /* number input lines */
68: #define M_ONEFILE 0400 /* If one file, don't stop at EOF */
69:
70:
71: extern struct flags flags;
72:
73: /*
74: * The invoke structure defines what filenames invoke what options.
75: */
76: struct invoke {
77: char *i_suffix;
78: argp_t i_arglist;
79: };
80: /* Fix me */
81: extern struct invoke invoke[NINVOKE];
82: extern struct invoke *pinvoke;
83:
84: argp_t process( );
85: char *getenv( );
86: long atol( );
87:
88: extern struct sgttyb tty; /* saved state of tty */
89: extern struct sgttyb tty2;
90: extern struct sgttyb ttytek;
91: extern unsigned line; /* input line in current file */
92: extern unsigned column;
93: extern unsigned xcolumn;
94: extern int is_a_tty; /* 1 if output is_a_tty, else 0 */
95: extern int ttyzapped; /* !0 if tty modes were changed */
96: #include <signal.h>
97:
98:
99: extern char *getenv( );
100:
101: struct invoke *pinvoke = invoke;
102: struct invoke invoke[NINVOKE];
103: struct flags flags;
104: struct sgttyb tty;
105: struct sgttyb tty2;
106: struct sgttyb ttytek;
107: unsigned line;
108: unsigned column;
109: unsigned xcolumn;
110: int is_a_tty;
111: int ttyzapped;
112:
113: int filecount = 0;
114:
115: char *firstfile = NULL;
116: struct flags firstflags;
117:
118: main( argc, argv)
119: argp_t argv;
120: {
121: static struct flags flgs;
122: arg_t av[NAV];
123: char ibuf[BUFSIZ],
124: obuf[BUFSIZ];
125:
126: setbuf( stdin, ibuf);
127: setbuf( stdout, obuf);
128: init( &flgs);
129: envargs( av);
130:
131: process( av, &flgs, SCAT);
132: process( &argv[1], &flgs, SCAT);
133: if (filecount <= 1)
134: scat( NULL, &flgs);
135: fflush( stdout);
136: finis( 0);
137: }
138:
139:
140: init( fp)
141: register struct flags *fp;
142: {
143: int finis( );
144: register char *p;
145:
146: fp->f_length = 24;
147: fp->f_width = 80;
148: if (ioctl( 1, TIOCGETP, &tty) == 0) {
149: ++is_a_tty;
150: tty2 = tty;
151: tty2.sg_flags |= CBREAK;
152: tty2.sg_flags &= ~ECHO;
153: p = getenv("TERM");
154: if (p!=NULL && strcmp("4012", p)==0) {
155: ttytek = tty;
156: ttytek.sg_flags |= CR2;
157: ttytek.sg_flags &= ~FF1;
158: fp->f_length = 34;
159: fp->f_width = 72;
160: }
161: }
162: if (signal( SIGINT, SIG_IGN) == SIG_DFL)
163: signal( SIGINT, finis);
164: }
165:
166:
167: envargs( av)
168: argp_t av;
169: {
170: register fl;
171: register char *p;
172: register argp_t ap;
173:
174: ap = av;
175: *ap = NULL;
176: if ((p=getenv( "SCAT")) == NULL)
177: return;
178:
179: fl = 0;
180: while (*p)
181: switch (*p++) {
182: case HT:
183: case NL:
184: case SP:
185: fl = 0;
186: p[-1] = NUL;
187: break;
188: default:
189: if (fl)
190: break;
191: if (ap >= &av[NAV-1])
192: fatal( "too many env args", NULL);
193: *ap++ = &p[-1];
194: ++fl;
195: break;
196: }
197:
198: *ap = NULL;
199: }
200:
201:
202: argp_t
203: process( av, fp, fl)
204: register argp_t av;
205: register struct flags *fp;
206: {
207: register char *p;
208: struct flags junkflags;
209:
210: while (av[0]) {
211: if (av[0][0] != '-') {
212: if (fl != SCAT)
213: return (av);
214: scat( av++[0], fp);
215: ++filecount;
216: continue;
217: }
218: switch (av[0][1]) {
219: case 't':
220: fp->f_modes |= M_TRUNC;
221: break;
222: case 'c':
223: p = av[0]+2;
224: for (; ; ) {
225: switch (*p++) {
226: case NUL:
227: fp->f_modes |= M_CTL;
228: break;
229: case 't':
230: fp->f_modes |= M_CTLHT;
231: continue;
232: case 's':
233: fp->f_modes |= M_CTLSP;
234: continue;
235: default:
236: fatal( "no such sub-options ", av[0]);
237: }
238: break;
239: }
240: break;
241: case 's':
242: fp->f_modes |= M_SQUASH;
243: break;
244: case 'x':
245: fp->f_modes |= M_XPAND;
246: break;
247: case 'n':
248: fp->f_modes |= M_NUMBER;
249: break;
250: case '1':
251: fp->f_modes |= M_ONEFILE;
252: break;
253: case 'l':
254: fp->f_length = atol( &av[0][2]);
255: break;
256: case 'w':
257: fp->f_width = atol( &av[0][2]);
258: break;
259: case 'S':
260: fp->f_seekoff = atol( &av[0][2]);
261: break;
262: case 'b':
263: fp->f_lineoff = atol( &av[0][2]);
264: break;
265: case 'i':
266: fp->f_inset = atol( &av[0][2]);
267: break;
268: case 'r':
269: fp->f_modes |= M_REMOTE;
270: break;
271: case '.':
272: if (fl != SCAT)
273: return (av);
274: if (pinvoke == &invoke[NINVOKE])
275: fatal( "too many invokes", NULL);
276: pinvoke->i_suffix = &av[0][1];
277: pinvoke->i_arglist = &av[1];
278: ++pinvoke;
279: av = process( &av[1], &junkflags, NOSCAT);
280: continue;
281: case '-':
282: return (&av[1]);
283: default:
284: fatal( "no such switch ", av[0]);
285: }
286: ++av;
287: }
288: return (av);
289: }
290:
291:
292: fatal( arg1, arg2)
293: char *arg1,
294: *arg2;
295: {
296:
297: fflush( stdout);
298: prs( "scat: ");
299: prs( arg1);
300: prs( arg2);
301: prs( "\n");
302: finis( 1);
303: }
304:
305:
306: finis( status)
307: {
308:
309: signal( SIGINT, SIG_IGN);
310: if (ttyzapped)
311: ioctl( 1, TIOCSETP, &tty);
312: _exit( status);
313: }
314:
315:
316: #include <errno.h>
317:
318:
319: char newline[] = "\n";
320:
321: int (*getline)( ),
322: getl1( ), getl2( ), getl3( );
323: puts1( ), puts2( );
324:
325: scat( file, fp)
326: register char *file;
327: struct flags *fp;
328: {
329: register i;
330: register char *p;
331: struct invoke *ip;
332: FILE *creopen( );
333: char *nconv( );
334: extern errno;
335: int (*puts)( );
336: char c;
337: int len;
338: static int norecurs = 0;
339:
340: if ( (filecount == 0) && (file != NULL) ) {
341: firstfile = file;
342: firstflags = *fp;
343: return;
344: } else if ( (filecount == 1) && (norecurs == 0) ) {
345: norecurs = 1;
346: if ( file != NULL ) {
347: firstflags.f_modes &= ~M_ONEFILE;
348: fp->f_modes &= ~M_ONEFILE;
349: }
350: scat( firstfile, &firstflags);
351: if ( file == NULL )
352: return;
353: }
354:
355: flags = *fp;
356:
357: if (file != NULL) {
358: if (creopen( file) == NULL) {
359: p = "can't find ";
360: if (errno == EACCES)
361: p = "no permission on ";
362: fatal( p, file);
363: }
364: }
365: else
366: file = "[stdin].";
367:
368: for (p=file; *p++; )
369: ;
370: do {
371: if (*--p == '.') {
372: for (ip=invoke; ip<pinvoke; ++ip)
373: if (strcmp( p, ip->i_suffix) == 0)
374: process( ip->i_arglist, &flags, NOSCAT);
375: break;
376: }
377: } while (p > file);
378:
379: if (flags.f_modes & M_NUMBER)
380: flags.f_width -= 8;
381: flags.f_width += flags.f_inset;
382: if (flags.f_width-8 >= LBSIZE)
383: fatal( "page width don't jive", NULL);
384: getline = getl1;
385: if (flags.f_modes & M_TRUNC)
386: getline = getl2;
387: if (flags.f_modes & M_CTL)
388: getline = getl3;
389: puts = puts1;
390: if (flags.f_modes & M_XPAND)
391: puts = puts2;
392:
393: if (flags.f_seekoff)
394: lseek( 0, flags.f_seekoff, 0);
395: for (line=1; line<flags.f_lineoff; ++line)
396: while ((i=getchar( )) != NL)
397: if (i < 0)
398: return;
399:
400: i = flags.f_length;
401: while (len=page( i, puts)) {
402: if ( (len < i) && (flags.f_modes&M_ONEFILE) ) {
403: putchar( NL);
404: break;
405: }
406: if (is_a_tty && (flags.f_modes&M_REMOTE)==0) {
407: fflush( stdout);
408: if (ttyzapped == 0) {
409: ++ttyzapped;
410: ioctl( 1, TIOCSETN, &tty2);
411: }
412: for (; ; ) {
413: if (read( 2, &c, 1) <= 0)
414: finis( 0);
415: switch (c) {
416: case EOT:
417: case 'q':
418: prs( newline);
419: finis( 0);
420: case NL:
421: i = flags.f_length;
422: break;
423: case '/':
424: if (ttytek.sg_flags)
425: goto dfault;
426: i = flags.f_length/2 + 1;
427: break;
428: case SP:
429: if (ttytek.sg_flags)
430: goto dfault;
431: i = 1;
432: break;
433: case 'n':
434: prs( newline);
435: return;
436: case 'f':
437: prs( newline);
438: prs( file);
439: prs( nconv( line-1));
440: continue;
441: default:
442: dfault:
443: prs( "\7");
444: continue;
445: }
446: break;
447: }
448: }
449: putchar( NL);
450: }
451: }
452:
453:
454: page( length, puts)
455: int (*puts)( );
456: {
457: register char *p;
458: register i,
459: nflg;
460: int l;
461: static char lbuf[LBSIZE];
462: char *nconv( );
463:
464: nflg = 0;
465: l = length;
466: do {
467: p = lbuf;
468: i = (*getline)( p);
469: if (i < 0)
470: break;
471:
472: p += flags.f_inset;
473: if (p >= &lbuf[i] && flags.f_modes&M_SQUASH) {
474: ++l;
475: if (lbuf[i] == NL)
476: ++line;
477: continue;
478: }
479:
480: if (l != length)
481: putchar( NL);
482: else if (ttytek.sg_flags)
483: erase( );
484: column = xcolumn = 0;
485: if (flags.f_modes & M_NUMBER)
486: if (nflg)
487: (*puts)( " ", 8);
488: else {
489: (*puts)( nconv( line), 5);
490: (*puts)( ": ", 3);
491: ++nflg;
492: }
493: if (lbuf[i] == NL) {
494: ++line;
495: nflg = 0;
496: }
497: if ((*puts)( p, &lbuf[i]-p))
498: continue;
499: } while (--l);
500:
501: return (length - l);
502: }
503:
504:
505:
506:
507: getl1( lbuf)
508: register char *lbuf;
509: {
510: register i,
511: c;
512:
513: i = 0;
514: while ((c=cread( )) >= 0) {
515: if (c == NL)
516: break;
517: if (c == HT)
518: if ((i|7)+1 <= flags.f_width) {
519: do
520: lbuf[i++] = SP;
521: while (i & 7);
522: continue;
523: }
524: else
525: ; /* overflow */
526: else if (c == FF)
527: continue;
528: else if (i < flags.f_width) {
529: lbuf[i++] = c;
530: continue;
531: }
532:
533: /* line overflow condition */
534: i = overflow( lbuf, i, c);
535: c = NUL;
536: break;
537: }
538:
539: lbuf[i] = c;
540: if (i==0 && c<0)
541: return (-1);
542: return (i);
543: }
544:
545:
546: getl2( lbuf)
547: register char *lbuf;
548: {
549: register i,
550: c;
551:
552: i = 0;
553: while ((c=cread( )) >= 0) {
554: if (c == NL)
555: break;
556: if (c == HT)
557: do {
558: if (i < flags.f_width)
559: lbuf[i] = SP;
560: } while (++i & 7);
561: else if (c == FF)
562: continue;
563: else if (i < flags.f_width)
564: lbuf[i++] = c;
565: else
566: i += 2;
567: if (i > flags.f_width) {
568: while ((c=cread( )) >= 0)
569: if (c == NL)
570: break;
571: i = flags.f_width;
572: break;
573: }
574: }
575:
576: lbuf[i] = c;
577: if (i==0 && c<0)
578: return (-1);
579: return (i);
580: }
581:
582:
583: getl3( lbuf)
584: register char *lbuf;
585: {
586: register i,
587: c;
588:
589: i = 0;
590: while ((c=getchar( )) >= 0) {
591: if (c == NL)
592: break;
593: if (c & ~ASC) {
594: lbuf[i++] = '~';
595: c &= ASC;
596: }
597: if (c==HT && flags.f_modes&M_CTLHT)
598: do {
599: if (i < flags.f_width)
600: lbuf[i] = SP;
601: } while (++i & 7);
602: else if (c<SP || c==DEL) {
603: lbuf[i++] = '^';
604: lbuf[i++] = c + '@';
605: } else {
606: switch (c) {
607: case SP:
608: if (flags.f_modes & M_CTLSP)
609: c = '_';
610: break;
611: case '_':
612: if ((flags.f_modes&M_CTLSP) == 0)
613: break;
614: case '~':
615: case '^':
616: case '\\':
617: lbuf[i++] = '\\';
618: break;
619: }
620: lbuf[i++] = c;
621: }
622: if (i+3 >= flags.f_width) {
623: lbuf[i++] = '\\';
624: c = NUL;
625: break;
626: }
627: }
628:
629: lbuf[i] = c;
630: if (i==0 && c<0)
631: return (-1);
632: return (i);
633: }
634:
635:
636: #define alphanumeric( c) (alphnum[c>>3&017] & bitmask[c&7])
637: char alphnum[] = {
638: 0000, 0000, 0000, 0000, 0000, 0000, 0377, 0300,
639: 0177, 0377, 0377, 0351, 0177, 0377, 0377, 0340
640: };
641: char bitmask[] = {
642: 0200, 0100, 0040, 0020, 0010, 0004, 0002, 0001
643: };
644:
645:
646: overflow( lbuf, pos, c)
647: register char *lbuf;
648: register pos;
649: {
650: register i;
651:
652: uncread( c);
653: if (pos == flags.f_width) /* ***THINK ABOUT THOSE LIMITS*** */
654: c = uncread( lbuf[--pos]);
655:
656: for (i=pos; i>HOTZONE && i>pos-HOTZONE; ) {
657: --i;
658: if (!alphanumeric( lbuf[i])) {
659: for (++i; pos>i; )
660: uncread( lbuf[--pos]);
661: break;
662: }
663: }
664:
665: lbuf[pos++] = '\\';
666: return (pos);
667: }
668:
669:
670: puts1( p, n)
671: register char *p;
672: register n;
673: {
674: register i;
675:
676: while (--n >= 0)
677: if (*p++ == SP)
678: ++xcolumn;
679: else {
680: if (xcolumn > column) {
681: while (i=(column|7)+1, i<=xcolumn) {
682: putchar( HT);
683: column = i;
684: }
685: while (column < xcolumn) {
686: putchar( SP);
687: ++column;
688: }
689: }
690: putchar( p[-1]);
691: xcolumn = ++column;
692: }
693:
694: return (0);
695: }
696:
697:
698: puts2( p, n)
699: register char *p;
700: register n;
701: {
702:
703: while (--n >= 0)
704: putchar( *p++);
705:
706: return (0);
707: }
708:
709:
710:
711:
712: #define CQSIZE 256
713: #define CQMASK (CQSIZE-1)
714:
715: #define chr( i) (cbuf[i&CQMASK])
716:
717:
718: unsigned get,
719: cnt,
720: cntmax,
721: eof;
722: char cbuf[CQSIZE];
723:
724:
725: FILE *
726: creopen( file)
727: char *file;
728: {
729: register char *p;
730: FILE *freopen( );
731:
732: cnt = 0;
733: cntmax = 0;
734: eof = 0;
735: for (p=cbuf; p<cbuf+CQSIZE; )
736: *p++ = NUL;
737: return (freopen( file, "r", stdin));
738: }
739:
740:
741: uncread( c)
742: {
743:
744: chr( --get) = c;
745: ++cnt, ++cntmax;
746: return (c);
747: }
748:
749:
750:
751:
752: #define CQSIZE 256
753: #define CQMASK (CQSIZE-1)
754:
755:
756:
757:
758: cread( )
759: {
760: register c;
761:
762: if ( ! eof)
763: while (cntmax < CQSIZE-HOTZONE) {
764: if ((c=getchar( )) < 0) {
765: ++eof;
766: break;
767: }
768: switch (c &= ASC) {
769: case BS:
770: if (cnt && cbuf[get+cnt-1&CQMASK] != NL)
771: --cnt;
772: continue;
773: case ESC:
774: c = '$';
775: goto dfault;
776: case CR:
777: while (cnt && cbuf[get+cnt-1&CQMASK] != NL)
778: --cnt;
779: continue;
780: case NL:
781: cnt = cntmax;
782: goto dfault;
783: case '_':
784: switch (cbuf[get+cnt&CQMASK]) {
785: case NUL:
786: case SP:
787: goto dfault;
788: }
789: break;
790: case SP:
791: if (cbuf[get+cnt&CQMASK])
792: break;
793: default:
794: dfault:
795: cbuf[get+cnt&CQMASK] = c;
796: break;
797: }
798: if (++cnt > cntmax)
799: ++cntmax;
800: }
801:
802: if (eof) {
803: if (cntmax == 0)
804: return (-1);
805: }
806: --cnt;
807: --cntmax;
808: c = cbuf[get&CQMASK];
809: cbuf[get++&CQMASK] = 0;
810: return (c);
811: }
812:
813:
814:
815:
816: prs( s)
817: register char *s;
818: {
819: register char *p;
820:
821: if ((p=s) == NULL)
822: return;
823: while (*p++)
824: ;
825: write( 2, s, p-s-1);
826: }
827:
828:
829: long
830: atol( p)
831: char *p;
832: {
833: register c,
834: radix,
835: pow;
836: long l;
837:
838: radix = 10;
839: if (*p == '0')
840: radix = 8;
841: pow = 0;
842: l = 0;
843:
844: for (; ; ) {
845: c = *p++;
846: if (c == 'b') {
847: pow = 9;
848: break;
849: }
850: if (c == 'k') {
851: pow = 10;
852: break;
853: }
854: c -= '0';
855: if ((unsigned)c > 9)
856: break;
857: l = l*radix + c;
858: }
859:
860: return (l << pow);
861: }
862:
863:
864: char *
865: nconv( u)
866: register unsigned u;
867: {
868: register char *p;
869: static char nbuf[] = "12345 ";
870:
871: for (p=nbuf+5;
872: p>nbuf;
873: u=u/10)
874: if (u)
875: *--p = u%10 + '0';
876: else
877: *--p = ' ';
878:
879: return (p);
880: }
881:
882:
883: erase( )
884: {
885: register char *p;
886:
887: fflush( stdout);
888: ++ttyzapped;
889: ioctl( 1, TIOCSETP, &ttytek);
890: for (p="\33\f\r\r\r"; *p; )
891: putchar( *p++);
892: fflush( stdout);
893: ioctl( 1, TIOCSETP, &tty);
894: ttyzapped = 0;
895: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.