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