#if M_RCSID
#ifndef lint
static char rcsID[] = "$Header: /rd/src/libc/xcurses/rcs/m_cc.c 1.8 1995/09/20 15:26:52 ant Exp $";
#endif
#endif
#include <private.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <m_wio.h>
typedef struct {
int max;
int used;
char *mbs;
} t_string;
static int
write_string(byte, sp)
int byte;
t_string *sp;
{
if (sp->max <= sp->used)
return EOF;
sp->mbs[sp->used++] = byte;
return byte;
}
int
wistombs(mbs, wis, n)
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) {
last = string.used;
if (m_wio_put(*wis, &convert) < 0) {
string.used = last;
break;
}
if (*wis == '\0' || *wis == WEOF)
break;
}
string.mbs[string.used] = '\0';
return string.used;
}
int
wistowcs(wcs, wis, n)
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';
return (int) (wcs - start);
}
int
__m_chtype_cc(ch, cc)
chtype ch;
cchar_t *cc;
{
char mb;
cc->_f = 1;
cc->_n = 1;
mb = (char)(ch & A_CHARTEXT);
if (mbtowc(cc->_wc, &mb, 1) < 0)
return ERR;
cc->_co = (short) PAIR_NUMBER(ch);
cc->_at = (attr_t) ((ch & (A_ATTRIBUTES & ~A_COLOR)) >> 16);
return OK;
}
chtype
__m_cc_chtype(cc)
const cchar_t *cc;
{
chtype ch;
unsigned char mb[MB_LEN_MAX];
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;
}
int
__m_cc_mbs(cc, mbs, n)
const cchar_t *cc;
char *mbs;
int n;
{
cchar_t *cp;
int i, bytes, count, last;
mbstate_t initial = { 0 };
static t_string string = { 0 };
static t_wide_io convert = { 0 };
if (n < 0) {
return string.used;
} else if (0 < n) {
string.max = n;
string.used = 0;
string.mbs = mbs;
convert._state = initial;
convert._next = convert._size = 0;
convert.object = (void *) &string;
convert.put = (int (*)(int, void *)) write_string;
}
last = string.used;
if (cc == (cchar_t *) 0) {
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;
}
int
__m_tty_wc(index, wcp)
int index;
wchar_t *wcp;
{
char mb;
int code;
mb = cur_term->_shell.c_cc[index];
code = mbtowc(wcp, &mb, 1) < 0 ? ERR : OK;
return code;
}
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)
return -1;
if ((nbytes = mbtowc(&wc, mbs, UINT_MAX)) < 0)
return -1;
if (nbytes == 0)
break;
if (iscntrl(*mbs))
width = 1;
else if ((width = wcwidth(wc)) < 0)
return -1;
if (0 < width) {
if (have_one)
break;
have_one = 1;
}
cc->_wc[i] = wc;
}
cc->_f = 1;
cc->_n = i;
cc->_co = co;
cc->_at = at;
(void) __m_cc_sort(cc);
return (int) (mbs - start);
}
int
__m_wcs_cc(const wchar_t *wcs, attr_t at, short co, cchar_t *cc)
{
short i;
int width, have_one;
const wchar_t *start;
for (start = wcs, have_one = i = 0; *wcs != '\0'; ++wcs, ++i) {
if (sizeof cc->_wc <= i)
return -1;
if ((width = wcwidth(*wcs)) < 0)
return -1;
if (0 < width) {
if (have_one)
break;
have_one = 1;
}
cc->_wc[i] = *wcs;
}
cc->_f = 1;
cc->_n = i;
cc->_co = co;
cc->_at = at;
(void) __m_cc_sort(cc);
return (int) (wcs - start);
}
int
__m_wc_cc(wint_t wc, cchar_t *cc)
{
wchar_t wcs[2];
if (wc == WEOF)
return -1;
wcs[0] = (wchar_t)wc;
wcs[1] = '\0';
(void) __m_wcs_cc(wcs, WA_NORMAL, 0, cc);
return 0;
}
int
__m_cc_sort(cc)
cchar_t *cc;
{
wchar_t wc;
int width, i, j, spacing;
for (width = spacing = i = 0; i < cc->_n; ++i) {
j = wcwidth(cc->_wc[i]);
if (0 < j) {
if (0 < width)
return -1;
wc = cc->_wc[0];
cc->_wc[0] = cc->_wc[i];
cc->_wc[i] = wc;
spacing = 1;
width = j;
break;
}
}
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;
}
int
__m_cc_width(cc)
const cchar_t *cc;
{
return wcwidth(cc->_wc[0]);
}
int
__m_cc_first(w, y, x)
WINDOW *w;
int y, x;
{
register cchar_t *lp;
for (lp = w->_line[y]; 0 < x; --x) {
if (lp[x]._f)
break;
}
return x;
}
int
__m_cc_next(w, y, x)
WINDOW *w;
int y, x;
{
cchar_t *lp;
for (lp = w->_line[y]; ++x < w->_maxx; ) {
if (lp[x]._f)
break;
}
return x;
}
int
__m_cc_islast(w, y, x)
WINDOW *w;
int y, x;
{
int first, width;
first = __m_cc_first(w, y, x);
width = __m_cc_width(&w->_line[y][x]);
return first + width == x + 1;
}
int
__m_cc_replace(w, y, x, cc, as_is)
WINDOW *w;
int y, x;
const cchar_t *cc;
int as_is;
{
int i, width;
cchar_t *cp, *np;
width = __m_cc_width(cc);
if (0 < width && w->_maxx < x + width) {
(void) __m_cc_erase(w, y, x, y, w->_maxx-1);
return -1;
}
(void) __m_cc_erase(w, y, x, y, x + width - 1);
cp = &w->_line[y][x++];
if (cc->_wc[0] == ' ' || cc->_wc[0] == M_MB_L(' ')) {
*cp = w->_bg;
cp->_at |= cc->_at;
if (cc->_co != 0)
cp->_co = cc->_co;
} else {
(void) __m_wacs_cc(cc, cp);
if (cc->_co == 0)
cp->_co = w->_fg._co;
}
cp->_at |= w->_fg._at | w->_bg._at;
cp->_f = 1;
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)
{
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;
}
} else if (w->_maxy <= y) {
y = w->_maxy-1;
} else {
x = 0;
}
*yp = y;
*xp = x;
return OK;
}
int
__m_cc_add(w, y, x, cc, as_is, yp, xp)
WINDOW *w;
int y, x;
const cchar_t *cc;
int as_is, *yp, *xp;
{
int nx, width, code = ERR;
#ifdef M_CURSES_TRACE
__m_trace(
"__m_cc_add(%p, %d, %d, %p, %d, %p, %p)",
w, y, x, cc, as_is, yp, xp
);
#endif
switch (cc->_wc[0]) {
case '\t':
nx = x + (8 - (x & 07));
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 '\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 '\r':
x = 0;
break;
case '\b':
if (0 < x)
--x;
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 __m_return_code("__m_cc_add", code);
}
int
__m_cc_erase(w, y, x, ly, lx)
WINDOW *w;
int y, x, ly, lx;
{
cchar_t *cp;
int i, width;
if (ly < y)
return -1;
if (w->_maxy <= ly)
ly = w->_maxy - 1;
if (w->_maxx <= lx)
lx = w->_maxx - 1;
x = __m_cc_first(w, y, x);
lx = __m_cc_next(w, ly, lx) - 1;
width = __m_cc_width(&w->_bg);
if (y < ly && (lx + 1) % width != 0)
return -1;
if ((lx - x + 1) % width != 0)
return -1;
for (; y < ly; ++y, x = 0) {
if (x < w->_first[y])
w->_first[y] = (short) x;
for (cp = w->_line[y], i = 0; x < w->_maxx; ++x, ++i) {
cp[x] = w->_bg;
cp[x]._f = (short) (i % width == 0);
}
if (w->_last[y] < x)
w->_last[y] = (short) x;
}
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;
cp[x]._f = (short) (i % width == 0);
}
if (w->_last[y] < x)
w->_last[y] = (short) x;
return 0;
}
int
__m_cc_expand(w, y, x, side)
WINDOW *w;
int y, x, 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;
cc = w->_line[y][x];
return __m_cc_replace(w, y, dx, &cc, 0);
}
int
__m_cc_compare(c1, c2, exact)
const cchar_t *c1, *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;
}
int
__m_cc_write(cc)
const cchar_t *cc;
{
size_t i, j;
char mb[MB_LEN_MAX];
errno = 0;
for (i = 0; i < cc->_n; ++i) {
j = wcrtomb(mb, cc->_wc[i], &__m_screen->_state);
if (errno != 0)
return EOF;
if (fwrite(mb, sizeof *mb, j, __m_screen->_of) == 0)
return EOF;
}
return 0;
}