1 /* $OpenBSD: lib_addch.c,v 1.4 2001/01/22 18:01:37 millert Exp $ */ 2 3 /**************************************************************************** 4 * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc. * 5 * * 6 * Permission is hereby granted, free of charge, to any person obtaining a * 7 * copy of this software and associated documentation files (the * 8 * "Software"), to deal in the Software without restriction, including * 9 * without limitation the rights to use, copy, modify, merge, publish, * 10 * distribute, distribute with modifications, sublicense, and/or sell * 11 * copies of the Software, and to permit persons to whom the Software is * 12 * furnished to do so, subject to the following conditions: * 13 * * 14 * The above copyright notice and this permission notice shall be included * 15 * in all copies or substantial portions of the Software. * 16 * * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 20 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 23 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 24 * * 25 * Except as contained in this notice, the name(s) of the above copyright * 26 * holders shall not be used in advertising or otherwise to promote the * 27 * sale, use or other dealings in this Software without prior written * 28 * authorization. * 29 ****************************************************************************/ 30 31 /**************************************************************************** 32 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 33 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 34 ****************************************************************************/ 35 36 /* 37 ** lib_addch.c 38 ** 39 ** The routine waddch(). 40 ** 41 */ 42 43 #include <curses.priv.h> 44 #include <ctype.h> 45 46 MODULE_ID("$From: lib_addch.c,v 1.47 2000/12/10 02:43:26 tom Exp $") 47 48 /* 49 * Ugly microtweaking alert. Everything from here to end of module is 50 * likely to be speed-critical -- profiling data sure says it is! 51 * Most of the important screen-painting functions are shells around 52 * waddch(). So we make every effort to reduce function-call overhead 53 * by inlining stuff, even at the cost of making wrapped copies for 54 * export. Also we supply some internal versions that don't call the 55 * window sync hook, for use by string-put functions. 56 */ 57 58 /* Return bit mask for clearing color pair number if given ch has color */ 59 #define COLOR_MASK(ch) (~(chtype)((ch)&A_COLOR?A_COLOR:0)) 60 61 static inline chtype 62 render_char(WINDOW *win, chtype ch) 63 /* compute a rendition of the given char correct for the current context */ 64 { 65 chtype a = win->_attrs; 66 67 if (ch == ' ') { 68 /* color in attrs has precedence over bkgd */ 69 ch = a | (win->_bkgd & COLOR_MASK(a)); 70 } else { 71 /* color in attrs has precedence over bkgd */ 72 a |= (win->_bkgd & A_ATTRIBUTES) & COLOR_MASK(a); 73 /* color in ch has precedence */ 74 ch |= (a & COLOR_MASK(ch)); 75 } 76 77 TR(TRACE_VIRTPUT, ("bkg = %lx, attrs = %lx -> ch = %lx", win->_bkgd, 78 win->_attrs, ch)); 79 80 return (ch); 81 } 82 83 NCURSES_EXPORT(chtype) 84 _nc_background 85 (WINDOW *win) 86 /* make render_char() visible while still allowing us to inline it below */ 87 { 88 return (win->_bkgd); 89 } 90 91 NCURSES_EXPORT(chtype) 92 _nc_render 93 (WINDOW *win, chtype ch) 94 /* make render_char() visible while still allowing us to inline it below */ 95 { 96 return render_char(win, ch); 97 } 98 99 /* check if position is legal; if not, return error */ 100 #ifndef NDEBUG /* treat this like an assertion */ 101 #define CHECK_POSITION(win, x, y) \ 102 if (y > win->_maxy \ 103 || x > win->_maxx \ 104 || y < 0 \ 105 || x < 0) { \ 106 TR(TRACE_VIRTPUT, ("Alert! Win=%p _curx = %d, _cury = %d " \ 107 "(_maxx = %d, _maxy = %d)", win, x, y, \ 108 win->_maxx, win->_maxy)); \ 109 return(ERR); \ 110 } 111 #else 112 #define CHECK_POSITION(win, x, y) /* nothing */ 113 #endif 114 115 static inline int 116 waddch_literal(WINDOW *win, chtype ch) 117 { 118 int x; 119 struct ldat *line; 120 121 x = win->_curx; 122 123 CHECK_POSITION(win, x, win->_cury); 124 125 /* 126 * If we're trying to add a character at the lower-right corner more 127 * than once, fail. (Moving the cursor will clear the flag). 128 */ 129 #if 0 /* Solaris 2.6 allows updating the corner more than once */ 130 if (win->_flags & _WRAPPED) { 131 if (x >= win->_maxx) 132 return (ERR); 133 win->_flags &= ~_WRAPPED; 134 } 135 #endif 136 137 ch = render_char(win, ch); 138 TR(TRACE_VIRTPUT, ("win attr = %s", _traceattr(win->_attrs))); 139 140 line = win->_line + win->_cury; 141 142 CHANGED_CELL(line, x); 143 144 line->text[x++] = ch; 145 146 TR(TRACE_VIRTPUT, ("(%d, %d) = %s", win->_cury, x, _tracechtype(ch))); 147 if (x > win->_maxx) { 148 /* 149 * The _WRAPPED flag is useful only for telling an application that 150 * we've just wrapped the cursor. We don't do anything with this flag 151 * except set it when wrapping, and clear it whenever we move the 152 * cursor. If we try to wrap at the lower-right corner of a window, we 153 * cannot move the cursor (since that wouldn't be legal). So we return 154 * an error (which is what SVr4 does). Unlike SVr4, we can 155 * successfully add a character to the lower-right corner (Solaris 2.6 156 * does this also, however). 157 */ 158 win->_flags |= _WRAPPED; 159 if (++win->_cury > win->_regbottom) { 160 win->_cury = win->_regbottom; 161 win->_curx = win->_maxx; 162 if (!win->_scroll) 163 return (ERR); 164 scroll(win); 165 } 166 win->_curx = 0; 167 return (OK); 168 } 169 win->_curx = x; 170 return OK; 171 } 172 173 static inline int 174 waddch_nosync(WINDOW *win, const chtype ch) 175 /* the workhorse function -- add a character to the given window */ 176 { 177 int x, y; 178 chtype t = 0; 179 const char *s = 0; 180 181 if ((ch & A_ALTCHARSET) 182 || ((t = TextOf(ch)) > 127) 183 || ((s = unctrl(t))[1] == 0)) 184 return waddch_literal(win, ch); 185 186 x = win->_curx; 187 y = win->_cury; 188 189 switch (t) { 190 case '\t': 191 x += (TABSIZE - (x % TABSIZE)); 192 193 /* 194 * Space-fill the tab on the bottom line so that we'll get the 195 * "correct" cursor position. 196 */ 197 if ((!win->_scroll && (y == win->_regbottom)) 198 || (x <= win->_maxx)) { 199 chtype blank = (' ' | AttrOf(ch)); 200 while (win->_curx < x) { 201 if (waddch_literal(win, blank) == ERR) 202 return (ERR); 203 } 204 break; 205 } else { 206 wclrtoeol(win); 207 win->_flags |= _WRAPPED; 208 if (++y > win->_regbottom) { 209 x = win->_maxx; 210 y--; 211 if (win->_scroll) { 212 scroll(win); 213 x = 0; 214 } 215 } else { 216 x = 0; 217 } 218 } 219 break; 220 case '\n': 221 wclrtoeol(win); 222 if (++y > win->_regbottom) { 223 y--; 224 if (win->_scroll) 225 scroll(win); 226 else 227 return (ERR); 228 } 229 /* FALLTHRU */ 230 case '\r': 231 x = 0; 232 win->_flags &= ~_WRAPPED; 233 break; 234 case '\b': 235 if (x == 0) 236 return (OK); 237 x--; 238 win->_flags &= ~_WRAPPED; 239 break; 240 default: 241 while (*s) 242 if (waddch_literal(win, (*s++) | AttrOf(ch)) == ERR) 243 return ERR; 244 return (OK); 245 } 246 247 win->_curx = x; 248 win->_cury = y; 249 250 return (OK); 251 } 252 253 NCURSES_EXPORT(int) 254 _nc_waddch_nosync 255 (WINDOW *win, const chtype c) 256 /* export copy of waddch_nosync() so the string-put functions can use it */ 257 { 258 return (waddch_nosync(win, c)); 259 } 260 261 /* 262 * The versions below call _nc_synhook(). We wanted to avoid this in the 263 * version exported for string puts; they'll call _nc_synchook once at end 264 * of run. 265 */ 266 267 /* These are actual entry points */ 268 269 NCURSES_EXPORT(int) 270 waddch 271 (WINDOW *win, const chtype ch) 272 { 273 int code = ERR; 274 275 TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_CALLED("waddch(%p, %s)"), win, 276 _tracechtype(ch))); 277 278 if (win && (waddch_nosync(win, ch) != ERR)) { 279 _nc_synchook(win); 280 code = OK; 281 } 282 283 TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_RETURN("%d"), code)); 284 return (code); 285 } 286 287 NCURSES_EXPORT(int) 288 wechochar 289 (WINDOW *win, const chtype ch) 290 { 291 int code = ERR; 292 293 TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_CALLED("wechochar(%p, %s)"), win, 294 _tracechtype(ch))); 295 296 if (win && (waddch_nosync(win, ch) != ERR)) { 297 bool save_immed = win->_immed; 298 win->_immed = TRUE; 299 _nc_synchook(win); 300 win->_immed = save_immed; 301 code = OK; 302 } 303 TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_RETURN("%d"), code)); 304 return (code); 305 } 306