ncurses 4.1
[ncurses.git] / ncurses / lib_addch.c
1
2 /***************************************************************************
3 *                            COPYRIGHT NOTICE                              *
4 ****************************************************************************
5 *                ncurses is copyright (C) 1992-1995                        *
6 *                          Zeyd M. Ben-Halim                               *
7 *                          zmbenhal@netcom.com                             *
8 *                          Eric S. Raymond                                 *
9 *                          esr@snark.thyrsus.com                           *
10 *                                                                          *
11 *        Permission is hereby granted to reproduce and distribute ncurses  *
12 *        by any means and for any fee, whether alone or as part of a       *
13 *        larger distribution, in source or in binary form, PROVIDED        *
14 *        this notice is included with any such distribution, and is not    *
15 *        removed from any of its header files. Mention of ncurses in any   *
16 *        applications linked with it is highly appreciated.                *
17 *                                                                          *
18 *        ncurses comes AS IS with no warranty, implied or expressed.       *
19 *                                                                          *
20 ***************************************************************************/
21
22 /*
23 **      lib_addch.c
24 **
25 **      The routines waddch(), wattr_on(), wattr_off(), wchgat().
26 **
27 */
28
29 #include <curses.priv.h>
30 #include <ctype.h>
31
32 MODULE_ID("$Id: lib_addch.c,v 1.30 1997/04/12 17:45:55 tom Exp $")
33
34 int wattr_on(WINDOW *win, const attr_t at)
35 {
36         T((T_CALLED("wattr_on(%p,%s)"), win, _traceattr(at)));
37         T(("... current %s", _traceattr(win->_attrs)));
38         toggle_attr_on(win->_attrs,at);
39         returnCode(OK);
40 }
41
42 int wattr_off(WINDOW *win, const attr_t at)
43 {
44         T((T_CALLED("wattr_off(%p,%s)"), win, _traceattr(at)));
45         T(("... current %s", _traceattr(win->_attrs)));
46         toggle_attr_off(win->_attrs,at);
47         returnCode(OK);
48 }
49
50 int wchgat(WINDOW *win, int n, attr_t attr, short color, const void *opts GCC_UNUSED)
51 {
52     int i;
53
54     T((T_CALLED("wchgat(%p,%d,%s,%d)"), win, n, _traceattr(attr), color));
55
56     toggle_attr_on(attr,COLOR_PAIR(color));
57
58     for (i = win->_curx; i <= win->_maxx && (n == -1 || (n-- > 0)); i++)
59         win->_line[win->_cury].text[i]
60             = ch_or_attr(TextOf(win->_line[win->_cury].text[i]),attr);
61
62     returnCode(OK);
63 }
64
65 /*
66  * Ugly microtweaking alert.  Everything from here to end of module is
67  * likely to be speed-critical -- profiling data sure says it is!
68  * Most of the important screen-painting functions are shells around
69  * waddch().  So we make every effort to reduce function-call overhead
70  * by inlining stuff, even at the cost of making wrapped copies for
71  * export.  Also we supply some internal versions that don't call the
72  * window sync hook, for use by string-put functions.
73  */
74
75 static inline chtype render_char(WINDOW *win, chtype ch)
76 /* compute a rendition of the given char correct for the current context */
77 {
78         if (TextOf(ch) == ' ')
79                 ch = ch_or_attr(ch, win->_bkgd);
80         else if (!(ch & A_ATTRIBUTES))
81                 ch = ch_or_attr(ch, (win->_bkgd & A_ATTRIBUTES));
82         TR(TRACE_VIRTPUT, ("bkg = %#lx -> ch = %#lx", win->_bkgd, ch));
83
84         return(ch);
85 }
86
87 chtype _nc_background(WINDOW *win)
88 /* make render_char() visible while still allowing us to inline it below */
89 {
90     return(render_char(win, BLANK));
91 }
92
93 chtype _nc_render(WINDOW *win, chtype ch)
94 /* make render_char() visible while still allowing us to inline it below */
95 {
96     chtype c = render_char(win,ch);
97     return (ch_or_attr(c,win->_attrs));
98 }
99
100 /* check if position is legal; if not, return error */
101 #ifdef NDEBUG                   /* treat this like an assertion */
102 #define CHECK_POSITION(win, x, y) \
103         if (y > win->_maxy \
104          || x > win->_maxx \
105          || y < 0 \
106          || x < 0) { \
107                 TR(TRACE_VIRTPUT, ("Alert! Win=%p _curx = %d, _cury = %d " \
108                                    "(_maxx = %d, _maxy = %d)", win, x, y, \
109                                    win->_maxx, win->_maxy)); \
110                 return(ERR); \
111         }
112 #else
113 #define CHECK_POSITION(win, x, y) /* nothing */
114 #endif
115
116 static inline
117 int waddch_literal(WINDOW *win, chtype ch)
118 {
119 register int x, y;
120
121         x = win->_curx;
122         y = win->_cury;
123
124         CHECK_POSITION(win, x, y);
125
126         /*
127          * If we're trying to add a character at the lower-right corner more
128          * than once, fail.  (Moving the cursor will clear the flag).
129          */
130         if (win->_flags & _WRAPPED) {
131                 if (x >= win->_maxx)
132                         return (ERR);
133                 win->_flags &= ~_WRAPPED;
134         }
135
136         ch = render_char(win, ch);
137         ch = ch_or_attr(ch,win->_attrs);
138         TR(TRACE_VIRTPUT, ("win attr = %s", _traceattr(win->_attrs)));
139
140         if (win->_line[y].text[x] != ch) {
141                 if (win->_line[y].firstchar == _NOCHANGE)
142                         win->_line[y].firstchar = win->_line[y].lastchar = x;
143                 else if (x < win->_line[y].firstchar)
144                         win->_line[y].firstchar = x;
145                 else if (x > win->_line[y].lastchar)
146                         win->_line[y].lastchar = x;
147
148         }
149
150         win->_line[y].text[x++] = ch;
151         TR(TRACE_VIRTPUT, ("(%d, %d) = %s", y, x, _tracechtype(ch)));
152         if (x > win->_maxx) {
153                 /*
154                  * The _WRAPPED flag is useful only for telling an application
155                  * that we've just wrapped the cursor.  We don't do anything
156                  * with this flag except set it when wrapping, and clear it
157                  * whenever we move the cursor.  If we try to wrap at the
158                  * lower-right corner of a window, we cannot move the cursor
159                  * (since that wouldn't be legal).  So we return an error
160                  * (which is what SVr4 does).  Unlike SVr4, we can successfully
161                  * add a character to the lower-right corner.
162                  */
163                 win->_flags |= _WRAPPED;
164                 if (++y > win->_regbottom) {
165                         y = win->_regbottom;
166                         x = win->_maxx;
167                         if (win->_scroll)
168                                 scroll(win);
169                         else {
170                                 win->_curx = x;
171                                 win->_cury = y;
172                                 return (ERR);
173                         }
174                 }
175                 x = 0;
176         }
177
178         win->_curx = x;
179         win->_cury = y;
180
181         return OK;
182 }
183
184 static inline
185 int waddch_nosync(WINDOW *win, const chtype c)
186 /* the workhorse function -- add a character to the given window */
187 {
188 register chtype ch = c;
189 register int    x, y;
190
191         x = win->_curx;
192         y = win->_cury;
193
194         CHECK_POSITION(win, x, y);
195
196         if (ch & A_ALTCHARSET)
197                 goto noctrl;
198
199         switch ((int)TextOf(ch)) {
200         case '\t':
201                 x += (TABSIZE-(x%TABSIZE));
202
203                 /*
204                  * Space-fill the tab on the bottom line so that we'll get the
205                  * "correct" cursor position.
206                  */
207                 if ((! win->_scroll && (y == win->_regbottom))
208                  || (x <= win->_maxx)) {
209                         while (win->_curx < x) {
210                                 if (waddch_literal(win, (' ' | AttrOf(ch))) == ERR)
211                                         return(ERR);
212                         }
213                         break;
214                 } else {
215                         wclrtoeol(win);
216                         win->_flags |= _WRAPPED;
217                         if (++y > win->_regbottom) {
218                                 x = win->_maxx;
219                                 y--;
220                                 if (win->_scroll) {
221                                         scroll(win);
222                                         x = 0;
223                                 }
224                         } else {
225                                 x = 0;
226                         }
227                 }
228                 break;
229         case '\n':
230                 wclrtoeol(win);
231                 if (++y > win->_regbottom) {
232                         y--;
233                         if (win->_scroll)
234                                 scroll(win);
235                         else
236                                 return (ERR);
237                 }
238                 /* FALLTHRU */
239         case '\r':
240                 x = 0;
241                 win->_flags &= ~_WRAPPED;
242                 break;
243         case '\b':
244                 if (x > 0) {
245                         x--;
246                         win->_flags &= ~_WRAPPED;
247                 }
248                 break;
249         default:
250                 if (is7bits(TextOf(ch)) && iscntrl(TextOf(ch)))
251                         return(waddstr(win, unctrl((unsigned char)ch)));
252
253                 /* FALLTHRU */
254         noctrl:
255                 return waddch_literal(win, ch);
256         }
257
258         win->_curx = x;
259         win->_cury = y;
260
261         return(OK);
262 }
263
264 int _nc_waddch_nosync(WINDOW *win, const chtype c)
265 /* export copy of waddch_nosync() so the string-put functions can use it */
266 {
267     return(waddch_nosync(win, c));
268 }
269
270 /*
271  * The versions below call _nc_synhook().  We wanted to avoid this in the
272  * version exported for string puts; they'll call _nc_synchook once at end
273  * of run.
274  */
275
276 /* These are actual entry points */
277
278 int waddch(WINDOW *win, const chtype ch)
279 {
280         int code = ERR;
281
282         TR(TRACE_VIRTPUT|TRACE_CCALLS, (T_CALLED("waddch(%p, %s)"), win, _tracechtype(ch)));
283
284         if (waddch_nosync(win, ch) != ERR)
285         {
286                 _nc_synchook(win);
287                 code = OK;
288         }
289
290         TR(TRACE_VIRTPUT|TRACE_CCALLS, (T_RETURN("%d"), code));
291         return(code);
292 }
293
294 int wechochar(WINDOW *win, const chtype ch)
295 {
296         int code = ERR;
297
298         TR(TRACE_VIRTPUT|TRACE_CCALLS, (T_CALLED("wechochar(%p, %s)"), win, _tracechtype(ch)));
299
300         if (waddch_literal(win, ch) != ERR)
301         {
302                 bool    save_immed = win->_immed;
303                 win->_immed = TRUE;
304                 _nc_synchook(win);
305                 win->_immed = save_immed;
306                 code = OK;
307         }
308         TR(TRACE_VIRTPUT|TRACE_CCALLS, (T_RETURN("%d"), code));
309         return(code);
310 }