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