150276Speter/****************************************************************************
2176187Srafan * Copyright (c) 1998-2006,2008 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/*
3050276Speter**	lib_addch.c
3150276Speter**
3250276Speter**	The routine waddch().
3350276Speter**
3450276Speter*/
3550276Speter
3650276Speter#include <curses.priv.h>
3750276Speter#include <ctype.h>
3850276Speter
39184989SrafanMODULE_ID("$Id: lib_addch.c,v 1.113 2008/08/16 19:20:04 tom Exp $")
4050276Speter
41166124Srafanstatic const NCURSES_CH_T blankchar = NewChar(BLANK_TEXT);
42166124Srafan
4350276Speter/*
4450276Speter * Ugly microtweaking alert.  Everything from here to end of module is
4550276Speter * likely to be speed-critical -- profiling data sure says it is!
4650276Speter * Most of the important screen-painting functions are shells around
4750276Speter * waddch().  So we make every effort to reduce function-call overhead
4850276Speter * by inlining stuff, even at the cost of making wrapped copies for
4950276Speter * export.  Also we supply some internal versions that don't call the
5050276Speter * window sync hook, for use by string-put functions.
5150276Speter */
5250276Speter
5350276Speter/* Return bit mask for clearing color pair number if given ch has color */
54166124Srafan#define COLOR_MASK(ch) (~(attr_t)((ch) & A_COLOR ? A_COLOR : 0))
5550276Speter
56166124Srafanstatic NCURSES_INLINE NCURSES_CH_T
5797049Speterrender_char(WINDOW *win, NCURSES_CH_T ch)
5850276Speter/* compute a rendition of the given char correct for the current context */
5950276Speter{
60166124Srafan    attr_t a = WINDOW_ATTRS(win);
61166124Srafan    int pair = GetPair(ch);
6250276Speter
63166124Srafan    if (ISBLANK(ch)
64166124Srafan	&& AttrOf(ch) == A_NORMAL
65166124Srafan	&& pair == 0) {
66166124Srafan	/* color/pair in attrs has precedence over bkgrnd */
6797049Speter	ch = win->_nc_bkgd;
68166124Srafan	SetAttr(ch, a | AttrOf(win->_nc_bkgd));
69166124Srafan	if ((pair = GET_WINDOW_PAIR(win)) == 0)
70166124Srafan	    pair = GetPair(win->_nc_bkgd);
71166124Srafan	SetPair(ch, pair);
7262449Speter    } else {
7397049Speter	/* color in attrs has precedence over bkgrnd */
74166124Srafan	a |= AttrOf(win->_nc_bkgd) & COLOR_MASK(a);
7562449Speter	/* color in ch has precedence */
76166124Srafan	if (pair == 0) {
77166124Srafan	    if ((pair = GET_WINDOW_PAIR(win)) == 0)
78166124Srafan		pair = GetPair(win->_nc_bkgd);
79166124Srafan	}
80166124Srafan#if 0
81166124Srafan	if (pair > 255) {
82166124Srafan	    NCURSES_CH_T fixme = ch;
83166124Srafan	    SetPair(fixme, pair);
84166124Srafan	}
85166124Srafan#endif
8697049Speter	AddAttr(ch, (a & COLOR_MASK(AttrOf(ch))));
87166124Srafan	SetPair(ch, pair);
8862449Speter    }
8950276Speter
90166124Srafan    TR(TRACE_VIRTPUT,
91166124Srafan       ("render_char bkg %s (%d), attrs %s (%d) -> ch %s (%d)",
92166124Srafan	_tracech_t2(1, CHREF(win->_nc_bkgd)),
93166124Srafan	GetPair(win->_nc_bkgd),
94166124Srafan	_traceattr(WINDOW_ATTRS(win)),
95166124Srafan	GET_WINDOW_PAIR(win),
96166124Srafan	_tracech_t2(3, CHREF(ch)),
97166124Srafan	GetPair(ch)));
9862449Speter
9962449Speter    return (ch);
10050276Speter}
10150276Speter
10297049SpeterNCURSES_EXPORT(NCURSES_CH_T)
10397049Speter_nc_render(WINDOW *win, NCURSES_CH_T ch)
10450276Speter/* make render_char() visible while still allowing us to inline it below */
10550276Speter{
10662449Speter    return render_char(win, ch);
10750276Speter}
10850276Speter
10950276Speter/* check if position is legal; if not, return error */
11050276Speter#ifndef NDEBUG			/* treat this like an assertion */
11150276Speter#define CHECK_POSITION(win, x, y) \
11250276Speter	if (y > win->_maxy \
11350276Speter	 || x > win->_maxx \
11450276Speter	 || y < 0 \
11550276Speter	 || x < 0) { \
11650276Speter		TR(TRACE_VIRTPUT, ("Alert! Win=%p _curx = %d, _cury = %d " \
11750276Speter				   "(_maxx = %d, _maxy = %d)", win, x, y, \
11850276Speter				   win->_maxx, win->_maxy)); \
11950276Speter		return(ERR); \
12050276Speter	}
12150276Speter#else
12262449Speter#define CHECK_POSITION(win, x, y)	/* nothing */
12350276Speter#endif
12450276Speter
125166124Srafanstatic bool
126166124Srafannewline_forces_scroll(WINDOW *win, NCURSES_SIZE_T * ypos)
127166124Srafan{
128166124Srafan    bool result = FALSE;
129166124Srafan
130166124Srafan    if (*ypos >= win->_regtop && *ypos == win->_regbottom) {
131166124Srafan	*ypos = win->_regbottom;
132166124Srafan	result = TRUE;
133166124Srafan    } else {
134166124Srafan	*ypos += 1;
135166124Srafan    }
136166124Srafan    return result;
137166124Srafan}
138166124Srafan
139166124Srafan/*
140166124Srafan * The _WRAPPED flag is useful only for telling an application that we've just
141166124Srafan * wrapped the cursor.  We don't do anything with this flag except set it when
142166124Srafan * wrapping, and clear it whenever we move the cursor.  If we try to wrap at
143166124Srafan * the lower-right corner of a window, we cannot move the cursor (since that
144166124Srafan * wouldn't be legal).  So we return an error (which is what SVr4 does).
145166124Srafan * Unlike SVr4, we can successfully add a character to the lower-right corner
146166124Srafan * (Solaris 2.6 does this also, however).
147166124Srafan */
148166124Srafanstatic int
149166124Srafanwrap_to_next_line(WINDOW *win)
150166124Srafan{
151166124Srafan    win->_flags |= _WRAPPED;
152166124Srafan    if (newline_forces_scroll(win, &(win->_cury))) {
153166124Srafan	win->_curx = win->_maxx;
154166124Srafan	if (!win->_scroll)
155166124Srafan	    return (ERR);
156166124Srafan	scroll(win);
157166124Srafan    }
158166124Srafan    win->_curx = 0;
159166124Srafan    return (OK);
160166124Srafan}
161166124Srafan
162166124Srafan#if USE_WIDEC_SUPPORT
163166124Srafanstatic int waddch_literal(WINDOW *, NCURSES_CH_T);
164166124Srafan/*
165166124Srafan * Fill the given number of cells with blanks using the current background
166166124Srafan * rendition.  This saves/restores the current x-position.
167166124Srafan */
168166124Srafanstatic void
169166124Srafanfill_cells(WINDOW *win, int count)
170166124Srafan{
171166124Srafan    NCURSES_CH_T blank = blankchar;
172166124Srafan    int save_x = win->_curx;
173166124Srafan    int save_y = win->_cury;
174166124Srafan
175166124Srafan    while (count-- > 0) {
176166124Srafan	if (waddch_literal(win, blank) == ERR)
177166124Srafan	    break;
178166124Srafan    }
179166124Srafan    win->_curx = save_x;
180166124Srafan    win->_cury = save_y;
181166124Srafan}
182166124Srafan#endif
183166124Srafan
184166124Srafan/*
185166124Srafan * Build up the bytes for a multibyte character, returning the length when
186166124Srafan * complete (a positive number), -1 for error and -2 for incomplete.
187166124Srafan */
188166124Srafan#if USE_WIDEC_SUPPORT
189166124SrafanNCURSES_EXPORT(int)
190166124Srafan_nc_build_wch(WINDOW *win, ARG_CH_T ch)
191166124Srafan{
192166124Srafan    char *buffer = WINDOW_EXT(win, addch_work);
193166124Srafan    int len;
194166124Srafan    int x = win->_curx;
195166124Srafan    int y = win->_cury;
196166124Srafan    mbstate_t state;
197166124Srafan    wchar_t result;
198166124Srafan
199166124Srafan    if ((WINDOW_EXT(win, addch_used) != 0) &&
200166124Srafan	(WINDOW_EXT(win, addch_x) != x ||
201166124Srafan	 WINDOW_EXT(win, addch_y) != y)) {
202166124Srafan	/* discard the incomplete multibyte character */
203166124Srafan	WINDOW_EXT(win, addch_used) = 0;
204166124Srafan	TR(TRACE_VIRTPUT,
205166124Srafan	   ("Alert discarded multibyte on move (%d,%d) -> (%d,%d)",
206166124Srafan	    WINDOW_EXT(win, addch_y), WINDOW_EXT(win, addch_x),
207166124Srafan	    y, x));
208166124Srafan    }
209166124Srafan    WINDOW_EXT(win, addch_x) = x;
210166124Srafan    WINDOW_EXT(win, addch_y) = y;
211166124Srafan
212166124Srafan    init_mb(state);
213184989Srafan    buffer[WINDOW_EXT(win, addch_used)] = (char) CharOf(CHDEREF(ch));
214166124Srafan    WINDOW_EXT(win, addch_used) += 1;
215166124Srafan    buffer[WINDOW_EXT(win, addch_used)] = '\0';
216166124Srafan    if ((len = mbrtowc(&result,
217166124Srafan		       buffer,
218166124Srafan		       WINDOW_EXT(win, addch_used), &state)) > 0) {
219166124Srafan	attr_t attrs = AttrOf(CHDEREF(ch));
220178866Srafan	if_EXT_COLORS(int pair = GetPair(CHDEREF(ch)));
221166124Srafan	SetChar(CHDEREF(ch), result, attrs);
222178866Srafan	if_EXT_COLORS(SetPair(CHDEREF(ch), pair));
223166124Srafan	WINDOW_EXT(win, addch_used) = 0;
224176187Srafan    } else if (len == -1) {
225176187Srafan	/*
226176187Srafan	 * An error occurred.  We could either discard everything,
227176187Srafan	 * or assume that the error was in the previous input.
228176187Srafan	 * Try the latter.
229176187Srafan	 */
230176187Srafan	TR(TRACE_VIRTPUT, ("Alert! mbrtowc returns error"));
231176187Srafan	/* handle this with unctrl() */
232176187Srafan	WINDOW_EXT(win, addch_used) = 0;
233166124Srafan    }
234166124Srafan    return len;
235166124Srafan}
236166124Srafan#endif /* USE_WIDEC_SUPPORT */
237166124Srafan
238166124Srafanstatic
239166124Srafan#if !USE_WIDEC_SUPPORT		/* cannot be inline if it is recursive */
240166124SrafanNCURSES_INLINE
241166124Srafan#endif
242166124Srafanint
24397049Speterwaddch_literal(WINDOW *win, NCURSES_CH_T ch)
24450276Speter{
24562449Speter    int x;
246166124Srafan    int y;
24762449Speter    struct ldat *line;
24850276Speter
24962449Speter    x = win->_curx;
250166124Srafan    y = win->_cury;
25150276Speter
252166124Srafan    CHECK_POSITION(win, x, y);
25350276Speter
25462449Speter    ch = render_char(win, ch);
25550276Speter
256166124Srafan    line = win->_line + y;
25750276Speter
25862449Speter    CHANGED_CELL(line, x);
25962449Speter
260166124Srafan    /*
261166124Srafan     * Build up multibyte characters until we have a wide-character.
262166124Srafan     */
26397049Speter    if_WIDEC({
264166124Srafan	if (WINDOW_EXT(win, addch_used) != 0 || !Charable(ch)) {
265166124Srafan	    int len = _nc_build_wch(win, CHREF(ch));
266166124Srafan
267176187Srafan	    if (len >= -1) {
268176187Srafan		/* handle EILSEQ */
269166124Srafan		if (is8bits(CharOf(ch))) {
270166124Srafan		    const char *s = unctrl((chtype) CharOf(ch));
271166124Srafan		    if (s[1] != 0) {
272166124Srafan			return waddstr(win, s);
273166124Srafan		    }
274166124Srafan		}
275176187Srafan		if (len == -1)
276176187Srafan		    return waddch(win, ' ');
277166124Srafan	    } else {
278166124Srafan		return OK;
279166124Srafan	    }
280166124Srafan	}
28197049Speter    });
28262449Speter
283166124Srafan    /*
284166124Srafan     * Non-spacing characters are added to the current cell.
285166124Srafan     *
286166124Srafan     * Spacing characters that are wider than one column require some display
287166124Srafan     * adjustments.
288166124Srafan     */
289166124Srafan    if_WIDEC({
290166124Srafan	int len = wcwidth(CharOf(ch));
291166124Srafan	int i;
292166124Srafan	int j;
293184989Srafan	wchar_t *chars;
294166124Srafan
295166124Srafan	if (len == 0) {		/* non-spacing */
296166124Srafan	    if ((x > 0 && y >= 0)
297184989Srafan		|| (win->_maxx >= 0 && win->_cury >= 1)) {
298184989Srafan		if (x > 0 && y >= 0)
299184989Srafan		    chars = (win->_line[y].text[x - 1].chars);
300184989Srafan		else
301184989Srafan		    chars = (win->_line[y - 1].text[win->_maxx].chars);
302166124Srafan		for (i = 0; i < CCHARW_MAX; ++i) {
303166124Srafan		    if (chars[i] == 0) {
304166124Srafan			TR(TRACE_VIRTPUT,
305166124Srafan			   ("added non-spacing %d: %x",
306166124Srafan			    x, (int) CharOf(ch)));
307166124Srafan			chars[i] = CharOf(ch);
308166124Srafan			break;
309166124Srafan		    }
310166124Srafan		}
311166124Srafan	    }
312166124Srafan	    goto testwrapping;
313166124Srafan	} else if (len > 1) {	/* multi-column characters */
314166124Srafan	    /*
315166124Srafan	     * Check if the character will fit on the current line.  If it does
316166124Srafan	     * not fit, fill in the remainder of the line with blanks.  and
317166124Srafan	     * move to the next line.
318166124Srafan	     */
319166124Srafan	    if (len > win->_maxx + 1) {
320166124Srafan		TR(TRACE_VIRTPUT, ("character will not fit"));
321166124Srafan		return ERR;
322166124Srafan	    } else if (x + len > win->_maxx + 1) {
323166124Srafan		int count = win->_maxx + 1 - x;
324166124Srafan		TR(TRACE_VIRTPUT, ("fill %d remaining cells", count));
325166124Srafan		fill_cells(win, count);
326166124Srafan		if (wrap_to_next_line(win) == ERR)
327166124Srafan		    return ERR;
328166124Srafan		x = win->_curx;
329166124Srafan		y = win->_cury;
330166124Srafan	    }
331166124Srafan	    /*
332166124Srafan	     * Check for cells which are orphaned by adding this character, set
333166124Srafan	     * those to blanks.
334166124Srafan	     *
335166124Srafan	     * FIXME: this actually could fill j-i cells, more complicated to
336166124Srafan	     * setup though.
337166124Srafan	     */
338166124Srafan	    for (i = 0; i < len; ++i) {
339166124Srafan		if (isWidecBase(win->_line[y].text[x + i])) {
340166124Srafan		    break;
341166124Srafan		} else if (isWidecExt(win->_line[y].text[x + i])) {
342166124Srafan		    for (j = i; x + j <= win->_maxx; ++j) {
343166124Srafan			if (!isWidecExt(win->_line[y].text[x + j])) {
344166124Srafan			    TR(TRACE_VIRTPUT, ("fill %d orphan cells", j));
345166124Srafan			    fill_cells(win, j);
346166124Srafan			    break;
347166124Srafan			}
348166124Srafan		    }
349166124Srafan		    break;
350166124Srafan		}
351166124Srafan	    }
352166124Srafan	    /*
353166124Srafan	     * Finally, add the cells for this character.
354166124Srafan	     */
355166124Srafan	    for (i = 0; i < len; ++i) {
356166124Srafan		NCURSES_CH_T value = ch;
357166124Srafan		SetWidecExt(value, i);
358166124Srafan		TR(TRACE_VIRTPUT, ("multicolumn %d:%d (%d,%d)",
359166124Srafan				   i + 1, len,
360166124Srafan				   win->_begy + y, win->_begx + x));
361166124Srafan		line->text[x] = value;
362166124Srafan		CHANGED_CELL(line, x);
363166124Srafan		++x;
364166124Srafan	    }
365166124Srafan	    goto testwrapping;
366166124Srafan	}
367166124Srafan    });
368166124Srafan
369166124Srafan    /*
370166124Srafan     * Single-column characters.
371166124Srafan     */
372166124Srafan    line->text[x++] = ch;
373166124Srafan    /*
374166124Srafan     * This label is used only for wide-characters.
375166124Srafan     */
376166124Srafan    if_WIDEC(
377166124Srafan  testwrapping:
378166124Srafan    );
379166124Srafan
380166124Srafan    TR(TRACE_VIRTPUT, ("cell (%ld, %ld..%d) = %s",
381166124Srafan		       (long) win->_cury, (long) win->_curx, x - 1,
382166124Srafan		       _tracech_t(CHREF(ch))));
383166124Srafan
38462449Speter    if (x > win->_maxx) {
385166124Srafan	return wrap_to_next_line(win);
38662449Speter    }
38762449Speter    win->_curx = x;
38862449Speter    return OK;
38950276Speter}
39050276Speter
391166124Srafanstatic NCURSES_INLINE int
39297049Speterwaddch_nosync(WINDOW *win, const NCURSES_CH_T ch)
39350276Speter/* the workhorse function -- add a character to the given window */
39450276Speter{
395166124Srafan    NCURSES_SIZE_T x, y;
396166124Srafan    chtype t = CharOf(ch);
397166124Srafan    const char *s = unctrl(t);
39850276Speter
399166124Srafan    /*
400166124Srafan     * If we are using the alternate character set, forget about locale.
401166124Srafan     * Otherwise, if unctrl() returns a single-character or the locale
402166124Srafan     * claims the code is printable, treat it that way.
403166124Srafan     */
40497049Speter    if ((AttrOf(ch) & A_ALTCHARSET)
405166124Srafan	|| (
406166124Srafan#if USE_WIDEC_SUPPORT
407166124Srafan	       (SP != 0 && SP->_legacy_coding) &&
408166124Srafan#endif
409166124Srafan	       s[1] == 0
410166124Srafan	)
411166124Srafan	|| (
412166124Srafan	       isprint(t)
413166124Srafan#if USE_WIDEC_SUPPORT
414166124Srafan	       || ((SP == 0 || !SP->_legacy_coding) &&
415166124Srafan		   (WINDOW_EXT(win, addch_used)
416166124Srafan		    || !_nc_is_charable(CharOf(ch))))
417166124Srafan#endif
418166124Srafan	))
41962449Speter	return waddch_literal(win, ch);
42050276Speter
421166124Srafan    /*
422166124Srafan     * Handle carriage control and other codes that are not printable, or are
423166124Srafan     * known to expand to more than one character according to unctrl().
424166124Srafan     */
42562449Speter    x = win->_curx;
42662449Speter    y = win->_cury;
42750276Speter
42862449Speter    switch (t) {
42962449Speter    case '\t':
43062449Speter	x += (TABSIZE - (x % TABSIZE));
43150276Speter
43262449Speter	/*
43362449Speter	 * Space-fill the tab on the bottom line so that we'll get the
43462449Speter	 * "correct" cursor position.
43562449Speter	 */
43662449Speter	if ((!win->_scroll && (y == win->_regbottom))
43762449Speter	    || (x <= win->_maxx)) {
438166124Srafan	    NCURSES_CH_T blank = blankchar;
43997049Speter	    AddAttr(blank, AttrOf(ch));
44062449Speter	    while (win->_curx < x) {
44162449Speter		if (waddch_literal(win, blank) == ERR)
44262449Speter		    return (ERR);
44362449Speter	    }
44462449Speter	    break;
44562449Speter	} else {
44662449Speter	    wclrtoeol(win);
44762449Speter	    win->_flags |= _WRAPPED;
448166124Srafan	    if (newline_forces_scroll(win, &y)) {
44962449Speter		x = win->_maxx;
45062449Speter		if (win->_scroll) {
45162449Speter		    scroll(win);
45262449Speter		    x = 0;
45350276Speter		}
45462449Speter	    } else {
45550276Speter		x = 0;
45662449Speter	    }
45750276Speter	}
45862449Speter	break;
45962449Speter    case '\n':
46062449Speter	wclrtoeol(win);
461166124Srafan	if (newline_forces_scroll(win, &y)) {
46262449Speter	    if (win->_scroll)
46362449Speter		scroll(win);
46462449Speter	    else
46562449Speter		return (ERR);
46662449Speter	}
46762449Speter	/* FALLTHRU */
46862449Speter    case '\r':
46962449Speter	x = 0;
47062449Speter	win->_flags &= ~_WRAPPED;
47162449Speter	break;
47262449Speter    case '\b':
47362449Speter	if (x == 0)
47462449Speter	    return (OK);
47562449Speter	x--;
47662449Speter	win->_flags &= ~_WRAPPED;
47762449Speter	break;
47862449Speter    default:
47997049Speter	while (*s) {
48097049Speter	    NCURSES_CH_T sch;
48197049Speter	    SetChar(sch, *s++, AttrOf(ch));
482178866Srafan	    if_EXT_COLORS(SetPair(sch, GetPair(ch)));
48397049Speter	    if (waddch_literal(win, sch) == ERR)
48462449Speter		return ERR;
48597049Speter	}
48662449Speter	return (OK);
48762449Speter    }
48850276Speter
48962449Speter    win->_curx = x;
49062449Speter    win->_cury = y;
49150276Speter
49262449Speter    return (OK);
49350276Speter}
49450276Speter
49576726SpeterNCURSES_EXPORT(int)
49697049Speter_nc_waddch_nosync(WINDOW *win, const NCURSES_CH_T c)
49750276Speter/* export copy of waddch_nosync() so the string-put functions can use it */
49850276Speter{
49962449Speter    return (waddch_nosync(win, c));
50050276Speter}
50150276Speter
50250276Speter/*
503166124Srafan * The versions below call _nc_synchook().  We wanted to avoid this in the
50450276Speter * version exported for string puts; they'll call _nc_synchook once at end
50550276Speter * of run.
50650276Speter */
50750276Speter
50850276Speter/* These are actual entry points */
50950276Speter
51076726SpeterNCURSES_EXPORT(int)
51197049Speterwaddch(WINDOW *win, const chtype ch)
51250276Speter{
51362449Speter    int code = ERR;
51497049Speter    NCURSES_CH_T wch;
51597049Speter    SetChar2(wch, ch);
51650276Speter
51762449Speter    TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_CALLED("waddch(%p, %s)"), win,
51876726Speter				      _tracechtype(ch)));
51950276Speter
52097049Speter    if (win && (waddch_nosync(win, wch) != ERR)) {
52162449Speter	_nc_synchook(win);
52262449Speter	code = OK;
52362449Speter    }
52450276Speter
52562449Speter    TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_RETURN("%d"), code));
52662449Speter    return (code);
52750276Speter}
52850276Speter
52976726SpeterNCURSES_EXPORT(int)
53097049Speterwechochar(WINDOW *win, const chtype ch)
53150276Speter{
53262449Speter    int code = ERR;
53397049Speter    NCURSES_CH_T wch;
53497049Speter    SetChar2(wch, ch);
53550276Speter
53662449Speter    TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_CALLED("wechochar(%p, %s)"), win,
53776726Speter				      _tracechtype(ch)));
53850276Speter
53997049Speter    if (win && (waddch_nosync(win, wch) != ERR)) {
54062449Speter	bool save_immed = win->_immed;
54162449Speter	win->_immed = TRUE;
54262449Speter	_nc_synchook(win);
54362449Speter	win->_immed = save_immed;
54462449Speter	code = OK;
54562449Speter    }
54662449Speter    TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_RETURN("%d"), code));
54762449Speter    return (code);
54850276Speter}
549