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