xref: /titanic_44/usr/src/cmd/ul/ul.c (revision dc5a8425272d2602e4c21b95b9eeac2b897f45a1)
1*dc5a8425Srobbin /*
2*dc5a8425Srobbin  * Copyright 2000 Sun Microsystems, Inc.  All rights reserved.
3*dc5a8425Srobbin  * Use is subject to license terms.
4*dc5a8425Srobbin  */
5*dc5a8425Srobbin 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
117c478bd9Sstevel@tonic-gate  * All rights reserved. The Berkeley software License Agreement
127c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
15*dc5a8425Srobbin #pragma ident	"%Z%%M%	%I%	%E% SMI"
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #include <stdio.h>
187c478bd9Sstevel@tonic-gate #include <locale.h>
197c478bd9Sstevel@tonic-gate #include <wctype.h>
207c478bd9Sstevel@tonic-gate #include <widec.h>
217c478bd9Sstevel@tonic-gate #include <euc.h>
22*dc5a8425Srobbin #include <getwidth.h>
237c478bd9Sstevel@tonic-gate #include <limits.h>
247c478bd9Sstevel@tonic-gate #include <stdlib.h>
25*dc5a8425Srobbin #include <curses.h>
26*dc5a8425Srobbin #include <term.h>
27*dc5a8425Srobbin #include <string.h>
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #define	IESC	L'\033'
307c478bd9Sstevel@tonic-gate #define	SO	L'\016'
317c478bd9Sstevel@tonic-gate #define	SI	L'\017'
327c478bd9Sstevel@tonic-gate #define	HFWD	L'9'
337c478bd9Sstevel@tonic-gate #define	HREV	L'8'
347c478bd9Sstevel@tonic-gate #define	FREV	L'7'
357c478bd9Sstevel@tonic-gate #define	CDUMMY	-1
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #define	NORMAL	000
387c478bd9Sstevel@tonic-gate #define	ALTSET	001	/* Reverse */
397c478bd9Sstevel@tonic-gate #define	SUPERSC	002	/* Dim */
407c478bd9Sstevel@tonic-gate #define	SUBSC	004	/* Dim | Ul */
417c478bd9Sstevel@tonic-gate #define	UNDERL	010	/* Ul */
427c478bd9Sstevel@tonic-gate #define	BOLD	020	/* Bold */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #define	MEMFCT	16
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * MEMFCT is a number that is likely to be large enough as a factor for
477c478bd9Sstevel@tonic-gate  * allocating more memory and to be small enough so as not wasting memory
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate int	must_use_uc, must_overstrike;
517c478bd9Sstevel@tonic-gate char	*CURS_UP, *CURS_RIGHT, *CURS_LEFT,
527c478bd9Sstevel@tonic-gate 	*ENTER_STANDOUT, *EXIT_STANDOUT, *ENTER_UNDERLINE, *EXIT_UNDERLINE,
537c478bd9Sstevel@tonic-gate 	*ENTER_DIM, *ENTER_BOLD, *ENTER_REVERSE, *UNDER_CHAR, *EXIT_ATTRIBUTES;
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate struct	CHAR	{
567c478bd9Sstevel@tonic-gate 	char	c_mode;
577c478bd9Sstevel@tonic-gate 	wchar_t	c_char;
587c478bd9Sstevel@tonic-gate };
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate struct	CHAR	obuf[LINE_MAX];
617c478bd9Sstevel@tonic-gate int	col, maxcol;
627c478bd9Sstevel@tonic-gate int	mode;
637c478bd9Sstevel@tonic-gate int	halfpos;
647c478bd9Sstevel@tonic-gate int	upln;
657c478bd9Sstevel@tonic-gate int	iflag;
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate eucwidth_t wp;
687c478bd9Sstevel@tonic-gate int scrw[4];
697c478bd9Sstevel@tonic-gate 
70*dc5a8425Srobbin void setmode(int newmode);
71*dc5a8425Srobbin void outc(wchar_t c);
72*dc5a8425Srobbin int outchar(char c);
73*dc5a8425Srobbin void initcap(void);
74*dc5a8425Srobbin void reverse(void);
75*dc5a8425Srobbin void fwd(void);
76*dc5a8425Srobbin void initbuf(void);
77*dc5a8425Srobbin void iattr(void);
78*dc5a8425Srobbin void overstrike(void);
79*dc5a8425Srobbin void flushln(void);
80*dc5a8425Srobbin void ul_filter(FILE *f);
81*dc5a8425Srobbin void ul_puts(char *str);
82*dc5a8425Srobbin 
83*dc5a8425Srobbin int
main(int argc,char ** argv)84*dc5a8425Srobbin main(int argc, char **argv)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	int c;
87*dc5a8425Srobbin 	char *termtype;
887c478bd9Sstevel@tonic-gate 	FILE *f;
897c478bd9Sstevel@tonic-gate 	char termcap[1024];
907c478bd9Sstevel@tonic-gate 	extern int optind;
917c478bd9Sstevel@tonic-gate 	extern char *optarg;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
947c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
957c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
967c478bd9Sstevel@tonic-gate #endif
977c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	getwidth(&wp);
1007c478bd9Sstevel@tonic-gate 	scrw[0] = 1;
1017c478bd9Sstevel@tonic-gate 	scrw[1] = wp._scrw1;
1027c478bd9Sstevel@tonic-gate 	scrw[2] = wp._scrw2;
1037c478bd9Sstevel@tonic-gate 	scrw[3] = wp._scrw3;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	termtype = getenv("TERM");
1067c478bd9Sstevel@tonic-gate 	if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1)))
1077c478bd9Sstevel@tonic-gate 		termtype = "lpr";
1087c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "it:T:")) != EOF)
1097c478bd9Sstevel@tonic-gate 		switch (c) {
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 		case 't':
1127c478bd9Sstevel@tonic-gate 		case 'T': /* for nroff compatibility */
1137c478bd9Sstevel@tonic-gate 				termtype = optarg;
1147c478bd9Sstevel@tonic-gate 			break;
1157c478bd9Sstevel@tonic-gate 		case 'i':
1167c478bd9Sstevel@tonic-gate 			iflag = 1;
1177c478bd9Sstevel@tonic-gate 			break;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 		default:
120*dc5a8425Srobbin 			(void) fprintf(stderr,
1217c478bd9Sstevel@tonic-gate 			gettext("\
1227c478bd9Sstevel@tonic-gate Usage: %s [ -i ] [ -t terminal ] [ filename...]\n"),
1237c478bd9Sstevel@tonic-gate 				argv[0]);
1247c478bd9Sstevel@tonic-gate 			exit(1);
1257c478bd9Sstevel@tonic-gate 		}
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	switch (tgetent(termcap, termtype)) {
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	case 1:
1307c478bd9Sstevel@tonic-gate 		break;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	default:
133*dc5a8425Srobbin 		(void) fprintf(stderr, gettext("trouble reading termcap"));
134*dc5a8425Srobbin 		/*FALLTHROUGH*/
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	case 0:
1377c478bd9Sstevel@tonic-gate 		/* No such terminal type - assume dumb */
138*dc5a8425Srobbin 		(void) strcpy(termcap, "dumb:os:col#80:cr=^M:sf=^J:am:");
1397c478bd9Sstevel@tonic-gate 		break;
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate 	initcap();
142*dc5a8425Srobbin 	if ((tgetflag("os") && ENTER_BOLD == NULL) || (tgetflag("ul") &&
143*dc5a8425Srobbin 		ENTER_UNDERLINE == NULL && UNDER_CHAR == NULL))
1447c478bd9Sstevel@tonic-gate 			must_overstrike = 1;
1457c478bd9Sstevel@tonic-gate 	initbuf();
1467c478bd9Sstevel@tonic-gate 	if (optind == argc)
147*dc5a8425Srobbin 		ul_filter(stdin);
1487c478bd9Sstevel@tonic-gate 	else for (; optind < argc; optind++) {
1497c478bd9Sstevel@tonic-gate 		f = fopen(argv[optind], "r");
1507c478bd9Sstevel@tonic-gate 		if (f == NULL) {
1517c478bd9Sstevel@tonic-gate 			perror(argv[optind]);
1527c478bd9Sstevel@tonic-gate 			exit(1);
1537c478bd9Sstevel@tonic-gate 		} else
154*dc5a8425Srobbin 			ul_filter(f);
1557c478bd9Sstevel@tonic-gate 	}
156*dc5a8425Srobbin 	return (0);
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate 
159*dc5a8425Srobbin void
ul_filter(FILE * f)160*dc5a8425Srobbin ul_filter(FILE *f)
1617c478bd9Sstevel@tonic-gate {
162*dc5a8425Srobbin 	wchar_t c;
163*dc5a8425Srobbin 	int i;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	while ((c = getwc(f)) != EOF) {
166*dc5a8425Srobbin 		if (maxcol >= LINE_MAX) {
167*dc5a8425Srobbin 			(void) fprintf(stderr,
1687c478bd9Sstevel@tonic-gate 	gettext("Input line longer than %d characters\n"), LINE_MAX);
1697c478bd9Sstevel@tonic-gate 			exit(1);
1707c478bd9Sstevel@tonic-gate 		}
1717c478bd9Sstevel@tonic-gate 		switch (c) {
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 		case L'\b':
1747c478bd9Sstevel@tonic-gate 			if (col > 0)
1757c478bd9Sstevel@tonic-gate 				col--;
1767c478bd9Sstevel@tonic-gate 			continue;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 		case L'\t':
1797c478bd9Sstevel@tonic-gate 			col = (col+8) & ~07;
1807c478bd9Sstevel@tonic-gate 			if (col > maxcol)
1817c478bd9Sstevel@tonic-gate 				maxcol = col;
1827c478bd9Sstevel@tonic-gate 			continue;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 		case L'\r':
1857c478bd9Sstevel@tonic-gate 			col = 0;
1867c478bd9Sstevel@tonic-gate 			continue;
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 		case SO:
1897c478bd9Sstevel@tonic-gate 			mode |= ALTSET;
1907c478bd9Sstevel@tonic-gate 			continue;
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 		case SI:
1937c478bd9Sstevel@tonic-gate 			mode &= ~ALTSET;
1947c478bd9Sstevel@tonic-gate 			continue;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 		case IESC:
1977c478bd9Sstevel@tonic-gate 			switch (c = getwc(f)) {
1987c478bd9Sstevel@tonic-gate 			case HREV:
1997c478bd9Sstevel@tonic-gate 				if (halfpos == 0) {
2007c478bd9Sstevel@tonic-gate 					mode |= SUPERSC;
2017c478bd9Sstevel@tonic-gate 					halfpos--;
2027c478bd9Sstevel@tonic-gate 				} else if (halfpos > 0) {
2037c478bd9Sstevel@tonic-gate 					mode &= ~SUBSC;
2047c478bd9Sstevel@tonic-gate 					halfpos--;
2057c478bd9Sstevel@tonic-gate 				} else {
2067c478bd9Sstevel@tonic-gate 					halfpos = 0;
2077c478bd9Sstevel@tonic-gate 					reverse();
2087c478bd9Sstevel@tonic-gate 				}
2097c478bd9Sstevel@tonic-gate 				continue;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 			case HFWD:
2127c478bd9Sstevel@tonic-gate 				if (halfpos == 0) {
2137c478bd9Sstevel@tonic-gate 					mode |= SUBSC;
2147c478bd9Sstevel@tonic-gate 					halfpos++;
2157c478bd9Sstevel@tonic-gate 				} else if (halfpos < 0) {
2167c478bd9Sstevel@tonic-gate 					mode &= ~SUPERSC;
2177c478bd9Sstevel@tonic-gate 					halfpos++;
2187c478bd9Sstevel@tonic-gate 				} else {
2197c478bd9Sstevel@tonic-gate 					halfpos = 0;
2207c478bd9Sstevel@tonic-gate 					fwd();
2217c478bd9Sstevel@tonic-gate 				}
2227c478bd9Sstevel@tonic-gate 				continue;
2237c478bd9Sstevel@tonic-gate 			case FREV:
2247c478bd9Sstevel@tonic-gate 				reverse();
2257c478bd9Sstevel@tonic-gate 				continue;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 			default:
228*dc5a8425Srobbin 				(void) fprintf(stderr,
2297c478bd9Sstevel@tonic-gate 			gettext("Unknown escape sequence in input: %o, %o\n"),
2307c478bd9Sstevel@tonic-gate 					IESC, c);
2317c478bd9Sstevel@tonic-gate 				exit(1);
2327c478bd9Sstevel@tonic-gate 			}
2337c478bd9Sstevel@tonic-gate 			continue;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 		case L'_':
2367c478bd9Sstevel@tonic-gate 			if (obuf[col].c_char)
2377c478bd9Sstevel@tonic-gate 				obuf[col].c_mode |= UNDERL | mode;
2387c478bd9Sstevel@tonic-gate 			else
2397c478bd9Sstevel@tonic-gate 				obuf[col].c_char = '_';
240*dc5a8425Srobbin 			/*FALLTHROUGH*/
241*dc5a8425Srobbin 
2427c478bd9Sstevel@tonic-gate 		case L' ':
2437c478bd9Sstevel@tonic-gate 			col++;
2447c478bd9Sstevel@tonic-gate 			if (col > maxcol)
2457c478bd9Sstevel@tonic-gate 				maxcol = col;
2467c478bd9Sstevel@tonic-gate 			continue;
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 		case L'\n':
2497c478bd9Sstevel@tonic-gate 			flushln();
2507c478bd9Sstevel@tonic-gate 			continue;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 		default:
2537c478bd9Sstevel@tonic-gate 			if (c < L' ')	/* non printing */
2547c478bd9Sstevel@tonic-gate 				continue;
2557c478bd9Sstevel@tonic-gate 			if (obuf[col].c_char == L'\0') {
2567c478bd9Sstevel@tonic-gate 				obuf[col].c_char = c;
2577c478bd9Sstevel@tonic-gate 				obuf[col].c_mode = mode;
2587c478bd9Sstevel@tonic-gate 				i = scrw[wcsetno(c)];
2597c478bd9Sstevel@tonic-gate 				while (--i > 0)
2607c478bd9Sstevel@tonic-gate 					obuf[++col].c_char = CDUMMY;
2617c478bd9Sstevel@tonic-gate 			} else if (obuf[col].c_char == L'_') {
2627c478bd9Sstevel@tonic-gate 				obuf[col].c_char = c;
2637c478bd9Sstevel@tonic-gate 				obuf[col].c_mode |= UNDERL|mode;
2647c478bd9Sstevel@tonic-gate 				i = scrw[wcsetno(c)];
2657c478bd9Sstevel@tonic-gate 				while (--i > 0)
2667c478bd9Sstevel@tonic-gate 					obuf[++col].c_char = CDUMMY;
2677c478bd9Sstevel@tonic-gate 			} else if (obuf[col].c_char == c)
2687c478bd9Sstevel@tonic-gate 				obuf[col].c_mode |= BOLD|mode;
2697c478bd9Sstevel@tonic-gate 			else {
2707c478bd9Sstevel@tonic-gate 				obuf[col].c_char = c;
2717c478bd9Sstevel@tonic-gate 				obuf[col].c_mode = mode;
2727c478bd9Sstevel@tonic-gate 			}
2737c478bd9Sstevel@tonic-gate 			col++;
2747c478bd9Sstevel@tonic-gate 			if (col > maxcol)
2757c478bd9Sstevel@tonic-gate 				maxcol = col;
2767c478bd9Sstevel@tonic-gate 			continue;
2777c478bd9Sstevel@tonic-gate 		}
2787c478bd9Sstevel@tonic-gate 	}
2797c478bd9Sstevel@tonic-gate 	if (maxcol)
2807c478bd9Sstevel@tonic-gate 		flushln();
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate 
283*dc5a8425Srobbin void
flushln(void)284*dc5a8425Srobbin flushln(void)
2857c478bd9Sstevel@tonic-gate {
286*dc5a8425Srobbin 	int lastmode;
287*dc5a8425Srobbin 	int i;
2887c478bd9Sstevel@tonic-gate 	int hadmodes = 0;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	lastmode = NORMAL;
2917c478bd9Sstevel@tonic-gate 	for (i = 0; i < maxcol; i++) {
2927c478bd9Sstevel@tonic-gate 		if (obuf[i].c_mode != lastmode) {
2937c478bd9Sstevel@tonic-gate 			hadmodes++;
2947c478bd9Sstevel@tonic-gate 			setmode(obuf[i].c_mode);
2957c478bd9Sstevel@tonic-gate 			lastmode = obuf[i].c_mode;
2967c478bd9Sstevel@tonic-gate 		}
2977c478bd9Sstevel@tonic-gate 		if (obuf[i].c_char == L'\0') {
2987c478bd9Sstevel@tonic-gate 			if (upln) {
299*dc5a8425Srobbin 				ul_puts(CURS_RIGHT);
3007c478bd9Sstevel@tonic-gate 			} else
3017c478bd9Sstevel@tonic-gate 				outc(L' ');
3027c478bd9Sstevel@tonic-gate 		} else
3037c478bd9Sstevel@tonic-gate 			outc(obuf[i].c_char);
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 	if (lastmode != NORMAL) {
3067c478bd9Sstevel@tonic-gate 		setmode(0);
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate 	if (must_overstrike && hadmodes)
3097c478bd9Sstevel@tonic-gate 		overstrike();
310*dc5a8425Srobbin 	(void) putwchar(L'\n');
3117c478bd9Sstevel@tonic-gate 	if (iflag && hadmodes)
3127c478bd9Sstevel@tonic-gate 		iattr();
3137c478bd9Sstevel@tonic-gate 	if (upln)
3147c478bd9Sstevel@tonic-gate 		upln--;
3157c478bd9Sstevel@tonic-gate 	initbuf();
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate /*
3197c478bd9Sstevel@tonic-gate  * For terminals that can overstrike, overstrike underlines and bolds.
3207c478bd9Sstevel@tonic-gate  * We don't do anything with halfline ups and downs, or Greek.
3217c478bd9Sstevel@tonic-gate  */
322*dc5a8425Srobbin void
overstrike(void)323*dc5a8425Srobbin overstrike(void)
3247c478bd9Sstevel@tonic-gate {
325*dc5a8425Srobbin 	int i, n;
3267c478bd9Sstevel@tonic-gate 	wchar_t *cp, *scp;
3277c478bd9Sstevel@tonic-gate 	size_t  szbf = 256, tszbf;
3287c478bd9Sstevel@tonic-gate 	int hadbold = 0;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	scp = (wchar_t *)malloc(sizeof (wchar_t) * szbf);
3317c478bd9Sstevel@tonic-gate 	if (!scp) {
3327c478bd9Sstevel@tonic-gate 	/* this kind of message need not to be gettext'ed */
3337c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "malloc failed\n");
3347c478bd9Sstevel@tonic-gate 		exit(1);
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 	cp = scp;
3377c478bd9Sstevel@tonic-gate 	tszbf = szbf;
3387c478bd9Sstevel@tonic-gate #ifdef DEBUG
3397c478bd9Sstevel@tonic-gate 	/*
3407c478bd9Sstevel@tonic-gate 	 * to allocate a memory after the chunk of the current scp
3417c478bd9Sstevel@tonic-gate 	 * and to make sure the following realloc() allocates
3427c478bd9Sstevel@tonic-gate 	 * memory from different chunks.
3437c478bd9Sstevel@tonic-gate 	 */
3447c478bd9Sstevel@tonic-gate 	(void) malloc(1024 * 1024);
3457c478bd9Sstevel@tonic-gate #endif
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	/* Set up overstrike buffer */
3487c478bd9Sstevel@tonic-gate 	for (i = 0; i < maxcol; i++) {
3497c478bd9Sstevel@tonic-gate 		n = scrw[wcsetno(obuf[i].c_char)];
3507c478bd9Sstevel@tonic-gate 		if (tszbf <= n) {
3517c478bd9Sstevel@tonic-gate 		/* may not enough buffer for this char */
3527c478bd9Sstevel@tonic-gate 			size_t  pos;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 			/* obtain the offset of cp */
3557c478bd9Sstevel@tonic-gate 			pos = cp - scp;
3567c478bd9Sstevel@tonic-gate 			/* reallocate another (n * MEMFCT) * sizeof (wchar_t) */
3577c478bd9Sstevel@tonic-gate 			scp = (wchar_t *)realloc(scp,
3587c478bd9Sstevel@tonic-gate 				sizeof (wchar_t) * (szbf + (n * MEMFCT)));
3597c478bd9Sstevel@tonic-gate 			if (!scp) {
3607c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "malloc failed\n");
3617c478bd9Sstevel@tonic-gate 				exit(1);
3627c478bd9Sstevel@tonic-gate 			}
3637c478bd9Sstevel@tonic-gate 			/* get the new address of cp */
3647c478bd9Sstevel@tonic-gate 			cp = scp + pos;
3657c478bd9Sstevel@tonic-gate 			szbf += n * MEMFCT;
3667c478bd9Sstevel@tonic-gate 			tszbf += n * MEMFCT;
3677c478bd9Sstevel@tonic-gate 		}
3687c478bd9Sstevel@tonic-gate 		switch (obuf[i].c_mode) {
3697c478bd9Sstevel@tonic-gate 		case NORMAL:
3707c478bd9Sstevel@tonic-gate 		default:
3717c478bd9Sstevel@tonic-gate 			tszbf -= n;
3727c478bd9Sstevel@tonic-gate 			*cp++ = L' ';
3737c478bd9Sstevel@tonic-gate 			while (--n > 0) {
3747c478bd9Sstevel@tonic-gate 				*cp++ = L' ';
3757c478bd9Sstevel@tonic-gate 				i++;
3767c478bd9Sstevel@tonic-gate 			}
3777c478bd9Sstevel@tonic-gate 			break;
3787c478bd9Sstevel@tonic-gate 		case UNDERL:
3797c478bd9Sstevel@tonic-gate 			tszbf -= n;
3807c478bd9Sstevel@tonic-gate 			*cp++ = L'_';
3817c478bd9Sstevel@tonic-gate 			while (--n > 0) {
3827c478bd9Sstevel@tonic-gate 				*cp++ = L'_';
3837c478bd9Sstevel@tonic-gate 				i++;
3847c478bd9Sstevel@tonic-gate 			}
3857c478bd9Sstevel@tonic-gate 			break;
3867c478bd9Sstevel@tonic-gate 		case BOLD:
3877c478bd9Sstevel@tonic-gate 			tszbf--;
3887c478bd9Sstevel@tonic-gate 			*cp++ = obuf[i].c_char;
3897c478bd9Sstevel@tonic-gate 			hadbold = 1;
3907c478bd9Sstevel@tonic-gate 			break;
3917c478bd9Sstevel@tonic-gate 		}
3927c478bd9Sstevel@tonic-gate 	}
393*dc5a8425Srobbin 	(void) putwchar(L'\r');
3947c478bd9Sstevel@tonic-gate 	for (*cp = L' '; *cp == L' '; cp--)
3957c478bd9Sstevel@tonic-gate 		*cp = L'\0';
3967c478bd9Sstevel@tonic-gate 	for (cp = scp; *cp; cp++)
397*dc5a8425Srobbin 		(void) putwchar(*cp);
3987c478bd9Sstevel@tonic-gate 	if (hadbold) {
399*dc5a8425Srobbin 		(void) putwchar(L'\r');
4007c478bd9Sstevel@tonic-gate 		for (cp = scp; *cp; cp++)
401*dc5a8425Srobbin 			(void) putwchar(*cp == L'_' ? L' ' : *cp);
402*dc5a8425Srobbin 		(void) putwchar(L'\r');
4037c478bd9Sstevel@tonic-gate 		for (cp = scp; *cp; cp++)
404*dc5a8425Srobbin 			(void) putwchar(*cp == L'_' ? L' ' : *cp);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 	free(scp);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
409*dc5a8425Srobbin void
iattr(void)410*dc5a8425Srobbin iattr(void)
4117c478bd9Sstevel@tonic-gate {
412*dc5a8425Srobbin 	int i, n;
4137c478bd9Sstevel@tonic-gate 	wchar_t *cp, *scp;
414*dc5a8425Srobbin 	wchar_t cx;
4157c478bd9Sstevel@tonic-gate 	size_t  szbf = 256, tszbf;
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	scp = (wchar_t *)malloc(sizeof (wchar_t) * szbf);
4187c478bd9Sstevel@tonic-gate 	if (!scp) {
4197c478bd9Sstevel@tonic-gate 		/* this kind of message need not to be gettext'ed */
4207c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "malloc failed\n");
4217c478bd9Sstevel@tonic-gate 		exit(1);
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 	cp = scp;
4247c478bd9Sstevel@tonic-gate 	tszbf = szbf;
4257c478bd9Sstevel@tonic-gate #ifdef DEBUG
4267c478bd9Sstevel@tonic-gate 	/*
4277c478bd9Sstevel@tonic-gate 	 * to allocate a memory after the chunk of the current scp
4287c478bd9Sstevel@tonic-gate 	 * and to make sure the following realloc() allocates
4297c478bd9Sstevel@tonic-gate 	 * memory from different chunks.
4307c478bd9Sstevel@tonic-gate 	 */
4317c478bd9Sstevel@tonic-gate 	(void) malloc(1024 * 1024);
4327c478bd9Sstevel@tonic-gate #endif
4337c478bd9Sstevel@tonic-gate 	for (i = 0; i < maxcol; i++) {
4347c478bd9Sstevel@tonic-gate 		switch (obuf[i].c_mode) {
4357c478bd9Sstevel@tonic-gate 		case NORMAL:	cx = ' '; break;
4367c478bd9Sstevel@tonic-gate 		case ALTSET:	cx = 'g'; break;
4377c478bd9Sstevel@tonic-gate 		case SUPERSC:	cx = '^'; break;
4387c478bd9Sstevel@tonic-gate 		case SUBSC:	cx = 'v'; break;
4397c478bd9Sstevel@tonic-gate 		case UNDERL:	cx = '_'; break;
4407c478bd9Sstevel@tonic-gate 		case BOLD:	cx = '!'; break;
4417c478bd9Sstevel@tonic-gate 		default:	cx = 'X'; break;
4427c478bd9Sstevel@tonic-gate 		}
4437c478bd9Sstevel@tonic-gate 		n = scrw[wcsetno(obuf[i].c_char)];
4447c478bd9Sstevel@tonic-gate 		if (tszbf <= n) {
4457c478bd9Sstevel@tonic-gate 			/* may not enough buffer for this char */
4467c478bd9Sstevel@tonic-gate 			size_t  pos;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 			/* obtain the offset of cp */
4497c478bd9Sstevel@tonic-gate 			pos = cp - scp;
4507c478bd9Sstevel@tonic-gate 			/* reallocate another (n * MEMFCT) * sizeof (wchar_t) */
4517c478bd9Sstevel@tonic-gate 			scp = (wchar_t *)realloc(scp,
4527c478bd9Sstevel@tonic-gate 				sizeof (wchar_t) * (szbf + (n * MEMFCT)));
4537c478bd9Sstevel@tonic-gate 			if (!scp) {
4547c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "malloc failed\n");
4557c478bd9Sstevel@tonic-gate 				exit(1);
4567c478bd9Sstevel@tonic-gate 			}
4577c478bd9Sstevel@tonic-gate 			/* get the new address of cp */
4587c478bd9Sstevel@tonic-gate 			cp = scp + pos;
4597c478bd9Sstevel@tonic-gate 			szbf += n * MEMFCT;
4607c478bd9Sstevel@tonic-gate 			tszbf += n * MEMFCT;
4617c478bd9Sstevel@tonic-gate 		}
4627c478bd9Sstevel@tonic-gate 		tszbf -= n;
4637c478bd9Sstevel@tonic-gate 		 *cp++ = cx;
4647c478bd9Sstevel@tonic-gate 		while (--n > 0) {
4657c478bd9Sstevel@tonic-gate 			*cp++ = cx;
4667c478bd9Sstevel@tonic-gate 			i++;
4677c478bd9Sstevel@tonic-gate 		}
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate 	for (*cp = L' '; *cp == L' '; cp--)
4707c478bd9Sstevel@tonic-gate 		*cp = L'\0';
4717c478bd9Sstevel@tonic-gate 	for (cp = scp; *cp; cp++)
472*dc5a8425Srobbin 		(void) putwchar(*cp);
473*dc5a8425Srobbin 	(void) putwchar(L'\n');
4747c478bd9Sstevel@tonic-gate 	free(scp);
4757c478bd9Sstevel@tonic-gate }
4767c478bd9Sstevel@tonic-gate 
477*dc5a8425Srobbin void
initbuf(void)478*dc5a8425Srobbin initbuf(void)
4797c478bd9Sstevel@tonic-gate {
480*dc5a8425Srobbin 	int i;
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	/* following depends on NORMAL == 000 */
4837c478bd9Sstevel@tonic-gate 	for (i = 0; i < LINE_MAX; i++)
4847c478bd9Sstevel@tonic-gate 		obuf[i].c_char = obuf[i].c_mode = 0;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	col = 0;
4877c478bd9Sstevel@tonic-gate 	maxcol = 0;
4887c478bd9Sstevel@tonic-gate 	mode &= ALTSET;
4897c478bd9Sstevel@tonic-gate }
4907c478bd9Sstevel@tonic-gate 
491*dc5a8425Srobbin void
fwd(void)492*dc5a8425Srobbin fwd(void)
4937c478bd9Sstevel@tonic-gate {
494*dc5a8425Srobbin 	int oldcol, oldmax;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	oldcol = col;
4977c478bd9Sstevel@tonic-gate 	oldmax = maxcol;
4987c478bd9Sstevel@tonic-gate 	flushln();
4997c478bd9Sstevel@tonic-gate 	col = oldcol;
5007c478bd9Sstevel@tonic-gate 	maxcol = oldmax;
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate 
503*dc5a8425Srobbin void
reverse(void)504*dc5a8425Srobbin reverse(void)
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 	upln++;
5077c478bd9Sstevel@tonic-gate 	fwd();
508*dc5a8425Srobbin 	ul_puts(CURS_UP);
509*dc5a8425Srobbin 	ul_puts(CURS_UP);
5107c478bd9Sstevel@tonic-gate 	upln++;
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate 
513*dc5a8425Srobbin void
initcap(void)514*dc5a8425Srobbin initcap(void)
5157c478bd9Sstevel@tonic-gate {
5167c478bd9Sstevel@tonic-gate 	static char tcapbuf[512];
5177c478bd9Sstevel@tonic-gate 	char *bp = tcapbuf;
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	/* This nonsense attempts to work with both old and new termcap */
5207c478bd9Sstevel@tonic-gate 	CURS_UP =		tgetstr("up", &bp);
5217c478bd9Sstevel@tonic-gate 	CURS_RIGHT =		tgetstr("ri", &bp);
5227c478bd9Sstevel@tonic-gate 	if (CURS_RIGHT == NULL)
5237c478bd9Sstevel@tonic-gate 		CURS_RIGHT =	tgetstr("nd", &bp);
5247c478bd9Sstevel@tonic-gate 	CURS_LEFT =		tgetstr("le", &bp);
5257c478bd9Sstevel@tonic-gate 	if (CURS_LEFT == NULL)
5267c478bd9Sstevel@tonic-gate 		CURS_LEFT =	tgetstr("bc", &bp);
5277c478bd9Sstevel@tonic-gate 	if (CURS_LEFT == NULL && tgetflag("bs"))
5287c478bd9Sstevel@tonic-gate 		CURS_LEFT =	"\b";
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	ENTER_STANDOUT =	tgetstr("so", &bp);
5317c478bd9Sstevel@tonic-gate 	EXIT_STANDOUT =		tgetstr("se", &bp);
5327c478bd9Sstevel@tonic-gate 	ENTER_UNDERLINE =	tgetstr("us", &bp);
5337c478bd9Sstevel@tonic-gate 	EXIT_UNDERLINE =	tgetstr("ue", &bp);
5347c478bd9Sstevel@tonic-gate 	ENTER_DIM =		tgetstr("mh", &bp);
5357c478bd9Sstevel@tonic-gate 	ENTER_BOLD =		tgetstr("md", &bp);
5367c478bd9Sstevel@tonic-gate 	ENTER_REVERSE =		tgetstr("mr", &bp);
5377c478bd9Sstevel@tonic-gate 	EXIT_ATTRIBUTES =	tgetstr("me", &bp);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	if (!ENTER_BOLD && ENTER_REVERSE)
5407c478bd9Sstevel@tonic-gate 		ENTER_BOLD = ENTER_REVERSE;
5417c478bd9Sstevel@tonic-gate 	if (!ENTER_BOLD && ENTER_STANDOUT)
5427c478bd9Sstevel@tonic-gate 		ENTER_BOLD = ENTER_STANDOUT;
5437c478bd9Sstevel@tonic-gate 	if (!ENTER_UNDERLINE && ENTER_STANDOUT) {
5447c478bd9Sstevel@tonic-gate 		ENTER_UNDERLINE = ENTER_STANDOUT;
5457c478bd9Sstevel@tonic-gate 		EXIT_UNDERLINE = EXIT_STANDOUT;
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 	if (!ENTER_DIM && ENTER_STANDOUT)
5487c478bd9Sstevel@tonic-gate 		ENTER_DIM = ENTER_STANDOUT;
5497c478bd9Sstevel@tonic-gate 	if (!ENTER_REVERSE && ENTER_STANDOUT)
5507c478bd9Sstevel@tonic-gate 		ENTER_REVERSE = ENTER_STANDOUT;
5517c478bd9Sstevel@tonic-gate 	if (!EXIT_ATTRIBUTES && EXIT_STANDOUT)
5527c478bd9Sstevel@tonic-gate 		EXIT_ATTRIBUTES = EXIT_STANDOUT;
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	/*
5557c478bd9Sstevel@tonic-gate 	 * Note that we use REVERSE for the alternate character set,
5567c478bd9Sstevel@tonic-gate 	 * not the as/ae capabilities.  This is because we are modelling
5577c478bd9Sstevel@tonic-gate 	 * the model 37 teletype (since that's what nroff outputs) and
5587c478bd9Sstevel@tonic-gate 	 * the typical as/ae is more of a graphics set, not the greek
5597c478bd9Sstevel@tonic-gate 	 * letters the 37 has.
5607c478bd9Sstevel@tonic-gate 	 */
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate #ifdef notdef
5637c478bd9Sstevel@tonic-gate printf("so %s se %s us %s ue %s me %s\n",
5647c478bd9Sstevel@tonic-gate 	ENTER_STANDOUT, EXIT_STANDOUT, ENTER_UNDERLINE,
5657c478bd9Sstevel@tonic-gate 	EXIT_UNDERLINE, EXIT_ATTRIBUTES);
5667c478bd9Sstevel@tonic-gate #endif
5677c478bd9Sstevel@tonic-gate 	UNDER_CHAR =		tgetstr("uc", &bp);
5687c478bd9Sstevel@tonic-gate 	must_use_uc = (UNDER_CHAR && !ENTER_UNDERLINE);
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate 
571*dc5a8425Srobbin int
outchar(char c)572*dc5a8425Srobbin outchar(char c)
5737c478bd9Sstevel@tonic-gate {
574*dc5a8425Srobbin 	(void) putchar(c&0177);
575*dc5a8425Srobbin 	return (0);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate 
578*dc5a8425Srobbin void
ul_puts(char * str)579*dc5a8425Srobbin ul_puts(char *str)
5807c478bd9Sstevel@tonic-gate {
5817c478bd9Sstevel@tonic-gate 	if (str)
582*dc5a8425Srobbin 		(void) tputs(str, 1, outchar);
5837c478bd9Sstevel@tonic-gate }
5847c478bd9Sstevel@tonic-gate 
585*dc5a8425Srobbin static int curmode = 0;
586*dc5a8425Srobbin 
587*dc5a8425Srobbin void
outc(wchar_t c)588*dc5a8425Srobbin outc(wchar_t c)
5897c478bd9Sstevel@tonic-gate {
590*dc5a8425Srobbin 	int m, n;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	if (c == CDUMMY)
5937c478bd9Sstevel@tonic-gate 		return;
594*dc5a8425Srobbin 	(void) putwchar(c);
5957c478bd9Sstevel@tonic-gate 	if (must_use_uc && (curmode & UNDERL)) {
5967c478bd9Sstevel@tonic-gate 		m = n = scrw[wcsetno(c)];
597*dc5a8425Srobbin 		ul_puts(CURS_LEFT);
5987c478bd9Sstevel@tonic-gate 		while (--m > 0)
599*dc5a8425Srobbin 			ul_puts(CURS_LEFT);
600*dc5a8425Srobbin 		ul_puts(UNDER_CHAR);
6017c478bd9Sstevel@tonic-gate 		while (--n > 0)
602*dc5a8425Srobbin 			ul_puts(UNDER_CHAR);
6037c478bd9Sstevel@tonic-gate 	}
6047c478bd9Sstevel@tonic-gate }
6057c478bd9Sstevel@tonic-gate 
606*dc5a8425Srobbin void
setmode(int newmode)607*dc5a8425Srobbin setmode(int newmode)
6087c478bd9Sstevel@tonic-gate {
609*dc5a8425Srobbin 	if (!iflag) {
6107c478bd9Sstevel@tonic-gate 		if (curmode != NORMAL && newmode != NORMAL)
6117c478bd9Sstevel@tonic-gate 			setmode(NORMAL);
6127c478bd9Sstevel@tonic-gate 		switch (newmode) {
6137c478bd9Sstevel@tonic-gate 		case NORMAL:
6147c478bd9Sstevel@tonic-gate 			switch (curmode) {
6157c478bd9Sstevel@tonic-gate 			case NORMAL:
6167c478bd9Sstevel@tonic-gate 				break;
6177c478bd9Sstevel@tonic-gate 			case UNDERL:
618*dc5a8425Srobbin 				ul_puts(EXIT_UNDERLINE);
6197c478bd9Sstevel@tonic-gate 				break;
6207c478bd9Sstevel@tonic-gate 			default:
6217c478bd9Sstevel@tonic-gate 				/* This includes standout */
622*dc5a8425Srobbin 				ul_puts(EXIT_ATTRIBUTES);
6237c478bd9Sstevel@tonic-gate 				break;
6247c478bd9Sstevel@tonic-gate 			}
6257c478bd9Sstevel@tonic-gate 			break;
6267c478bd9Sstevel@tonic-gate 		case ALTSET:
627*dc5a8425Srobbin 			ul_puts(ENTER_REVERSE);
6287c478bd9Sstevel@tonic-gate 			break;
6297c478bd9Sstevel@tonic-gate 		case SUPERSC:
6307c478bd9Sstevel@tonic-gate 			/*
6317c478bd9Sstevel@tonic-gate 			 * This only works on a few terminals.
6327c478bd9Sstevel@tonic-gate 			 * It should be fixed.
6337c478bd9Sstevel@tonic-gate 			 */
634*dc5a8425Srobbin 			ul_puts(ENTER_UNDERLINE);
635*dc5a8425Srobbin 			ul_puts(ENTER_DIM);
6367c478bd9Sstevel@tonic-gate 			break;
6377c478bd9Sstevel@tonic-gate 		case SUBSC:
638*dc5a8425Srobbin 			ul_puts(ENTER_DIM);
6397c478bd9Sstevel@tonic-gate 			break;
6407c478bd9Sstevel@tonic-gate 		case UNDERL:
641*dc5a8425Srobbin 			ul_puts(ENTER_UNDERLINE);
6427c478bd9Sstevel@tonic-gate 			break;
6437c478bd9Sstevel@tonic-gate 		case BOLD:
644*dc5a8425Srobbin 			ul_puts(ENTER_BOLD);
6457c478bd9Sstevel@tonic-gate 			break;
6467c478bd9Sstevel@tonic-gate 		default:
6477c478bd9Sstevel@tonic-gate 			/*
6487c478bd9Sstevel@tonic-gate 			 * We should have some provision here for multiple modes
6497c478bd9Sstevel@tonic-gate 			 * on at once.  This will have to come later.
6507c478bd9Sstevel@tonic-gate 			 */
651*dc5a8425Srobbin 			ul_puts(ENTER_STANDOUT);
6527c478bd9Sstevel@tonic-gate 			break;
6537c478bd9Sstevel@tonic-gate 		}
6547c478bd9Sstevel@tonic-gate 	}
6557c478bd9Sstevel@tonic-gate 	curmode = newmode;
6567c478bd9Sstevel@tonic-gate }
657