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 * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
301590Srgrimes#ifndef lint
3128454Scharnierstatic const char copyright[] =
321590Srgrimes"@(#) Copyright (c) 1980, 1993\n\
331590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
341590Srgrimes#endif /* not lint */
351590Srgrimes
361590Srgrimes#ifndef lint
3728454Scharnier#if 0
381590Srgrimesstatic char sccsid[] = "@(#)ul.c	8.1 (Berkeley) 6/6/93";
3928454Scharnier#endif
4028454Scharnierstatic const char rcsid[] =
4150477Speter  "$FreeBSD$";
421590Srgrimes#endif /* not lint */
431590Srgrimes
4428454Scharnier#include <err.h>
45132858Stjr#include <locale.h>
461590Srgrimes#include <stdio.h>
4728454Scharnier#include <stdlib.h>
4828454Scharnier#include <string.h>
4928454Scharnier#include <termcap.h>
5028454Scharnier#include <unistd.h>
51132858Stjr#include <wchar.h>
52200462Sdelphij#include <wctype.h>
531590Srgrimes
541590Srgrimes#define	IESC	'\033'
551590Srgrimes#define	SO	'\016'
561590Srgrimes#define	SI	'\017'
571590Srgrimes#define	HFWD	'9'
581590Srgrimes#define	HREV	'8'
591590Srgrimes#define	FREV	'7'
601590Srgrimes#define	MAXBUF	512
611590Srgrimes
621590Srgrimes#define	NORMAL	000
631590Srgrimes#define	ALTSET	001	/* Reverse */
641590Srgrimes#define	SUPERSC	002	/* Dim */
651590Srgrimes#define	SUBSC	004	/* Dim | Ul */
661590Srgrimes#define	UNDERL	010	/* Ul */
671590Srgrimes#define	BOLD	020	/* Bold */
681590Srgrimes
69227190Sedstatic int	must_use_uc, must_overstrike;
70227190Sedstatic const char
7187303Sdwmalone	*CURS_UP, *CURS_RIGHT, *CURS_LEFT,
721590Srgrimes	*ENTER_STANDOUT, *EXIT_STANDOUT, *ENTER_UNDERLINE, *EXIT_UNDERLINE,
731590Srgrimes	*ENTER_DIM, *ENTER_BOLD, *ENTER_REVERSE, *UNDER_CHAR, *EXIT_ATTRIBUTES;
741590Srgrimes
751590Srgrimesstruct	CHAR	{
761590Srgrimes	char	c_mode;
77132858Stjr	wchar_t	c_char;
78132858Stjr	int	c_width;	/* width or -1 if multi-column char. filler */
791590Srgrimes} ;
801590Srgrimes
81303075Sgahrstatic struct	CHAR	sobuf[MAXBUF]; /* static output buffer */
82303075Sgahrstatic struct	CHAR	*obuf = sobuf;
83303075Sgahrstatic int	buflen = MAXBUF;
84227190Sedstatic int	col, maxcol;
85227190Sedstatic int	mode;
86227190Sedstatic int	halfpos;
87227190Sedstatic int	upln;
88227190Sedstatic int	iflag;
891590Srgrimes
9092922Simpstatic void usage(void);
91227190Sedstatic void setnewmode(int);
92227190Sedstatic void initcap(void);
93227190Sedstatic void reverse(void);
94227190Sedstatic int outchar(int);
95227190Sedstatic void fwd(void);
96227190Sedstatic void initbuf(void);
97227190Sedstatic void iattr(void);
98227190Sedstatic void overstrike(void);
99227190Sedstatic void flushln(void);
100227190Sedstatic void filter(FILE *);
101227190Sedstatic void outc(wint_t, int);
10228454Scharnier
1031590Srgrimes#define	PRINT(s)	if (s == NULL) /* void */; else tputs(s, 1, outchar)
1041590Srgrimes
10528789Scharnierint
106102944Sdwmalonemain(int argc, char **argv)
1071590Srgrimes{
1081590Srgrimes	int c;
10987303Sdwmalone	const char *termtype;
1101590Srgrimes	FILE *f;
1111590Srgrimes	char termcap[1024];
1121590Srgrimes
113132858Stjr	setlocale(LC_ALL, "");
114132858Stjr
1151590Srgrimes	termtype = getenv("TERM");
1161590Srgrimes	if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1)))
1171590Srgrimes		termtype = "lpr";
11824360Simp	while ((c=getopt(argc, argv, "it:T:")) != -1)
1191590Srgrimes		switch(c) {
1201590Srgrimes
1211590Srgrimes		case 't':
1221590Srgrimes		case 'T': /* for nroff compatibility */
12387303Sdwmalone			termtype = optarg;
1241590Srgrimes			break;
1251590Srgrimes		case 'i':
1261590Srgrimes			iflag = 1;
1271590Srgrimes			break;
1281590Srgrimes		default:
12928454Scharnier			usage();
1301590Srgrimes		}
1311590Srgrimes
1321590Srgrimes	switch(tgetent(termcap, termtype)) {
1331590Srgrimes
1341590Srgrimes	case 1:
1351590Srgrimes		break;
1361590Srgrimes
1371590Srgrimes	default:
13828454Scharnier		warnx("trouble reading termcap");
139102412Scharnier		/* FALLTHROUGH */
1401590Srgrimes
1411590Srgrimes	case 0:
1421590Srgrimes		/* No such terminal type - assume dumb */
1431590Srgrimes		(void)strcpy(termcap, "dumb:os:col#80:cr=^M:sf=^J:am:");
1441590Srgrimes		break;
1451590Srgrimes	}
1461590Srgrimes	initcap();
1471590Srgrimes	if (    (tgetflag("os") && ENTER_BOLD==NULL ) ||
1481590Srgrimes		(tgetflag("ul") && ENTER_UNDERLINE==NULL && UNDER_CHAR==NULL))
1491590Srgrimes			must_overstrike = 1;
1501590Srgrimes	initbuf();
1511590Srgrimes	if (optind == argc)
1521590Srgrimes		filter(stdin);
1531590Srgrimes	else for (; optind<argc; optind++) {
1541590Srgrimes		f = fopen(argv[optind],"r");
15528454Scharnier		if (f == NULL)
15628454Scharnier			err(1, "%s", argv[optind]);
15728454Scharnier		else
1581590Srgrimes			filter(f);
1591590Srgrimes	}
160303075Sgahr	if (obuf != sobuf) {
161303075Sgahr		free(obuf);
162303075Sgahr	}
1631590Srgrimes	exit(0);
1641590Srgrimes}
1651590Srgrimes
16628454Scharnierstatic void
167102944Sdwmaloneusage(void)
16828454Scharnier{
169146466Sru	fprintf(stderr, "usage: ul [-i] [-t terminal] [file ...]\n");
17028454Scharnier	exit(1);
17128454Scharnier}
17228454Scharnier
173227190Sedstatic void
174102944Sdwmalonefilter(FILE *f)
1751590Srgrimes{
176132858Stjr	wint_t c;
177132858Stjr	int i, w;
178303075Sgahr	int copy;
179303075Sgahr
180303075Sgahr	copy = 0;
1811590Srgrimes
182303075Sgahr	while ((c = getwc(f)) != WEOF) {
183303075Sgahr		if (col == buflen) {
184303075Sgahr			if (obuf == sobuf) {
185303075Sgahr				obuf = NULL;
186303075Sgahr				copy = 1;
187303075Sgahr			}
188303075Sgahr			obuf = realloc(obuf, sizeof(*obuf) * 2 * buflen);
189303075Sgahr			if (obuf == NULL) {
190303075Sgahr				obuf = sobuf;
191303075Sgahr				break;
192303075Sgahr			} else if (copy) {
193303075Sgahr				memcpy(obuf, sobuf, sizeof(*obuf) * buflen);
194303075Sgahr				copy = 0;
195303075Sgahr			}
196303075Sgahr			bzero((char *)(obuf + buflen), sizeof(*obuf) * buflen);
197303075Sgahr			buflen *= 2;
198303075Sgahr		}
199303075Sgahr		switch(c) {
200303075Sgahr		case '\b':
201303075Sgahr			if (col > 0)
202303075Sgahr				col--;
203303075Sgahr			continue;
2041590Srgrimes
205303075Sgahr		case '\t':
206303075Sgahr			col = (col+8) & ~07;
207303075Sgahr			if (col > maxcol)
208303075Sgahr				maxcol = col;
209303075Sgahr			continue;
2101590Srgrimes
211303075Sgahr		case '\r':
212303075Sgahr			col = 0;
213303075Sgahr			continue;
2141590Srgrimes
215303075Sgahr		case SO:
216303075Sgahr			mode |= ALTSET;
217303075Sgahr			continue;
2181590Srgrimes
219303075Sgahr		case SI:
220303075Sgahr			mode &= ~ALTSET;
221303075Sgahr			continue;
2221590Srgrimes
223303075Sgahr		case IESC:
224303075Sgahr			switch (c = getwc(f)) {
2251590Srgrimes
226303075Sgahr			case HREV:
227303075Sgahr				if (halfpos == 0) {
228303075Sgahr					mode |= SUPERSC;
229303075Sgahr					halfpos--;
230303075Sgahr				} else if (halfpos > 0) {
231303075Sgahr					mode &= ~SUBSC;
232303075Sgahr					halfpos--;
233303075Sgahr				} else {
234303075Sgahr					halfpos = 0;
235303075Sgahr					reverse();
236303075Sgahr				}
237303075Sgahr				continue;
2381590Srgrimes
239303075Sgahr			case HFWD:
240303075Sgahr				if (halfpos == 0) {
241303075Sgahr					mode |= SUBSC;
242303075Sgahr					halfpos++;
243303075Sgahr				} else if (halfpos < 0) {
244303075Sgahr					mode &= ~SUPERSC;
245303075Sgahr					halfpos++;
246303075Sgahr				} else {
247303075Sgahr					halfpos = 0;
248303075Sgahr					fwd();
249303075Sgahr				}
250303075Sgahr				continue;
251303075Sgahr
252303075Sgahr			case FREV:
2531590Srgrimes				reverse();
254303075Sgahr				continue;
255303075Sgahr
256303075Sgahr			default:
257303075Sgahr				errx(1, "unknown escape sequence in input: %o, %o", IESC, c);
2581590Srgrimes			}
2591590Srgrimes			continue;
2601590Srgrimes
261303075Sgahr		case '_':
262303075Sgahr			if (obuf[col].c_char || obuf[col].c_width < 0) {
263303075Sgahr				while (col > 0 && obuf[col].c_width < 0)
264303075Sgahr					col--;
265303075Sgahr				w = obuf[col].c_width;
266303075Sgahr				for (i = 0; i < w; i++)
267303075Sgahr					obuf[col++].c_mode |= UNDERL | mode;
268303075Sgahr				if (col > maxcol)
269303075Sgahr					maxcol = col;
270303075Sgahr				continue;
2711590Srgrimes			}
272303075Sgahr			obuf[col].c_char = '_';
273303075Sgahr			obuf[col].c_width = 1;
274303075Sgahr			/* FALLTHROUGH */
275303075Sgahr		case ' ':
276303075Sgahr			col++;
277303075Sgahr			if (col > maxcol)
278303075Sgahr				maxcol = col;
2791590Srgrimes			continue;
2801590Srgrimes
281303075Sgahr		case '\n':
282303075Sgahr			flushln();
2831590Srgrimes			continue;
2841590Srgrimes
285303075Sgahr		case '\f':
286303075Sgahr			flushln();
287303075Sgahr			putwchar('\f');
288303075Sgahr			continue;
289303075Sgahr
2901590Srgrimes		default:
291303075Sgahr			if ((w = wcwidth(c)) <= 0)	/* non printing */
292303075Sgahr				continue;
293303075Sgahr			if (obuf[col].c_char == '\0') {
294303075Sgahr				obuf[col].c_char = c;
295303075Sgahr				for (i = 0; i < w; i++)
296303075Sgahr					obuf[col + i].c_mode = mode;
297303075Sgahr				obuf[col].c_width = w;
298303075Sgahr				for (i = 1; i < w; i++)
299303075Sgahr					obuf[col + i].c_width = -1;
300303075Sgahr			} else if (obuf[col].c_char == '_') {
301303075Sgahr				obuf[col].c_char = c;
302303075Sgahr				for (i = 0; i < w; i++)
303303075Sgahr					obuf[col + i].c_mode |= UNDERL|mode;
304303075Sgahr				obuf[col].c_width = w;
305303075Sgahr				for (i = 1; i < w; i++)
306303075Sgahr					obuf[col + i].c_width = -1;
307303075Sgahr			} else if ((wint_t)obuf[col].c_char == c) {
308303075Sgahr				for (i = 0; i < w; i++)
309303075Sgahr					obuf[col + i].c_mode |= BOLD|mode;
310303075Sgahr			} else {
311303075Sgahr				w = obuf[col].c_width;
312303075Sgahr				for (i = 0; i < w; i++)
313303075Sgahr					obuf[col + i].c_mode = mode;
314303075Sgahr			}
315303075Sgahr			col += w;
316132858Stjr			if (col > maxcol)
317132858Stjr				maxcol = col;
318132858Stjr			continue;
319132858Stjr		}
3201590Srgrimes	}
321132882Stjr	if (ferror(f))
322132882Stjr		err(1, NULL);
3231590Srgrimes	if (maxcol)
3241590Srgrimes		flushln();
3251590Srgrimes}
3261590Srgrimes
327227190Sedstatic void
328102944Sdwmaloneflushln(void)
3291590Srgrimes{
33087303Sdwmalone	int lastmode;
33187303Sdwmalone	int i;
3321590Srgrimes	int hadmodes = 0;
3331590Srgrimes
3341590Srgrimes	lastmode = NORMAL;
3351590Srgrimes	for (i=0; i<maxcol; i++) {
3361590Srgrimes		if (obuf[i].c_mode != lastmode) {
3371590Srgrimes			hadmodes++;
33828454Scharnier			setnewmode(obuf[i].c_mode);
3391590Srgrimes			lastmode = obuf[i].c_mode;
3401590Srgrimes		}
3411590Srgrimes		if (obuf[i].c_char == '\0') {
3421590Srgrimes			if (upln)
3431590Srgrimes				PRINT(CURS_RIGHT);
3441590Srgrimes			else
345132858Stjr				outc(' ', 1);
3461590Srgrimes		} else
347132858Stjr			outc(obuf[i].c_char, obuf[i].c_width);
348132858Stjr		if (obuf[i].c_width > 1)
349132858Stjr			i += obuf[i].c_width - 1;
3501590Srgrimes	}
3511590Srgrimes	if (lastmode != NORMAL) {
35228454Scharnier		setnewmode(0);
3531590Srgrimes	}
3541590Srgrimes	if (must_overstrike && hadmodes)
3551590Srgrimes		overstrike();
356132858Stjr	putwchar('\n');
3571590Srgrimes	if (iflag && hadmodes)
3581590Srgrimes		iattr();
3591590Srgrimes	(void)fflush(stdout);
3601590Srgrimes	if (upln)
3611590Srgrimes		upln--;
3621590Srgrimes	initbuf();
3631590Srgrimes}
3641590Srgrimes
3651590Srgrimes/*
3661590Srgrimes * For terminals that can overstrike, overstrike underlines and bolds.
3671590Srgrimes * We don't do anything with halfline ups and downs, or Greek.
3681590Srgrimes */
369227190Sedstatic void
370102944Sdwmaloneoverstrike(void)
3711590Srgrimes{
372102944Sdwmalone	int i;
373132858Stjr	wchar_t lbuf[256];
374132858Stjr	wchar_t *cp = lbuf;
3751590Srgrimes	int hadbold=0;
3761590Srgrimes
3771590Srgrimes	/* Set up overstrike buffer */
3781590Srgrimes	for (i=0; i<maxcol; i++)
3791590Srgrimes		switch (obuf[i].c_mode) {
3801590Srgrimes		case NORMAL:
3811590Srgrimes		default:
3821590Srgrimes			*cp++ = ' ';
3831590Srgrimes			break;
3841590Srgrimes		case UNDERL:
3851590Srgrimes			*cp++ = '_';
3861590Srgrimes			break;
3871590Srgrimes		case BOLD:
3881590Srgrimes			*cp++ = obuf[i].c_char;
389132858Stjr			if (obuf[i].c_width > 1)
390132858Stjr				i += obuf[i].c_width - 1;
3911590Srgrimes			hadbold=1;
3921590Srgrimes			break;
3931590Srgrimes		}
394132858Stjr	putwchar('\r');
3951590Srgrimes	for (*cp=' '; *cp==' '; cp--)
3961590Srgrimes		*cp = 0;
3971590Srgrimes	for (cp=lbuf; *cp; cp++)
398132858Stjr		putwchar(*cp);
3991590Srgrimes	if (hadbold) {
400132858Stjr		putwchar('\r');
4011590Srgrimes		for (cp=lbuf; *cp; cp++)
402132858Stjr			putwchar(*cp=='_' ? ' ' : *cp);
403132858Stjr		putwchar('\r');
4041590Srgrimes		for (cp=lbuf; *cp; cp++)
405132858Stjr			putwchar(*cp=='_' ? ' ' : *cp);
4061590Srgrimes	}
4071590Srgrimes}
4081590Srgrimes
409227190Sedstatic void
410102944Sdwmaloneiattr(void)
4111590Srgrimes{
412102944Sdwmalone	int i;
413132858Stjr	wchar_t lbuf[256];
414132858Stjr	wchar_t *cp = lbuf;
4151590Srgrimes
4161590Srgrimes	for (i=0; i<maxcol; i++)
4171590Srgrimes		switch (obuf[i].c_mode) {
4181590Srgrimes		case NORMAL:	*cp++ = ' '; break;
4191590Srgrimes		case ALTSET:	*cp++ = 'g'; break;
4201590Srgrimes		case SUPERSC:	*cp++ = '^'; break;
4211590Srgrimes		case SUBSC:	*cp++ = 'v'; break;
4221590Srgrimes		case UNDERL:	*cp++ = '_'; break;
4231590Srgrimes		case BOLD:	*cp++ = '!'; break;
4241590Srgrimes		default:	*cp++ = 'X'; break;
4251590Srgrimes		}
4261590Srgrimes	for (*cp=' '; *cp==' '; cp--)
4271590Srgrimes		*cp = 0;
4281590Srgrimes	for (cp=lbuf; *cp; cp++)
429132858Stjr		putwchar(*cp);
430132858Stjr	putwchar('\n');
4311590Srgrimes}
4321590Srgrimes
433227190Sedstatic void
434102944Sdwmaloneinitbuf(void)
4351590Srgrimes{
4361590Srgrimes
437303075Sgahr	bzero((char *)obuf, buflen * sizeof(*obuf)); /* depends on NORMAL == 0 */
4381590Srgrimes	col = 0;
4391590Srgrimes	maxcol = 0;
4401590Srgrimes	mode &= ALTSET;
4411590Srgrimes}
4421590Srgrimes
443227190Sedstatic void
444102944Sdwmalonefwd(void)
4451590Srgrimes{
44687303Sdwmalone	int oldcol, oldmax;
4471590Srgrimes
4481590Srgrimes	oldcol = col;
4491590Srgrimes	oldmax = maxcol;
4501590Srgrimes	flushln();
4511590Srgrimes	col = oldcol;
4521590Srgrimes	maxcol = oldmax;
4531590Srgrimes}
4541590Srgrimes
455227190Sedstatic void
456102944Sdwmalonereverse(void)
4571590Srgrimes{
4581590Srgrimes	upln++;
4591590Srgrimes	fwd();
4601590Srgrimes	PRINT(CURS_UP);
4611590Srgrimes	PRINT(CURS_UP);
4621590Srgrimes	upln++;
4631590Srgrimes}
4641590Srgrimes
465227190Sedstatic void
466102944Sdwmaloneinitcap(void)
4671590Srgrimes{
4681590Srgrimes	static char tcapbuf[512];
4691590Srgrimes	char *bp = tcapbuf;
4701590Srgrimes
4711590Srgrimes	/* This nonsense attempts to work with both old and new termcap */
4721590Srgrimes	CURS_UP =		tgetstr("up", &bp);
4731590Srgrimes	CURS_RIGHT =		tgetstr("ri", &bp);
4741590Srgrimes	if (CURS_RIGHT == NULL)
4751590Srgrimes		CURS_RIGHT =	tgetstr("nd", &bp);
4761590Srgrimes	CURS_LEFT =		tgetstr("le", &bp);
4771590Srgrimes	if (CURS_LEFT == NULL)
4781590Srgrimes		CURS_LEFT =	tgetstr("bc", &bp);
4791590Srgrimes	if (CURS_LEFT == NULL && tgetflag("bs"))
4801590Srgrimes		CURS_LEFT =	"\b";
4811590Srgrimes
4821590Srgrimes	ENTER_STANDOUT =	tgetstr("so", &bp);
4831590Srgrimes	EXIT_STANDOUT =		tgetstr("se", &bp);
4841590Srgrimes	ENTER_UNDERLINE =	tgetstr("us", &bp);
4851590Srgrimes	EXIT_UNDERLINE =	tgetstr("ue", &bp);
4861590Srgrimes	ENTER_DIM =		tgetstr("mh", &bp);
4871590Srgrimes	ENTER_BOLD =		tgetstr("md", &bp);
4881590Srgrimes	ENTER_REVERSE =		tgetstr("mr", &bp);
4891590Srgrimes	EXIT_ATTRIBUTES =	tgetstr("me", &bp);
4901590Srgrimes
4911590Srgrimes	if (!ENTER_BOLD && ENTER_REVERSE)
4921590Srgrimes		ENTER_BOLD = ENTER_REVERSE;
4931590Srgrimes	if (!ENTER_BOLD && ENTER_STANDOUT)
4941590Srgrimes		ENTER_BOLD = ENTER_STANDOUT;
4951590Srgrimes	if (!ENTER_UNDERLINE && ENTER_STANDOUT) {
4961590Srgrimes		ENTER_UNDERLINE = ENTER_STANDOUT;
4971590Srgrimes		EXIT_UNDERLINE = EXIT_STANDOUT;
4981590Srgrimes	}
4991590Srgrimes	if (!ENTER_DIM && ENTER_STANDOUT)
5001590Srgrimes		ENTER_DIM = ENTER_STANDOUT;
5011590Srgrimes	if (!ENTER_REVERSE && ENTER_STANDOUT)
5021590Srgrimes		ENTER_REVERSE = ENTER_STANDOUT;
5031590Srgrimes	if (!EXIT_ATTRIBUTES && EXIT_STANDOUT)
5041590Srgrimes		EXIT_ATTRIBUTES = EXIT_STANDOUT;
5058874Srgrimes
5061590Srgrimes	/*
5071590Srgrimes	 * Note that we use REVERSE for the alternate character set,
5081590Srgrimes	 * not the as/ae capabilities.  This is because we are modelling
5091590Srgrimes	 * the model 37 teletype (since that's what nroff outputs) and
5101590Srgrimes	 * the typical as/ae is more of a graphics set, not the greek
5111590Srgrimes	 * letters the 37 has.
5121590Srgrimes	 */
5131590Srgrimes
5141590Srgrimes	UNDER_CHAR =		tgetstr("uc", &bp);
5151590Srgrimes	must_use_uc = (UNDER_CHAR && !ENTER_UNDERLINE);
5161590Srgrimes}
5171590Srgrimes
518227190Sedstatic int
519102944Sdwmaloneoutchar(int c)
5201590Srgrimes{
521132858Stjr	return (putwchar(c) != WEOF ? c : EOF);
5221590Srgrimes}
5231590Srgrimes
5241590Srgrimesstatic int curmode = 0;
5251590Srgrimes
526227190Sedstatic void
527132858Stjroutc(wint_t c, int width)
5281590Srgrimes{
529132858Stjr	int i;
530132858Stjr
531132858Stjr	putwchar(c);
5321590Srgrimes	if (must_use_uc && (curmode&UNDERL)) {
533132858Stjr		for (i = 0; i < width; i++)
534132858Stjr			PRINT(CURS_LEFT);
535132858Stjr		for (i = 0; i < width; i++)
536132858Stjr			PRINT(UNDER_CHAR);
5371590Srgrimes	}
5381590Srgrimes}
5391590Srgrimes
540227190Sedstatic void
541102944Sdwmalonesetnewmode(int newmode)
5421590Srgrimes{
5431590Srgrimes	if (!iflag) {
5441590Srgrimes		if (curmode != NORMAL && newmode != NORMAL)
54528454Scharnier			setnewmode(NORMAL);
5461590Srgrimes		switch (newmode) {
5471590Srgrimes		case NORMAL:
5481590Srgrimes			switch(curmode) {
5491590Srgrimes			case NORMAL:
5501590Srgrimes				break;
5511590Srgrimes			case UNDERL:
5521590Srgrimes				PRINT(EXIT_UNDERLINE);
5531590Srgrimes				break;
5541590Srgrimes			default:
5551590Srgrimes				/* This includes standout */
5561590Srgrimes				PRINT(EXIT_ATTRIBUTES);
5571590Srgrimes				break;
5581590Srgrimes			}
5591590Srgrimes			break;
5601590Srgrimes		case ALTSET:
5611590Srgrimes			PRINT(ENTER_REVERSE);
5621590Srgrimes			break;
5631590Srgrimes		case SUPERSC:
5641590Srgrimes			/*
5651590Srgrimes			 * This only works on a few terminals.
5661590Srgrimes			 * It should be fixed.
5671590Srgrimes			 */
5681590Srgrimes			PRINT(ENTER_UNDERLINE);
5691590Srgrimes			PRINT(ENTER_DIM);
5701590Srgrimes			break;
5711590Srgrimes		case SUBSC:
5721590Srgrimes			PRINT(ENTER_DIM);
5731590Srgrimes			break;
5741590Srgrimes		case UNDERL:
5751590Srgrimes			PRINT(ENTER_UNDERLINE);
5761590Srgrimes			break;
5771590Srgrimes		case BOLD:
5781590Srgrimes			PRINT(ENTER_BOLD);
5791590Srgrimes			break;
5801590Srgrimes		default:
5811590Srgrimes			/*
5821590Srgrimes			 * We should have some provision here for multiple modes
5831590Srgrimes			 * on at once.  This will have to come later.
5841590Srgrimes			 */
5851590Srgrimes			PRINT(ENTER_STANDOUT);
5861590Srgrimes			break;
5871590Srgrimes		}
5881590Srgrimes	}
5891590Srgrimes	curmode = newmode;
5901590Srgrimes}
591