Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 1 | /**************************************************************************** |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 2 | * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc. * |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 3 | * * |
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a * |
| 5 | * copy of this software and associated documentation files (the * |
| 6 | * "Software"), to deal in the Software without restriction, including * |
| 7 | * without limitation the rights to use, copy, modify, merge, publish, * |
| 8 | * distribute, distribute with modifications, sublicense, and/or sell * |
| 9 | * copies of the Software, and to permit persons to whom the Software is * |
| 10 | * furnished to do so, subject to the following conditions: * |
| 11 | * * |
| 12 | * The above copyright notice and this permission notice shall be included * |
| 13 | * in all copies or substantial portions of the Software. * |
| 14 | * * |
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * |
| 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * |
| 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * |
| 18 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * |
| 19 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * |
| 20 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * |
| 21 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * |
| 22 | * * |
| 23 | * Except as contained in this notice, the name(s) of the above copyright * |
| 24 | * holders shall not be used in advertising or otherwise to promote the * |
| 25 | * sale, use or other dealings in this Software without prior written * |
| 26 | * authorization. * |
| 27 | ****************************************************************************/ |
| 28 | |
| 29 | /* |
| 30 | ** lib_addch.c |
| 31 | ** |
| 32 | ** The routine waddch(). |
| 33 | ** |
| 34 | */ |
| 35 | |
| 36 | #include <curses.priv.h> |
| 37 | #include <ctype.h> |
| 38 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 39 | MODULE_ID("$Id: lib_addch.c,v 1.129 2014/08/16 20:41:04 tom Exp $") |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 40 | |
| 41 | static const NCURSES_CH_T blankchar = NewChar(BLANK_TEXT); |
| 42 | |
| 43 | /* |
| 44 | * Ugly microtweaking alert. Everything from here to end of module is |
| 45 | * likely to be speed-critical -- profiling data sure says it is! |
| 46 | * Most of the important screen-painting functions are shells around |
| 47 | * waddch(). So we make every effort to reduce function-call overhead |
| 48 | * by inlining stuff, even at the cost of making wrapped copies for |
| 49 | * export. Also we supply some internal versions that don't call the |
| 50 | * window sync hook, for use by string-put functions. |
| 51 | */ |
| 52 | |
| 53 | /* Return bit mask for clearing color pair number if given ch has color */ |
| 54 | #define COLOR_MASK(ch) (~(attr_t)((ch) & A_COLOR ? A_COLOR : 0)) |
| 55 | |
| 56 | static NCURSES_INLINE NCURSES_CH_T |
| 57 | render_char(WINDOW *win, NCURSES_CH_T ch) |
| 58 | /* compute a rendition of the given char correct for the current context */ |
| 59 | { |
| 60 | attr_t a = WINDOW_ATTRS(win); |
| 61 | int pair = GetPair(ch); |
| 62 | |
| 63 | if (ISBLANK(ch) |
| 64 | && AttrOf(ch) == A_NORMAL |
| 65 | && pair == 0) { |
| 66 | /* color/pair in attrs has precedence over bkgrnd */ |
| 67 | ch = win->_nc_bkgd; |
| 68 | SetAttr(ch, a | AttrOf(win->_nc_bkgd)); |
| 69 | if ((pair = GET_WINDOW_PAIR(win)) == 0) |
| 70 | pair = GetPair(win->_nc_bkgd); |
| 71 | SetPair(ch, pair); |
| 72 | } else { |
| 73 | /* color in attrs has precedence over bkgrnd */ |
| 74 | a |= AttrOf(win->_nc_bkgd) & COLOR_MASK(a); |
| 75 | /* color in ch has precedence */ |
| 76 | if (pair == 0) { |
| 77 | if ((pair = GET_WINDOW_PAIR(win)) == 0) |
| 78 | pair = GetPair(win->_nc_bkgd); |
| 79 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 80 | AddAttr(ch, (a & COLOR_MASK(AttrOf(ch)))); |
| 81 | SetPair(ch, pair); |
| 82 | } |
| 83 | |
| 84 | TR(TRACE_VIRTPUT, |
| 85 | ("render_char bkg %s (%d), attrs %s (%d) -> ch %s (%d)", |
| 86 | _tracech_t2(1, CHREF(win->_nc_bkgd)), |
| 87 | GetPair(win->_nc_bkgd), |
| 88 | _traceattr(WINDOW_ATTRS(win)), |
| 89 | GET_WINDOW_PAIR(win), |
| 90 | _tracech_t2(3, CHREF(ch)), |
| 91 | GetPair(ch))); |
| 92 | |
| 93 | return (ch); |
| 94 | } |
| 95 | |
| 96 | NCURSES_EXPORT(NCURSES_CH_T) |
| 97 | _nc_render(WINDOW *win, NCURSES_CH_T ch) |
| 98 | /* make render_char() visible while still allowing us to inline it below */ |
| 99 | { |
| 100 | return render_char(win, ch); |
| 101 | } |
| 102 | |
| 103 | /* check if position is legal; if not, return error */ |
| 104 | #ifndef NDEBUG /* treat this like an assertion */ |
| 105 | #define CHECK_POSITION(win, x, y) \ |
| 106 | if (y > win->_maxy \ |
| 107 | || x > win->_maxx \ |
| 108 | || y < 0 \ |
| 109 | || x < 0) { \ |
| 110 | TR(TRACE_VIRTPUT, ("Alert! Win=%p _curx = %d, _cury = %d " \ |
| 111 | "(_maxx = %d, _maxy = %d)", win, x, y, \ |
| 112 | win->_maxx, win->_maxy)); \ |
| 113 | return(ERR); \ |
| 114 | } |
| 115 | #else |
| 116 | #define CHECK_POSITION(win, x, y) /* nothing */ |
| 117 | #endif |
| 118 | |
| 119 | static bool |
| 120 | newline_forces_scroll(WINDOW *win, NCURSES_SIZE_T * ypos) |
| 121 | { |
| 122 | bool result = FALSE; |
| 123 | |
| 124 | if (*ypos >= win->_regtop && *ypos == win->_regbottom) { |
| 125 | *ypos = win->_regbottom; |
| 126 | result = TRUE; |
| 127 | } else { |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 128 | *ypos = (NCURSES_SIZE_T) (*ypos + 1); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 129 | } |
| 130 | return result; |
| 131 | } |
| 132 | |
| 133 | /* |
| 134 | * The _WRAPPED flag is useful only for telling an application that we've just |
| 135 | * wrapped the cursor. We don't do anything with this flag except set it when |
| 136 | * wrapping, and clear it whenever we move the cursor. If we try to wrap at |
| 137 | * the lower-right corner of a window, we cannot move the cursor (since that |
| 138 | * wouldn't be legal). So we return an error (which is what SVr4 does). |
| 139 | * Unlike SVr4, we can successfully add a character to the lower-right corner |
| 140 | * (Solaris 2.6 does this also, however). |
| 141 | */ |
| 142 | static int |
| 143 | wrap_to_next_line(WINDOW *win) |
| 144 | { |
| 145 | win->_flags |= _WRAPPED; |
| 146 | if (newline_forces_scroll(win, &(win->_cury))) { |
| 147 | win->_curx = win->_maxx; |
| 148 | if (!win->_scroll) |
| 149 | return (ERR); |
| 150 | scroll(win); |
| 151 | } |
| 152 | win->_curx = 0; |
| 153 | return (OK); |
| 154 | } |
| 155 | |
| 156 | #if USE_WIDEC_SUPPORT |
| 157 | static int waddch_literal(WINDOW *, NCURSES_CH_T); |
| 158 | /* |
| 159 | * Fill the given number of cells with blanks using the current background |
| 160 | * rendition. This saves/restores the current x-position. |
| 161 | */ |
| 162 | static void |
| 163 | fill_cells(WINDOW *win, int count) |
| 164 | { |
| 165 | NCURSES_CH_T blank = blankchar; |
| 166 | int save_x = win->_curx; |
| 167 | int save_y = win->_cury; |
| 168 | |
| 169 | while (count-- > 0) { |
| 170 | if (waddch_literal(win, blank) == ERR) |
| 171 | break; |
| 172 | } |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 173 | win->_curx = (NCURSES_SIZE_T) save_x; |
| 174 | win->_cury = (NCURSES_SIZE_T) save_y; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 175 | } |
| 176 | #endif |
| 177 | |
| 178 | /* |
| 179 | * Build up the bytes for a multibyte character, returning the length when |
| 180 | * complete (a positive number), -1 for error and -2 for incomplete. |
| 181 | */ |
| 182 | #if USE_WIDEC_SUPPORT |
| 183 | NCURSES_EXPORT(int) |
| 184 | _nc_build_wch(WINDOW *win, ARG_CH_T ch) |
| 185 | { |
| 186 | char *buffer = WINDOW_EXT(win, addch_work); |
| 187 | int len; |
| 188 | int x = win->_curx; |
| 189 | int y = win->_cury; |
| 190 | mbstate_t state; |
| 191 | wchar_t result; |
| 192 | |
| 193 | if ((WINDOW_EXT(win, addch_used) != 0) && |
| 194 | (WINDOW_EXT(win, addch_x) != x || |
| 195 | WINDOW_EXT(win, addch_y) != y)) { |
| 196 | /* discard the incomplete multibyte character */ |
| 197 | WINDOW_EXT(win, addch_used) = 0; |
| 198 | TR(TRACE_VIRTPUT, |
| 199 | ("Alert discarded multibyte on move (%d,%d) -> (%d,%d)", |
| 200 | WINDOW_EXT(win, addch_y), WINDOW_EXT(win, addch_x), |
| 201 | y, x)); |
| 202 | } |
| 203 | WINDOW_EXT(win, addch_x) = x; |
| 204 | WINDOW_EXT(win, addch_y) = y; |
| 205 | |
| 206 | init_mb(state); |
| 207 | buffer[WINDOW_EXT(win, addch_used)] = (char) CharOf(CHDEREF(ch)); |
| 208 | WINDOW_EXT(win, addch_used) += 1; |
| 209 | buffer[WINDOW_EXT(win, addch_used)] = '\0'; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 210 | if ((len = (int) mbrtowc(&result, |
| 211 | buffer, |
| 212 | (size_t) WINDOW_EXT(win, addch_used), |
| 213 | &state)) > 0) { |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 214 | attr_t attrs = AttrOf(CHDEREF(ch)); |
| 215 | if_EXT_COLORS(int pair = GetPair(CHDEREF(ch))); |
| 216 | SetChar(CHDEREF(ch), result, attrs); |
| 217 | if_EXT_COLORS(SetPair(CHDEREF(ch), pair)); |
| 218 | WINDOW_EXT(win, addch_used) = 0; |
| 219 | } else if (len == -1) { |
| 220 | /* |
| 221 | * An error occurred. We could either discard everything, |
| 222 | * or assume that the error was in the previous input. |
| 223 | * Try the latter. |
| 224 | */ |
| 225 | TR(TRACE_VIRTPUT, ("Alert! mbrtowc returns error")); |
| 226 | /* handle this with unctrl() */ |
| 227 | WINDOW_EXT(win, addch_used) = 0; |
| 228 | } |
| 229 | return len; |
| 230 | } |
| 231 | #endif /* USE_WIDEC_SUPPORT */ |
| 232 | |
| 233 | static |
| 234 | #if !USE_WIDEC_SUPPORT /* cannot be inline if it is recursive */ |
| 235 | NCURSES_INLINE |
| 236 | #endif |
| 237 | int |
| 238 | waddch_literal(WINDOW *win, NCURSES_CH_T ch) |
| 239 | { |
| 240 | int x; |
| 241 | int y; |
| 242 | struct ldat *line; |
| 243 | |
| 244 | x = win->_curx; |
| 245 | y = win->_cury; |
| 246 | |
| 247 | CHECK_POSITION(win, x, y); |
| 248 | |
| 249 | ch = render_char(win, ch); |
| 250 | |
| 251 | line = win->_line + y; |
| 252 | |
| 253 | CHANGED_CELL(line, x); |
| 254 | |
| 255 | /* |
| 256 | * Build up multibyte characters until we have a wide-character. |
| 257 | */ |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 258 | #if NCURSES_SP_FUNCS |
| 259 | #define DeriveSP() SCREEN *sp = _nc_screen_of(win); |
| 260 | #else |
| 261 | #define DeriveSP() /*nothing */ |
| 262 | #endif |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 263 | if_WIDEC({ |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 264 | DeriveSP(); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 265 | if (WINDOW_EXT(win, addch_used) != 0 || !Charable(ch)) { |
| 266 | int len = _nc_build_wch(win, CHREF(ch)); |
| 267 | |
| 268 | if (len >= -1) { |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 269 | attr_t attr = AttrOf(ch); |
| 270 | |
| 271 | /* handle EILSEQ (i.e., when len >= -1) */ |
| 272 | if (len == -1 && is8bits(CharOf(ch))) { |
| 273 | int rc = OK; |
| 274 | const char *s = NCURSES_SP_NAME(unctrl) |
| 275 | (NCURSES_SP_ARGx (chtype) CharOf(ch)); |
| 276 | |
| 277 | if (s[1] != '\0') { |
| 278 | while (*s != '\0') { |
| 279 | rc = waddch(win, UChar(*s) | attr); |
| 280 | if (rc != OK) |
| 281 | break; |
| 282 | ++s; |
| 283 | } |
| 284 | return rc; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 285 | } |
| 286 | } |
| 287 | if (len == -1) |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 288 | return waddch(win, ' ' | attr); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 289 | } else { |
| 290 | return OK; |
| 291 | } |
| 292 | } |
| 293 | }); |
| 294 | |
| 295 | /* |
| 296 | * Non-spacing characters are added to the current cell. |
| 297 | * |
| 298 | * Spacing characters that are wider than one column require some display |
| 299 | * adjustments. |
| 300 | */ |
| 301 | if_WIDEC({ |
| 302 | int len = wcwidth(CharOf(ch)); |
| 303 | int i; |
| 304 | int j; |
| 305 | wchar_t *chars; |
| 306 | |
| 307 | if (len == 0) { /* non-spacing */ |
| 308 | if ((x > 0 && y >= 0) |
| 309 | || (win->_maxx >= 0 && win->_cury >= 1)) { |
| 310 | if (x > 0 && y >= 0) |
| 311 | chars = (win->_line[y].text[x - 1].chars); |
| 312 | else |
| 313 | chars = (win->_line[y - 1].text[win->_maxx].chars); |
| 314 | for (i = 0; i < CCHARW_MAX; ++i) { |
| 315 | if (chars[i] == 0) { |
| 316 | TR(TRACE_VIRTPUT, |
| 317 | ("added non-spacing %d: %x", |
| 318 | x, (int) CharOf(ch))); |
| 319 | chars[i] = CharOf(ch); |
| 320 | break; |
| 321 | } |
| 322 | } |
| 323 | } |
| 324 | goto testwrapping; |
| 325 | } else if (len > 1) { /* multi-column characters */ |
| 326 | /* |
| 327 | * Check if the character will fit on the current line. If it does |
| 328 | * not fit, fill in the remainder of the line with blanks. and |
| 329 | * move to the next line. |
| 330 | */ |
| 331 | if (len > win->_maxx + 1) { |
| 332 | TR(TRACE_VIRTPUT, ("character will not fit")); |
| 333 | return ERR; |
| 334 | } else if (x + len > win->_maxx + 1) { |
| 335 | int count = win->_maxx + 1 - x; |
| 336 | TR(TRACE_VIRTPUT, ("fill %d remaining cells", count)); |
| 337 | fill_cells(win, count); |
| 338 | if (wrap_to_next_line(win) == ERR) |
| 339 | return ERR; |
| 340 | x = win->_curx; |
| 341 | y = win->_cury; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 342 | line = win->_line + y; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 343 | } |
| 344 | /* |
| 345 | * Check for cells which are orphaned by adding this character, set |
| 346 | * those to blanks. |
| 347 | * |
| 348 | * FIXME: this actually could fill j-i cells, more complicated to |
| 349 | * setup though. |
| 350 | */ |
| 351 | for (i = 0; i < len; ++i) { |
| 352 | if (isWidecBase(win->_line[y].text[x + i])) { |
| 353 | break; |
| 354 | } else if (isWidecExt(win->_line[y].text[x + i])) { |
| 355 | for (j = i; x + j <= win->_maxx; ++j) { |
| 356 | if (!isWidecExt(win->_line[y].text[x + j])) { |
| 357 | TR(TRACE_VIRTPUT, ("fill %d orphan cells", j)); |
| 358 | fill_cells(win, j); |
| 359 | break; |
| 360 | } |
| 361 | } |
| 362 | break; |
| 363 | } |
| 364 | } |
| 365 | /* |
| 366 | * Finally, add the cells for this character. |
| 367 | */ |
| 368 | for (i = 0; i < len; ++i) { |
| 369 | NCURSES_CH_T value = ch; |
| 370 | SetWidecExt(value, i); |
| 371 | TR(TRACE_VIRTPUT, ("multicolumn %d:%d (%d,%d)", |
| 372 | i + 1, len, |
| 373 | win->_begy + y, win->_begx + x)); |
| 374 | line->text[x] = value; |
| 375 | CHANGED_CELL(line, x); |
| 376 | ++x; |
| 377 | } |
| 378 | goto testwrapping; |
| 379 | } |
| 380 | }); |
| 381 | |
| 382 | /* |
| 383 | * Single-column characters. |
| 384 | */ |
| 385 | line->text[x++] = ch; |
| 386 | /* |
| 387 | * This label is used only for wide-characters. |
| 388 | */ |
| 389 | if_WIDEC( |
| 390 | testwrapping: |
| 391 | ); |
| 392 | |
| 393 | TR(TRACE_VIRTPUT, ("cell (%ld, %ld..%d) = %s", |
| 394 | (long) win->_cury, (long) win->_curx, x - 1, |
| 395 | _tracech_t(CHREF(ch)))); |
| 396 | |
| 397 | if (x > win->_maxx) { |
| 398 | return wrap_to_next_line(win); |
| 399 | } |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 400 | win->_curx = (NCURSES_SIZE_T) x; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 401 | return OK; |
| 402 | } |
| 403 | |
| 404 | static NCURSES_INLINE int |
| 405 | waddch_nosync(WINDOW *win, const NCURSES_CH_T ch) |
| 406 | /* the workhorse function -- add a character to the given window */ |
| 407 | { |
| 408 | NCURSES_SIZE_T x, y; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 409 | chtype t = (chtype) CharOf(ch); |
| 410 | #if USE_WIDEC_SUPPORT || NCURSES_SP_FUNCS || USE_REENTRANT |
| 411 | SCREEN *sp = _nc_screen_of(win); |
| 412 | #endif |
| 413 | const char *s = NCURSES_SP_NAME(unctrl) (NCURSES_SP_ARGx t); |
| 414 | int tabsize = 8; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 415 | |
| 416 | /* |
| 417 | * If we are using the alternate character set, forget about locale. |
| 418 | * Otherwise, if unctrl() returns a single-character or the locale |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 419 | * claims the code is printable (and not also a control character), |
| 420 | * treat it that way. |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 421 | */ |
| 422 | if ((AttrOf(ch) & A_ALTCHARSET) |
| 423 | || ( |
| 424 | #if USE_WIDEC_SUPPORT |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 425 | (sp != 0 && sp->_legacy_coding) && |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 426 | #endif |
| 427 | s[1] == 0 |
| 428 | ) |
| 429 | || ( |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 430 | (isprint((int)t) && !iscntrl((int)t)) |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 431 | #if USE_WIDEC_SUPPORT |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 432 | || ((sp == 0 || !sp->_legacy_coding) && |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 433 | (WINDOW_EXT(win, addch_used) |
| 434 | || !_nc_is_charable(CharOf(ch)))) |
| 435 | #endif |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 436 | )) { |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 437 | return waddch_literal(win, ch); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 438 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 439 | |
| 440 | /* |
| 441 | * Handle carriage control and other codes that are not printable, or are |
| 442 | * known to expand to more than one character according to unctrl(). |
| 443 | */ |
| 444 | x = win->_curx; |
| 445 | y = win->_cury; |
| 446 | |
| 447 | switch (t) { |
| 448 | case '\t': |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 449 | #if USE_REENTRANT |
| 450 | tabsize = *ptrTabsize(sp); |
| 451 | #else |
| 452 | tabsize = TABSIZE; |
| 453 | #endif |
| 454 | x = (NCURSES_SIZE_T) (x + (tabsize - (x % tabsize))); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 455 | /* |
| 456 | * Space-fill the tab on the bottom line so that we'll get the |
| 457 | * "correct" cursor position. |
| 458 | */ |
| 459 | if ((!win->_scroll && (y == win->_regbottom)) |
| 460 | || (x <= win->_maxx)) { |
| 461 | NCURSES_CH_T blank = blankchar; |
| 462 | AddAttr(blank, AttrOf(ch)); |
| 463 | while (win->_curx < x) { |
| 464 | if (waddch_literal(win, blank) == ERR) |
| 465 | return (ERR); |
| 466 | } |
| 467 | break; |
| 468 | } else { |
| 469 | wclrtoeol(win); |
| 470 | win->_flags |= _WRAPPED; |
| 471 | if (newline_forces_scroll(win, &y)) { |
| 472 | x = win->_maxx; |
| 473 | if (win->_scroll) { |
| 474 | scroll(win); |
| 475 | x = 0; |
| 476 | } |
| 477 | } else { |
| 478 | x = 0; |
| 479 | } |
| 480 | } |
| 481 | break; |
| 482 | case '\n': |
| 483 | wclrtoeol(win); |
| 484 | if (newline_forces_scroll(win, &y)) { |
| 485 | if (win->_scroll) |
| 486 | scroll(win); |
| 487 | else |
| 488 | return (ERR); |
| 489 | } |
| 490 | /* FALLTHRU */ |
| 491 | case '\r': |
| 492 | x = 0; |
| 493 | win->_flags &= ~_WRAPPED; |
| 494 | break; |
| 495 | case '\b': |
| 496 | if (x == 0) |
| 497 | return (OK); |
| 498 | x--; |
| 499 | win->_flags &= ~_WRAPPED; |
| 500 | break; |
| 501 | default: |
| 502 | while (*s) { |
| 503 | NCURSES_CH_T sch; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 504 | SetChar(sch, UChar(*s++), AttrOf(ch)); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 505 | if_EXT_COLORS(SetPair(sch, GetPair(ch))); |
| 506 | if (waddch_literal(win, sch) == ERR) |
| 507 | return ERR; |
| 508 | } |
| 509 | return (OK); |
| 510 | } |
| 511 | |
| 512 | win->_curx = x; |
| 513 | win->_cury = y; |
| 514 | |
| 515 | return (OK); |
| 516 | } |
| 517 | |
| 518 | NCURSES_EXPORT(int) |
| 519 | _nc_waddch_nosync(WINDOW *win, const NCURSES_CH_T c) |
| 520 | /* export copy of waddch_nosync() so the string-put functions can use it */ |
| 521 | { |
| 522 | return (waddch_nosync(win, c)); |
| 523 | } |
| 524 | |
| 525 | /* |
| 526 | * The versions below call _nc_synchook(). We wanted to avoid this in the |
| 527 | * version exported for string puts; they'll call _nc_synchook once at end |
| 528 | * of run. |
| 529 | */ |
| 530 | |
| 531 | /* These are actual entry points */ |
| 532 | |
| 533 | NCURSES_EXPORT(int) |
| 534 | waddch(WINDOW *win, const chtype ch) |
| 535 | { |
| 536 | int code = ERR; |
| 537 | NCURSES_CH_T wch; |
| 538 | SetChar2(wch, ch); |
| 539 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 540 | TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_CALLED("waddch(%p, %s)"), (void *) win, |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 541 | _tracechtype(ch))); |
| 542 | |
| 543 | if (win && (waddch_nosync(win, wch) != ERR)) { |
| 544 | _nc_synchook(win); |
| 545 | code = OK; |
| 546 | } |
| 547 | |
| 548 | TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_RETURN("%d"), code)); |
| 549 | return (code); |
| 550 | } |
| 551 | |
| 552 | NCURSES_EXPORT(int) |
| 553 | wechochar(WINDOW *win, const chtype ch) |
| 554 | { |
| 555 | int code = ERR; |
| 556 | NCURSES_CH_T wch; |
| 557 | SetChar2(wch, ch); |
| 558 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 559 | TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_CALLED("wechochar(%p, %s)"), |
| 560 | (void *) win, |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 561 | _tracechtype(ch))); |
| 562 | |
| 563 | if (win && (waddch_nosync(win, wch) != ERR)) { |
| 564 | bool save_immed = win->_immed; |
| 565 | win->_immed = TRUE; |
| 566 | _nc_synchook(win); |
| 567 | win->_immed = save_immed; |
| 568 | code = OK; |
| 569 | } |
| 570 | TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_RETURN("%d"), code)); |
| 571 | return (code); |
| 572 | } |