ul.c revision 132882
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
3528454Scharnierstatic const 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
4128454Scharnier#if 0
421590Srgrimesstatic char sccsid[] = "@(#)ul.c	8.1 (Berkeley) 6/6/93";
4328454Scharnier#endif
4428454Scharnierstatic const char rcsid[] =
4550477Speter  "$FreeBSD: head/usr.bin/ul/ul.c 132882 2004-07-30 10:58:06Z tjr $";
461590Srgrimes#endif /* not lint */
471590Srgrimes
4828454Scharnier#include <err.h>
49132858Stjr#include <locale.h>
501590Srgrimes#include <stdio.h>
5128454Scharnier#include <stdlib.h>
5228454Scharnier#include <string.h>
5328454Scharnier#include <termcap.h>
5428454Scharnier#include <unistd.h>
55132858Stjr#include <wchar.h>
56132858Stjr#include <wctype.h>
571590Srgrimes
581590Srgrimes#define	IESC	'\033'
591590Srgrimes#define	SO	'\016'
601590Srgrimes#define	SI	'\017'
611590Srgrimes#define	HFWD	'9'
621590Srgrimes#define	HREV	'8'
631590Srgrimes#define	FREV	'7'
641590Srgrimes#define	MAXBUF	512
651590Srgrimes
661590Srgrimes#define	NORMAL	000
671590Srgrimes#define	ALTSET	001	/* Reverse */
681590Srgrimes#define	SUPERSC	002	/* Dim */
691590Srgrimes#define	SUBSC	004	/* Dim | Ul */
701590Srgrimes#define	UNDERL	010	/* Ul */
711590Srgrimes#define	BOLD	020	/* Bold */
721590Srgrimes
731590Srgrimesint	must_use_uc, must_overstrike;
7487303Sdwmaloneconst char
7587303Sdwmalone	*CURS_UP, *CURS_RIGHT, *CURS_LEFT,
761590Srgrimes	*ENTER_STANDOUT, *EXIT_STANDOUT, *ENTER_UNDERLINE, *EXIT_UNDERLINE,
771590Srgrimes	*ENTER_DIM, *ENTER_BOLD, *ENTER_REVERSE, *UNDER_CHAR, *EXIT_ATTRIBUTES;
781590Srgrimes
791590Srgrimesstruct	CHAR	{
801590Srgrimes	char	c_mode;
81132858Stjr	wchar_t	c_char;
82132858Stjr	int	c_width;	/* width or -1 if multi-column char. filler */
831590Srgrimes} ;
841590Srgrimes
851590Srgrimesstruct	CHAR	obuf[MAXBUF];
861590Srgrimesint	col, maxcol;
871590Srgrimesint	mode;
881590Srgrimesint	halfpos;
891590Srgrimesint	upln;
901590Srgrimesint	iflag;
911590Srgrimes
9292922Simpstatic void usage(void);
9392922Simpvoid setnewmode(int);
9492922Simpvoid initcap(void);
9592922Simpvoid reverse(void);
9692922Simpint outchar(int);
9792922Simpvoid fwd(void);
9892922Simpvoid initbuf(void);
9992922Simpvoid iattr(void);
10092922Simpvoid overstrike(void);
10192922Simpvoid flushln(void);
10292922Simpvoid filter(FILE *);
103132858Stjrvoid outc(wint_t, int);
10428454Scharnier
1051590Srgrimes#define	PRINT(s)	if (s == NULL) /* void */; else tputs(s, 1, outchar)
1061590Srgrimes
10728789Scharnierint
108102944Sdwmalonemain(int argc, char **argv)
1091590Srgrimes{
1101590Srgrimes	int c;
11187303Sdwmalone	const char *termtype;
1121590Srgrimes	FILE *f;
1131590Srgrimes	char termcap[1024];
1141590Srgrimes
115132858Stjr	setlocale(LC_ALL, "");
116132858Stjr
1171590Srgrimes	termtype = getenv("TERM");
1181590Srgrimes	if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1)))
1191590Srgrimes		termtype = "lpr";
12024360Simp	while ((c=getopt(argc, argv, "it:T:")) != -1)
1211590Srgrimes		switch(c) {
1221590Srgrimes
1231590Srgrimes		case 't':
1241590Srgrimes		case 'T': /* for nroff compatibility */
12587303Sdwmalone			termtype = optarg;
1261590Srgrimes			break;
1271590Srgrimes		case 'i':
1281590Srgrimes			iflag = 1;
1291590Srgrimes			break;
1301590Srgrimes		default:
13128454Scharnier			usage();
1321590Srgrimes		}
1331590Srgrimes
1341590Srgrimes	switch(tgetent(termcap, termtype)) {
1351590Srgrimes
1361590Srgrimes	case 1:
1371590Srgrimes		break;
1381590Srgrimes
1391590Srgrimes	default:
14028454Scharnier		warnx("trouble reading termcap");
141102412Scharnier		/* FALLTHROUGH */
1421590Srgrimes
1431590Srgrimes	case 0:
1441590Srgrimes		/* No such terminal type - assume dumb */
1451590Srgrimes		(void)strcpy(termcap, "dumb:os:col#80:cr=^M:sf=^J:am:");
1461590Srgrimes		break;
1471590Srgrimes	}
1481590Srgrimes	initcap();
1491590Srgrimes	if (    (tgetflag("os") && ENTER_BOLD==NULL ) ||
1501590Srgrimes		(tgetflag("ul") && ENTER_UNDERLINE==NULL && UNDER_CHAR==NULL))
1511590Srgrimes			must_overstrike = 1;
1521590Srgrimes	initbuf();
1531590Srgrimes	if (optind == argc)
1541590Srgrimes		filter(stdin);
1551590Srgrimes	else for (; optind<argc; optind++) {
1561590Srgrimes		f = fopen(argv[optind],"r");
15728454Scharnier		if (f == NULL)
15828454Scharnier			err(1, "%s", argv[optind]);
15928454Scharnier		else
1601590Srgrimes			filter(f);
1611590Srgrimes	}
1621590Srgrimes	exit(0);
1631590Srgrimes}
1641590Srgrimes
16528454Scharnierstatic void
166102944Sdwmaloneusage(void)
16728454Scharnier{
16828454Scharnier	fprintf(stderr, "usage: ul [-i] [-t terminal] file...\n");
16928454Scharnier	exit(1);
17028454Scharnier}
17128454Scharnier
17228454Scharniervoid
173102944Sdwmalonefilter(FILE *f)
1741590Srgrimes{
175132858Stjr	wint_t c;
176132858Stjr	int i, w;
1771590Srgrimes
178132858Stjr	while ((c = getwc(f)) != WEOF && col < MAXBUF) switch(c) {
1791590Srgrimes
1801590Srgrimes	case '\b':
1811590Srgrimes		if (col > 0)
1821590Srgrimes			col--;
1831590Srgrimes		continue;
1841590Srgrimes
1851590Srgrimes	case '\t':
1861590Srgrimes		col = (col+8) & ~07;
1871590Srgrimes		if (col > maxcol)
1881590Srgrimes			maxcol = col;
1891590Srgrimes		continue;
1901590Srgrimes
1911590Srgrimes	case '\r':
1921590Srgrimes		col = 0;
1931590Srgrimes		continue;
1941590Srgrimes
1951590Srgrimes	case SO:
1961590Srgrimes		mode |= ALTSET;
1971590Srgrimes		continue;
1981590Srgrimes
1991590Srgrimes	case SI:
2001590Srgrimes		mode &= ~ALTSET;
2011590Srgrimes		continue;
2021590Srgrimes
2031590Srgrimes	case IESC:
204132858Stjr		switch (c = getwc(f)) {
2051590Srgrimes
2061590Srgrimes		case HREV:
2071590Srgrimes			if (halfpos == 0) {
2081590Srgrimes				mode |= SUPERSC;
2091590Srgrimes				halfpos--;
2101590Srgrimes			} else if (halfpos > 0) {
2111590Srgrimes				mode &= ~SUBSC;
2121590Srgrimes				halfpos--;
2131590Srgrimes			} else {
2141590Srgrimes				halfpos = 0;
2151590Srgrimes				reverse();
2161590Srgrimes			}
2171590Srgrimes			continue;
2181590Srgrimes
2191590Srgrimes		case HFWD:
2201590Srgrimes			if (halfpos == 0) {
2211590Srgrimes				mode |= SUBSC;
2221590Srgrimes				halfpos++;
2231590Srgrimes			} else if (halfpos < 0) {
2241590Srgrimes				mode &= ~SUPERSC;
2251590Srgrimes				halfpos++;
2261590Srgrimes			} else {
2271590Srgrimes				halfpos = 0;
2281590Srgrimes				fwd();
2291590Srgrimes			}
2301590Srgrimes			continue;
2311590Srgrimes
2321590Srgrimes		case FREV:
2331590Srgrimes			reverse();
2341590Srgrimes			continue;
2351590Srgrimes
2361590Srgrimes		default:
23728454Scharnier			errx(1, "unknown escape sequence in input: %o, %o", IESC, c);
2381590Srgrimes		}
2391590Srgrimes		continue;
2401590Srgrimes
2411590Srgrimes	case '_':
242132858Stjr		if (obuf[col].c_char || obuf[col].c_width < 0) {
243132858Stjr			while (col > 0 && obuf[col].c_width < 0)
244132858Stjr				col--;
245132858Stjr			w = obuf[col].c_width;
246132858Stjr			for (i = 0; i < w; i++)
247132858Stjr				obuf[col++].c_mode |= UNDERL | mode;
248132858Stjr			if (col > maxcol)
249132858Stjr				maxcol = col;
250132858Stjr			continue;
251132858Stjr		}
252132858Stjr		obuf[col].c_char = '_';
253132858Stjr		obuf[col].c_width = 1;
254132858Stjr		/* FALLTHROUGH */
2551590Srgrimes	case ' ':
2561590Srgrimes		col++;
2571590Srgrimes		if (col > maxcol)
2581590Srgrimes			maxcol = col;
2591590Srgrimes		continue;
2601590Srgrimes
2611590Srgrimes	case '\n':
2621590Srgrimes		flushln();
2631590Srgrimes		continue;
2641590Srgrimes
2651590Srgrimes	case '\f':
2661590Srgrimes		flushln();
267132858Stjr		putwchar('\f');
2681590Srgrimes		continue;
2691590Srgrimes
2701590Srgrimes	default:
271132858Stjr		if ((w = wcwidth(c)) <= 0)	/* non printing */
2721590Srgrimes			continue;
2731590Srgrimes		if (obuf[col].c_char == '\0') {
2741590Srgrimes			obuf[col].c_char = c;
275132858Stjr			for (i = 0; i < w; i++)
276132858Stjr				obuf[col + i].c_mode = mode;
277132858Stjr			obuf[col].c_width = w;
278132858Stjr			for (i = 1; i < w; i++)
279132858Stjr				obuf[col + i].c_width = -1;
2801590Srgrimes		} else if (obuf[col].c_char == '_') {
2811590Srgrimes			obuf[col].c_char = c;
282132858Stjr			for (i = 0; i < w; i++)
283132858Stjr				obuf[col + i].c_mode |= UNDERL|mode;
284132858Stjr			obuf[col].c_width = w;
285132858Stjr			for (i = 1; i < w; i++)
286132858Stjr				obuf[col + i].c_width = -1;
287132858Stjr		} else if (obuf[col].c_char == c) {
288132858Stjr			for (i = 0; i < w; i++)
289132858Stjr				obuf[col + i].c_mode |= BOLD|mode;
290132858Stjr		} else {
291132858Stjr			w = obuf[col].c_width;
292132858Stjr			for (i = 0; i < w; i++)
293132858Stjr				obuf[col + i].c_mode = mode;
294132858Stjr		}
295132858Stjr		col += w;
2961590Srgrimes		if (col > maxcol)
2971590Srgrimes			maxcol = col;
2981590Srgrimes		continue;
2991590Srgrimes	}
300132882Stjr	if (ferror(f))
301132882Stjr		err(1, NULL);
3021590Srgrimes	if (maxcol)
3031590Srgrimes		flushln();
3041590Srgrimes}
3051590Srgrimes
30628454Scharniervoid
307102944Sdwmaloneflushln(void)
3081590Srgrimes{
30987303Sdwmalone	int lastmode;
31087303Sdwmalone	int i;
3111590Srgrimes	int hadmodes = 0;
3121590Srgrimes
3131590Srgrimes	lastmode = NORMAL;
3141590Srgrimes	for (i=0; i<maxcol; i++) {
3151590Srgrimes		if (obuf[i].c_mode != lastmode) {
3161590Srgrimes			hadmodes++;
31728454Scharnier			setnewmode(obuf[i].c_mode);
3181590Srgrimes			lastmode = obuf[i].c_mode;
3191590Srgrimes		}
3201590Srgrimes		if (obuf[i].c_char == '\0') {
3211590Srgrimes			if (upln)
3221590Srgrimes				PRINT(CURS_RIGHT);
3231590Srgrimes			else
324132858Stjr				outc(' ', 1);
3251590Srgrimes		} else
326132858Stjr			outc(obuf[i].c_char, obuf[i].c_width);
327132858Stjr		if (obuf[i].c_width > 1)
328132858Stjr			i += obuf[i].c_width - 1;
3291590Srgrimes	}
3301590Srgrimes	if (lastmode != NORMAL) {
33128454Scharnier		setnewmode(0);
3321590Srgrimes	}
3331590Srgrimes	if (must_overstrike && hadmodes)
3341590Srgrimes		overstrike();
335132858Stjr	putwchar('\n');
3361590Srgrimes	if (iflag && hadmodes)
3371590Srgrimes		iattr();
3381590Srgrimes	(void)fflush(stdout);
3391590Srgrimes	if (upln)
3401590Srgrimes		upln--;
3411590Srgrimes	initbuf();
3421590Srgrimes}
3431590Srgrimes
3441590Srgrimes/*
3451590Srgrimes * For terminals that can overstrike, overstrike underlines and bolds.
3461590Srgrimes * We don't do anything with halfline ups and downs, or Greek.
3471590Srgrimes */
34828454Scharniervoid
349102944Sdwmaloneoverstrike(void)
3501590Srgrimes{
351102944Sdwmalone	int i;
352132858Stjr	wchar_t lbuf[256];
353132858Stjr	wchar_t *cp = lbuf;
3541590Srgrimes	int hadbold=0;
3551590Srgrimes
3561590Srgrimes	/* Set up overstrike buffer */
3571590Srgrimes	for (i=0; i<maxcol; i++)
3581590Srgrimes		switch (obuf[i].c_mode) {
3591590Srgrimes		case NORMAL:
3601590Srgrimes		default:
3611590Srgrimes			*cp++ = ' ';
3621590Srgrimes			break;
3631590Srgrimes		case UNDERL:
3641590Srgrimes			*cp++ = '_';
3651590Srgrimes			break;
3661590Srgrimes		case BOLD:
3671590Srgrimes			*cp++ = obuf[i].c_char;
368132858Stjr			if (obuf[i].c_width > 1)
369132858Stjr				i += obuf[i].c_width - 1;
3701590Srgrimes			hadbold=1;
3711590Srgrimes			break;
3721590Srgrimes		}
373132858Stjr	putwchar('\r');
3741590Srgrimes	for (*cp=' '; *cp==' '; cp--)
3751590Srgrimes		*cp = 0;
3761590Srgrimes	for (cp=lbuf; *cp; cp++)
377132858Stjr		putwchar(*cp);
3781590Srgrimes	if (hadbold) {
379132858Stjr		putwchar('\r');
3801590Srgrimes		for (cp=lbuf; *cp; cp++)
381132858Stjr			putwchar(*cp=='_' ? ' ' : *cp);
382132858Stjr		putwchar('\r');
3831590Srgrimes		for (cp=lbuf; *cp; cp++)
384132858Stjr			putwchar(*cp=='_' ? ' ' : *cp);
3851590Srgrimes	}
3861590Srgrimes}
3871590Srgrimes
38828454Scharniervoid
389102944Sdwmaloneiattr(void)
3901590Srgrimes{
391102944Sdwmalone	int i;
392132858Stjr	wchar_t lbuf[256];
393132858Stjr	wchar_t *cp = lbuf;
3941590Srgrimes
3951590Srgrimes	for (i=0; i<maxcol; i++)
3961590Srgrimes		switch (obuf[i].c_mode) {
3971590Srgrimes		case NORMAL:	*cp++ = ' '; break;
3981590Srgrimes		case ALTSET:	*cp++ = 'g'; break;
3991590Srgrimes		case SUPERSC:	*cp++ = '^'; break;
4001590Srgrimes		case SUBSC:	*cp++ = 'v'; break;
4011590Srgrimes		case UNDERL:	*cp++ = '_'; break;
4021590Srgrimes		case BOLD:	*cp++ = '!'; break;
4031590Srgrimes		default:	*cp++ = 'X'; break;
4041590Srgrimes		}
4051590Srgrimes	for (*cp=' '; *cp==' '; cp--)
4061590Srgrimes		*cp = 0;
4071590Srgrimes	for (cp=lbuf; *cp; cp++)
408132858Stjr		putwchar(*cp);
409132858Stjr	putwchar('\n');
4101590Srgrimes}
4111590Srgrimes
41228454Scharniervoid
413102944Sdwmaloneinitbuf(void)
4141590Srgrimes{
4151590Srgrimes
4161590Srgrimes	bzero((char *)obuf, sizeof (obuf));	/* depends on NORMAL == 0 */
4171590Srgrimes	col = 0;
4181590Srgrimes	maxcol = 0;
4191590Srgrimes	mode &= ALTSET;
4201590Srgrimes}
4211590Srgrimes
42228454Scharniervoid
423102944Sdwmalonefwd(void)
4241590Srgrimes{
42587303Sdwmalone	int oldcol, oldmax;
4261590Srgrimes
4271590Srgrimes	oldcol = col;
4281590Srgrimes	oldmax = maxcol;
4291590Srgrimes	flushln();
4301590Srgrimes	col = oldcol;
4311590Srgrimes	maxcol = oldmax;
4321590Srgrimes}
4331590Srgrimes
43428454Scharniervoid
435102944Sdwmalonereverse(void)
4361590Srgrimes{
4371590Srgrimes	upln++;
4381590Srgrimes	fwd();
4391590Srgrimes	PRINT(CURS_UP);
4401590Srgrimes	PRINT(CURS_UP);
4411590Srgrimes	upln++;
4421590Srgrimes}
4431590Srgrimes
44428454Scharniervoid
445102944Sdwmaloneinitcap(void)
4461590Srgrimes{
4471590Srgrimes	static char tcapbuf[512];
4481590Srgrimes	char *bp = tcapbuf;
4491590Srgrimes
4501590Srgrimes	/* This nonsense attempts to work with both old and new termcap */
4511590Srgrimes	CURS_UP =		tgetstr("up", &bp);
4521590Srgrimes	CURS_RIGHT =		tgetstr("ri", &bp);
4531590Srgrimes	if (CURS_RIGHT == NULL)
4541590Srgrimes		CURS_RIGHT =	tgetstr("nd", &bp);
4551590Srgrimes	CURS_LEFT =		tgetstr("le", &bp);
4561590Srgrimes	if (CURS_LEFT == NULL)
4571590Srgrimes		CURS_LEFT =	tgetstr("bc", &bp);
4581590Srgrimes	if (CURS_LEFT == NULL && tgetflag("bs"))
4591590Srgrimes		CURS_LEFT =	"\b";
4601590Srgrimes
4611590Srgrimes	ENTER_STANDOUT =	tgetstr("so", &bp);
4621590Srgrimes	EXIT_STANDOUT =		tgetstr("se", &bp);
4631590Srgrimes	ENTER_UNDERLINE =	tgetstr("us", &bp);
4641590Srgrimes	EXIT_UNDERLINE =	tgetstr("ue", &bp);
4651590Srgrimes	ENTER_DIM =		tgetstr("mh", &bp);
4661590Srgrimes	ENTER_BOLD =		tgetstr("md", &bp);
4671590Srgrimes	ENTER_REVERSE =		tgetstr("mr", &bp);
4681590Srgrimes	EXIT_ATTRIBUTES =	tgetstr("me", &bp);
4691590Srgrimes
4701590Srgrimes	if (!ENTER_BOLD && ENTER_REVERSE)
4711590Srgrimes		ENTER_BOLD = ENTER_REVERSE;
4721590Srgrimes	if (!ENTER_BOLD && ENTER_STANDOUT)
4731590Srgrimes		ENTER_BOLD = ENTER_STANDOUT;
4741590Srgrimes	if (!ENTER_UNDERLINE && ENTER_STANDOUT) {
4751590Srgrimes		ENTER_UNDERLINE = ENTER_STANDOUT;
4761590Srgrimes		EXIT_UNDERLINE = EXIT_STANDOUT;
4771590Srgrimes	}
4781590Srgrimes	if (!ENTER_DIM && ENTER_STANDOUT)
4791590Srgrimes		ENTER_DIM = ENTER_STANDOUT;
4801590Srgrimes	if (!ENTER_REVERSE && ENTER_STANDOUT)
4811590Srgrimes		ENTER_REVERSE = ENTER_STANDOUT;
4821590Srgrimes	if (!EXIT_ATTRIBUTES && EXIT_STANDOUT)
4831590Srgrimes		EXIT_ATTRIBUTES = EXIT_STANDOUT;
4848874Srgrimes
4851590Srgrimes	/*
4861590Srgrimes	 * Note that we use REVERSE for the alternate character set,
4871590Srgrimes	 * not the as/ae capabilities.  This is because we are modelling
4881590Srgrimes	 * the model 37 teletype (since that's what nroff outputs) and
4891590Srgrimes	 * the typical as/ae is more of a graphics set, not the greek
4901590Srgrimes	 * letters the 37 has.
4911590Srgrimes	 */
4921590Srgrimes
4931590Srgrimes	UNDER_CHAR =		tgetstr("uc", &bp);
4941590Srgrimes	must_use_uc = (UNDER_CHAR && !ENTER_UNDERLINE);
4951590Srgrimes}
4961590Srgrimes
49728454Scharnierint
498102944Sdwmaloneoutchar(int c)
4991590Srgrimes{
500132858Stjr	return (putwchar(c) != WEOF ? c : EOF);
5011590Srgrimes}
5021590Srgrimes
5031590Srgrimesstatic int curmode = 0;
5041590Srgrimes
50528454Scharniervoid
506132858Stjroutc(wint_t c, int width)
5071590Srgrimes{
508132858Stjr	int i;
509132858Stjr
510132858Stjr	putwchar(c);
5111590Srgrimes	if (must_use_uc && (curmode&UNDERL)) {
512132858Stjr		for (i = 0; i < width; i++)
513132858Stjr			PRINT(CURS_LEFT);
514132858Stjr		for (i = 0; i < width; i++)
515132858Stjr			PRINT(UNDER_CHAR);
5161590Srgrimes	}
5171590Srgrimes}
5181590Srgrimes
51928454Scharniervoid
520102944Sdwmalonesetnewmode(int newmode)
5211590Srgrimes{
5221590Srgrimes	if (!iflag) {
5231590Srgrimes		if (curmode != NORMAL && newmode != NORMAL)
52428454Scharnier			setnewmode(NORMAL);
5251590Srgrimes		switch (newmode) {
5261590Srgrimes		case NORMAL:
5271590Srgrimes			switch(curmode) {
5281590Srgrimes			case NORMAL:
5291590Srgrimes				break;
5301590Srgrimes			case UNDERL:
5311590Srgrimes				PRINT(EXIT_UNDERLINE);
5321590Srgrimes				break;
5331590Srgrimes			default:
5341590Srgrimes				/* This includes standout */
5351590Srgrimes				PRINT(EXIT_ATTRIBUTES);
5361590Srgrimes				break;
5371590Srgrimes			}
5381590Srgrimes			break;
5391590Srgrimes		case ALTSET:
5401590Srgrimes			PRINT(ENTER_REVERSE);
5411590Srgrimes			break;
5421590Srgrimes		case SUPERSC:
5431590Srgrimes			/*
5441590Srgrimes			 * This only works on a few terminals.
5451590Srgrimes			 * It should be fixed.
5461590Srgrimes			 */
5471590Srgrimes			PRINT(ENTER_UNDERLINE);
5481590Srgrimes			PRINT(ENTER_DIM);
5491590Srgrimes			break;
5501590Srgrimes		case SUBSC:
5511590Srgrimes			PRINT(ENTER_DIM);
5521590Srgrimes			break;
5531590Srgrimes		case UNDERL:
5541590Srgrimes			PRINT(ENTER_UNDERLINE);
5551590Srgrimes			break;
5561590Srgrimes		case BOLD:
5571590Srgrimes			PRINT(ENTER_BOLD);
5581590Srgrimes			break;
5591590Srgrimes		default:
5601590Srgrimes			/*
5611590Srgrimes			 * We should have some provision here for multiple modes
5621590Srgrimes			 * on at once.  This will have to come later.
5631590Srgrimes			 */
5641590Srgrimes			PRINT(ENTER_STANDOUT);
5651590Srgrimes			break;
5661590Srgrimes		}
5671590Srgrimes	}
5681590Srgrimes	curmode = newmode;
5691590Srgrimes}
570