ul.c revision 8874
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 351590Srgrimesstatic char copyright[] = 361590Srgrimes"@(#) Copyright (c) 1980, 1993\n\ 371590Srgrimes The Regents of the University of California. All rights reserved.\n"; 381590Srgrimes#endif /* not lint */ 391590Srgrimes 401590Srgrimes#ifndef lint 411590Srgrimesstatic char sccsid[] = "@(#)ul.c 8.1 (Berkeley) 6/6/93"; 421590Srgrimes#endif /* not lint */ 431590Srgrimes 441590Srgrimes#include <stdio.h> 451590Srgrimes 461590Srgrimes#define IESC '\033' 471590Srgrimes#define SO '\016' 481590Srgrimes#define SI '\017' 491590Srgrimes#define HFWD '9' 501590Srgrimes#define HREV '8' 511590Srgrimes#define FREV '7' 521590Srgrimes#define MAXBUF 512 531590Srgrimes 541590Srgrimes#define NORMAL 000 551590Srgrimes#define ALTSET 001 /* Reverse */ 561590Srgrimes#define SUPERSC 002 /* Dim */ 571590Srgrimes#define SUBSC 004 /* Dim | Ul */ 581590Srgrimes#define UNDERL 010 /* Ul */ 591590Srgrimes#define BOLD 020 /* Bold */ 601590Srgrimes 611590Srgrimesint must_use_uc, must_overstrike; 621590Srgrimeschar *CURS_UP, *CURS_RIGHT, *CURS_LEFT, 631590Srgrimes *ENTER_STANDOUT, *EXIT_STANDOUT, *ENTER_UNDERLINE, *EXIT_UNDERLINE, 641590Srgrimes *ENTER_DIM, *ENTER_BOLD, *ENTER_REVERSE, *UNDER_CHAR, *EXIT_ATTRIBUTES; 651590Srgrimes 661590Srgrimesstruct CHAR { 671590Srgrimes char c_mode; 681590Srgrimes char c_char; 691590Srgrimes} ; 701590Srgrimes 711590Srgrimesstruct CHAR obuf[MAXBUF]; 721590Srgrimesint col, maxcol; 731590Srgrimesint mode; 741590Srgrimesint halfpos; 751590Srgrimesint upln; 761590Srgrimesint iflag; 771590Srgrimes 781590Srgrimesint outchar(); 791590Srgrimes#define PRINT(s) if (s == NULL) /* void */; else tputs(s, 1, outchar) 801590Srgrimes 811590Srgrimesmain(argc, argv) 821590Srgrimes int argc; 831590Srgrimes char **argv; 841590Srgrimes{ 851590Srgrimes extern int optind; 861590Srgrimes extern char *optarg; 871590Srgrimes int c; 881590Srgrimes char *termtype; 891590Srgrimes FILE *f; 901590Srgrimes char termcap[1024]; 911590Srgrimes char *getenv(), *strcpy(); 921590Srgrimes 931590Srgrimes termtype = getenv("TERM"); 941590Srgrimes if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1))) 951590Srgrimes termtype = "lpr"; 961590Srgrimes while ((c=getopt(argc, argv, "it:T:")) != EOF) 971590Srgrimes switch(c) { 981590Srgrimes 991590Srgrimes case 't': 1001590Srgrimes case 'T': /* for nroff compatibility */ 1011590Srgrimes termtype = optarg; 1021590Srgrimes break; 1031590Srgrimes case 'i': 1041590Srgrimes iflag = 1; 1051590Srgrimes break; 1061590Srgrimes 1071590Srgrimes default: 1081590Srgrimes fprintf(stderr, 1091590Srgrimes "usage: %s [ -i ] [ -tTerm ] file...\n", 1101590Srgrimes argv[0]); 1111590Srgrimes exit(1); 1121590Srgrimes } 1131590Srgrimes 1141590Srgrimes switch(tgetent(termcap, termtype)) { 1151590Srgrimes 1161590Srgrimes case 1: 1171590Srgrimes break; 1181590Srgrimes 1191590Srgrimes default: 1201590Srgrimes fprintf(stderr,"trouble reading termcap"); 1211590Srgrimes /* fall through to ... */ 1221590Srgrimes 1231590Srgrimes case 0: 1241590Srgrimes /* No such terminal type - assume dumb */ 1251590Srgrimes (void)strcpy(termcap, "dumb:os:col#80:cr=^M:sf=^J:am:"); 1261590Srgrimes break; 1271590Srgrimes } 1281590Srgrimes initcap(); 1291590Srgrimes if ( (tgetflag("os") && ENTER_BOLD==NULL ) || 1301590Srgrimes (tgetflag("ul") && ENTER_UNDERLINE==NULL && UNDER_CHAR==NULL)) 1311590Srgrimes must_overstrike = 1; 1321590Srgrimes initbuf(); 1331590Srgrimes if (optind == argc) 1341590Srgrimes filter(stdin); 1351590Srgrimes else for (; optind<argc; optind++) { 1361590Srgrimes f = fopen(argv[optind],"r"); 1371590Srgrimes if (f == NULL) { 1381590Srgrimes perror(argv[optind]); 1391590Srgrimes exit(1); 1401590Srgrimes } else 1411590Srgrimes filter(f); 1421590Srgrimes } 1431590Srgrimes exit(0); 1441590Srgrimes} 1451590Srgrimes 1461590Srgrimesfilter(f) 1471590Srgrimes FILE *f; 1481590Srgrimes{ 1491590Srgrimes register c; 1501590Srgrimes 1511590Srgrimes while ((c = getc(f)) != EOF) switch(c) { 1521590Srgrimes 1531590Srgrimes case '\b': 1541590Srgrimes if (col > 0) 1551590Srgrimes col--; 1561590Srgrimes continue; 1571590Srgrimes 1581590Srgrimes case '\t': 1591590Srgrimes col = (col+8) & ~07; 1601590Srgrimes if (col > maxcol) 1611590Srgrimes maxcol = col; 1621590Srgrimes continue; 1631590Srgrimes 1641590Srgrimes case '\r': 1651590Srgrimes col = 0; 1661590Srgrimes continue; 1671590Srgrimes 1681590Srgrimes case SO: 1691590Srgrimes mode |= ALTSET; 1701590Srgrimes continue; 1711590Srgrimes 1721590Srgrimes case SI: 1731590Srgrimes mode &= ~ALTSET; 1741590Srgrimes continue; 1751590Srgrimes 1761590Srgrimes case IESC: 1771590Srgrimes switch (c = getc(f)) { 1781590Srgrimes 1791590Srgrimes case HREV: 1801590Srgrimes if (halfpos == 0) { 1811590Srgrimes mode |= SUPERSC; 1821590Srgrimes halfpos--; 1831590Srgrimes } else if (halfpos > 0) { 1841590Srgrimes mode &= ~SUBSC; 1851590Srgrimes halfpos--; 1861590Srgrimes } else { 1871590Srgrimes halfpos = 0; 1881590Srgrimes reverse(); 1891590Srgrimes } 1901590Srgrimes continue; 1911590Srgrimes 1921590Srgrimes case HFWD: 1931590Srgrimes if (halfpos == 0) { 1941590Srgrimes mode |= SUBSC; 1951590Srgrimes halfpos++; 1961590Srgrimes } else if (halfpos < 0) { 1971590Srgrimes mode &= ~SUPERSC; 1981590Srgrimes halfpos++; 1991590Srgrimes } else { 2001590Srgrimes halfpos = 0; 2011590Srgrimes fwd(); 2021590Srgrimes } 2031590Srgrimes continue; 2041590Srgrimes 2051590Srgrimes case FREV: 2061590Srgrimes reverse(); 2071590Srgrimes continue; 2081590Srgrimes 2091590Srgrimes default: 2101590Srgrimes fprintf(stderr, 2111590Srgrimes "Unknown escape sequence in input: %o, %o\n", 2121590Srgrimes IESC, c); 2131590Srgrimes exit(1); 2141590Srgrimes } 2151590Srgrimes continue; 2161590Srgrimes 2171590Srgrimes case '_': 2181590Srgrimes if (obuf[col].c_char) 2191590Srgrimes obuf[col].c_mode |= UNDERL | mode; 2201590Srgrimes else 2211590Srgrimes obuf[col].c_char = '_'; 2221590Srgrimes case ' ': 2231590Srgrimes col++; 2241590Srgrimes if (col > maxcol) 2251590Srgrimes maxcol = col; 2261590Srgrimes continue; 2271590Srgrimes 2281590Srgrimes case '\n': 2291590Srgrimes flushln(); 2301590Srgrimes continue; 2311590Srgrimes 2321590Srgrimes case '\f': 2331590Srgrimes flushln(); 2341590Srgrimes putchar('\f'); 2351590Srgrimes continue; 2361590Srgrimes 2371590Srgrimes default: 2381590Srgrimes if (c < ' ') /* non printing */ 2391590Srgrimes continue; 2401590Srgrimes if (obuf[col].c_char == '\0') { 2411590Srgrimes obuf[col].c_char = c; 2421590Srgrimes obuf[col].c_mode = mode; 2431590Srgrimes } else if (obuf[col].c_char == '_') { 2441590Srgrimes obuf[col].c_char = c; 2451590Srgrimes obuf[col].c_mode |= UNDERL|mode; 2461590Srgrimes } else if (obuf[col].c_char == c) 2471590Srgrimes obuf[col].c_mode |= BOLD|mode; 2481590Srgrimes else 2491590Srgrimes obuf[col].c_mode = mode; 2501590Srgrimes col++; 2511590Srgrimes if (col > maxcol) 2521590Srgrimes maxcol = col; 2531590Srgrimes continue; 2541590Srgrimes } 2551590Srgrimes if (maxcol) 2561590Srgrimes flushln(); 2571590Srgrimes} 2581590Srgrimes 2591590Srgrimesflushln() 2601590Srgrimes{ 2611590Srgrimes register lastmode; 2621590Srgrimes register i; 2631590Srgrimes int hadmodes = 0; 2641590Srgrimes 2651590Srgrimes lastmode = NORMAL; 2661590Srgrimes for (i=0; i<maxcol; i++) { 2671590Srgrimes if (obuf[i].c_mode != lastmode) { 2681590Srgrimes hadmodes++; 2691590Srgrimes setmode(obuf[i].c_mode); 2701590Srgrimes lastmode = obuf[i].c_mode; 2711590Srgrimes } 2721590Srgrimes if (obuf[i].c_char == '\0') { 2731590Srgrimes if (upln) 2741590Srgrimes PRINT(CURS_RIGHT); 2751590Srgrimes else 2761590Srgrimes outc(' '); 2771590Srgrimes } else 2781590Srgrimes outc(obuf[i].c_char); 2791590Srgrimes } 2801590Srgrimes if (lastmode != NORMAL) { 2811590Srgrimes setmode(0); 2821590Srgrimes } 2831590Srgrimes if (must_overstrike && hadmodes) 2841590Srgrimes overstrike(); 2851590Srgrimes putchar('\n'); 2861590Srgrimes if (iflag && hadmodes) 2871590Srgrimes iattr(); 2881590Srgrimes (void)fflush(stdout); 2891590Srgrimes if (upln) 2901590Srgrimes upln--; 2911590Srgrimes initbuf(); 2921590Srgrimes} 2931590Srgrimes 2941590Srgrimes/* 2951590Srgrimes * For terminals that can overstrike, overstrike underlines and bolds. 2961590Srgrimes * We don't do anything with halfline ups and downs, or Greek. 2971590Srgrimes */ 2981590Srgrimesoverstrike() 2991590Srgrimes{ 3001590Srgrimes register int i; 3011590Srgrimes char lbuf[256]; 3021590Srgrimes register char *cp = lbuf; 3031590Srgrimes int hadbold=0; 3041590Srgrimes 3051590Srgrimes /* Set up overstrike buffer */ 3061590Srgrimes for (i=0; i<maxcol; i++) 3071590Srgrimes switch (obuf[i].c_mode) { 3081590Srgrimes case NORMAL: 3091590Srgrimes default: 3101590Srgrimes *cp++ = ' '; 3111590Srgrimes break; 3121590Srgrimes case UNDERL: 3131590Srgrimes *cp++ = '_'; 3141590Srgrimes break; 3151590Srgrimes case BOLD: 3161590Srgrimes *cp++ = obuf[i].c_char; 3171590Srgrimes hadbold=1; 3181590Srgrimes break; 3191590Srgrimes } 3201590Srgrimes putchar('\r'); 3211590Srgrimes for (*cp=' '; *cp==' '; cp--) 3221590Srgrimes *cp = 0; 3231590Srgrimes for (cp=lbuf; *cp; cp++) 3241590Srgrimes putchar(*cp); 3251590Srgrimes if (hadbold) { 3261590Srgrimes putchar('\r'); 3271590Srgrimes for (cp=lbuf; *cp; cp++) 3281590Srgrimes putchar(*cp=='_' ? ' ' : *cp); 3291590Srgrimes putchar('\r'); 3301590Srgrimes for (cp=lbuf; *cp; cp++) 3311590Srgrimes putchar(*cp=='_' ? ' ' : *cp); 3321590Srgrimes } 3331590Srgrimes} 3341590Srgrimes 3351590Srgrimesiattr() 3361590Srgrimes{ 3371590Srgrimes register int i; 3381590Srgrimes char lbuf[256]; 3391590Srgrimes register char *cp = lbuf; 3401590Srgrimes 3411590Srgrimes for (i=0; i<maxcol; i++) 3421590Srgrimes switch (obuf[i].c_mode) { 3431590Srgrimes case NORMAL: *cp++ = ' '; break; 3441590Srgrimes case ALTSET: *cp++ = 'g'; break; 3451590Srgrimes case SUPERSC: *cp++ = '^'; break; 3461590Srgrimes case SUBSC: *cp++ = 'v'; break; 3471590Srgrimes case UNDERL: *cp++ = '_'; break; 3481590Srgrimes case BOLD: *cp++ = '!'; break; 3491590Srgrimes default: *cp++ = 'X'; break; 3501590Srgrimes } 3511590Srgrimes for (*cp=' '; *cp==' '; cp--) 3521590Srgrimes *cp = 0; 3531590Srgrimes for (cp=lbuf; *cp; cp++) 3541590Srgrimes putchar(*cp); 3551590Srgrimes putchar('\n'); 3561590Srgrimes} 3571590Srgrimes 3581590Srgrimesinitbuf() 3591590Srgrimes{ 3601590Srgrimes 3611590Srgrimes bzero((char *)obuf, sizeof (obuf)); /* depends on NORMAL == 0 */ 3621590Srgrimes col = 0; 3631590Srgrimes maxcol = 0; 3641590Srgrimes mode &= ALTSET; 3651590Srgrimes} 3661590Srgrimes 3671590Srgrimesfwd() 3681590Srgrimes{ 3691590Srgrimes register oldcol, oldmax; 3701590Srgrimes 3711590Srgrimes oldcol = col; 3721590Srgrimes oldmax = maxcol; 3731590Srgrimes flushln(); 3741590Srgrimes col = oldcol; 3751590Srgrimes maxcol = oldmax; 3761590Srgrimes} 3771590Srgrimes 3781590Srgrimesreverse() 3791590Srgrimes{ 3801590Srgrimes upln++; 3811590Srgrimes fwd(); 3821590Srgrimes PRINT(CURS_UP); 3831590Srgrimes PRINT(CURS_UP); 3841590Srgrimes upln++; 3851590Srgrimes} 3861590Srgrimes 3871590Srgrimesinitcap() 3881590Srgrimes{ 3891590Srgrimes static char tcapbuf[512]; 3901590Srgrimes char *bp = tcapbuf; 3911590Srgrimes char *getenv(), *tgetstr(); 3921590Srgrimes 3931590Srgrimes /* This nonsense attempts to work with both old and new termcap */ 3941590Srgrimes CURS_UP = tgetstr("up", &bp); 3951590Srgrimes CURS_RIGHT = tgetstr("ri", &bp); 3961590Srgrimes if (CURS_RIGHT == NULL) 3971590Srgrimes CURS_RIGHT = tgetstr("nd", &bp); 3981590Srgrimes CURS_LEFT = tgetstr("le", &bp); 3991590Srgrimes if (CURS_LEFT == NULL) 4001590Srgrimes CURS_LEFT = tgetstr("bc", &bp); 4011590Srgrimes if (CURS_LEFT == NULL && tgetflag("bs")) 4021590Srgrimes CURS_LEFT = "\b"; 4031590Srgrimes 4041590Srgrimes ENTER_STANDOUT = tgetstr("so", &bp); 4051590Srgrimes EXIT_STANDOUT = tgetstr("se", &bp); 4061590Srgrimes ENTER_UNDERLINE = tgetstr("us", &bp); 4071590Srgrimes EXIT_UNDERLINE = tgetstr("ue", &bp); 4081590Srgrimes ENTER_DIM = tgetstr("mh", &bp); 4091590Srgrimes ENTER_BOLD = tgetstr("md", &bp); 4101590Srgrimes ENTER_REVERSE = tgetstr("mr", &bp); 4111590Srgrimes EXIT_ATTRIBUTES = tgetstr("me", &bp); 4121590Srgrimes 4131590Srgrimes if (!ENTER_BOLD && ENTER_REVERSE) 4141590Srgrimes ENTER_BOLD = ENTER_REVERSE; 4151590Srgrimes if (!ENTER_BOLD && ENTER_STANDOUT) 4161590Srgrimes ENTER_BOLD = ENTER_STANDOUT; 4171590Srgrimes if (!ENTER_UNDERLINE && ENTER_STANDOUT) { 4181590Srgrimes ENTER_UNDERLINE = ENTER_STANDOUT; 4191590Srgrimes EXIT_UNDERLINE = EXIT_STANDOUT; 4201590Srgrimes } 4211590Srgrimes if (!ENTER_DIM && ENTER_STANDOUT) 4221590Srgrimes ENTER_DIM = ENTER_STANDOUT; 4231590Srgrimes if (!ENTER_REVERSE && ENTER_STANDOUT) 4241590Srgrimes ENTER_REVERSE = ENTER_STANDOUT; 4251590Srgrimes if (!EXIT_ATTRIBUTES && EXIT_STANDOUT) 4261590Srgrimes EXIT_ATTRIBUTES = EXIT_STANDOUT; 4278874Srgrimes 4281590Srgrimes /* 4291590Srgrimes * Note that we use REVERSE for the alternate character set, 4301590Srgrimes * not the as/ae capabilities. This is because we are modelling 4311590Srgrimes * the model 37 teletype (since that's what nroff outputs) and 4321590Srgrimes * the typical as/ae is more of a graphics set, not the greek 4331590Srgrimes * letters the 37 has. 4341590Srgrimes */ 4351590Srgrimes 4361590Srgrimes UNDER_CHAR = tgetstr("uc", &bp); 4371590Srgrimes must_use_uc = (UNDER_CHAR && !ENTER_UNDERLINE); 4381590Srgrimes} 4391590Srgrimes 4401590Srgrimesoutchar(c) 4411590Srgrimes int c; 4421590Srgrimes{ 4431590Srgrimes putchar(c & 0177); 4441590Srgrimes} 4451590Srgrimes 4461590Srgrimesstatic int curmode = 0; 4471590Srgrimes 4481590Srgrimesoutc(c) 4491590Srgrimes int c; 4501590Srgrimes{ 4511590Srgrimes putchar(c); 4521590Srgrimes if (must_use_uc && (curmode&UNDERL)) { 4531590Srgrimes PRINT(CURS_LEFT); 4541590Srgrimes PRINT(UNDER_CHAR); 4551590Srgrimes } 4561590Srgrimes} 4571590Srgrimes 4581590Srgrimessetmode(newmode) 4591590Srgrimes int newmode; 4601590Srgrimes{ 4611590Srgrimes if (!iflag) { 4621590Srgrimes if (curmode != NORMAL && newmode != NORMAL) 4631590Srgrimes setmode(NORMAL); 4641590Srgrimes switch (newmode) { 4651590Srgrimes case NORMAL: 4661590Srgrimes switch(curmode) { 4671590Srgrimes case NORMAL: 4681590Srgrimes break; 4691590Srgrimes case UNDERL: 4701590Srgrimes PRINT(EXIT_UNDERLINE); 4711590Srgrimes break; 4721590Srgrimes default: 4731590Srgrimes /* This includes standout */ 4741590Srgrimes PRINT(EXIT_ATTRIBUTES); 4751590Srgrimes break; 4761590Srgrimes } 4771590Srgrimes break; 4781590Srgrimes case ALTSET: 4791590Srgrimes PRINT(ENTER_REVERSE); 4801590Srgrimes break; 4811590Srgrimes case SUPERSC: 4821590Srgrimes /* 4831590Srgrimes * This only works on a few terminals. 4841590Srgrimes * It should be fixed. 4851590Srgrimes */ 4861590Srgrimes PRINT(ENTER_UNDERLINE); 4871590Srgrimes PRINT(ENTER_DIM); 4881590Srgrimes break; 4891590Srgrimes case SUBSC: 4901590Srgrimes PRINT(ENTER_DIM); 4911590Srgrimes break; 4921590Srgrimes case UNDERL: 4931590Srgrimes PRINT(ENTER_UNDERLINE); 4941590Srgrimes break; 4951590Srgrimes case BOLD: 4961590Srgrimes PRINT(ENTER_BOLD); 4971590Srgrimes break; 4981590Srgrimes default: 4991590Srgrimes /* 5001590Srgrimes * We should have some provision here for multiple modes 5011590Srgrimes * on at once. This will have to come later. 5021590Srgrimes */ 5031590Srgrimes PRINT(ENTER_STANDOUT); 5041590Srgrimes break; 5051590Srgrimes } 5061590Srgrimes } 5071590Srgrimes curmode = newmode; 5081590Srgrimes} 509