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 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