root/usr/src/lib/libcurses/screen/winsnstr.c
/*
 * 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 1997 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*      Copyright (c) 1988 AT&T */
/*        All Rights Reserved   */

/*
 * University Copyright- Copyright (c) 1982, 1986, 1988
 * The Regents of the University of California
 * All Rights Reserved
 *
 * University Acknowledgment- Portions of this document are derived from
 * software developed by the University of California, Berkeley, and its
 * contributors.
 */

/*LINTLIBRARY*/

#include        <sys/types.h>
#include        "curses_inc.h"

/*
 * Insert to 'win' at most n chars of a string
 * starting at (cury, curx). However, if n <= 0,
 * insert the entire string.
 * \n, \t, \r, \b are treated in the same way
 * as other control chars.
 */

int
winsnstr(WINDOW *win, char *tsp, int n)
{
        chtype          *wcp;
        int             x, cury, endx, maxx, len;
        bool            savscrl, savsync, savimmed;
        short           savx, savy;
        unsigned char   *sp = (unsigned char *)tsp;

        /* only insert at the start of a character */
        win->_nbyte = -1;
        win->_insmode = TRUE;
        if (_scrmax > 1 && _mbvalid(win) == ERR)
                return (ERR);

        if (n < 0)
                n = MAXINT;

        /* compute total length of the insertion */
        endx = win->_curx;
        maxx = win->_maxx;
        for (x = 0; sp[x] != '\0' && x < n && endx < maxx; ++x) {
                len = (sp[x] < ' '|| sp[x] == _CTRL('?')) ? 2 : 1;

                if (ISMBIT(sp[x])) {
                        int     m, k, ty;
                        chtype  c;

                        /* see if the entire character is defined */
                        c = RBYTE(sp[x]);
                        ty = TYPE(c);
                        m = x + cswidth[ty] - (ty == 0 ? 1 : 0);
                        for (k = x + 1; sp[k] != '\0' && k <= m; ++k) {
                                c = RBYTE(sp[k]);
                                if (TYPE(c) != 0)
                                        break;
                        }
                        if (k <= m)
                                break;
                        /* recompute # of columns used */
                        len = _curs_scrwidth[ty];
                        /* skip an appropriate number of bytes */
                        x = m;
                }

                if ((endx += len) > maxx) {
                        endx -= len;
                        break;
                }
        }

        /* length of chars to be shifted */
        if ((len = endx - win->_curx) <= 0)
                return (ERR);

        /* number of chars insertible */
        n = x;

        /* shift data */
        cury = win->_cury;

        if (_mbinsshift(win, len) == ERR)
                return (ERR);

        /* insert new data */
        wcp = win->_y[cury] + win->_curx;

        /* act as if we are adding characters */
        savx = win->_curx;
        savy = win->_cury;
        win->_insmode = FALSE;
        savscrl = win->_scroll;
        savimmed = win->_immed;
        savsync = win->_sync;
        win->_scroll = win->_sync;

        for (; n > 0; --n, ++sp) {
                /* multi-byte characters */
                if (_mbtrue && ISMBIT(*sp)) {
                        (void) _mbaddch(win, A_NORMAL, RBYTE(*sp));
                        wcp = win->_y[cury] + win->_curx;
                        continue;
                }
                if (_scrmax > 1 && ISMBIT(*wcp))
                        (void) _mbclrch(win, cury, win->_curx);
                /* single byte character */
                win->_nbyte = -1;

                if (*sp < ' ' || *sp == _CTRL('?')) {
                        *wcp++ = _CHAR('^') | win->_attrs;
                        *wcp = _CHAR(_UNCTRL(*sp)) | win->_attrs;
                } else
                        *wcp = _CHAR(*sp) | win->_attrs;
                win->_curx += (*sp < ' ' || *sp == _CTRL('?')) ? 2 : 1;
                ++wcp;
        }
        win->_curx = savx;
        win->_cury = savy;

        /* update the change structure */
        if (win->_firstch[cury] > win->_curx)
                win->_firstch[cury] = win->_curx;
        win->_lastch[cury] = maxx - 1;

        win->_flags |= _WINCHANGED;

        win->_scroll = savscrl;
        win->_sync = savsync;
        win->_immed = savimmed;

        if (win->_sync)
                wsyncup(win);
        return (win->_immed ? wrefresh(win) : OK);
}