#include <curses.priv.h>
#include <ctype.h>
MODULE_ID("$Id: lib_addch.c,v 1.80 2004/02/07 18:20:46 tom Exp $")
#define COLOR_MASK(ch) (~(attr_t)((ch)&A_COLOR?A_COLOR:0))
static inline NCURSES_CH_T
render_char(WINDOW *win, NCURSES_CH_T ch)
{
attr_t a = win->_attrs;
if (ISBLANK(ch) && AttrOf(ch) == A_NORMAL) {
ch = win->_nc_bkgd;
SetAttr(ch, a | (AttrOf(win->_nc_bkgd) & COLOR_MASK(a)));
} else {
a |= AttrOf(win->_nc_bkgd) & COLOR_MASK(a);
AddAttr(ch, (a & COLOR_MASK(AttrOf(ch))));
}
TR(TRACE_VIRTPUT, ("render_char bkg %s, attrs %s -> ch %s",
_tracech_t2(1, CHREF(win->_nc_bkgd)),
_traceattr(win->_attrs),
_tracech_t2(3, CHREF(ch))));
return (ch);
}
NCURSES_EXPORT(NCURSES_CH_T)
_nc_render(WINDOW *win, NCURSES_CH_T ch)
{
return render_char(win, ch);
}
#ifndef NDEBUG
#define CHECK_POSITION(win, x, y) \
if (y > win->_maxy \
|| x > win->_maxx \
|| y < 0 \
|| x < 0) { \
TR(TRACE_VIRTPUT, ("Alert! Win=%p _curx = %d, _cury = %d " \
"(_maxx = %d, _maxy = %d)", win, x, y, \
win->_maxx, win->_maxy)); \
return(ERR); \
}
#else
#define CHECK_POSITION(win, x, y)
#endif
static
#if !USE_WIDEC_SUPPORT
inline
#endif
int
waddch_literal(WINDOW *win, NCURSES_CH_T ch)
{
int x;
int y;
struct ldat *line;
x = win->_curx;
y = win->_cury;
CHECK_POSITION(win, x, y);
#if 0
if (win->_flags & _WRAPPED) {
if (x >= win->_maxx)
return (ERR);
win->_flags &= ~_WRAPPED;
}
#endif
ch = render_char(win, ch);
line = win->_line + y;
CHANGED_CELL(line, x);
if_WIDEC({
if (WINDOW_EXT(win, addch_used) == 0 && Charable(ch)) {
WINDOW_EXT(win, addch_used) = 0;
} else {
char *buffer = WINDOW_EXT(win, addch_work);
int len;
mbstate_t state;
wchar_t result;
if ((WINDOW_EXT(win, addch_used) != 0) &&
(WINDOW_EXT(win, addch_x) != x ||
WINDOW_EXT(win, addch_y) != y)) {
WINDOW_EXT(win, addch_used) = 0;
}
WINDOW_EXT(win, addch_x) = x;
WINDOW_EXT(win, addch_y) = y;
memset(&state, 0, sizeof(state));
buffer[WINDOW_EXT(win, addch_used)] = CharOf(ch);
WINDOW_EXT(win, addch_used) += 1;
buffer[WINDOW_EXT(win, addch_used)] = '\0';
if ((len = mbrtowc(&result,
buffer,
WINDOW_EXT(win, addch_used), &state)) > 0) {
attr_t attrs = AttrOf(ch);
SetChar(ch, result, attrs);
WINDOW_EXT(win, addch_used) = 0;
if (CharOf(ch) < 256) {
const char *s = unctrl(CharOf(ch));
if (s[1] != 0) {
return waddstr(win, s);
}
}
} else {
if (len == -1) {
TR(TRACE_VIRTPUT, ("Alert! mbrtowc returns error"));
buffer[0] = CharOf(ch);
WINDOW_EXT(win, addch_used) = 1;
}
return OK;
}
}
});
if_WIDEC({
if (wcwidth(CharOf(ch)) == 0) {
int i;
if ((x > 0 && y >= 0)
|| ((y = win->_cury - 1) >= 0 &&
(x = win->_maxx) > 0)) {
wchar_t *chars = (win->_line[y].text[x - 1].chars);
for (i = 0; i < CCHARW_MAX; ++i) {
if (chars[i] == 0) {
chars[i] = CharOf(ch);
break;
}
}
}
goto testwrapping;
}
});
line->text[x++] = ch;
if_WIDEC({
int len = wcwidth(CharOf(ch));
while (len-- > 1) {
if (x + (len - 1) > win->_maxx) {
NCURSES_CH_T blank = NewChar2(BLANK_TEXT, BLANK_ATTR);
AddAttr(blank, AttrOf(ch));
if (waddch_literal(win, blank) != ERR)
return waddch_literal(win, ch);
return ERR;
}
AddAttr(line->text[x++], WA_NAC);
TR(TRACE_VIRTPUT, ("added NAC %d", x - 1));
}
}
testwrapping:
);
TR(TRACE_VIRTPUT, ("(%d, %d) = %s", win->_cury, x, _tracech_t(CHREF(ch))));
if (x > win->_maxx) {
win->_flags |= _WRAPPED;
if (++win->_cury > win->_regbottom) {
win->_cury = win->_regbottom;
win->_curx = win->_maxx;
if (!win->_scroll)
return (ERR);
scroll(win);
}
win->_curx = 0;
return (OK);
}
win->_curx = x;
return OK;
}
static inline int
waddch_nosync(WINDOW *win, const NCURSES_CH_T ch)
{
int x, y;
chtype t = CharOf(ch);
const char *s = 0;
if ((AttrOf(ch) & A_ALTCHARSET)
|| ((s = unctrl(t))[1] == 0 ||
(
isprint(t)
#if USE_WIDEC_SUPPORT
|| WINDOW_EXT(win, addch_used)
#endif
)))
return waddch_literal(win, ch);
x = win->_curx;
y = win->_cury;
switch (t) {
case '\t':
x += (TABSIZE - (x % TABSIZE));
if ((!win->_scroll && (y == win->_regbottom))
|| (x <= win->_maxx)) {
NCURSES_CH_T blank = NewChar2(BLANK_TEXT, BLANK_ATTR);
AddAttr(blank, AttrOf(ch));
while (win->_curx < x) {
if (waddch_literal(win, blank) == ERR)
return (ERR);
}
break;
} else {
wclrtoeol(win);
win->_flags |= _WRAPPED;
if (++y > win->_regbottom) {
x = win->_maxx;
y--;
if (win->_scroll) {
scroll(win);
x = 0;
}
} else {
x = 0;
}
}
break;
case '\n':
wclrtoeol(win);
if (++y > win->_regbottom) {
y--;
if (win->_scroll)
scroll(win);
else
return (ERR);
}
case '\r':
x = 0;
win->_flags &= ~_WRAPPED;
break;
case '\b':
if (x == 0)
return (OK);
x--;
win->_flags &= ~_WRAPPED;
break;
default:
while (*s) {
NCURSES_CH_T sch;
SetChar(sch, *s++, AttrOf(ch));
if (waddch_literal(win, sch) == ERR)
return ERR;
}
return (OK);
}
win->_curx = x;
win->_cury = y;
return (OK);
}
NCURSES_EXPORT(int)
_nc_waddch_nosync(WINDOW *win, const NCURSES_CH_T c)
{
return (waddch_nosync(win, c));
}
NCURSES_EXPORT(int)
waddch(WINDOW *win, const chtype ch)
{
int code = ERR;
NCURSES_CH_T wch;
SetChar2(wch, ch);
TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_CALLED("waddch(%p, %s)"), win,
_tracechtype(ch)));
if (win && (waddch_nosync(win, wch) != ERR)) {
_nc_synchook(win);
code = OK;
}
TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_RETURN("%d"), code));
return (code);
}
NCURSES_EXPORT(int)
wechochar(WINDOW *win, const chtype ch)
{
int code = ERR;
NCURSES_CH_T wch;
SetChar2(wch, ch);
TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_CALLED("wechochar(%p, %s)"), win,
_tracechtype(ch)));
if (win && (waddch_nosync(win, wch) != ERR)) {
bool save_immed = win->_immed;
win->_immed = TRUE;
_nc_synchook(win);
win->_immed = save_immed;
code = OK;
}
TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_RETURN("%d"), code));
return (code);
}