/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1997-1999 by Sun Microsystems, Inc. * All rights reserved. */ /*LINTLIBRARY*/ #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */ #include #include #include #include #include #include #include #include #include "libadm.h" #define MWIDTH 256 #define WIDTH 60 int puttext(FILE *fp, char *str, int lmarg, int rmarg) { wchar_t *wstr, *wp; wchar_t *copy, *lastword, *lastend, temp[MWIDTH+1]; size_t len, ret; int width, i, n, force, wordcnt; int wlen, mlen, bdg; char mbs[MB_LEN_MAX]; char mbtemp[(MWIDTH+1) * MB_LEN_MAX]; width = rmarg ? (rmarg - lmarg) : (WIDTH - lmarg); if (width > MWIDTH) width = MWIDTH; if (!str || !*str) return (width); len = strlen(str); wstr = (wchar_t *)malloc(sizeof (wchar_t) * (len + 1)); if (wstr == NULL) return (width); ret = mbstowcs(wstr, (const char *)str, len + 1); if (ret == (size_t)-1) { free(wstr); return (width); } wp = wstr; if (*wp == L'!') { wp++; force = 1; for (i = 0; i < lmarg; i++) (void) putc(' ', fp); } else { while (iswspace(*wp)) ++wp; /* eat leading white space */ force = 0; } wordcnt = 0; n = 0; copy = temp; lastword = wp; lastend = NULL; do { if (force) { if (*wp == L'\n') { (void) putc('\n', fp); for (i = 0; i < lmarg; i++) (void) putc(' ', fp); wp++; n = 0; } else { wlen = wcwidth(*wp); /* * Using putc instead of fputwc here to avoid * mixing up the byte stream and the wide stream * for fp. */ mlen = wctomb(mbs, *wp); if (mlen == -1) { /* * wctomb failed * nothing will be outputted */ wp++; } else { for (i = 0; i < mlen; i++) (void) putc(mbs[i], fp); wp++; /* * if wlen is a negative value (*wp is not printable), * add 1 to n. (non-printable char shares 1 column. */ if (wlen >= 0) n += wlen; else n++; } } continue; } if (iswspace(*wp)) { /* eat multiple tabs/nl after whitespace */ while ((*++wp == L'\t') || (*wp == '\n')); wordcnt++; lastword = wp; lastend = copy; *copy++ = L' '; n++; } else if (*wp == L'\\') { if (*(wp + 1) == L'n') { wordcnt++; n = width + 1; wp += 2; lastword = wp; lastend = copy; } else if (*(wp + 1) == L't') { wordcnt++; do { *copy++ = L' '; } while (++n % 8); n++; wp += 2; lastword = wp; lastend = copy; } else if (*(wp + 1) == L' ') { *copy++ = L' '; wp += 2; n++; } else { if (iswprint(*wp) && iswprint(*(wp + 1))) { /* * Only if both *wp and *(wp +1) are printable, * tries to check the binding weight between them. */ wlen = wcwidth(*wp); if (n + wlen > width) { /* * if (n + wlen) is larger than width, *wp will be * put to the next line. */ *copy++ = *wp++; n = width + 1; goto fold; } else { n += wlen; bdg = wdbindf(*wp, *(wp + 1), 1); *copy++ = *wp++; if (bdg < 5) { /* * binding weight between *wp and *(wp + 1) is * enough small to fold the line there. */ lastword = wp; lastend = copy; wordcnt++; } } } else { wlen = wcwidth(*wp); if (wlen > 0) { /* * *wp is printable */ if (n + wlen > width) { /* * if (n + wlen) is larger than width, *wp will * be put to the next line. */ *copy++ = *wp++; n = width + 1; goto fold; } else { n += wlen; } } else { /* * *wp is not printable, and shares 1 column. */ n++; } *copy++ = *wp++; } } } else { if (iswprint(*wp) && iswprint(*(wp + 1))) { /* * Only if both *wp and *(wp + 1) are printable, * tries to check the binding weight between them. */ wlen = wcwidth(*wp); if (n + wlen > width) { /* * if (n + wlen) is larger than width, *wp will be * put to the next line. */ *copy++ = *wp++; n = width + 1; goto fold; } n += wlen; bdg = wdbindf(*wp, *(wp + 1), 1); *copy++ = *wp++; if (bdg < 5) { /* * binding weight between *wp and *(wp + 1) is * enough small to fold the line there. */ lastword = wp; lastend = copy; wordcnt++; } } else { wlen = wcwidth(*wp); if (wlen > 0) { /* * *wp is printable */ if (n + wlen > width) { /* * if (n + wlen) is larger than width, *wp will * be put to the next line. */ *copy++ = *wp++; n = width + 1; goto fold; } else { n += wlen; } } else { /* * *wp is not printable, and shares 1 column. */ n++; } *copy++ = *wp++; } } fold: if (n >= width) { if (lastend) *lastend = L'\0'; else *copy = L'\0'; for (i = 0; i < lmarg; i++) (void) putc(' ', fp); mlen = wcstombs(mbtemp, temp, MWIDTH+1); for (i = 0; i < mlen; i++) (void) putc(mbtemp[i], fp); (void) putc('\n', fp); lastend = NULL; copy = temp; if (wordcnt) wp = lastword; wordcnt = 0; n = 0; if (!force) { while (iswspace(*wp)) wp++; } } } while (*wp != L'\0'); if (!force) { *copy = L'\0'; for (i = 0; i < lmarg; i++) (void) putc(' ', fp); mlen = wcstombs(mbtemp, temp, MWIDTH+1); for (i = 0; i < mlen; i++) (void) putc(mbtemp[i], fp); } free(wstr); return (width - n - !force); }