|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 12996 (0x32c4) Types: TextFile Notes: UNIX file Names: »scat.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦f4b8d8c84⟧ UNIX Filesystem └─ ⟦this⟧ »cmd/scat.c«
#include "stdio.h" #include <sgtty.h> /* * tunables */ #define NAV 20 #define NINVOKE 5 #define LBSIZE 256 #define HOTZONE 10 /* */ #define SCAT 0 #define NOSCAT (!SCAT) #define not_a_tty (!is_a_tty) #define NUL '\0' #define EOT '\4' #define BS '\b' #define HT '\t' #define NL '\n' #define FF '\f' #define CR '\r' #define ESC '\33' #define SP ' ' #define DEL '\177' #define ASC 0177 /* * Kludge around a bug in * sgtty.h file */ #define CR2 0 #define FF1 0 typedef char *arg_t; /* argument string */ typedef char **argp_t; /* pointer to the above */ /* * The flags structure that stores the command options. */ struct flags { int f_modes; /* mode bits */ long f_seekoff; /* seek into file before scatting */ unsigned f_length, /* page length */ f_width; /* page width */ int f_lineoff, /* starting scatting at this line */ f_inset; /* shift display window right */ }; /* f_modes */ #define M_TRUNC 01 /* truncate lines */ #define M_CTL 02 /* display unambiguously: */ #define M_CTLSP 04 /* map spaces to '_' */ #define M_CTLHT 010 /* print literal tabs, not ^I */ #define M_SQUASH 020 /* squash empty lines */ #define M_XPAND 040 /* expand tabs */ #define M_REMOTE 0100 /* don't hold pages */ #define M_NUMBER 0200 /* number input lines */ extern struct flags flags; /* * The invoke structure defines what filenames invoke what options. */ struct invoke { char *i_suffix; argp_t i_arglist; }; /* Fix me */ extern struct invoke invoke[NINVOKE]; extern struct invoke *pinvoke; argp_t process( ); char *getenv( ); long atol( ); extern struct sgttyb tty; /* saved state of tty */ extern struct sgttyb tty2; extern struct sgttyb ttytek; extern unsigned line; /* input line in current file */ extern unsigned column; extern unsigned xcolumn; extern int is_a_tty; /* 1 if output is_a_tty, else 0 */ extern int ttyzapped; /* !0 if tty modes were changed */ #include <signal.h> extern char *getenv( ); struct invoke *pinvoke = invoke; struct invoke invoke[NINVOKE]; struct flags flags; struct sgttyb tty; struct sgttyb tty2; struct sgttyb ttytek; unsigned line; unsigned column; unsigned xcolumn; int is_a_tty; int ttyzapped; int filecount; main( argc, argv) argp_t argv; { static struct flags flgs; arg_t av[NAV]; char ibuf[BUFSIZ], obuf[BUFSIZ]; setbuf( stdin, ibuf); setbuf( stdout, obuf); init( &flgs); envargs( av); process( av, &flgs, SCAT); process( &argv[1], &flgs, SCAT); if (filecount == 0) scat( (char *)0, &flgs); fflush( stdout); finis( 0); } init( fp) register struct flags *fp; { int finis( ); register char *p; fp->f_length = 24; fp->f_width = 80; if (ioctl( 1, TIOCGETP, &tty) == 0) { ++is_a_tty; tty2 = tty; tty2.sg_flags |= CBREAK; tty2.sg_flags &= ~ECHO; p = getenv("TERM"); if (p!=NULL && strcmp("4012", p)==0) { ttytek = tty; ttytek.sg_flags |= CR2; ttytek.sg_flags &= ~FF1; fp->f_length = 34; fp->f_width = 72; } } if (signal( SIGINT, SIG_IGN) == SIG_DFL) signal( SIGINT, finis); } envargs( av) argp_t av; { register fl; register char *p; register argp_t ap; ap = av; *ap = NULL; if ((p=getenv( "SCAT")) == NULL) return; fl = 0; while (*p) switch (*p++) { case HT: case NL: case SP: fl = 0; p[-1] = NUL; break; default: if (fl) break; if (ap >= &av[NAV-1]) fatal( "too many env args", (char *)0); *ap++ = &p[-1]; ++fl; break; } *ap = NULL; } argp_t process( av, fp, fl) register argp_t av; register struct flags *fp; { register char *p; struct flags junkflags; while (av[0]) { if (av[0][0] != '-') { if (fl != SCAT) return (av); scat( av++[0], fp); ++filecount; continue; } switch (av[0][1]) { case 't': fp->f_modes |= M_TRUNC; break; case 'c': p = av[0]+2; for (; ; ) { switch (*p++) { case NUL: fp->f_modes |= M_CTL; break; case 't': fp->f_modes |= M_CTLHT; continue; case 's': fp->f_modes |= M_CTLSP; continue; default: fatal( "no such sub-options ", av[0]); } break; } break; case 's': fp->f_modes |= M_SQUASH; break; case 'x': fp->f_modes |= M_XPAND; break; case 'n': fp->f_modes |= M_NUMBER; break; case 'l': fp->f_length = atol( &av[0][2]); break; case 'w': fp->f_width = atol( &av[0][2]); break; case 'S': fp->f_seekoff = atol( &av[0][2]); break; case 'b': fp->f_lineoff = atol( &av[0][2]); break; case 'i': fp->f_inset = atol( &av[0][2]); break; case 'r': fp->f_modes |= M_REMOTE; break; case '.': if (fl != SCAT) return (av); if (pinvoke == &invoke[NINVOKE]) fatal( "too many invokes", (char *)0); pinvoke->i_suffix = &av[0][1]; pinvoke->i_arglist = &av[1]; ++pinvoke; av = process( &av[1], &junkflags, NOSCAT); continue; case '-': return (&av[1]); default: fatal( "no such switch ", av[0]); } ++av; } return (av); } fatal( arg1, arg2) char *arg1, *arg2; { fflush( stdout); prs( "scat: "); prs( arg1); prs( arg2); prs( "\n"); finis( 1); } finis( status) { signal( SIGINT, SIG_IGN); if (ttyzapped) ioctl( 1, TIOCSETP, &tty); _exit( status); } #include <errno.h> char newline[] = "\n"; int (*getline)( ), getl1( ), getl2( ), getl3( ); puts1( ), puts2( ); scat( file, fp) register char *file; struct flags *fp; { register i; register char *p; struct invoke *ip; FILE *creopen( ); char *nconv( ); extern errno; int (*puts)( ); char c; flags = *fp; if (file) { if (creopen( file) == NULL) { p = "can't find "; if (errno == EACCES) p = "no permission on "; fatal( p, file); } } else file = "[stdin]."; for (p=file; *p++; ) ; do { if (*--p == '.') { for (ip=invoke; ip<pinvoke; ++ip) if (strcmp( p, ip->i_suffix) == 0) process( ip->i_arglist, &flags, NOSCAT); break; } } while (p > file); if (flags.f_modes & M_NUMBER) flags.f_width -= 8; flags.f_width += flags.f_inset; if (flags.f_width-8 >= LBSIZE) fatal( "page width don't jive", (char *)0); getline = getl1; if (flags.f_modes & M_TRUNC) getline = getl2; if (flags.f_modes & M_CTL) getline = getl3; puts = puts1; if (flags.f_modes & M_XPAND) puts = puts2; if (flags.f_seekoff) lseek( 0, flags.f_seekoff, 0); for (line=1; line<flags.f_lineoff; ++line) while ((i=getchar( )) != NL) if (i < 0) return; i = flags.f_length; while (page( i, puts)) { if (is_a_tty && (flags.f_modes&M_REMOTE)==0) { fflush( stdout); if (ttyzapped == 0) { ++ttyzapped; ioctl( 1, TIOCSETN, &tty2); } for (; ; ) { if (read( 2, &c, 1) <= 0) finis( 0); switch (c) { case EOT: case 'q': prs( newline); finis( 0); case NL: i = flags.f_length; break; case '/': if (ttytek.sg_flags) goto dfault; i = flags.f_length/2 + 1; break; case SP: if (ttytek.sg_flags) goto dfault; i = 1; break; case 'n': prs( newline); return; case 'f': prs( newline); prs( file); prs( nconv( line-1)); continue; default: dfault: prs( "\7"); continue; } break; } } putchar( NL); } } page( length, puts) int (*puts)( ); { register char *p; register i, nflg; int l; static char lbuf[LBSIZE]; char *nconv( ); nflg = 0; l = length; do { p = lbuf; i = (*getline)( p); if (i < 0) break; p += flags.f_inset; if (p >= &lbuf[i] && flags.f_modes&M_SQUASH) { ++l; if (lbuf[i] == NL) ++line; continue; } if (l != length) putchar( NL); else if (ttytek.sg_flags) erase( ); column = xcolumn = 0; if (flags.f_modes & M_NUMBER) if (nflg) (*puts)( " ", 8); else { (*puts)( nconv( line), 5); (*puts)( ": ", 3); ++nflg; } if (lbuf[i] == NL) { ++line; nflg = 0; } if ((*puts)( p, &lbuf[i]-p)) continue; } while (--l); return (length - l); } getl1( lbuf) register char *lbuf; { register i, c; i = 0; while ((c=cread( )) >= 0) { if (c == NL) break; if (c == HT) if ((i|7)+1 <= flags.f_width) { do lbuf[i++] = SP; while (i & 7); continue; } else ; /* overflow */ else if (c == FF) continue; else if (i < flags.f_width) { lbuf[i++] = c; continue; } /* line overflow condition */ i = overflow( lbuf, i, c); c = NUL; break; } lbuf[i] = c; if (i==0 && c<0) return (-1); return (i); } getl2( lbuf) register char *lbuf; { register i, c; i = 0; while ((c=cread( )) >= 0) { if (c == NL) break; if (c == HT) do { if (i < flags.f_width) lbuf[i] = SP; } while (++i & 7); else if (c == FF) continue; else if (i < flags.f_width) lbuf[i++] = c; else i += 2; if (i > flags.f_width) { while ((c=cread( )) >= 0) if (c == NL) break; i = flags.f_width; break; } } lbuf[i] = c; if (i==0 && c<0) return (-1); return (i); } getl3( lbuf) register char *lbuf; { register i, c; i = 0; while ((c=getchar( )) >= 0) { if (c == NL) break; if (c & ~ASC) { lbuf[i++] = '~'; c &= ASC; } if (c==HT && flags.f_modes&M_CTLHT) do { if (i < flags.f_width) lbuf[i] = SP; } while (++i & 7); else if (c<SP || c==DEL) { lbuf[i++] = '^'; lbuf[i++] = c + '@'; } else { switch (c) { case SP: if (flags.f_modes & M_CTLSP) c = '_'; break; case '_': if ((flags.f_modes&M_CTLSP) == 0) break; case '~': case '^': case '\\': lbuf[i++] = '\\'; break; } lbuf[i++] = c; } if (i+3 >= flags.f_width) { lbuf[i++] = '\\'; c = NUL; break; } } lbuf[i] = c; if (i==0 && c<0) return (-1); return (i); } #define alphanumeric( c) (alphnum[c>>3&017] & bitmask[c&7]) char alphnum[] = { 0000, 0000, 0000, 0000, 0000, 0000, 0377, 0300, 0177, 0377, 0377, 0351, 0177, 0377, 0377, 0340 }; char bitmask[] = { 0200, 0100, 0040, 0020, 0010, 0004, 0002, 0001 }; overflow( lbuf, pos, c) register char *lbuf; register pos; { register i; uncread( c); if (pos == flags.f_width) /* ***THINK ABOUT THOSE LIMITS*** */ c = uncread( lbuf[--pos]); for (i=pos; i>HOTZONE && i>pos-HOTZONE; ) { --i; if (!alphanumeric( lbuf[i])) { for (++i; pos>i; ) uncread( lbuf[--pos]); break; } } lbuf[pos++] = '\\'; return (pos); } puts1( p, n) register char *p; register n; { register i; while (--n >= 0) if (*p++ == SP) ++xcolumn; else { if (xcolumn > column) { while (i=(column|7)+1, i<=xcolumn) { putchar( HT); column = i; } while (column < xcolumn) { putchar( SP); ++column; } } putchar( p[-1]); xcolumn = ++column; } return (0); } puts2( p, n) register char *p; register n; { while (--n >= 0) putchar( *p++); return (0); } #define CQSIZE 256 #define CQMASK (CQSIZE-1) #define chr( i) (cbuf[i&CQMASK]) unsigned get, cnt, cntmax, eof; char cbuf[CQSIZE]; FILE * creopen( file) char *file; { register char *p; FILE *freopen( ); cnt = 0; cntmax = 0; eof = 0; for (p=cbuf; p<cbuf+CQSIZE; ) *p++ = NUL; return (freopen( file, "r", stdin)); } uncread( c) { chr( --get) = c; ++cnt, ++cntmax; return (c); } #define CQSIZE 256 #define CQMASK (CQSIZE-1) cread( ) { register c; if ( ! eof) while (cntmax < CQSIZE-HOTZONE) { if ((c=getchar( )) < 0) { ++eof; break; } switch (c &= ASC) { case BS: if (cnt && cbuf[get+cnt-1&CQMASK] != NL) --cnt; continue; case ESC: c = '$'; goto dfault; case CR: while (cnt && cbuf[get+cnt-1&CQMASK] != NL) --cnt; continue; case NL: cnt = cntmax; goto dfault; case '_': switch (cbuf[get+cnt&CQMASK]) { case NUL: case SP: goto dfault; } break; case SP: if (cbuf[get+cnt&CQMASK]) break; default: dfault: cbuf[get+cnt&CQMASK] = c; break; } if (++cnt > cntmax) ++cntmax; } if (eof) { if (cntmax == 0) return (-1); } --cnt; --cntmax; c = cbuf[get&CQMASK]; cbuf[get++&CQMASK] = 0; return (c); } prs( s) register char *s; { register char *p; if ((p=s) == NULL) return; while (*p++) ; write( 2, s, p-s-1); } long atol( p) char *p; { register c, radix, pow; long l; radix = 10; if (*p == '0') radix = 8; pow = 0; l = 0; for (; ; ) { c = *p++; if (c == 'b') { pow = 9; break; } if (c == 'k') { pow = 10; break; } c -= '0'; if ((unsigned)c > 9) break; l = l*radix + c; } return (l << pow); } char * nconv( u) register unsigned u; { register char *p; static char nbuf[] = "12345 "; for (p=nbuf+5; p>nbuf; u=u/10) if (u) *--p = u%10 + '0'; else *--p = ' '; return (p); } erase( ) { register char *p; fflush( stdout); ++ttyzapped; ioctl( 1, TIOCSETP, &ttytek); for (p="\33\f\r\r\r"; *p; ) putchar( *p++); fflush( stdout); ioctl( 1, TIOCSETP, &tty); ttyzapped = 0; }