1 /* $OpenBSD: lib_addch.c,v 1.1 1999/01/18 19:09:34 millert Exp $ */ 2 3 /**************************************************************************** 4 * Copyright (c) 1998 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.41 1998/06/28 00:10:21 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 render_char(WINDOW *win, chtype ch) 62 /* compute a rendition of the given char correct for the current context */ 63 { 64 chtype a = win->_attrs; 65 66 if (ch == ' ') 67 { 68 /* color in attrs has precedence over bkgd */ 69 ch = a | (win->_bkgd & COLOR_MASK(a)); 70 } 71 else 72 { 73 /* color in attrs has precedence over bkgd */ 74 a |= (win->_bkgd & A_ATTRIBUTES) & COLOR_MASK(a); 75 /* color in ch has precedence */ 76 ch |= (a & COLOR_MASK(ch)); 77 } 78 79 TR(TRACE_VIRTPUT, ("bkg = %lx, attrs = %lx -> ch = %lx", win->_bkgd, 80 win->_attrs, ch)); 81 82 return(ch); 83 } 84 85 chtype _nc_background(WINDOW *win) 86 /* make render_char() visible while still allowing us to inline it below */ 87 { 88 return (win->_bkgd); 89 } 90 91 chtype _nc_render(WINDOW *win, chtype ch) 92 /* make render_char() visible while still allowing us to inline it below */ 93 { 94 return render_char(win, ch); 95 } 96 97 /* check if position is legal; if not, return error */ 98 #ifndef NDEBUG /* treat this like an assertion */ 99 #define CHECK_POSITION(win, x, y) \ 100 if (y > win->_maxy \ 101 || x > win->_maxx \ 102 || y < 0 \ 103 || x < 0) { \ 104 TR(TRACE_VIRTPUT, ("Alert! Win=%p _curx = %d, _cury = %d " \ 105 "(_maxx = %d, _maxy = %d)", win, x, y, \ 106 win->_maxx, win->_maxy)); \ 107 return(ERR); \ 108 } 109 #else 110 #define CHECK_POSITION(win, x, y) /* nothing */ 111 #endif 112 113 static inline 114 int waddch_literal(WINDOW *win, chtype ch) 115 { 116 int x; 117 struct ldat *line; 118 119 x = win->_curx; 120 121 CHECK_POSITION(win, x, win->_cury); 122 123 /* 124 * If we're trying to add a character at the lower-right corner more 125 * than once, fail. (Moving the cursor will clear the flag). 126 */ 127 if (win->_flags & _WRAPPED) { 128 if (x >= win->_maxx) 129 return (ERR); 130 win->_flags &= ~_WRAPPED; 131 } 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 146 * that we've just wrapped the cursor. We don't do anything 147 * with this flag except set it when wrapping, and clear it 148 * whenever we move the cursor. If we try to wrap at the 149 * lower-right corner of a window, we cannot move the cursor 150 * (since that wouldn't be legal). So we return an error 151 * (which is what SVr4 does). Unlike SVr4, we can successfully 152 * add a character to the lower-right corner. 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 170 int 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; 175 const char *s; 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 _nc_waddch_nosync(WINDOW *win, const chtype c) 250 /* export copy of waddch_nosync() so the string-put functions can use it */ 251 { 252 return(waddch_nosync(win, c)); 253 } 254 255 /* 256 * The versions below call _nc_synhook(). We wanted to avoid this in the 257 * version exported for string puts; they'll call _nc_synchook once at end 258 * of run. 259 */ 260 261 /* These are actual entry points */ 262 263 int waddch(WINDOW *win, const chtype ch) 264 { 265 int code = ERR; 266 267 TR(TRACE_VIRTPUT|TRACE_CCALLS, (T_CALLED("waddch(%p, %s)"), win, _tracechtype(ch))); 268 269 if (win && (waddch_nosync(win, ch) != ERR)) 270 { 271 _nc_synchook(win); 272 code = OK; 273 } 274 275 TR(TRACE_VIRTPUT|TRACE_CCALLS, (T_RETURN("%d"), code)); 276 return(code); 277 } 278 279 int wechochar(WINDOW *win, const chtype ch) 280 { 281 int code = ERR; 282 283 TR(TRACE_VIRTPUT|TRACE_CCALLS, (T_CALLED("wechochar(%p, %s)"), win, _tracechtype(ch))); 284 285 if (win && (waddch_nosync(win, ch) != ERR)) 286 { 287 bool save_immed = win->_immed; 288 win->_immed = TRUE; 289 _nc_synchook(win); 290 win->_immed = save_immed; 291 code = OK; 292 } 293 TR(TRACE_VIRTPUT|TRACE_CCALLS, (T_RETURN("%d"), code)); 294 return(code); 295 } 296