GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcurses/base/lib_addch.c Lines: 0 128 0.0 %
Date: 2016-12-06 Branches: 0 163 0.0 %

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