xref: /illumos-gate/usr/src/lib/libadm/common/puttext.c (revision 1da57d55)
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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate /*
27*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1997-1999 by Sun Microsystems, Inc.
28*7c478bd9Sstevel@tonic-gate  * All rights reserved.
29*7c478bd9Sstevel@tonic-gate  */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
34*7c478bd9Sstevel@tonic-gate #include <stdio.h>
35*7c478bd9Sstevel@tonic-gate #include <ctype.h>
36*7c478bd9Sstevel@tonic-gate #include <wchar.h>
37*7c478bd9Sstevel@tonic-gate #include <libintl.h>
38*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
39*7c478bd9Sstevel@tonic-gate #include <string.h>
40*7c478bd9Sstevel@tonic-gate #include <limits.h>
41*7c478bd9Sstevel@tonic-gate #include "libadm.h"
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #define	MWIDTH	256
44*7c478bd9Sstevel@tonic-gate #define	WIDTH	60
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate int
puttext(FILE * fp,char * str,int lmarg,int rmarg)47*7c478bd9Sstevel@tonic-gate puttext(FILE *fp, char *str, int lmarg, int rmarg)
48*7c478bd9Sstevel@tonic-gate {
49*7c478bd9Sstevel@tonic-gate 	wchar_t	*wstr, *wp;
50*7c478bd9Sstevel@tonic-gate 	wchar_t	*copy, *lastword, *lastend, temp[MWIDTH+1];
51*7c478bd9Sstevel@tonic-gate 	size_t	len, ret;
52*7c478bd9Sstevel@tonic-gate 	int	width, i, n, force, wordcnt;
53*7c478bd9Sstevel@tonic-gate 	int	wlen, mlen, bdg;
54*7c478bd9Sstevel@tonic-gate 	char	mbs[MB_LEN_MAX];
55*7c478bd9Sstevel@tonic-gate 	char	mbtemp[(MWIDTH+1) * MB_LEN_MAX];
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate 	width = rmarg ? (rmarg - lmarg) : (WIDTH - lmarg);
58*7c478bd9Sstevel@tonic-gate 	if (width > MWIDTH)
59*7c478bd9Sstevel@tonic-gate 		width = MWIDTH;
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate 	if (!str || !*str)
62*7c478bd9Sstevel@tonic-gate 		return (width);
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	len = strlen(str);
65*7c478bd9Sstevel@tonic-gate 	wstr = (wchar_t *)malloc(sizeof (wchar_t) * (len + 1));
66*7c478bd9Sstevel@tonic-gate 	if (wstr == NULL)
67*7c478bd9Sstevel@tonic-gate 		return (width);
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate 	ret = mbstowcs(wstr, (const char *)str, len + 1);
70*7c478bd9Sstevel@tonic-gate 	if (ret == (size_t)-1) {
71*7c478bd9Sstevel@tonic-gate 		free(wstr);
72*7c478bd9Sstevel@tonic-gate 		return (width);
73*7c478bd9Sstevel@tonic-gate 	}
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate 	wp = wstr;
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate 	if (*wp == L'!') {
78*7c478bd9Sstevel@tonic-gate 		wp++;
79*7c478bd9Sstevel@tonic-gate 		force = 1;
80*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < lmarg; i++)
81*7c478bd9Sstevel@tonic-gate 			(void) putc(' ', fp);
82*7c478bd9Sstevel@tonic-gate 	} else {
83*7c478bd9Sstevel@tonic-gate 		while (iswspace(*wp))
84*7c478bd9Sstevel@tonic-gate 			++wp;	/* eat leading white space */
85*7c478bd9Sstevel@tonic-gate 		force = 0;
86*7c478bd9Sstevel@tonic-gate 	}
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 	wordcnt = 0;
89*7c478bd9Sstevel@tonic-gate 	n = 0;
90*7c478bd9Sstevel@tonic-gate 	copy = temp;
91*7c478bd9Sstevel@tonic-gate 	lastword = wp;
92*7c478bd9Sstevel@tonic-gate 	lastend = NULL;
93*7c478bd9Sstevel@tonic-gate 	do {
94*7c478bd9Sstevel@tonic-gate 		if (force) {
95*7c478bd9Sstevel@tonic-gate 			if (*wp == L'\n') {
96*7c478bd9Sstevel@tonic-gate 				(void) putc('\n', fp);
97*7c478bd9Sstevel@tonic-gate 				for (i = 0; i < lmarg; i++)
98*7c478bd9Sstevel@tonic-gate 					(void) putc(' ', fp);
99*7c478bd9Sstevel@tonic-gate 				wp++;
100*7c478bd9Sstevel@tonic-gate 				n = 0;
101*7c478bd9Sstevel@tonic-gate 			} else {
102*7c478bd9Sstevel@tonic-gate 				wlen = wcwidth(*wp);
103*7c478bd9Sstevel@tonic-gate 		/*
104*7c478bd9Sstevel@tonic-gate 		 * Using putc instead of fputwc here to avoid
105*7c478bd9Sstevel@tonic-gate 		 * mixing up the byte stream and the wide stream
106*7c478bd9Sstevel@tonic-gate 		 * for fp.
107*7c478bd9Sstevel@tonic-gate 		 */
108*7c478bd9Sstevel@tonic-gate 				mlen = wctomb(mbs, *wp);
109*7c478bd9Sstevel@tonic-gate 				if (mlen == -1) {
110*7c478bd9Sstevel@tonic-gate 		/*
111*7c478bd9Sstevel@tonic-gate 		 * wctomb failed
112*7c478bd9Sstevel@tonic-gate 		 * nothing will be outputted
113*7c478bd9Sstevel@tonic-gate 		 */
114*7c478bd9Sstevel@tonic-gate 					wp++;
115*7c478bd9Sstevel@tonic-gate 				} else {
116*7c478bd9Sstevel@tonic-gate 					for (i = 0; i < mlen; i++)
117*7c478bd9Sstevel@tonic-gate 						(void) putc(mbs[i], fp);
118*7c478bd9Sstevel@tonic-gate 					wp++;
119*7c478bd9Sstevel@tonic-gate 		/*
120*7c478bd9Sstevel@tonic-gate 		 * if wlen is a negative value (*wp is not printable),
121*7c478bd9Sstevel@tonic-gate 		 * add 1 to n. (non-printable char shares 1 column.
122*7c478bd9Sstevel@tonic-gate 		 */
123*7c478bd9Sstevel@tonic-gate 					if (wlen >= 0)
124*7c478bd9Sstevel@tonic-gate 						n += wlen;
125*7c478bd9Sstevel@tonic-gate 					else
126*7c478bd9Sstevel@tonic-gate 						n++;
127*7c478bd9Sstevel@tonic-gate 				}
128*7c478bd9Sstevel@tonic-gate 			}
129*7c478bd9Sstevel@tonic-gate 			continue;
130*7c478bd9Sstevel@tonic-gate 		}
131*7c478bd9Sstevel@tonic-gate 		if (iswspace(*wp)) {
132*7c478bd9Sstevel@tonic-gate 			/* eat multiple tabs/nl after whitespace */
133*7c478bd9Sstevel@tonic-gate 			while ((*++wp == L'\t') || (*wp == '\n'));
134*7c478bd9Sstevel@tonic-gate 			wordcnt++;
135*7c478bd9Sstevel@tonic-gate 			lastword = wp;
136*7c478bd9Sstevel@tonic-gate 			lastend = copy;
137*7c478bd9Sstevel@tonic-gate 			*copy++ = L' ';
138*7c478bd9Sstevel@tonic-gate 			n++;
139*7c478bd9Sstevel@tonic-gate 		} else if (*wp == L'\\') {
140*7c478bd9Sstevel@tonic-gate 			if (*(wp + 1) == L'n') {
141*7c478bd9Sstevel@tonic-gate 				wordcnt++;
142*7c478bd9Sstevel@tonic-gate 				n = width + 1;
143*7c478bd9Sstevel@tonic-gate 				wp += 2;
144*7c478bd9Sstevel@tonic-gate 				lastword = wp;
145*7c478bd9Sstevel@tonic-gate 				lastend = copy;
146*7c478bd9Sstevel@tonic-gate 			} else if (*(wp + 1) == L't') {
147*7c478bd9Sstevel@tonic-gate 				wordcnt++;
148*7c478bd9Sstevel@tonic-gate 				do {
149*7c478bd9Sstevel@tonic-gate 					*copy++ = L' ';
150*7c478bd9Sstevel@tonic-gate 				} while (++n % 8);
151*7c478bd9Sstevel@tonic-gate 				n++;
152*7c478bd9Sstevel@tonic-gate 				wp += 2;
153*7c478bd9Sstevel@tonic-gate 				lastword = wp;
154*7c478bd9Sstevel@tonic-gate 				lastend = copy;
155*7c478bd9Sstevel@tonic-gate 			} else if (*(wp + 1) == L' ') {
156*7c478bd9Sstevel@tonic-gate 				*copy++ = L' ';
157*7c478bd9Sstevel@tonic-gate 				wp += 2;
158*7c478bd9Sstevel@tonic-gate 				n++;
159*7c478bd9Sstevel@tonic-gate 			} else {
160*7c478bd9Sstevel@tonic-gate 				if (iswprint(*wp) && iswprint(*(wp + 1))) {
161*7c478bd9Sstevel@tonic-gate 		/*
162*7c478bd9Sstevel@tonic-gate 		 * Only if both *wp and *(wp +1) are printable,
163*7c478bd9Sstevel@tonic-gate 		 * tries to check the binding weight between them.
164*7c478bd9Sstevel@tonic-gate 		 */
165*7c478bd9Sstevel@tonic-gate 					wlen = wcwidth(*wp);
166*7c478bd9Sstevel@tonic-gate 					if (n + wlen > width) {
167*7c478bd9Sstevel@tonic-gate 		/*
168*7c478bd9Sstevel@tonic-gate 		 * if (n + wlen) is larger than width, *wp will be
169*7c478bd9Sstevel@tonic-gate 		 * put to the next line.
170*7c478bd9Sstevel@tonic-gate 		 */
171*7c478bd9Sstevel@tonic-gate 						*copy++ = *wp++;
172*7c478bd9Sstevel@tonic-gate 						n = width + 1;
173*7c478bd9Sstevel@tonic-gate 						goto fold;
174*7c478bd9Sstevel@tonic-gate 					} else {
175*7c478bd9Sstevel@tonic-gate 						n += wlen;
176*7c478bd9Sstevel@tonic-gate 						bdg = wdbindf(*wp,
177*7c478bd9Sstevel@tonic-gate 							*(wp + 1), 1);
178*7c478bd9Sstevel@tonic-gate 						*copy++ = *wp++;
179*7c478bd9Sstevel@tonic-gate 						if (bdg < 5) {
180*7c478bd9Sstevel@tonic-gate 		/*
181*7c478bd9Sstevel@tonic-gate 		 * binding weight between *wp and *(wp + 1) is
182*7c478bd9Sstevel@tonic-gate 		 * enough small to fold the line there.
183*7c478bd9Sstevel@tonic-gate 		 */
184*7c478bd9Sstevel@tonic-gate 							lastword = wp;
185*7c478bd9Sstevel@tonic-gate 							lastend = copy;
186*7c478bd9Sstevel@tonic-gate 							wordcnt++;
187*7c478bd9Sstevel@tonic-gate 						}
188*7c478bd9Sstevel@tonic-gate 					}
189*7c478bd9Sstevel@tonic-gate 				} else {
190*7c478bd9Sstevel@tonic-gate 					wlen = wcwidth(*wp);
191*7c478bd9Sstevel@tonic-gate 					if (wlen > 0) {
192*7c478bd9Sstevel@tonic-gate 		/*
193*7c478bd9Sstevel@tonic-gate 		 * *wp is printable
194*7c478bd9Sstevel@tonic-gate 		 */
195*7c478bd9Sstevel@tonic-gate 						if (n + wlen > width) {
196*7c478bd9Sstevel@tonic-gate 		/*
197*7c478bd9Sstevel@tonic-gate 		 * if (n + wlen) is larger than width, *wp will
198*7c478bd9Sstevel@tonic-gate 		 * be put to the next line.
199*7c478bd9Sstevel@tonic-gate 		 */
200*7c478bd9Sstevel@tonic-gate 							*copy++ = *wp++;
201*7c478bd9Sstevel@tonic-gate 							n = width + 1;
202*7c478bd9Sstevel@tonic-gate 							goto fold;
203*7c478bd9Sstevel@tonic-gate 						} else {
204*7c478bd9Sstevel@tonic-gate 							n += wlen;
205*7c478bd9Sstevel@tonic-gate 						}
206*7c478bd9Sstevel@tonic-gate 					} else {
207*7c478bd9Sstevel@tonic-gate 		/*
208*7c478bd9Sstevel@tonic-gate 		 * *wp is not printable, and shares 1 column.
209*7c478bd9Sstevel@tonic-gate 		 */
210*7c478bd9Sstevel@tonic-gate 						n++;
211*7c478bd9Sstevel@tonic-gate 					}
212*7c478bd9Sstevel@tonic-gate 					*copy++ = *wp++;
213*7c478bd9Sstevel@tonic-gate 				}
214*7c478bd9Sstevel@tonic-gate 			}
215*7c478bd9Sstevel@tonic-gate 		} else {
216*7c478bd9Sstevel@tonic-gate 			if (iswprint(*wp) && iswprint(*(wp + 1))) {
217*7c478bd9Sstevel@tonic-gate 		/*
218*7c478bd9Sstevel@tonic-gate 		 * Only if both *wp and *(wp + 1) are printable,
219*7c478bd9Sstevel@tonic-gate 		 * tries to check the binding weight between them.
220*7c478bd9Sstevel@tonic-gate 		 */
221*7c478bd9Sstevel@tonic-gate 				wlen = wcwidth(*wp);
222*7c478bd9Sstevel@tonic-gate 				if (n + wlen > width) {
223*7c478bd9Sstevel@tonic-gate 		/*
224*7c478bd9Sstevel@tonic-gate 		 * if (n + wlen) is larger than width, *wp will be
225*7c478bd9Sstevel@tonic-gate 		 * put to the next line.
226*7c478bd9Sstevel@tonic-gate 		 */
227*7c478bd9Sstevel@tonic-gate 					*copy++ = *wp++;
228*7c478bd9Sstevel@tonic-gate 					n = width + 1;
229*7c478bd9Sstevel@tonic-gate 					goto fold;
230*7c478bd9Sstevel@tonic-gate 				}
231*7c478bd9Sstevel@tonic-gate 				n += wlen;
232*7c478bd9Sstevel@tonic-gate 				bdg = wdbindf(*wp, *(wp + 1), 1);
233*7c478bd9Sstevel@tonic-gate 				*copy++ = *wp++;
234*7c478bd9Sstevel@tonic-gate 				if (bdg < 5) {
235*7c478bd9Sstevel@tonic-gate 		/*
236*7c478bd9Sstevel@tonic-gate 		 * binding weight between *wp and *(wp + 1) is
237*7c478bd9Sstevel@tonic-gate 		 * enough small to fold the line there.
238*7c478bd9Sstevel@tonic-gate 		 */
239*7c478bd9Sstevel@tonic-gate 					lastword = wp;
240*7c478bd9Sstevel@tonic-gate 					lastend = copy;
241*7c478bd9Sstevel@tonic-gate 					wordcnt++;
242*7c478bd9Sstevel@tonic-gate 				}
243*7c478bd9Sstevel@tonic-gate 			} else {
244*7c478bd9Sstevel@tonic-gate 				wlen = wcwidth(*wp);
245*7c478bd9Sstevel@tonic-gate 				if (wlen > 0) {
246*7c478bd9Sstevel@tonic-gate 		/*
247*7c478bd9Sstevel@tonic-gate 		 * *wp is printable
248*7c478bd9Sstevel@tonic-gate 		 */
249*7c478bd9Sstevel@tonic-gate 					if (n + wlen > width) {
250*7c478bd9Sstevel@tonic-gate 		/*
251*7c478bd9Sstevel@tonic-gate 		 * if (n + wlen) is larger than width, *wp will
252*7c478bd9Sstevel@tonic-gate 		 * be put to the next line.
253*7c478bd9Sstevel@tonic-gate 		 */
254*7c478bd9Sstevel@tonic-gate 						*copy++ = *wp++;
255*7c478bd9Sstevel@tonic-gate 						n = width + 1;
256*7c478bd9Sstevel@tonic-gate 						goto fold;
257*7c478bd9Sstevel@tonic-gate 					} else {
258*7c478bd9Sstevel@tonic-gate 						n += wlen;
259*7c478bd9Sstevel@tonic-gate 					}
260*7c478bd9Sstevel@tonic-gate 				} else {
261*7c478bd9Sstevel@tonic-gate 		/*
262*7c478bd9Sstevel@tonic-gate 		 * *wp is not printable, and shares 1 column.
263*7c478bd9Sstevel@tonic-gate 		 */
264*7c478bd9Sstevel@tonic-gate 					n++;
265*7c478bd9Sstevel@tonic-gate 				}
266*7c478bd9Sstevel@tonic-gate 				*copy++ = *wp++;
267*7c478bd9Sstevel@tonic-gate 			}
268*7c478bd9Sstevel@tonic-gate 		}
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate fold:
271*7c478bd9Sstevel@tonic-gate 		if (n >= width) {
272*7c478bd9Sstevel@tonic-gate 			if (lastend)
273*7c478bd9Sstevel@tonic-gate 				*lastend = L'\0';
274*7c478bd9Sstevel@tonic-gate 			else
275*7c478bd9Sstevel@tonic-gate 				*copy = L'\0';
276*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < lmarg; i++)
277*7c478bd9Sstevel@tonic-gate 				(void) putc(' ', fp);
278*7c478bd9Sstevel@tonic-gate 			mlen = wcstombs(mbtemp, temp, MWIDTH+1);
279*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < mlen; i++)
280*7c478bd9Sstevel@tonic-gate 				(void) putc(mbtemp[i], fp);
281*7c478bd9Sstevel@tonic-gate 			(void) putc('\n', fp);
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 			lastend = NULL;
284*7c478bd9Sstevel@tonic-gate 			copy = temp;
285*7c478bd9Sstevel@tonic-gate 			if (wordcnt)
286*7c478bd9Sstevel@tonic-gate 				wp = lastword;
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 			wordcnt = 0;
289*7c478bd9Sstevel@tonic-gate 			n = 0;
290*7c478bd9Sstevel@tonic-gate 			if (!force) {
291*7c478bd9Sstevel@tonic-gate 				while (iswspace(*wp))
292*7c478bd9Sstevel@tonic-gate 					wp++;
293*7c478bd9Sstevel@tonic-gate 			}
294*7c478bd9Sstevel@tonic-gate 		}
295*7c478bd9Sstevel@tonic-gate 	} while (*wp != L'\0');
296*7c478bd9Sstevel@tonic-gate 	if (!force) {
297*7c478bd9Sstevel@tonic-gate 		*copy = L'\0';
298*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < lmarg; i++)
299*7c478bd9Sstevel@tonic-gate 			(void) putc(' ', fp);
300*7c478bd9Sstevel@tonic-gate 		mlen = wcstombs(mbtemp, temp, MWIDTH+1);
301*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < mlen; i++)
302*7c478bd9Sstevel@tonic-gate 			(void) putc(mbtemp[i], fp);
303*7c478bd9Sstevel@tonic-gate 	}
304*7c478bd9Sstevel@tonic-gate 	free(wstr);
305*7c478bd9Sstevel@tonic-gate 	return (width - n - !force);
306*7c478bd9Sstevel@tonic-gate }
307