/* * hp [-e] [-m] * convert nroff TTY37 output to right form for HP2640x terminals. * -e indicates enhanced terminal with underline, etc. * -m requests minimization of output by removing multiple newlines */ char hpvers[] = "@(#)hp.c 1.6"; #include <stdio.h> #include <signal.h> #include <sys/types.h> #include <sys/stat.h> #include <sgtty.h> #define ESC 033 /* escape */ #define HFWD '9' #define HREV '8' #define FREV '7' #define SO 016 /* shift out - enter greek */ #define SI 017 /* shift in */ #define LF '\n' #define CR 015 #define NFLAG 0200 /* hi-bit flag for non-showing chars */ #define NMASK 0177 #define AMP 046 /* & */ #define DEE 0144 /* d */ #define BFSIZ 4096 /* size of output buffer */ /* (bigger because of tbl weirds */ /* and nroff idiosyncracies */ /* puty adds control char to output, marked by hi-bit */ #define puty(c) putx(c|NFLAG) #define flg(x) ((char)(x|NFLAG)) /* set hi-bit of x */ int nlcnt, /* accumulated newline count */ frevcnt, /* accumulated reverse line-feeds */ halfpos, /* half-line position: -1 = above, +1 = below */ restrict = 1, /* 0==> full terminal, 1==> no display enhancements */ minimiz; /* 0==> normal, 1==> remove extra newlines */ char *ttydev; int svstmode; /* for mesg restore */ int restore(); char *ttyname(); int svsgflgs; struct sgttyb sgb; int retcode = 2; /* return code */ char peekbuf[2]; char *peekstr = peekbuf; /* lookahead ptr */ char outbf[BFSIZ]; /* output assembly buffer */ char *bfnext = outbf, /* addr of next empty byte */ *bflast = &outbf[BFSIZ-1]; /* addr of last usable byte */ /* normal display enhancement strings */ char *enunder = "\033&dD", /* underline */ *ennorml = "\033&d@", /* normal output */ *ensuper = "\033&dH", /* superscript (half) */ *ensubsc = "\033&dL", /* subscript (half, underlined */ *enrestr = "\033&dB"; /* restricted (inverse only) */ int restore(); main(argc, argv) char **argv; { register c; scanarg(argc,argv); if (((int)signal(SIGINT, SIG_IGN) & 01) == 0) signal(SIGINT, restore); if (gtty(1, &sgb) == 0) fixtty(); setbuf(stdin, calloc(BUFSIZ,1)); while((c = getchal()) != EOF) { if (nlcnt && c != LF) flushnl(); if (frevcnt && c != ESC) flushrv(); if (c == LF) { if (++nlcnt == 1) flushln(); continue; } if (c == ESC) escape(); else if (c == SO) special(); else if (c == '\b') backsp(); else if (c == '_') { /* C nroff */ if ((c = getchal()) == '\b') { undersc(); } else { putx('_'); peekbuf[0] = c; peekstr = peekbuf; } } else putx(c); } flusher(); retcode = 0; restore(); } getchal() { if (*peekstr) return(*peekstr++); return(getchar()); } /* scanarg: scan arguments and set flags; ignore unknown args */ scanarg(argc,argv) int argc; char **argv; { register char *p; while ( --argc > 0) { p = *++argv; if (*p == '-') { ++p; if (*p == 'e') restrict = 0; else if (*p == 'm') minimiz = 1; } } if (restrict) enunder = ensuper = ensubsc = enrestr; } /* fixtty: get tty status and save; remove delay and CR-LF mapping */ fixtty() { struct stat sb; svsgflgs = sgb.sg_flags; sgb.sg_flags &= ~(ALLDELAY|CRMOD); stty(1, &sgb); /* stty nl nl0 cr0 tab0 ff0 */ fstat(1, &sb); svstmode = sb.st_mode; ttydev = ttyname(1); if (ttydev && *ttydev) chmod(ttydev, 0600); /* mesg n */ } /* flusher: flush accumulated newlines, reverse line feeds, buffer */ flusher() { flushln(); if (nlcnt) flushnl(); if (frevcnt) flushrv(); fflush(stdout); } /* flushrv: flush accumulated reverse line feeds */ flushrv() { while (frevcnt--) putstr("\033T"); putstr(ennorml); frevcnt = 0; } /* flushnl: flush accumulated newlines (count in nlcnt) */ flushnl() { if (minimiz != 0 && nlcnt > 2) nlcnt = 2; putchar(CR); while (nlcnt--) putchar(LF); nlcnt = 0; } putstr(p) char *p; { register char *pp; pp = p; while (*pp) puty(*pp++); } restore(){ if (isatty(1)) { sgb.sg_flags = svsgflgs; stty(1, &sgb); if (ttydev && *ttydev) chmod(ttydev, svstmode); } exit(retcode); } char tab[] = { 'A','A', /* alpha */ 'B','B', /* beta */ 'D','W', /* delta */ 'W','V', /* DELTA */ 'S','E', /* epsilon */ 'N','H', /* eta */ '\\','Q', /* gamma */ 'G','+', /* GAMMA */ 'o','<', /* infinity - not in M37 */ '^','\'', /* integral */ 'L','G', /* lambda */ 'E',';', /* LAMBDA */ 'M','M', /* mu */ '[','$', /* nabla (del) */ '_','\\', /* not */ '@','N', /* nu */ 'C','L', /* omega */ 'Z',':', /* OMEGA */ ']','F', /* partial */ 'U','D', /* phi */ 'F','.', /* PHI */ 'V','C', /* psi */ 'H',',', /* PSI */ 'J','P', /* pi */ 'P','*', /* PI */ 'K','O', /* rho */ 'Y','S', /* sigma */ 'R','?', /* SIGMA */ 'I','T', /* tau */ 'T','R', /* theta */ 'O','J', /* THETA */ 'X','U', /* xi */ 'Q','Z', /* zeta */ 'v','Y', 0 }; char spec1[] = {LF,SO,0}; special(){ register int c; register char *p; puty(SO); while ((c = getchal()) != EOF) { if (c == SI) { puty(c); return; } if (c == LF) { peekstr = spec1; return; } for (p = tab; *p != 0; p += 2) if (c == *p) { c = *++p; break; } putx(c); } } /* escape: handle escape sequences */ escape() { register int c; c = getchal(); if (frevcnt && c != FREV) flushrv(); switch (c) { case FREV: frevcnt++; break; case HREV: if (halfpos == 0) { putstr(ensuper); halfpos--; } else if (halfpos > 0) { putstr(ennorml); halfpos--; } else { putstr("\033T"); /* roll back 1 */ putstr(ennorml); halfpos = 0; } break; case HFWD: if (halfpos == 0) { putstr(ensubsc); halfpos++; } else if (halfpos < 0) { putstr(ennorml); halfpos++; } else { putstr("\033S"); /* roll up 1, i.e., LF w/o CR */ putstr(ennorml); halfpos = 0; } break; case '&': putstr("\033&"); puty(c = getchal()); if (c == 'd') puty(getchal()); break; case ')': putstr("\033)"); puty(getchal()); break; default: puty(ESC); puty(getchal()); break; } } char peeku[3]; /* backsp: handle backspacing */ /* sequences are handled such that : ( \b is backspace ) */ /* a\b_ -> a in inverse video */ /* _\ba -> a in inverse video */ /* c\bd -> c in inverse video */ /* if a control char (ESC) precedes or follows '\b' */ /* then an actual backspace movement is performed */ backsp() { register char *bftmp; register int c; char *bfhi; int i, j, ncnt, bscnt; char *p, *p1; p = bfnext-2; p1 = bfnext-4; /* check if last char put in buffer was escape sequence */ /* if so, put backspace control sequence in buffer */ /* check against "\033&d" */ if ((*p == flg(ESC)) || (*p1++ == flg(ESC) && *p1++==flg(AMP) && *p1==flg(DEE))) { putstr("\033D"); while((c=getchal())=='\b') putstr("\033D"); /* put last char back */ peeku[0] = c; peeku[1] = '\0'; peekstr = peeku; return; } bscnt = 1; c = getchal(); /* count backspaces */ while (c == '\b') { bscnt++; c = getchal(); } /* read in chars until bscnt have been read */ /* or until an ESC is read */ ncnt = 0; if (c!=ESC) { for (ncnt=0; (ncnt<bscnt && c!=ESC); ncnt++) c = getchal(); /* since there were normal chars with backsp */ /* insert inverse video chars in buffer */ bftmp = bfhi = bfnext + 4; for (i=0; i<bscnt;) if (((*--bftmp = *--bfnext) & NFLAG) == 0) i++; putstr(enunder); bfnext = bfhi; } /* if number of bcksp is not = to number normal chars */ /* then some bcksp chars will be inserted as actual */ /* bcksp movement and not inverse video for another char */ j = bscnt - ncnt; if (j == 0) putstr(ennorml); else { /* move chars over and insert normal char seq */ if (ncnt > 0) { bftmp = bfhi = bfnext + 4; for (i=0; i<j;) if (((*--bftmp = *--bfnext) & NFLAG) == 0) i++; putstr(ennorml); bfnext = bfhi; } /* insert backspace movement chars */ while (j--) putstr("\033D"); } /* put last char read back */ peeku[0] = c; peeku[1] = '\0'; peekstr = peeku; } /* undersc: handle C nroff's (_ BS char)+ sequences * assumes _ BS already found * if char is a control char, put char back and break. */ undersc() { register char c; putstr(enunder); while (1) { if ((c=getchal())==ESC) { peeku[0] = c; peeku[1] = '\0'; peekstr = peeku; break; } else putx(c); if ((c = getchal()) != '_') { peeku[0] = c; peeku[1] = '\0'; peekstr = peeku; break; } if ((c = getchal()) != '\b') { peeku[0] = '_'; peeku[1] = c; peekstr = peeku; break; } } putstr(ennorml); } /* flushln: flush out accumulated line */ flushln() { register char c, *p; putx('\0'); p = outbf; while (c = (*p++ & NMASK)) putchar(c); bfnext = outbf; } /* putx: add normal (printing) char to output */ putx(c) char c; { if (bfnext <= bflast) *bfnext++ = c; else die("line too long\n"); } die(mesg) char *mesg; { register char *p; char *c = "hp: "; write(2, c, 4); p = mesg; while (*p) write(2, p++, 1); restore(); }