m_cc.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/* LINTLIBRARY */
/*
* m_cc.c
*
* XCurses Library
*
* Copyright 1990, 1995 by Mortice Kern Systems Inc. All rights reserved.
*
*/
#if M_RCSID
#ifndef lint
static char rcsID[] =
"$Header: /team/ps/sun_xcurses/archive/local_changes/xcurses/src/lib/"
"libxcurses/src/libc/xcurses/rcs/m_cc.c 1.40 1998/06/12 12:45:39 "
"cbates Exp $";
#endif
#endif
#include <private.h>
#include <limits.h>
#include <m_wio.h>
#include <string.h>
typedef struct {
int max;
int used;
char *mbs;
} t_string;
static int
write_string(int byte, t_string *sp)
{
if (sp->max <= sp->used)
return (EOF);
sp->mbs[sp->used++] = (char)byte;
return (byte);
}
/*
* Convert a wint_t string into a multibyte string.
*
* The conversion stops at the end of string or the first WEOF.
* Return the number of bytes successfully placed into mbs.
*/
int
wistombs(char *mbs, const wint_t *wis, int n)
{
int last;
t_string string = { 0 };
t_wide_io convert = { 0 };
string.max = n;
string.mbs = mbs;
convert.object = (void *) &string;
convert.put = (int (*)(int, void *)) write_string;
for (; ; ++wis) {
/* In case of error, rewind string to the last character. */
last = string.used;
if (m_wio_put(*wis, &convert) < 0) {
string.used = last;
break;
}
/*
* Test for end of string AFTER trying to copy into the
* buffer, because m_wio_put() has to handle state changes
* back to the initial state on '\0' or WEOF.
*/
if (*wis == '\0' || *wis == WEOF)
break;
}
/*
* m_wio_put() does not write '\0', because the "stream"
* object is considered to be in "text" mode, which in the
* case of file I/O produces undefined results for systems
* using locking-shift character sets.
*/
string.mbs[string.used] = '\0';
return (string.used);
}
/*
* Convert a wint_t string (filled in by wgetn_wstr()) to a wchar_t string.
* The conversion stops at the end of string or the first WEOF. Return the
* number of successfully copied characters.
*
* This routinue should be used when sizeof (wchar_t) < sizeof (wint_t).
*/
int
wistowcs(wchar_t *wcs, const wint_t *wis, int n)
{
wchar_t *start;
if (n < 0)
n = INT_MAX;
for (start = wcs; *wis != '\0' && 0 < n; ++wis, ++wcs, --n) {
if (*wis == WEOF)
break;
*wcs = (wchar_t)*wis;
}
*wcs = '\0';
/* (wcs - start) should be enough small to fit in "int" */
return ((int)(wcs - start));
}
void
__m_touch_locs(WINDOW *w, int row, int firstCol, int lastCol)
{
if (w) {
if (firstCol < w->_first[row])
w->_first[row] = (short)firstCol;
if (lastCol > w->_last[row])
w->_last[row] = (short)lastCol;
}
}
/*
* Convert a chtype to a cchar_t.
*/
int
__m_chtype_cc(chtype ch, cchar_t *cc)
{
char mb;
cc->_f = 1;
cc->_n = 1;
mb = (char)(ch & A_CHARTEXT);
cc->_co = (short)PAIR_NUMBER((int)ch);
cc->_at = (attr_t)((ch & (A_ATTRIBUTES & ~A_COLOR)) >> 16);
if (mb == 0)
cc->_wc[0] = cc->_wc[1] = 0;
else if (mbtowc(cc->_wc, &mb, 1) < 0) {
return (ERR);
}
return (OK);
}
/*
* Return a complex character as a chtype.
*/
chtype
__m_cc_chtype(const cchar_t *cc)
{
chtype ch;
unsigned char mb[MB_LEN_MAX];
/* Is it a single-byte character? */
if (cc->_n != 1 || wctomb((char *)mb, cc->_wc[0]) != 1)
return ((chtype) ERR);
ch = ((chtype) cc->_at << 16) & ~A_COLOR;
ch |= COLOR_PAIR(cc->_co) | mb[0];
return (ch);
}
/*
* Convert a complex character's "character" into a multibyte string.
* The attribute and colour are ignored.
*
* If 0 < n, set a new multibyte string and convert the first character,
* returning either -1 on error or the number of bytes used to convert the
* character.
*
* If n == 0, continue appending to the current multibyte string and return
* a value as for 0 < n case.
*
* If n < 0, return the accumulated byte length of the current multibyte
* string and do nothing else.
*
* When converting a character, a null cchar_t pointer will force the initial
* shift state and append a '\0' to the multibyte string. The return value
* will instead by the number of bytes used to shift to the initial state,
* and exclude the '\0'.
*/
int
__m_cc_mbs(const cchar_t *cc, char *mbs, int n)
{
int i, bytes, count, last;
static t_string string = { 0 };
static t_wide_io convert = { 0 };
if (n < 0) {
/* Return total number of bytes written to multibyte string. */
return (string.used);
} else if (0 < n) {
/* Start a new conversion. */
string.max = n;
string.used = 0;
string.mbs = mbs;
convert._next = convert._size = 0;
convert.object = (void *) &string;
convert.put = (int (*)(int, void *)) write_string;
} /* else n == 0, continue appending to previous mbs. */
/* In case of error, rewind string to the last character. */
last = string.used;
if (cc == NULL) {
/* Force initial shift state. */
if ((count = m_wio_put('\0', &convert)) < 0) {
string.used = last;
return (-1);
}
if (string.used < string.max)
string.mbs[string.used++] = '\0';
} else {
for (count = i = 0; i < cc->_n; ++i, count += bytes)
if ((bytes = m_wio_put(cc->_wc[i], &convert)) < 0) {
string.used = last;
return (-1);
}
}
return (count);
}
/*
* Convert a stty character into a wchar_t.
*/
int
__m_tty_wc(int index, wchar_t *wcp)
{
char mb;
int code;
/*
* Refer to _shell instead of _prog, since _shell will
* correctly reflect the user's prefered settings, whereas
* _prog may not have been initialised if both input and
* output have been redirected.
*/
mb = (char)PTERMIOS(_shell)->c_cc[index];
if (mb)
code = mbtowc(wcp, &mb, 1) < 0 ? ERR : OK;
else
code = ERR;
return (code);
}
/*
* Build a cchar_t from the leading spacing and non-spacing characters
* in the multibyte character string. Only one spacing character is copied
* from the multibyte character string.
*
* Return the number of characters copied from the string, or -1 on error.
*/
int
__m_mbs_cc(const char *mbs, attr_t at, short co, cchar_t *cc)
{
wchar_t wc;
const char *start;
int i, nbytes, width, have_one;
for (start = mbs, have_one = i = 0; *mbs != '\0'; mbs += nbytes, ++i) {
if (sizeof (cc->_wc) <= i)
/* Too many characters. */
return (-1);
if ((nbytes = mbtowc(&wc, mbs, UINT_MAX)) < 0)
/* Invalid multibyte sequence. */
return (-1);
if (nbytes == 0)
/* Remainder of string evaluates to the null byte. */
break;
if (iscntrl(*mbs))
/* Treat control codes like a spacing character. */
width = 1;
else
width = wcwidth(wc);
/* Do we have a spacing character? */
if (0 < width) {
if (have_one)
break;
have_one = 1;
}
cc->_wc[i] = wc;
}
cc->_f = 1;
cc->_n = (short)i;
cc->_co = co;
cc->_at = at;
(void) __m_cc_sort(cc);
/* (mbs - start) should be enough small to fit in "int" */
return ((int)(mbs - start));
}
/*
* Build a cchar_t from the leading spacing and non-spacing characters
* in the wide character string. Only one spacinig character is copied
* from the wide character string.
*
* Return the number of characters copied from the string, or -1 on error.
*/
int
__m_wcs_cc(const wchar_t *wcs, attr_t at, short co, cchar_t *cc)
{
short i;
const wchar_t *start;
for (start = wcs, i = 0; *wcs != '\0'; ++wcs, ++i) {
if (sizeof (cc->_wc) <= i) {
/* Too many characters. */
return (-1);
}
if (wcwidth(*wcs) > 0) {
if (i != 0)
break;
} else if ((*wcs == L'\n') || (*wcs == L'\t') ||
(*wcs == L'\b') || (*wcs == L'\r')) {
if (i != 0)
break;
cc->_wc[i++] = *wcs++;
break;
}
cc->_wc[i] = *wcs;
}
cc->_f = 1;
cc->_n = i;
cc->_co = co;
cc->_at = at;
/* (wcs - start) should be enough small to fit in "int" */
return ((int)(wcs - start));
}
/*
* Convert a single wide character into a complex character.
*/
int
__m_wc_cc(wint_t wc, cchar_t *cc)
{
wchar_t wcs[2];
if (wc == WEOF)
return (-1);
if (wc == 0) {
/*
* converting a null character to a complex character.
* __m_wcs_cc assumes that the string is empty, so
* just do it here.
*/
cc->_f = 1;
cc->_n = 1;
cc->_co = 0;
cc->_at = WA_NORMAL;
cc->_wc[0] = 0;
cc->_wc[1] = 0;
} else {
/* A real character */
wcs[0] = (wchar_t)wc;
wcs[1] = '\0';
(void) __m_wcs_cc(wcs, WA_NORMAL, 0, cc);
}
return (0);
}
/*
* Sort a complex character into a spacing character followed
* by any non-spacing characters in increasing order of oridinal
* values. This facilitates both comparision and writting of
* complex characters. More than one spacing character is
* considered an error.
*
* Return the spacing character's column width or -1 if more
* than one spacing character appears in cc.
*/
int
__m_cc_sort(cchar_t *cc)
{
wchar_t wc;
int width, i, j, spacing;
/* Find spacing character and place in as first element. */
for (width = spacing = i = 0; i < cc->_n; ++i) {
j = wcwidth(cc->_wc[i]);
if (0 < j) {
/* More than one spacing character is an error. */
if (0 < width)
return (-1);
wc = cc->_wc[0];
cc->_wc[0] = cc->_wc[i];
cc->_wc[i] = wc;
spacing = 1;
width = j;
break;
}
}
/* Bubble sort small array. */
for (i = spacing; i < cc->_n; ++i) {
for (j = cc->_n - 1; i < j; --j) {
if (cc->_wc[j-1] > cc->_wc[j]) {
wc = cc->_wc[j];
cc->_wc[j] = cc->_wc[j-1];
cc->_wc[j-1] = wc;
}
}
}
return (width);
}
/*
* Return the first column of a multi-column character, in window.
*/
int
__m_cc_first(WINDOW *w, int y, int x)
{
cchar_t *lp;
for (lp = w->_line[y]; 0 < x; --x) {
if (lp[x]._f)
break;
}
return (x);
}
/*
* Return the start of the next multi-column character, in window.
*/
int
__m_cc_next(WINDOW *w, int y, int x)
{
cchar_t *lp;
for (lp = w->_line[y]; ++x < w->_maxx; ) {
if (lp[x]._f)
break;
}
return (x);
}
/*
* Return true if valid last column of a multi-column character.
*/
int
__m_cc_islast(WINDOW *w, int y, int x)
{
int first, width;
first = __m_cc_first(w, y, x);
width = __m_cc_width(&w->_line[y][x]);
return ((first + width) == (x + 1));
}
/*
* Replace the character at the current cursor location
* according to the column width of the character. The
* cursor does not advance.
*
* Return -1 if the character won't fit on the line and the background
* was written in its place; else return the width of the character in
* screen columns.
*/
/* ARGSUSED */
int
__m_cc_replace(WINDOW *w, int y, int x,
const cchar_t *cc, int as_is)
{
int i, width;
cchar_t *cp, *np;
width = __m_cc_width(cc);
if (width <= 0)
return (__m_cc_modify(w, y, x, cc));
/*
* If we try to write a broad character that would exceed the
* right margin, then write the background character instead.
*/
if (0 < width && w->_maxx < x + width) {
(void) __m_cc_erase(w, y, x, y, w->_maxx-1);
return (-1);
}
/*
* Erase the region to be occupied by the new character.
* __m_cc_erase() will erase whole characters so that
* writing a multicolumn character that overwrites the
* trailing and leading portions of two already existing
* multicolumn characters, erases the remaining portions.
*/
(void) __m_cc_erase(w, y, x, y, x + width - 1);
/* Write the first column of the character. */
cp = &w->_line[y][x++];
if (cc->_wc[0] == L' ') {
*cp = w->_bg;
cp->_at = cc->_at | w->_fg._at;
/*
* This method fixes:
* /tset/CAPIxcurses/fmvwaddchs/fmvwaddchs1{3}
* /tset/CAPIxcurses/fwins_wch/fwins_wch1{5}
*/
cp->_co = (cc->_co) ? cc->_co : w->_fg._co;
} else {
if (__m_wacs_cc(cc, cp)) {
/*
* __m_wacs_cc says ALTCHARSET should be cleared
* ... Takes priority
*/
cp->_at = (cc->_at | w->_fg._at) & ~WA_ALTCHARSET;
} else {
cp->_at = cc->_at | w->_fg._at;
}
cp->_co = (cc->_co) ? cc->_co : w->_fg._co;
}
/* Mark this as the first column of the character. */
cp->_f = 1;
/* Duplicate the character in every column the character occupies. */
for (np = cp + 1, i = 1; i < width; ++i, ++x, ++np) {
*np = *cp;
np->_f = 0;
}
return (width);
}
int
__m_do_scroll(WINDOW *w, int y, int x, int *yp, int *xp)
{
int code = OK;
if (w->_maxx <= x)
x = w->_maxx - 1;
++y;
if (y == w->_bottom) {
--y;
if (w->_flags & W_CAN_SCROLL) {
if (wscrl(w, 1) == ERR)
return (ERR);
x = 0;
/* Test suite seems to want this */
w->_flags |= W_FLUSH;
} else {
#ifdef BREAKS
w->_curx = x; /* Cheezy doing it here */
w->_cury = y;
#endif /* BREAKS */
code = ERR; /* No scrolling allowed */
}
} else if (w->_maxy <= y) {
y = w->_maxy - 1;
} else {
/*
* The cursor wraps for any line (in and out of the scroll
* region) except for the last line of the scroll region.
*/
x = 0;
}
*yp = y;
*xp = x;
return (code);
}
/*
* Add the character at the current cursor location
* according to the column width of the character.
* The cursor will be advanced.
* Wrapping is done.
*
* Return ERR if adding the character causes the
* screen to scroll, when it is disallowed.
*/
int
__m_cc_add(WINDOW *w, int y, int x,
const cchar_t *cc, int as_is, int *yp, int *xp)
{
int nx, width, code = ERR;
switch (cc->_wc[0]) {
case L'\t':
nx = x + (8 - (x & 07));
if (nx >= w->_maxx) {
/* This fixes (scroll-disabled) */
/* /tset/CAPIxcurses/fwaddch/fwaddch1{4} but */
/* what does it break? */
nx = w->_maxx;
}
if (__m_cc_erase(w, y, x, y, nx-1) == -1)
goto error;
x = nx;
if (w->_maxx <= x) {
if (__m_do_scroll(w, y, x, &y, &x) == ERR)
goto error;
}
break;
case L'\n':
if (__m_cc_erase(w, y, x, y, w->_maxx-1) == -1)
goto error;
if (__m_do_scroll(w, y, x, &y, &x) == ERR)
goto error;
break;
case L'\r':
x = 0;
break;
case L'\b':
if (0 < x)
--x;
else
(void) beep();
break;
default:
width = __m_cc_replace(w, y, x, cc, as_is);
x += width;
if (width < 0 || w->_maxx <= x) {
if (__m_do_scroll(w, y, x, &y, &x) == ERR) {
goto error;
}
if (width < 0)
x += __m_cc_replace(w, y, x, cc, as_is);
}
}
code = OK;
error:
*yp = y;
*xp = x;
return (code);
}
/*
* Stripped version of __m_cc_add which does much less special character
* processing. Functions such as waddchnstr() are not supposed to do
* any special character processing but what does one do when a '\n'
* is sent? The test suite expects a new line to start...
*
* Return ERR if adding the character causes the
* screen to scroll, when it is disallowed.
*/
int
__m_cc_add_k(WINDOW *w, int y, int x,
const cchar_t *cc, int as_is, int *yp, int *xp)
{
int width, code = ERR;
switch (cc->_wc[0]) {
case L'\n':
if (__m_cc_erase(w, y, x, y, w->_maxx-1) == -1)
goto error;
if (__m_do_scroll(w, y, x, &y, &x) == ERR)
goto error;
break;
default:
width = __m_cc_replace(w, y, x, cc, as_is);
x += width;
}
code = OK;
error:
*yp = y;
*xp = x;
return (code);
}
/*
* Append non-spacing characters to the a spacing character at (y, x).
* Return -1 on error, else 0.
*/
int
__m_cc_modify(WINDOW *w, int y, int x, const cchar_t *cc)
{
cchar_t *cp, tch;
int i, j, width;
x = __m_cc_first(w, y, x);
cp = &w->_line[y][x];
/* Is there enough room for the non-spacing characters. */
if (_M_CCHAR_MAX < cp->_n + cc->_n)
return (-1);
for (i = cp->_n, j = 0; j < cc->_n; ++i, ++j)
cp->_wc[i] = cc->_wc[j];
cp->_n = (short)i;
width = __m_cc_width(cp);
__m_touch_locs(w, y, x, x + width);
/* Assert that the modified spacing character is sorted. */
(void) __m_cc_sort(cp);
/* Dulicate in every column occupied by the spacing character. */
while (0 < --width) {
tch = *cp;
cp[1] = tch;
cp++;
}
return (0);
}
static void
__m_cc_erase_in_line(WINDOW *w, int y, int x, int lx, int bgWidth)
{
cchar_t *cp;
int i;
if (x < w->_first[y])
w->_first[y] = (short)x;
for (cp = w->_line[y], i = 0; x <= lx; ++x, ++i) {
cp[x] = w->_bg;
/*
* The start of each new character will be set true
* while internal columns of the character will be
* reset to false.
*/
cp[x]._f = (short)(i % bgWidth == 0);
}
if (w->_last[y] < x)
w->_last[y] = (short)x;
}
/* Window has a parent. Handle width chars overlapping with parent */
static void
__m_cc_erase_in_line_sub(WINDOW *w, int y, int x,
int lx, int bgWidth, int parentBGWidth)
{
cchar_t *cp;
int i;
int xi;
int wmin, wmax;
int wlx;
int parentY = w->_begy + y;
WINDOW *parent = w->_parent;
/* Switch to parent context and calculate limits */
xi = x = __m_cc_first(parent, parentY, w->_begx + x);
wlx = lx = __m_cc_next(parent, parentY, w->_begx + lx) - 1;
if (wlx >= w->_begx + w->_maxx) wlx = w->_begx + w->_maxx - 1;
for (cp = parent->_line[parentY]; x <= lx; ) {
if ((x < w->_begx) || (x >= (w->_begx + w->_maxx))) {
/* Outside target window */
for (i = 0; x <= lx && i <= parentBGWidth; x++, i++) {
cp[x] = parent->_bg;
cp[x]._f = (i == 0);
}
} else {
/* Inside target window */
for (i = 0; x <= wlx; x++, i++) {
cp[x] = w->_bg;
cp[x]._f = (short)(i % bgWidth == 0);
}
}
}
wmax = x - w->_begx; /* Defaults */
wmin = xi - w->_begx;
if ((xi < w->_begx) || (x >= w->_begx + w->_maxx)) {
/* Overlaps parent. Must touch parent and child */
int pmin, pmax;
pmax = w->_begx; /* Defaults */
pmin = w->_begx + w->_maxx;
if (xi < w->_begx) {
wmin = 0;
pmin = xi;
}
if (x >= w->_begx + w->_maxx) {
/* Ends right of target window */
wmax = w->_maxx;
pmax = x;
}
if (pmin < parent->_first[parentY])
parent->_first[parentY] = (short)pmin;
if (pmax > parent->_last[parentY])
parent->_last[parentY] = (short)pmax;
}
if (wmin < w->_first[y])
w->_first[y] = (short)wmin;
if (wmax > w->_last[y])
w->_last[y] = (short)wmax;
}
/*
* Erase region from (y,x) to (ly, lx) inclusive. The
* region is extended left and right in the case where
* the portions of a multicolumn characters are erased.
*
* Return -1 if the region is not an integral multiple
* of the background character, else zero for success.
*/
int
__m_cc_erase(WINDOW *w, int y, int x, int ly, int lx)
{
int bgWidth;
if (ly < y)
return (-1);
if (w->_maxy <= ly)
ly = w->_maxy - 1;
/*
* Is the region to blank out an integral width of the
* background character?
*/
bgWidth = __m_cc_width(&w->_bg);
if (bgWidth <= 0)
return (-1);
/*
* Erase Pattern will look like:
* EEEEEEE|
* EEEEEEEEEEEEEEE|
* EEEEEEEEEEE |
*/
if (w->_parent) {
/*
* Use slower alg. for subwindows.
* They might erase stuff in parent-context
*/
int parentBGWidth = __m_cc_width(&w->_parent->_bg);
for (; y < ly; ++y, x = 0) {
__m_cc_erase_in_line_sub(w, y, x, w->_maxx-1,
bgWidth, parentBGWidth);
}
__m_cc_erase_in_line_sub(w, y, x, lx, bgWidth, parentBGWidth);
} else {
/* Root windows - no need to work in parent context at all */
if (w->_maxx <= lx)
lx = w->_maxx - 1;
/*
* Erase from first whole character (inclusive) to next
* character (exclusive).
*/
x = __m_cc_first(w, y, x);
lx = __m_cc_next(w, ly, lx) - 1;
for (; y < ly; ++y, x = 0) {
__m_cc_erase_in_line(w, y, x, w->_maxx-1, bgWidth);
}
__m_cc_erase_in_line(w, y, x, lx, bgWidth);
}
return (0);
}
/*
* Expand the character to the left or right of the given position.
* Return the value returned by __m_cc_replace().
*/
int
__m_cc_expand(WINDOW *w, int y, int x, int side)
{
cchar_t cc;
int dx, width;
width = __m_cc_width(&w->_line[y][x]);
if (side < 0)
dx = __m_cc_next(w, y, x) - width;
else if (0 < side)
dx = __m_cc_first(w, y, x);
else
return (-1);
/*
* __m_cc_replace() will erase the region containing
* the character we want to expand.
*/
cc = w->_line[y][x];
return (__m_cc_replace(w, y, dx, &cc, 0));
}
/* Revised version of __m_cc_compare() to compare only the char parts */
int
__m_cc_equal(const cchar_t *c1, const cchar_t *c2)
{
int i;
if (c1->_f != c2->_f)
return (0);
if (c1->_n != c2->_n)
return (0);
for (i = 0; i < c1->_n; ++i)
if (c1->_wc[i] != c2->_wc[i])
return (0);
return (1);
}
/*
* Return true if characters are equal.
*
* NOTE to guarantee correct results, make sure that both
* characters have been passed through __m_cc_sort().
*/
int
__m_cc_compare(const cchar_t *c1, const cchar_t *c2, int exact)
{
int i;
if (exact && c1->_f != c2->_f)
return (0);
if (c1->_n != c2->_n)
return (0);
if ((c1->_at & ~WA_COOKIE) != (c2->_at & ~WA_COOKIE))
return (0);
if (c1->_co != c2->_co)
return (0);
for (i = 0; i < c1->_n; ++i)
if (c1->_wc[i] != c2->_wc[i])
return (0);
return (1);
}
/*
* Write to the stream the character portion of a cchar_t.
*/
int
__m_cc_write(const cchar_t *cc)
{
int j;
size_t i;
char mb[MB_LEN_MAX];
/*
* 4131273 UNIX98: xcurses library renders complex characters incorrectly
*/
int backed_up = 0;
for (i = 0; i < cc->_n; ++i) {
j = wctomb(mb, cc->_wc[i]);
if (j == -1)
return (EOF);
if (i == 1) {
/*
* Move cursor back where it was
*/
if (fwrite(cursor_left, 1, strlen(cursor_left),
__m_screen->_of) == 0) {
return (EOF);
}
backed_up = 1;
}
if (fwrite(mb, sizeof (*mb), (size_t)j, __m_screen->_of) == 0) {
return (EOF);
}
}
if (backed_up) {
/*
* Move cursor back where it was
*/
if (fwrite(cursor_right, 1, strlen(cursor_right),
__m_screen->_of) == 0) {
return (EOF);
}
}
__m_screen->_flags |= W_FLUSH;
return (0);
}