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