xref: /titanic_53/usr/src/cmd/col/col.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1998, 2001 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  * All Rights Reserved
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate /*
33*7c478bd9Sstevel@tonic-gate  *	col - filter reverse carraige motions
34*7c478bd9Sstevel@tonic-gate  *
35*7c478bd9Sstevel@tonic-gate  */
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #include <stdio.h>
39*7c478bd9Sstevel@tonic-gate #include <ctype.h>
40*7c478bd9Sstevel@tonic-gate #include <locale.h>
41*7c478bd9Sstevel@tonic-gate #include <limits.h>
42*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
43*7c478bd9Sstevel@tonic-gate #include <wctype.h>
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate #define	PL 256
46*7c478bd9Sstevel@tonic-gate #define	ESC '\033'
47*7c478bd9Sstevel@tonic-gate #define	RLF '\013'
48*7c478bd9Sstevel@tonic-gate #define	SI '\017'
49*7c478bd9Sstevel@tonic-gate #define	SO '\016'
50*7c478bd9Sstevel@tonic-gate #define	GREEK 0200
51*7c478bd9Sstevel@tonic-gate #define	LINELN 4096
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate wchar_t	*page[PL];
54*7c478bd9Sstevel@tonic-gate wchar_t	lbuff[LINELN], *line;
55*7c478bd9Sstevel@tonic-gate wchar_t	ws_blank[2] = {' ', 0};
56*7c478bd9Sstevel@tonic-gate char	esc_chars, underline, temp_off, smart;
57*7c478bd9Sstevel@tonic-gate int	bflag, xflag, fflag, pflag;
58*7c478bd9Sstevel@tonic-gate int	greeked;
59*7c478bd9Sstevel@tonic-gate int	half;
60*7c478bd9Sstevel@tonic-gate int	cp, lp;
61*7c478bd9Sstevel@tonic-gate int	ll, llh, mustwr;
62*7c478bd9Sstevel@tonic-gate int	pcp = 0;
63*7c478bd9Sstevel@tonic-gate char	*pgmname;
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate #define	USAGEMSG	"usage:\tcol [-bfxp]\n"
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate static void	outc(wchar_t);
68*7c478bd9Sstevel@tonic-gate static void	store(int);
69*7c478bd9Sstevel@tonic-gate static void	fetch(int);
70*7c478bd9Sstevel@tonic-gate static void	emit(wchar_t *, int);
71*7c478bd9Sstevel@tonic-gate static void	incr(void);
72*7c478bd9Sstevel@tonic-gate static void	decr(void);
73*7c478bd9Sstevel@tonic-gate static void	wsinsert(wchar_t *, int);
74*7c478bd9Sstevel@tonic-gate static int	wcscrwidth(wchar_t);
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate int
77*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
78*7c478bd9Sstevel@tonic-gate {
79*7c478bd9Sstevel@tonic-gate 	int	i, n;
80*7c478bd9Sstevel@tonic-gate 	int	opt;
81*7c478bd9Sstevel@tonic-gate 	int	greek;
82*7c478bd9Sstevel@tonic-gate 	int	c;
83*7c478bd9Sstevel@tonic-gate 	wchar_t	wc;
84*7c478bd9Sstevel@tonic-gate 	char	byte;
85*7c478bd9Sstevel@tonic-gate 	static char	fbuff[BUFSIZ];
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 	setbuf(stdout, fbuff);
88*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
89*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
90*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
91*7c478bd9Sstevel@tonic-gate #endif
92*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
93*7c478bd9Sstevel@tonic-gate 	pgmname = argv[0];
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "bfxp")) != EOF)
96*7c478bd9Sstevel@tonic-gate 		switch (opt) {
97*7c478bd9Sstevel@tonic-gate 		case 'b':
98*7c478bd9Sstevel@tonic-gate 			bflag++;
99*7c478bd9Sstevel@tonic-gate 			break;
100*7c478bd9Sstevel@tonic-gate 		case 'x':
101*7c478bd9Sstevel@tonic-gate 			xflag++;
102*7c478bd9Sstevel@tonic-gate 			break;
103*7c478bd9Sstevel@tonic-gate 		case 'f':
104*7c478bd9Sstevel@tonic-gate 			fflag++;
105*7c478bd9Sstevel@tonic-gate 			break;
106*7c478bd9Sstevel@tonic-gate 		case 'p':
107*7c478bd9Sstevel@tonic-gate 			pflag++;
108*7c478bd9Sstevel@tonic-gate 			break;
109*7c478bd9Sstevel@tonic-gate 		case '?':
110*7c478bd9Sstevel@tonic-gate 		default:
111*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(USAGEMSG));
112*7c478bd9Sstevel@tonic-gate 			exit(2);
113*7c478bd9Sstevel@tonic-gate 		}
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 	argc -= optind;
116*7c478bd9Sstevel@tonic-gate 	if (argc >= 1) {
117*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(USAGEMSG));
118*7c478bd9Sstevel@tonic-gate 		exit(2);
119*7c478bd9Sstevel@tonic-gate 	}
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	for (ll = 0; ll < PL; ll++)
122*7c478bd9Sstevel@tonic-gate 		page[ll] = 0;
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	smart = temp_off = underline = esc_chars = '\0';
125*7c478bd9Sstevel@tonic-gate 	cp = 0;
126*7c478bd9Sstevel@tonic-gate 	ll = 0;
127*7c478bd9Sstevel@tonic-gate 	greek = 0;
128*7c478bd9Sstevel@tonic-gate 	mustwr = PL;
129*7c478bd9Sstevel@tonic-gate 	line = lbuff;
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	while ((c = getwchar()) != EOF) {
132*7c478bd9Sstevel@tonic-gate 		if (underline && temp_off && c > ' ') {
133*7c478bd9Sstevel@tonic-gate 			outc(ESC);
134*7c478bd9Sstevel@tonic-gate 			if (*line) line++;
135*7c478bd9Sstevel@tonic-gate 			*line++ = 'X';
136*7c478bd9Sstevel@tonic-gate 			*line = temp_off = '\0';
137*7c478bd9Sstevel@tonic-gate 		}
138*7c478bd9Sstevel@tonic-gate 		if (c != '\b')
139*7c478bd9Sstevel@tonic-gate 			if (esc_chars)
140*7c478bd9Sstevel@tonic-gate 				esc_chars = '\0';
141*7c478bd9Sstevel@tonic-gate 		switch (c) {
142*7c478bd9Sstevel@tonic-gate 		case '\n':
143*7c478bd9Sstevel@tonic-gate 			if (underline && !temp_off) {
144*7c478bd9Sstevel@tonic-gate 				if (*line)
145*7c478bd9Sstevel@tonic-gate 					line++;
146*7c478bd9Sstevel@tonic-gate 				*line++ = ESC;
147*7c478bd9Sstevel@tonic-gate 				*line++ = 'Y';
148*7c478bd9Sstevel@tonic-gate 				*line = '\0';
149*7c478bd9Sstevel@tonic-gate 				temp_off = '1';
150*7c478bd9Sstevel@tonic-gate 			}
151*7c478bd9Sstevel@tonic-gate 			incr();
152*7c478bd9Sstevel@tonic-gate 			incr();
153*7c478bd9Sstevel@tonic-gate 			cp = 0;
154*7c478bd9Sstevel@tonic-gate 			continue;
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 		case '\0':
157*7c478bd9Sstevel@tonic-gate 			continue;
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 		case ESC:
160*7c478bd9Sstevel@tonic-gate 			c = getwchar();
161*7c478bd9Sstevel@tonic-gate 			switch (c) {
162*7c478bd9Sstevel@tonic-gate 			case '7':	/* reverse full line feed */
163*7c478bd9Sstevel@tonic-gate 				decr();
164*7c478bd9Sstevel@tonic-gate 				decr();
165*7c478bd9Sstevel@tonic-gate 				break;
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 			case '8':	/* reverse half line feed */
168*7c478bd9Sstevel@tonic-gate 				if (fflag)
169*7c478bd9Sstevel@tonic-gate 					decr();
170*7c478bd9Sstevel@tonic-gate 				else {
171*7c478bd9Sstevel@tonic-gate 					if (--half < -1) {
172*7c478bd9Sstevel@tonic-gate 						decr();
173*7c478bd9Sstevel@tonic-gate 						decr();
174*7c478bd9Sstevel@tonic-gate 						half += 2;
175*7c478bd9Sstevel@tonic-gate 					}
176*7c478bd9Sstevel@tonic-gate 				}
177*7c478bd9Sstevel@tonic-gate 				break;
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 			case '9':	/* forward half line feed */
180*7c478bd9Sstevel@tonic-gate 				if (fflag)
181*7c478bd9Sstevel@tonic-gate 					incr();
182*7c478bd9Sstevel@tonic-gate 				else {
183*7c478bd9Sstevel@tonic-gate 					if (++half > 0) {
184*7c478bd9Sstevel@tonic-gate 						incr();
185*7c478bd9Sstevel@tonic-gate 						incr();
186*7c478bd9Sstevel@tonic-gate 						half -= 2;
187*7c478bd9Sstevel@tonic-gate 					}
188*7c478bd9Sstevel@tonic-gate 				}
189*7c478bd9Sstevel@tonic-gate 				break;
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate 			default:
192*7c478bd9Sstevel@tonic-gate 				if (pflag)	{	/* pass through esc */
193*7c478bd9Sstevel@tonic-gate 					outc(ESC);
194*7c478bd9Sstevel@tonic-gate 					line++;
195*7c478bd9Sstevel@tonic-gate 					*line = c;
196*7c478bd9Sstevel@tonic-gate 					line++;
197*7c478bd9Sstevel@tonic-gate 					*line = '\0';
198*7c478bd9Sstevel@tonic-gate 					esc_chars = 1;
199*7c478bd9Sstevel@tonic-gate 					if (c == 'X')
200*7c478bd9Sstevel@tonic-gate 						underline = 1;
201*7c478bd9Sstevel@tonic-gate 					if (c == 'Y' && underline)
202*7c478bd9Sstevel@tonic-gate 						underline =	temp_off = '\0';
203*7c478bd9Sstevel@tonic-gate 					if (c == ']')
204*7c478bd9Sstevel@tonic-gate 						smart = 1;
205*7c478bd9Sstevel@tonic-gate 					if (c == '[')
206*7c478bd9Sstevel@tonic-gate 						smart = '\0';
207*7c478bd9Sstevel@tonic-gate 					}
208*7c478bd9Sstevel@tonic-gate 				break;
209*7c478bd9Sstevel@tonic-gate 			}
210*7c478bd9Sstevel@tonic-gate 			continue;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 		case SO:
213*7c478bd9Sstevel@tonic-gate 			greek = GREEK;
214*7c478bd9Sstevel@tonic-gate 			greeked++;
215*7c478bd9Sstevel@tonic-gate 			continue;
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 		case SI:
218*7c478bd9Sstevel@tonic-gate 			greek = 0;
219*7c478bd9Sstevel@tonic-gate 			continue;
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 		case RLF:
222*7c478bd9Sstevel@tonic-gate 			decr();
223*7c478bd9Sstevel@tonic-gate 			decr();
224*7c478bd9Sstevel@tonic-gate 			continue;
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 		case '\r':
227*7c478bd9Sstevel@tonic-gate 			cp = 0;
228*7c478bd9Sstevel@tonic-gate 			continue;
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 		case '\t':
231*7c478bd9Sstevel@tonic-gate 			cp = (cp + 8) & -8;
232*7c478bd9Sstevel@tonic-gate 			continue;
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 		case '\b':
235*7c478bd9Sstevel@tonic-gate 			if (esc_chars) {
236*7c478bd9Sstevel@tonic-gate 				*line++ = '\b';
237*7c478bd9Sstevel@tonic-gate 				*line = '\0';
238*7c478bd9Sstevel@tonic-gate 			} else if (cp > 0)
239*7c478bd9Sstevel@tonic-gate 				cp--;
240*7c478bd9Sstevel@tonic-gate 			continue;
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 		case ' ':
243*7c478bd9Sstevel@tonic-gate 			cp++;
244*7c478bd9Sstevel@tonic-gate 			continue;
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 		default:
247*7c478bd9Sstevel@tonic-gate 			if (iswprint(c)) {	/* if printable */
248*7c478bd9Sstevel@tonic-gate 				if (!greek) {
249*7c478bd9Sstevel@tonic-gate 					outc((wchar_t)c);
250*7c478bd9Sstevel@tonic-gate 					cp += wcscrwidth(c);
251*7c478bd9Sstevel@tonic-gate 				}
252*7c478bd9Sstevel@tonic-gate 				/*
253*7c478bd9Sstevel@tonic-gate 				 * EUC (apply SO only when there can
254*7c478bd9Sstevel@tonic-gate 				 * be corresponding character in CS1)
255*7c478bd9Sstevel@tonic-gate 				 */
256*7c478bd9Sstevel@tonic-gate 				else if (iswascii(c)) {
257*7c478bd9Sstevel@tonic-gate 					byte = (c | greek);
258*7c478bd9Sstevel@tonic-gate 					n = mbtowc(&wc, &byte, 1);
259*7c478bd9Sstevel@tonic-gate 					if (!iswcntrl(c) && !iswspace(c) &&
260*7c478bd9Sstevel@tonic-gate 					    n == 1) {
261*7c478bd9Sstevel@tonic-gate 						outc(wc);
262*7c478bd9Sstevel@tonic-gate 						cp += wcscrwidth(wc);
263*7c478bd9Sstevel@tonic-gate 					} else {
264*7c478bd9Sstevel@tonic-gate 						outc((wchar_t)c);
265*7c478bd9Sstevel@tonic-gate 						cp += wcscrwidth(c);
266*7c478bd9Sstevel@tonic-gate 					}
267*7c478bd9Sstevel@tonic-gate 				} else {
268*7c478bd9Sstevel@tonic-gate 					outc((wchar_t)c);
269*7c478bd9Sstevel@tonic-gate 					cp += wcscrwidth(c);
270*7c478bd9Sstevel@tonic-gate 				}
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 				if ((cp + 1) > LINELN) {
273*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
274*7c478bd9Sstevel@tonic-gate 					    gettext("col: Line too long\n"));
275*7c478bd9Sstevel@tonic-gate 					exit(2);
276*7c478bd9Sstevel@tonic-gate 				}
277*7c478bd9Sstevel@tonic-gate 			}
278*7c478bd9Sstevel@tonic-gate 			continue;
279*7c478bd9Sstevel@tonic-gate 		}
280*7c478bd9Sstevel@tonic-gate 	}
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < PL; i++)
283*7c478bd9Sstevel@tonic-gate 		if (page[(mustwr+i)%PL] != 0)
284*7c478bd9Sstevel@tonic-gate 			emit(page[(mustwr+i) % PL], mustwr+i-PL);
285*7c478bd9Sstevel@tonic-gate 	emit(ws_blank, (llh + 1) & -2);
286*7c478bd9Sstevel@tonic-gate 	return (0);
287*7c478bd9Sstevel@tonic-gate }
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate static void
290*7c478bd9Sstevel@tonic-gate outc(wchar_t c)
291*7c478bd9Sstevel@tonic-gate {
292*7c478bd9Sstevel@tonic-gate 	int	n, i;
293*7c478bd9Sstevel@tonic-gate 	int	width, widthl, widthc;
294*7c478bd9Sstevel@tonic-gate 	wchar_t	*p1;
295*7c478bd9Sstevel@tonic-gate 	wchar_t c1;
296*7c478bd9Sstevel@tonic-gate 	char esc_chars = '\0';
297*7c478bd9Sstevel@tonic-gate 	if (lp > cp) {
298*7c478bd9Sstevel@tonic-gate 		line = lbuff;
299*7c478bd9Sstevel@tonic-gate 		lp = 0;
300*7c478bd9Sstevel@tonic-gate 	}
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	while (lp < cp) {
303*7c478bd9Sstevel@tonic-gate 		if (*line != '\b')
304*7c478bd9Sstevel@tonic-gate 			if (esc_chars)
305*7c478bd9Sstevel@tonic-gate 				esc_chars = '\0';
306*7c478bd9Sstevel@tonic-gate 			switch (*line)	{
307*7c478bd9Sstevel@tonic-gate 			case ESC:
308*7c478bd9Sstevel@tonic-gate 				line++;
309*7c478bd9Sstevel@tonic-gate 				esc_chars = 1;
310*7c478bd9Sstevel@tonic-gate 				break;
311*7c478bd9Sstevel@tonic-gate 			case '\0':
312*7c478bd9Sstevel@tonic-gate 				*line = ' ';
313*7c478bd9Sstevel@tonic-gate 				lp++;
314*7c478bd9Sstevel@tonic-gate 				break;
315*7c478bd9Sstevel@tonic-gate 			case '\b':
316*7c478bd9Sstevel@tonic-gate 				/* if ( ! esc_chars ) */
317*7c478bd9Sstevel@tonic-gate 					lp--;
318*7c478bd9Sstevel@tonic-gate 				break;
319*7c478bd9Sstevel@tonic-gate 			default:
320*7c478bd9Sstevel@tonic-gate 				lp += wcscrwidth(*line);
321*7c478bd9Sstevel@tonic-gate 			}
322*7c478bd9Sstevel@tonic-gate 		line++;
323*7c478bd9Sstevel@tonic-gate 	}
324*7c478bd9Sstevel@tonic-gate 	while (*line == '\b') {
325*7c478bd9Sstevel@tonic-gate 		/*
326*7c478bd9Sstevel@tonic-gate 		 * EUC (For a multi-column character, backspace characters
327*7c478bd9Sstevel@tonic-gate 		 * are assumed to be used like "__^H^HXX", where "XX"
328*7c478bd9Sstevel@tonic-gate 		 * represents a two-column character, and a backspace
329*7c478bd9Sstevel@tonic-gate 		 * always goes back by one column.)
330*7c478bd9Sstevel@tonic-gate 		 */
331*7c478bd9Sstevel@tonic-gate 		for (n = 0; *line == '\b'; line++) {
332*7c478bd9Sstevel@tonic-gate 			n++;
333*7c478bd9Sstevel@tonic-gate 			lp--;
334*7c478bd9Sstevel@tonic-gate 		}
335*7c478bd9Sstevel@tonic-gate 		while (n > 0 && lp < cp) {
336*7c478bd9Sstevel@tonic-gate 			i = *line++;
337*7c478bd9Sstevel@tonic-gate 			i = wcscrwidth(i);
338*7c478bd9Sstevel@tonic-gate 			n -= i;
339*7c478bd9Sstevel@tonic-gate 			lp += i;
340*7c478bd9Sstevel@tonic-gate 		}
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate 	while (*line == ESC)
343*7c478bd9Sstevel@tonic-gate 		line += 6;
344*7c478bd9Sstevel@tonic-gate 	widthc = wcscrwidth(c);
345*7c478bd9Sstevel@tonic-gate 	widthl = wcscrwidth(*line);
346*7c478bd9Sstevel@tonic-gate 	if (bflag || (*line == '\0') || *line == ' ') {
347*7c478bd9Sstevel@tonic-gate 		if (*line == '\0' || widthl == widthc) {
348*7c478bd9Sstevel@tonic-gate 			*line = c;
349*7c478bd9Sstevel@tonic-gate 		} else if (widthl > widthc) {
350*7c478bd9Sstevel@tonic-gate 			n = widthl - widthc;
351*7c478bd9Sstevel@tonic-gate 			wsinsert(line, n);
352*7c478bd9Sstevel@tonic-gate 			*line++ = c;
353*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < n; i++)
354*7c478bd9Sstevel@tonic-gate 				*line++ = ' ';
355*7c478bd9Sstevel@tonic-gate 			line = lbuff;
356*7c478bd9Sstevel@tonic-gate 			lp = 0;
357*7c478bd9Sstevel@tonic-gate 		} else {
358*7c478bd9Sstevel@tonic-gate 			n = widthc - widthl;
359*7c478bd9Sstevel@tonic-gate 			for (p1 = line+1; n > 0; n -= wcscrwidth(i))
360*7c478bd9Sstevel@tonic-gate 				i = *p1++;
361*7c478bd9Sstevel@tonic-gate 			*line = c;
362*7c478bd9Sstevel@tonic-gate 			(void) wcscpy(line+1, p1);
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 		}
365*7c478bd9Sstevel@tonic-gate 	} else {
366*7c478bd9Sstevel@tonic-gate 		if (smart && (widthl == 1) && (widthc == 1)) {
367*7c478bd9Sstevel@tonic-gate 			wchar_t	c1, c2, c3, c4, c5, c6, c7;
368*7c478bd9Sstevel@tonic-gate 			c1 = *++line;
369*7c478bd9Sstevel@tonic-gate 			*line++ = ESC;
370*7c478bd9Sstevel@tonic-gate 			c2 = *line;
371*7c478bd9Sstevel@tonic-gate 			*line++ = '[';
372*7c478bd9Sstevel@tonic-gate 			c3 = *line;
373*7c478bd9Sstevel@tonic-gate 			*line++ = '\b';
374*7c478bd9Sstevel@tonic-gate 			c4 = *line;
375*7c478bd9Sstevel@tonic-gate 			*line++ = ESC;
376*7c478bd9Sstevel@tonic-gate 			c5 = *line;
377*7c478bd9Sstevel@tonic-gate 			*line++ = ']';
378*7c478bd9Sstevel@tonic-gate 			c6 = *line;
379*7c478bd9Sstevel@tonic-gate 			*line++ = c;
380*7c478bd9Sstevel@tonic-gate 			while (c1) {
381*7c478bd9Sstevel@tonic-gate 				c7 = *line;
382*7c478bd9Sstevel@tonic-gate 				*line++ = c1;
383*7c478bd9Sstevel@tonic-gate 				c1 = c2;
384*7c478bd9Sstevel@tonic-gate 				c2 = c3;
385*7c478bd9Sstevel@tonic-gate 				c3 = c4;
386*7c478bd9Sstevel@tonic-gate 				c4 = c5;
387*7c478bd9Sstevel@tonic-gate 				c5 = c6;
388*7c478bd9Sstevel@tonic-gate 				c6 = c7;
389*7c478bd9Sstevel@tonic-gate 			}
390*7c478bd9Sstevel@tonic-gate 		} else	{
391*7c478bd9Sstevel@tonic-gate 			if ((widthl == 1) && (widthc == 1)) {
392*7c478bd9Sstevel@tonic-gate 				wchar_t	c1, c2, c3;
393*7c478bd9Sstevel@tonic-gate 				c1 = *++line;
394*7c478bd9Sstevel@tonic-gate 				*line++ = '\b';
395*7c478bd9Sstevel@tonic-gate 				c2 = *line;
396*7c478bd9Sstevel@tonic-gate 				*line++ = c;
397*7c478bd9Sstevel@tonic-gate 				while (c1) {
398*7c478bd9Sstevel@tonic-gate 					c3 = *line;
399*7c478bd9Sstevel@tonic-gate 					*line++ = c1;
400*7c478bd9Sstevel@tonic-gate 					c1 = c2;
401*7c478bd9Sstevel@tonic-gate 					c2 = c3;
402*7c478bd9Sstevel@tonic-gate 				}
403*7c478bd9Sstevel@tonic-gate 			} else {
404*7c478bd9Sstevel@tonic-gate 				width = (widthc > widthl) ? widthc : widthl;
405*7c478bd9Sstevel@tonic-gate 				for (i = 0; i < width; i += wcscrwidth(c1))
406*7c478bd9Sstevel@tonic-gate 					c1 = *line++;
407*7c478bd9Sstevel@tonic-gate 				wsinsert(line, width + (width - widthc + 1));
408*7c478bd9Sstevel@tonic-gate 				for (i = 0; i < width; i++)
409*7c478bd9Sstevel@tonic-gate 					*line++ = '\b';
410*7c478bd9Sstevel@tonic-gate 				*line++ = c;
411*7c478bd9Sstevel@tonic-gate 				for (i = widthc; i < width; i++)
412*7c478bd9Sstevel@tonic-gate 					*line++ = ' ';
413*7c478bd9Sstevel@tonic-gate 			}
414*7c478bd9Sstevel@tonic-gate 		}
415*7c478bd9Sstevel@tonic-gate 		lp = 0;
416*7c478bd9Sstevel@tonic-gate 		line = lbuff;
417*7c478bd9Sstevel@tonic-gate 	}
418*7c478bd9Sstevel@tonic-gate }
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate static void
421*7c478bd9Sstevel@tonic-gate store(int lno)
422*7c478bd9Sstevel@tonic-gate {
423*7c478bd9Sstevel@tonic-gate 	lno %= PL;
424*7c478bd9Sstevel@tonic-gate 	if (page[lno] != 0)
425*7c478bd9Sstevel@tonic-gate 		free((char *)page[lno]);
426*7c478bd9Sstevel@tonic-gate 	page[lno] = (wchar_t *)malloc((unsigned)(wcslen(lbuff) + 2)
427*7c478bd9Sstevel@tonic-gate 		* sizeof (wchar_t));
428*7c478bd9Sstevel@tonic-gate 	if (page[lno] == 0) {
429*7c478bd9Sstevel@tonic-gate 		/* fprintf(stderr, "%s: no storage\n", pgmname); */
430*7c478bd9Sstevel@tonic-gate 		exit(2);
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate 	(void) wcscpy(page[lno], lbuff);
433*7c478bd9Sstevel@tonic-gate }
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate static void
436*7c478bd9Sstevel@tonic-gate fetch(int lno)
437*7c478bd9Sstevel@tonic-gate {
438*7c478bd9Sstevel@tonic-gate 	wchar_t	*p;
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 	lno %= PL;
441*7c478bd9Sstevel@tonic-gate 	p = lbuff;
442*7c478bd9Sstevel@tonic-gate 	while (*p)
443*7c478bd9Sstevel@tonic-gate 		*p++ = '\0';
444*7c478bd9Sstevel@tonic-gate 	line = lbuff;
445*7c478bd9Sstevel@tonic-gate 	lp = 0;
446*7c478bd9Sstevel@tonic-gate 	if (page[lno])
447*7c478bd9Sstevel@tonic-gate 		(void) wcscpy(line, page[lno]);
448*7c478bd9Sstevel@tonic-gate }
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate static void
451*7c478bd9Sstevel@tonic-gate emit(wchar_t *s, int lineno)
452*7c478bd9Sstevel@tonic-gate {
453*7c478bd9Sstevel@tonic-gate 	static int	cline = 0;
454*7c478bd9Sstevel@tonic-gate 	int	ncp;
455*7c478bd9Sstevel@tonic-gate 	wchar_t	*p;
456*7c478bd9Sstevel@tonic-gate 	char	cshifted;
457*7c478bd9Sstevel@tonic-gate 	char	chr[MB_LEN_MAX + 1];
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	int	c;
460*7c478bd9Sstevel@tonic-gate 	static int	gflag = 0;
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 	if (*s) {
463*7c478bd9Sstevel@tonic-gate 		if (gflag) {
464*7c478bd9Sstevel@tonic-gate 			(void) putchar(SI);
465*7c478bd9Sstevel@tonic-gate 			gflag = 0;
466*7c478bd9Sstevel@tonic-gate 		}
467*7c478bd9Sstevel@tonic-gate 		while (cline < lineno - 1) {
468*7c478bd9Sstevel@tonic-gate 			(void) putchar('\n');
469*7c478bd9Sstevel@tonic-gate 			pcp = 0;
470*7c478bd9Sstevel@tonic-gate 			cline += 2;
471*7c478bd9Sstevel@tonic-gate 		}
472*7c478bd9Sstevel@tonic-gate 		if (cline != lineno) {
473*7c478bd9Sstevel@tonic-gate 			(void) putchar(ESC);
474*7c478bd9Sstevel@tonic-gate 			(void) putchar('9');
475*7c478bd9Sstevel@tonic-gate 			cline++;
476*7c478bd9Sstevel@tonic-gate 		}
477*7c478bd9Sstevel@tonic-gate 		if (pcp)
478*7c478bd9Sstevel@tonic-gate 			(void) putchar('\r');
479*7c478bd9Sstevel@tonic-gate 		pcp = 0;
480*7c478bd9Sstevel@tonic-gate 		p = s;
481*7c478bd9Sstevel@tonic-gate 		while (*p) {
482*7c478bd9Sstevel@tonic-gate 			ncp = pcp;
483*7c478bd9Sstevel@tonic-gate 			while (*p++ == ' ') {
484*7c478bd9Sstevel@tonic-gate 				if ((++ncp & 7) == 0 && !xflag) {
485*7c478bd9Sstevel@tonic-gate 					pcp = ncp;
486*7c478bd9Sstevel@tonic-gate 					(void) putchar('\t');
487*7c478bd9Sstevel@tonic-gate 				}
488*7c478bd9Sstevel@tonic-gate 			}
489*7c478bd9Sstevel@tonic-gate 			if (!*--p)
490*7c478bd9Sstevel@tonic-gate 				break;
491*7c478bd9Sstevel@tonic-gate 			while (pcp < ncp) {
492*7c478bd9Sstevel@tonic-gate 				(void) putchar(' ');
493*7c478bd9Sstevel@tonic-gate 				pcp++;
494*7c478bd9Sstevel@tonic-gate 			}
495*7c478bd9Sstevel@tonic-gate 			if (greeked) {
496*7c478bd9Sstevel@tonic-gate 				if (wctomb(chr, *p) == 1) {
497*7c478bd9Sstevel@tonic-gate 					if (gflag != (*chr & GREEK) &&
498*7c478bd9Sstevel@tonic-gate 					    *p != '\b' &&
499*7c478bd9Sstevel@tonic-gate 					    isascii(*chr ^ (gflag ^ GREEK)) &&
500*7c478bd9Sstevel@tonic-gate 					    !iscntrl(*chr ^ (gflag ^ GREEK)) &&
501*7c478bd9Sstevel@tonic-gate 					    !isspace(*chr ^ (gflag ^ GREEK))) {
502*7c478bd9Sstevel@tonic-gate 						if (gflag)
503*7c478bd9Sstevel@tonic-gate 							(void) putchar(SI);
504*7c478bd9Sstevel@tonic-gate 						else
505*7c478bd9Sstevel@tonic-gate 							(void) putchar(SO);
506*7c478bd9Sstevel@tonic-gate 						gflag ^= GREEK;
507*7c478bd9Sstevel@tonic-gate 					}
508*7c478bd9Sstevel@tonic-gate 				}
509*7c478bd9Sstevel@tonic-gate 			}
510*7c478bd9Sstevel@tonic-gate 			c = *p;
511*7c478bd9Sstevel@tonic-gate 			if (greeked) {
512*7c478bd9Sstevel@tonic-gate 				if (wctomb(chr, (wchar_t)c) == 1) {
513*7c478bd9Sstevel@tonic-gate 					cshifted = (*chr ^ GREEK);
514*7c478bd9Sstevel@tonic-gate 					if (isascii(cshifted) &&
515*7c478bd9Sstevel@tonic-gate 					    !iscntrl(cshifted) &&
516*7c478bd9Sstevel@tonic-gate 					    !isspace(cshifted))
517*7c478bd9Sstevel@tonic-gate 						(void) putchar(*chr & ~GREEK);
518*7c478bd9Sstevel@tonic-gate 				} else
519*7c478bd9Sstevel@tonic-gate 					(void) putwchar(c);
520*7c478bd9Sstevel@tonic-gate 			} else
521*7c478bd9Sstevel@tonic-gate 				(void) putwchar(c);
522*7c478bd9Sstevel@tonic-gate 			if (c == '\b') {
523*7c478bd9Sstevel@tonic-gate 				if (*(p-2) && *(p-2) == ESC) {
524*7c478bd9Sstevel@tonic-gate 					pcp++;
525*7c478bd9Sstevel@tonic-gate 				} else
526*7c478bd9Sstevel@tonic-gate 					pcp--;
527*7c478bd9Sstevel@tonic-gate 			} else {
528*7c478bd9Sstevel@tonic-gate 				pcp += wcscrwidth(c);
529*7c478bd9Sstevel@tonic-gate 			}
530*7c478bd9Sstevel@tonic-gate 			p++;
531*7c478bd9Sstevel@tonic-gate 		}
532*7c478bd9Sstevel@tonic-gate 	}
533*7c478bd9Sstevel@tonic-gate }
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate static void
536*7c478bd9Sstevel@tonic-gate incr(void)
537*7c478bd9Sstevel@tonic-gate {
538*7c478bd9Sstevel@tonic-gate 	store(ll++);
539*7c478bd9Sstevel@tonic-gate 	if (ll > llh)
540*7c478bd9Sstevel@tonic-gate 		llh = ll;
541*7c478bd9Sstevel@tonic-gate 	if (ll >= mustwr && page[ll%PL]) {
542*7c478bd9Sstevel@tonic-gate 		emit(page[ll%PL], ll - PL);
543*7c478bd9Sstevel@tonic-gate 		mustwr++;
544*7c478bd9Sstevel@tonic-gate 		free((char *)page[ll%PL]);
545*7c478bd9Sstevel@tonic-gate 		page[ll%PL] = 0;
546*7c478bd9Sstevel@tonic-gate 	}
547*7c478bd9Sstevel@tonic-gate 	fetch(ll);
548*7c478bd9Sstevel@tonic-gate }
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate static void
551*7c478bd9Sstevel@tonic-gate decr(void)
552*7c478bd9Sstevel@tonic-gate {
553*7c478bd9Sstevel@tonic-gate 	if (ll > mustwr - PL) {
554*7c478bd9Sstevel@tonic-gate 		store(ll--);
555*7c478bd9Sstevel@tonic-gate 		fetch(ll);
556*7c478bd9Sstevel@tonic-gate 	}
557*7c478bd9Sstevel@tonic-gate }
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate static void
560*7c478bd9Sstevel@tonic-gate wsinsert(wchar_t *s, int n)
561*7c478bd9Sstevel@tonic-gate {
562*7c478bd9Sstevel@tonic-gate 	wchar_t	*p1, *p2;
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	p1 = s + wcslen(s);
566*7c478bd9Sstevel@tonic-gate 	p2 = p1 + n;
567*7c478bd9Sstevel@tonic-gate 	while (p1 >= s)
568*7c478bd9Sstevel@tonic-gate 		*p2-- = *p1--;
569*7c478bd9Sstevel@tonic-gate }
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate static int
572*7c478bd9Sstevel@tonic-gate wcscrwidth(wchar_t wc)
573*7c478bd9Sstevel@tonic-gate {
574*7c478bd9Sstevel@tonic-gate 	int	nc;
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	if (wc == 0) {
577*7c478bd9Sstevel@tonic-gate 		/*
578*7c478bd9Sstevel@tonic-gate 		 * if wc is a null character, needs to
579*7c478bd9Sstevel@tonic-gate 		 * return 1 instead of 0.
580*7c478bd9Sstevel@tonic-gate 		 */
581*7c478bd9Sstevel@tonic-gate 		return (1);
582*7c478bd9Sstevel@tonic-gate 	}
583*7c478bd9Sstevel@tonic-gate 	nc = wcwidth(wc);
584*7c478bd9Sstevel@tonic-gate 	if (nc > 0) {
585*7c478bd9Sstevel@tonic-gate 		return (nc);
586*7c478bd9Sstevel@tonic-gate 	} else {
587*7c478bd9Sstevel@tonic-gate 		return (0);
588*7c478bd9Sstevel@tonic-gate 	}
589*7c478bd9Sstevel@tonic-gate }
590