1 /**************************************************************************** 2 * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc. * 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 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 31 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32 ****************************************************************************/ 33 34 /* 35 ** lib_addch.c 36 ** 37 ** The routine waddch(). 38 ** 39 */ 40 41 #include <curses.priv.h> 42 #include <ctype.h> 43 44 MODULE_ID("$Id: lib_addch.c,v 1.44 2000/05/20 21:13:11 tom Exp $") 45 46 /* 47 * Ugly microtweaking alert. Everything from here to end of module is 48 * likely to be speed-critical -- profiling data sure says it is! 49 * Most of the important screen-painting functions are shells around 50 * waddch(). So we make every effort to reduce function-call overhead 51 * by inlining stuff, even at the cost of making wrapped copies for 52 * export. Also we supply some internal versions that don't call the 53 * window sync hook, for use by string-put functions. 54 */ 55 56 /* Return bit mask for clearing color pair number if given ch has color */ 57 #define COLOR_MASK(ch) (~(chtype)((ch)&A_COLOR?A_COLOR:0)) 58 59 static inline chtype 60 render_char(WINDOW *win, chtype ch) 61 /* compute a rendition of the given char correct for the current context */ 62 { 63 chtype a = win->_attrs; 64 65 if (ch == ' ') { 66 /* color in attrs has precedence over bkgd */ 67 ch = a | (win->_bkgd & COLOR_MASK(a)); 68 } else { 69 /* color in attrs has precedence over bkgd */ 70 a |= (win->_bkgd & A_ATTRIBUTES) & COLOR_MASK(a); 71 /* color in ch has precedence */ 72 ch |= (a & COLOR_MASK(ch)); 73 } 74 75 TR(TRACE_VIRTPUT, ("bkg = %lx, attrs = %lx -> ch = %lx", win->_bkgd, 76 win->_attrs, ch)); 77 78 return (ch); 79 } 80 81 chtype 82 _nc_background(WINDOW *win) 83 /* make render_char() visible while still allowing us to inline it below */ 84 { 85 return (win->_bkgd); 86 } 87 88 chtype 89 _nc_render(WINDOW *win, chtype ch) 90 /* make render_char() visible while still allowing us to inline it below */ 91 { 92 return render_char(win, ch); 93 } 94 95 /* check if position is legal; if not, return error */ 96 #ifndef NDEBUG /* treat this like an assertion */ 97 #define CHECK_POSITION(win, x, y) \ 98 if (y > win->_maxy \ 99 || x > win->_maxx \ 100 || y < 0 \ 101 || x < 0) { \ 102 TR(TRACE_VIRTPUT, ("Alert! Win=%p _curx = %d, _cury = %d " \ 103 "(_maxx = %d, _maxy = %d)", win, x, y, \ 104 win->_maxx, win->_maxy)); \ 105 return(ERR); \ 106 } 107 #else 108 #define CHECK_POSITION(win, x, y) /* nothing */ 109 #endif 110 111 static inline int 112 waddch_literal(WINDOW *win, chtype ch) 113 { 114 int x; 115 struct ldat *line; 116 117 x = win->_curx; 118 119 CHECK_POSITION(win, x, win->_cury); 120 121 /* 122 * If we're trying to add a character at the lower-right corner more 123 * than once, fail. (Moving the cursor will clear the flag). 124 */ 125 #if 0 /* Solaris 2.6 allows updating the corner more than once */ 126 if (win->_flags & _WRAPPED) { 127 if (x >= win->_maxx) 128 return (ERR); 129 win->_flags &= ~_WRAPPED; 130 } 131 #endif 132 133 ch = render_char(win, ch); 134 TR(TRACE_VIRTPUT, ("win attr = %s", _traceattr(win->_attrs))); 135 136 line = win->_line + win->_cury; 137 138 CHANGED_CELL(line, x); 139 140 line->text[x++] = ch; 141 142 TR(TRACE_VIRTPUT, ("(%d, %d) = %s", win->_cury, x, _tracechtype(ch))); 143 if (x > win->_maxx) { 144 /* 145 * The _WRAPPED flag is useful only for telling an application that 146 * we've just wrapped the cursor. We don't do anything with this flag 147 * except set it when wrapping, and clear it whenever we move the 148 * cursor. If we try to wrap at the lower-right corner of a window, we 149 * cannot move the cursor (since that wouldn't be legal). So we return 150 * an error (which is what SVr4 does). Unlike SVr4, we can 151 * successfully add a character to the lower-right corner (Solaris 2.6 152 * does this also, however). 153 */ 154 win->_flags |= _WRAPPED; 155 if (++win->_cury > win->_regbottom) { 156 win->_cury = win->_regbottom; 157 win->_curx = win->_maxx; 158 if (!win->_scroll) 159 return (ERR); 160 scroll(win); 161 } 162 win->_curx = 0; 163 return (OK); 164 } 165 win->_curx = x; 166 return OK; 167 } 168 169 static inline int 170 waddch_nosync(WINDOW *win, const chtype ch) 171 /* the workhorse function -- add a character to the given window */ 172 { 173 int x, y; 174 int t = 0; 175 const char *s = 0; 176 177 if ((ch & A_ALTCHARSET) 178 || ((t = TextOf(ch)) > 127) 179 || ((s = unctrl(t))[1] == 0)) 180 return waddch_literal(win, ch); 181 182 x = win->_curx; 183 y = win->_cury; 184 185 switch (t) { 186 case '\t': 187 x += (TABSIZE - (x % TABSIZE)); 188 189 /* 190 * Space-fill the tab on the bottom line so that we'll get the 191 * "correct" cursor position. 192 */ 193 if ((!win->_scroll && (y == win->_regbottom)) 194 || (x <= win->_maxx)) { 195 chtype blank = (' ' | AttrOf(ch)); 196 while (win->_curx < x) { 197 if (waddch_literal(win, blank) == ERR) 198 return (ERR); 199 } 200 break; 201 } else { 202 wclrtoeol(win); 203 win->_flags |= _WRAPPED; 204 if (++y > win->_regbottom) { 205 x = win->_maxx; 206 y--; 207 if (win->_scroll) { 208 scroll(win); 209 x = 0; 210 } 211 } else { 212 x = 0; 213 } 214 } 215 break; 216 case '\n': 217 wclrtoeol(win); 218 if (++y > win->_regbottom) { 219 y--; 220 if (win->_scroll) 221 scroll(win); 222 else 223 return (ERR); 224 } 225 /* FALLTHRU */ 226 case '\r': 227 x = 0; 228 win->_flags &= ~_WRAPPED; 229 break; 230 case '\b': 231 if (x == 0) 232 return (OK); 233 x--; 234 win->_flags &= ~_WRAPPED; 235 break; 236 default: 237 while (*s) 238 if (waddch_literal(win, (*s++) | AttrOf(ch)) == ERR) 239 return ERR; 240 return (OK); 241 } 242 243 win->_curx = x; 244 win->_cury = y; 245 246 return (OK); 247 } 248 249 int 250 _nc_waddch_nosync(WINDOW *win, const chtype c) 251 /* export copy of waddch_nosync() so the string-put functions can use it */ 252 { 253 return (waddch_nosync(win, c)); 254 } 255 256 /* 257 * The versions below call _nc_synhook(). We wanted to avoid this in the 258 * version exported for string puts; they'll call _nc_synchook once at end 259 * of run. 260 */ 261 262 /* These are actual entry points */ 263 264 int 265 waddch(WINDOW *win, const chtype ch) 266 { 267 int code = ERR; 268 269 TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_CALLED("waddch(%p, %s)"), win, 270 _tracechtype(ch))); 271 272 if (win && (waddch_nosync(win, ch) != ERR)) { 273 _nc_synchook(win); 274 code = OK; 275 } 276 277 TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_RETURN("%d"), code)); 278 return (code); 279 } 280 281 int 282 wechochar(WINDOW *win, const chtype ch) 283 { 284 int code = ERR; 285 286 TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_CALLED("wechochar(%p, %s)"), win, 287 _tracechtype(ch))); 288 289 if (win && (waddch_nosync(win, ch) != ERR)) { 290 bool save_immed = win->_immed; 291 win->_immed = TRUE; 292 _nc_synchook(win); 293 win->_immed = save_immed; 294 code = OK; 295 } 296 TR(TRACE_VIRTPUT | TRACE_CCALLS, (T_RETURN("%d"), code)); 297 return (code); 298 } 299