diff options
Diffstat (limited to 'usr/src/lib/libadm/common/puttext.c')
-rw-r--r-- | usr/src/lib/libadm/common/puttext.c | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/usr/src/lib/libadm/common/puttext.c b/usr/src/lib/libadm/common/puttext.c new file mode 100644 index 0000000000..71870a8078 --- /dev/null +++ b/usr/src/lib/libadm/common/puttext.c @@ -0,0 +1,307 @@ +/* + * 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 <sys/types.h> +#include <stdio.h> +#include <ctype.h> +#include <wchar.h> +#include <libintl.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#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); +} |