BSD 3 release
[unix-history] / usr / src / cmd / col.c
# include <stdio.h>
# define PL 256
# define ESC '\033'
# define RLF '\013'
# define SI '\017'
# define SO '\016'
# define GREEK 0200
# define LINELN 800
char *page[PL];
char lbuff [LINELN], *line;
int bflag, hflag, fflag;
int half;
int cp, lp;
int ll, llh, mustwr;
int pcp = 0;
char *pgmname;
char *strcpy();
main (argc, argv)
int argc; char **argv;
{
int i;
int greek;
register int c;
char fbuff[BUFSIZ];
setbuf (stdout, fbuff);
pgmname = argv[0];
for (i = 1; i < argc; i++) {
register char *p;
if (*argv[i] != '-') {
fprintf (stderr, "%s: bad option %s\n",
pgmname, argv[i]);
exit (2);
}
for (p = argv[i]+1; *p; p++) {
switch (*p) {
case 'b':
bflag++;
break;
case 'h':
hflag++;
break;
case 'f':
fflag++;
break;
default:
fprintf (stderr, "%s: bad option letter %c\n",
pgmname, *p);
exit (2);
}
}
}
for (ll=0; ll<PL; ll++)
page[ll] = 0;
cp = 0;
ll = 0;
greek = 0;
mustwr = PL;
line = lbuff;
while ((c = getchar()) != EOF) {
switch (c) {
case '\n':
incr();
incr();
cp = 0;
continue;
case '\0':
continue;
case ESC:
c = getchar();
switch (c) {
case '7': /* reverse full line feed */
decr();
decr();
break;
case '8': /* reverse half line feed */
if (fflag)
decr();
else {
if (--half < -1) {
decr();
decr();
half += 2;
}
}
break;
case '9': /* forward half line feed */
if (fflag)
incr();
else {
if (++half > 0) {
incr();
incr();
half -= 2;
}
}
break;
}
continue;
case SO:
greek = GREEK;
continue;
case SI:
greek = 0;
continue;
case RLF:
decr();
decr();
continue;
case '\r':
cp = 0;
continue;
case '\t':
cp = (cp + 8) & -8;
continue;
case '\b':
if (cp > 0)
cp--;
continue;
case ' ':
cp++;
continue;
default:
c &= 0177;
if (c > 040 && c < 0177) { /* if printable */
outc(c | greek);
cp++;
}
continue;
}
}
for (i=0; i<PL; i++)
if (page[(mustwr+i)%PL] != 0)
emit (page[(mustwr+i) % PL], mustwr+i-PL);
emit (" ", (llh + 1) & -2);
return 0;
}
outc (c)
register char c;
{
if (lp > cp) {
line = lbuff;
lp = 0;
}
while (lp < cp) {
switch (*line) {
case '\0':
*line = ' ';
lp++;
break;
case '\b':
lp--;
break;
default:
lp++;
}
line++;
}
while (*line == '\b') {
line += 2;
}
if (bflag || *line == '\0' || *line == ' ')
*line = c;
else {
register char c1, c2, c3;
c1 = *++line;
*line++ = '\b';
c2 = *line;
*line++ = c;
while (c1) {
c3 = *line;
*line++ = c1;
c1 = c2;
c2 = c3;
}
lp = 0;
line = lbuff;
}
}
store (lno)
{
char *malloc();
lno %= PL;
if (page[lno] != 0)
free (page[lno]);
page[lno] = malloc((unsigned)strlen(lbuff) + 2);
if (page[lno] == 0) {
fprintf (stderr, "%s: no storage\n", pgmname);
exit (2);
}
strcpy (page[lno],lbuff);
}
fetch(lno)
{
register char *p;
lno %= PL;
p = lbuff;
while (*p)
*p++ = '\0';
line = lbuff;
lp = 0;
if (page[lno])
strcpy (line, page[lno]);
}
emit (s, lineno)
char *s;
int lineno;
{
static int cline = 0;
register int ncp;
register char *p;
static int gflag = 0;
if (*s) {
while (cline < lineno - 1) {
putchar ('\n');
pcp = 0;
cline += 2;
}
if (cline != lineno) {
putchar (ESC);
putchar ('9');
cline++;
}
if (pcp)
putchar ('\r');
pcp = 0;
p = s;
while (*p) {
ncp = pcp;
while (*p++ == ' ') {
if ((++ncp & 7) == 0 && hflag) {
pcp = ncp;
putchar ('\t');
}
}
if (!*--p)
break;
while (pcp < ncp) {
putchar (' ');
pcp++;
}
if (gflag != (*p & GREEK) && *p != '\b') {
if (gflag)
putchar (SI);
else
putchar (SO);
gflag ^= GREEK;
}
putchar (*p & ~GREEK);
if (*p++ == '\b')
pcp--;
else
pcp++;
}
}
}
incr()
{
store (ll++);
if (ll > llh)
llh = ll;
if (ll >= mustwr && page[ll%PL]) {
emit (page[ll%PL], ll - PL);
mustwr++;
free (page[ll%PL]);
page[ll%PL] = 0;
}
fetch (ll);
}
decr()
{
if (ll > mustwr - PL) {
store (ll--);
fetch (ll);
}
}