root/usr/src/lib/libcurses/screen/mbaddch.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 (c) 1988 AT&T */
/*    All Rights Reserved   */


/*
 *      Copyright (c) 1997, by Sun Microsystems, Inc.
 *      All rights reserved.
 */

/*LINTLIBRARY*/

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

/*
 *      Clear the space occupied by a multicolumn character
 */

int
_mbclrch(WINDOW *win, int y, int x)
{
        chtype  *wcp, *ep, *wp, wc;

        /* ASSERT(_scrmax > 1); */

        wcp = win->_y[y];
        wp = wcp + x;

        /* compute the bounds for the character */
        if (ISCBIT(*wp)) {
                for (; wp >= wcp; --wp)
                        if (!ISCBIT(*wp))
                                break;
                if (wp < wcp)
                        return (ERR);
        }
        wc = RBYTE(*wp);
        ep = wp + _curs_scrwidth[TYPE(wc)];
        if (ep > wcp + win->_maxx)
                return (ERR);

        /* update the change structure */
        /*LINTED*/
        if ((x = (int)(wp - wcp)) < win->_firstch[y])
                /*LINTED*/
                win->_firstch[y] = (short)x;
        /*LINTED*/
        if ((x = (int)(ep - wcp) - 1) > win->_lastch[y])
                /*LINTED*/
                win->_lastch[y] = (short)x;

        /* clear the character */
        for (; wp < ep; ++wp)
                *wp = win->_bkgd;
        return (OK);
}



/*
 *      Make sure the window cursor point to a valid place.
 *      If win->_insmode or isedge, the cursor has to
 *      point to the start of a whole character; otherwise, the
 *      cursor has to point to a part of a whole character.
 */

int
_mbvalid(WINDOW *win)
{
        chtype  *wp, *wcp, *ecp, wc;
        int             x;
        bool    isedge;

        /* ASSERT(_scrmax > 1); */

        x = win->_curx;
        wcp = win->_y[win->_cury];
        wp = wcp + x;
        if (!ISMBIT(*wp))
                return (OK);

        ecp = wcp + win->_maxx;
        isedge = FALSE;

        /* make wp points to the start column of a mb-character */
        if (ISCBIT(*wp)) {
                for (; wp >= wcp; --wp)
                        if (!ISCBIT(*wp))
                                break;
                if (wp < wcp) {
                        for (wp = wcp + x + 1; wp < ecp; ++wp)
                                if (!ISCBIT(*wp))
                                        break;
                        if (wp >= ecp)
                                return (ERR);
                        isedge = TRUE;
                }
        }

        /* make sure that wp points to a whole character */
        wc = RBYTE(*wp);
        if (wp + _curs_scrwidth[TYPE(wc)] > ecp) {
                for (wp -= 1; wp >= wcp; --wp)
                        if (!ISCBIT(*wp))
                                break;
                if (wp < wcp)
                        return (ERR);
                isedge = TRUE;
        }

        if (isedge || win->_insmode)
                /*LINTED*/
                win->_curx = (short)(wp-wcp);
        return (OK);
}



/*
 *      Add/insert multi-byte characters
 */

int
_mbaddch(WINDOW *win, chtype a, chtype c)
{
        int             n, x, y, nc, m, len, nbyte, ty;
        chtype          *wcp, wc;
        char            *wch, rc[2];

        /* ASSERT(_mbtrue); */

        /* decode the character into a sequence of bytes */
        nc = 0;
        if (ISCBIT(c))
                /*LINTED*/
                rc[nc++] = (char)(LBYTE(c)|MBIT);
        if (ISMBIT(c))
                /*LINTED*/
                rc[nc++] = (char)RBYTE(c);

        a |= win->_attrs;

        /* add the sequence to the image */
        for (n = 0; n < nc; ++n) {
                wc = RBYTE(rc[n]);
                ty = TYPE(wc);
                wch = win->_waitc;

                /* first byte of a multi-byte character */
                if (ty > 0 || win->_nbyte < 0) {
                        /*LINTED*/
                        wch[0] = (char)wc;
                        win->_nbyte = cswidth[ty] + (ty == 0 ? 0 : 1);
                        win->_index = 1;
                } else {
                /* non-first byte */
                        /*LINTED*/
                        wch[win->_index] = (char)wc;
                        win->_index += 1;
                }

                /* if character is not ready to process */
                if (win->_index < win->_nbyte)
                        continue;

                /* begin processing the character */
                nbyte = win->_nbyte;
                win->_nbyte = -1;
                wc = RBYTE(wch[0]);
                len = _curs_scrwidth[TYPE(wc)];

                /* window too small or char cannot be stored */
                if (len > win->_maxx || 2*len < nbyte)
                        continue;

                /* if the character won't fit into the line */
                if ((win->_curx + len) > win->_maxx &&
                    (win->_insmode || waddch(win, '\n') == ERR))
                        continue;

                y = win->_cury;
                x = win->_curx;
                wcp = win->_y[y] + x;

                if (win->_insmode) {
                        /* perform the right shift */
                        if (_mbinsshift(win, len) == ERR)
                                continue;
                } else if (_scrmax > 1) {
                        /* clear any multi-byte char about to be overwritten */
                        for (m = 0; m < len; ++m)
                                if (ISMBIT(wcp[m]) &&
                                    _mbclrch(win, y, x + m) == ERR)
                                        break;
                        if (m < len)
                                continue;
                }

                /* pack two bytes at a time */
                for (m = nbyte/2; m > 0; m -= 1, wch += 2)
                        *wcp++ = _CHAR((RBYTE(wch[1]) << 8) |
                            RBYTE(wch[0])) | CBIT | a;

                /* do the remaining byte if any */
                if ((nbyte%2) != 0)
                        *wcp++ = RBYTE(wch[0]) | CBIT | a;

                /* fill-in for remaining display columns */
                for (m = (nbyte / 2) + (nbyte % 2); m < len; ++m)
                        *wcp++ = (CBIT|MBIT) | a;

                /* the first column has Continue BIT off */
                win->_y[y][x] &= ~CBIT;

                if (win->_insmode == FALSE) {
                        if (x < win->_firstch[y])
                                /*LINTED*/
                                win->_firstch[y] = (short)x;
                        if ((x += len-1) >= win->_maxx)
                                x = win->_maxx-1;
                        if (x > win->_lastch[y])
                                /*LINTED*/
                                win->_lastch[y] = (short)x;

                        if ((win->_curx += len) >= win->_maxx) {
                                if (y >= (win->_maxy-1) || y == win->_bmarg) {
                                        win->_curx = win->_maxx-1;
                                        if (wscrl(win, 1) == ERR)
                                                continue;
                                } else {
                                        win->_cury += 1;
                                        win->_curx = 0;
                                }
                        }
                }
        }

        return (OK);
}