Home | History | Annotate | Line # | Download | only in libcurses
addbytes.c revision 1.30.6.7
      1 /*	$NetBSD: addbytes.c,v 1.30.6.7 2007/03/18 10:04:59 jdc Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1987, 1993, 1994
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 #if 0
     35 static char sccsid[] = "@(#)addbytes.c	8.4 (Berkeley) 5/4/94";
     36 #else
     37 __RCSID("$NetBSD: addbytes.c,v 1.30.6.7 2007/03/18 10:04:59 jdc Exp $");
     38 #endif
     39 #endif				/* not lint */
     40 
     41 #include <stdlib.h>
     42 #include "curses.h"
     43 #include "curses_private.h"
     44 #ifdef DEBUG
     45 #include <assert.h>
     46 #endif
     47 
     48 #define	SYNCH_IN	{y = win->cury; x = win->curx;}
     49 #define	SYNCH_OUT	{win->cury = y; win->curx = x;}
     50 #define	PSYNCH_IN	{*y = win->cury; *x = win->curx;}
     51 #define	PSYNCH_OUT	{win->cury = *y; win->curx = *x;}
     52 
     53 #ifndef _CURSES_USE_MACROS
     54 
     55 /*
     56  * addbytes --
     57  *      Add the character to the current position in stdscr.
     58  */
     59 int
     60 addbytes(const char *bytes, int count)
     61 {
     62 	return __waddbytes(stdscr, bytes, count, 0);
     63 }
     64 
     65 /*
     66  * waddbytes --
     67  *      Add the character to the current position in the given window.
     68  */
     69 int
     70 waddbytes(WINDOW *win, const char *bytes, int count)
     71 {
     72 	return __waddbytes(win, bytes, count, 0);
     73 }
     74 
     75 /*
     76  * mvaddbytes --
     77  *      Add the characters to stdscr at the location given.
     78  */
     79 int
     80 mvaddbytes(int y, int x, const char *bytes, int count)
     81 {
     82 	return mvwaddbytes(stdscr, y, x, bytes, count);
     83 }
     84 
     85 /*
     86  * mvwaddbytes --
     87  *      Add the characters to the given window at the location given.
     88  */
     89 int
     90 mvwaddbytes(WINDOW *win, int y, int x, const char *bytes, int count)
     91 {
     92 	if (wmove(win, y, x) == ERR)
     93 		return ERR;
     94 
     95 	return __waddbytes(win, bytes, count, 0);
     96 }
     97 
     98 #endif
     99 
    100 /*
    101  * waddbytes --
    102  *	Add the character to the current position in the given window.
    103  */
    104 int
    105 __waddbytes(WINDOW *win, const char *bytes, int count, attr_t attr)
    106 {
    107 	int		 x, y, err;
    108 	__LINE		*lp;
    109 #ifdef HAVE_WCHAR
    110 	int		n;
    111 	cchar_t		cc;
    112 	wchar_t		wc;
    113 #else
    114 	int		c;
    115 #endif
    116 #ifdef DEBUG
    117 	int             i;
    118 
    119 	for (i = 0; i < win->maxy; i++) {
    120 		assert(win->lines[i]->sentinel == SENTINEL_VALUE);
    121 	}
    122 
    123 	__CTRACE(__CTRACE_INPUT, "ADDBYTES: add %d bytes\n", count);
    124 #endif
    125 
    126 	err = OK;
    127 	SYNCH_IN;
    128 	lp = win->lines[y];
    129 
    130 	while (count > 0) {
    131 #ifndef HAVE_WCHAR
    132 		c = *bytes++;
    133 #ifdef DEBUG
    134 	__CTRACE(__CTRACE_INPUT, "ADDBYTES('%c', %x) at (%d, %d)\n",
    135 		 c, attr, y, x);
    136 #endif
    137 		err = _cursesi_addbyte(win, &lp, &y, &x, c, attr);
    138 		count--;
    139 #else
    140 		/*
    141 		 * For wide character support only, try and convert the
    142 		 * given string into a wide character - we do this because
    143 		 * this is how ncurses behaves (not that I think this is
    144 		 * actually the correct thing to do but if we don't do it
    145 		 * a lot of things that rely on this behaviour will break
    146 		 * and we will be blamed).  If the conversion succeeds
    147 		 * then we eat the n characters used to make the wide char
    148 		 * from the string.
    149 		 */
    150 		n = mbtowc(&wc, bytes, count);
    151 		if (n == 0)
    152 			break;
    153 		else if (n < 0) { /* not a valid conversion just eat a char */
    154 			wc = *bytes;
    155 			n = 1;
    156 		}
    157 
    158 
    159 #ifdef DEBUG
    160 	__CTRACE(__CTRACE_INPUT,
    161 		 "ADDBYTES WIDE(0x%x [%s], %x) at (%d, %d), ate %d bytes\n",
    162 		 (unsigned) wc, unctrl((unsigned) wc), attr, y, x, n);
    163 #endif
    164 		cc.vals[0] = wc;
    165 		cc.elements = 1;
    166 		cc.attributes = attr;
    167 		err = _cursesi_addwchar(win, &lp, &y, &x, &cc);
    168 		bytes += n;
    169 		count -= n;
    170 #endif
    171 	}
    172 
    173 	SYNCH_OUT;
    174 
    175 #ifdef DEBUG
    176 	for (i = 0; i < win->maxy; i++) {
    177 		assert(win->lines[i]->sentinel == SENTINEL_VALUE);
    178 	}
    179 #endif
    180 
    181 	return (err);
    182 }
    183 
    184 /*
    185  * _cursesi_addbyte -
    186  *	Internal function to add a byte and update the row and column
    187  * positions as appropriate.  This function is only used in the narrow
    188  * character version of curses.
    189  */
    190 int
    191 _cursesi_addbyte(WINDOW *win, __LINE **lp, int *y, int *x, int c,
    192 		 attr_t attr)
    193 {
    194 	static char	 blanks[] = "        ";
    195 	int		 newx;
    196 	attr_t		 attributes;
    197 
    198 	switch (c) {
    199 	case '\t':
    200 		PSYNCH_OUT;
    201 		if (waddbytes(win, blanks, 8 - (*x % 8)) == ERR)
    202 			return (ERR);
    203 		PSYNCH_IN;
    204 		break;
    205 
    206 	default:
    207 #ifdef DEBUG
    208 		__CTRACE(__CTRACE_INPUT, "ADDBYTES(%p, %d, %d)\n",
    209 			 win, *y, *x);
    210 #endif
    211 
    212 		if ((*lp)->flags & __ISPASTEOL) {
    213 		  newline:
    214 			*x = 0;
    215 			(*lp)->flags &= ~__ISPASTEOL;
    216 			if (*y == win->scr_b) {
    217 #ifdef DEBUG
    218 				__CTRACE(__CTRACE_INPUT,
    219 					 "ADDBYTES - on bottom "
    220 					 "of scrolling region\n");
    221 #endif
    222 				if (!(win->flags & __SCROLLOK))
    223 					return ERR;
    224 				PSYNCH_OUT;
    225 				scroll(win);
    226 				PSYNCH_IN;
    227 			} else {
    228 				(*y)++;
    229 			}
    230 			*lp = win->lines[*y];
    231 			if (c == '\n')
    232 				break;
    233 		}
    234 
    235 		attributes = (win->wattr | attr) &
    236 			(__ATTRIBUTES & ~__COLOR);
    237 		if (attr & __COLOR)
    238 			attributes |= attr & __COLOR;
    239 		else if (win->wattr & __COLOR)
    240 			attributes |= win->wattr & __COLOR;
    241 #ifdef DEBUG
    242 		__CTRACE(__CTRACE_INPUT,
    243 			 "ADDBYTES: 1: y = %d, x = %d, firstch = %d, "
    244 			 "lastch = %d\n",
    245 			 *y, *x, *win->lines[*y]->firstchp,
    246 			 *win->lines[*y]->lastchp);
    247 #endif
    248 		/*
    249 		 * Always update the change pointers.  Otherwise,
    250 		 * we could end up not displaying 'blank' characters
    251 		 * when overlapping windows are displayed.
    252 		 */
    253 		newx = *x + win->ch_off;
    254 		(*lp)->flags |= __ISDIRTY;
    255 		/*
    256 		 * firstchp/lastchp are shared between
    257 		 * parent window and sub-window.
    258 		 */
    259 		if (newx < *(*lp)->firstchp)
    260 			*(*lp)->firstchp = newx;
    261 		if (newx > *(*lp)->lastchp)
    262 			*(*lp)->lastchp = newx;
    263 #ifdef DEBUG
    264 		__CTRACE(__CTRACE_INPUT,
    265 			 "ADDBYTES: change gives f/l: %d/%d [%d/%d]\n",
    266 			 *(*lp)->firstchp, *(*lp)->lastchp,
    267 			 *(*lp)->firstchp - win->ch_off,
    268 			 *(*lp)->lastchp - win->ch_off);
    269 #endif
    270 		if (win->bch != ' ' && c == ' ')
    271 			(*lp)->line[*x].ch = win->bch;
    272 		else
    273 			(*lp)->line[*x].ch = c;
    274 
    275 		if (attributes & __COLOR)
    276 			(*lp)->line[*x].attr =
    277 				attributes | (win->battr & ~__COLOR);
    278 		else
    279 			(*lp)->line[*x].attr = attributes | win->battr;
    280 
    281 		if (*x == win->maxx - 1)
    282 			(*lp)->flags |= __ISPASTEOL;
    283 		else
    284 			(*x)++;
    285 #ifdef DEBUG
    286 		__CTRACE(__CTRACE_INPUT,
    287 			 "ADDBYTES: 2: y = %d, x = %d, firstch = %d, "
    288 			 "lastch = %d\n",
    289 			 *y, *x, *win->lines[*y]->firstchp,
    290 			 *win->lines[*y]->lastchp);
    291 #endif
    292 		break;
    293 	case '\n':
    294 		PSYNCH_OUT;
    295 		wclrtoeol(win);
    296 		PSYNCH_IN;
    297 		goto newline;
    298 	case '\r':
    299 		*x = 0;
    300 		break;
    301 	case '\b':
    302 		if (--(*x) < 0)
    303 			*x = 0;
    304 		break;
    305 	}
    306 
    307 	return (OK);
    308 }
    309 
    310 /*
    311  * _cursesi_addwchar -
    312  *	Internal function to add a wide character and update the row
    313  * and column positions.
    314  */
    315 int
    316 _cursesi_addwchar(WINDOW *win, __LINE **lnp, int *y, int *x,
    317 		  const cchar_t *wch)
    318 {
    319 #ifndef HAVE_WCHAR
    320 	return (ERR);
    321 #else
    322 	int sx = 0, ex = 0, cw = 0, i = 0, newx = 0;
    323 	__LDATA *lp = &win->lines[*y]->line[*x], *tp = NULL;
    324 	nschar_t *np = NULL;
    325 	cchar_t cc;
    326 	attr_t attributes;
    327 
    328 	/* special characters handling */
    329 	switch (wch->vals[0]) {
    330 	case L'\b':
    331 		if (--*x < 0)
    332 			*x = 0;
    333 		win->curx = *x;
    334 		return OK;
    335 	case L'\r':
    336 		win->curx = 0;
    337 		return OK;
    338 	case L'\n':
    339 		wclrtoeol(win);
    340 		PSYNCH_IN;
    341 		*x = 0;
    342 		(*lnp)->flags &= ~__ISPASTEOL;
    343 		if (*y == win->scr_b) {
    344 			if (!(win->flags & __SCROLLOK))
    345 				return ERR;
    346 			PSYNCH_OUT;
    347 			scroll(win);
    348 			PSYNCH_IN;
    349 		} else {
    350 			(*y)++;
    351 		}
    352 		PSYNCH_OUT;
    353 		return OK;
    354 	case L'\t':
    355 		cc.vals[0] = L' ';
    356 		cc.elements = 1;
    357 		cc.attributes = win->wattr;
    358 		for (i = 0; i < 8 - (*x % 8); i++) {
    359 			if (wadd_wch(win, &cc) == ERR)
    360 				return ERR;
    361 		}
    362 		return OK;
    363 	}
    364 
    365 	/* check for non-spacing character */
    366 	if (!wcwidth(wch->vals[0])) {
    367 #ifdef DEBUG
    368 		__CTRACE(__CTRACE_INPUT,
    369 			 "_cursesi_addwchar: char '%c' is non-spacing\n",
    370 			 wch->vals[0]);
    371 #endif /* DEBUG */
    372 		cw = WCOL(*lp);
    373 		if (cw < 0) {
    374 			lp += cw;
    375 			*x += cw;
    376 		}
    377 		for (i = 0; i < wch->elements; i++) {
    378 			if (!(np = (nschar_t *) malloc(sizeof(nschar_t))))
    379 				return ERR;;
    380 			np->ch = wch->vals[i];
    381 			np->next = lp->nsp;
    382 			lp->nsp = np;
    383 		}
    384 		(*lnp)->flags |= __ISDIRTY;
    385 		newx = *x + win->ch_off;
    386 		if (newx < *(*lnp)->firstchp)
    387 			*(*lnp)->firstchp = newx;
    388 		if (newx > *(*lnp)->lastchp)
    389 			*(*lnp)->lastchp = newx;
    390 		__touchline(win, *y, *x, *x);
    391 		return OK;
    392 	}
    393 	/* check for new line first */
    394 	if ((*lnp)->flags & __ISPASTEOL) {
    395 		*x = 0;
    396 		(*lnp)->flags &= ~__ISPASTEOL;
    397 		if (*y == win->scr_b) {
    398 			if (!(win->flags & __SCROLLOK))
    399 				return ERR;
    400 			PSYNCH_OUT;
    401 			scroll(win);
    402 			PSYNCH_IN;
    403 		} else {
    404 			(*y)++;
    405 		}
    406 		(*lnp) = win->lines[*y];
    407 		lp = &win->lines[*y]->line[*x];
    408 	}
    409 	/* clear out the current character */
    410 	cw = WCOL(*lp);
    411 	if (cw >= 0) {
    412 		sx = *x;
    413 	} else {
    414 		for (sx = *x - 1; sx >= max(*x + cw, 0); sx--) {
    415 #ifdef DEBUG
    416 			__CTRACE(__CTRACE_INPUT,
    417 				 "_cursesi_addwchar: clear current char (%d,%d)\n",
    418 				 *y, sx);
    419 #endif /* DEBUG */
    420 			tp = &win->lines[*y]->line[sx];
    421 			tp->ch = (wchar_t) btowc((int) win->bch);
    422 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    423 				return ERR;
    424 
    425 			tp->attr = win->battr;
    426 			SET_WCOL(*tp, 1);
    427 		}
    428 		sx = *x + cw;
    429 		(*lnp)->flags |= __ISDIRTY;
    430 		newx = sx + win->ch_off;
    431 		if (newx < *(*lnp)->firstchp)
    432 			*(*lnp)->firstchp = newx;
    433 	}
    434 
    435 	/* check for enough space before the end of line */
    436 	cw = wcwidth(wch->vals[0]);
    437 	if (cw > win->maxx - *x) {
    438 #ifdef DEBUG
    439 		__CTRACE(__CTRACE_INPUT,
    440 			 "_cursesi_addwchar: clear EOL (%d,%d)\n",
    441 			 *y, *x);
    442 #endif /* DEBUG */
    443 		(*lnp)->flags |= __ISDIRTY;
    444 		newx = *x + win->ch_off;
    445 		if (newx < *(*lnp)->firstchp)
    446 			*(*lnp)->firstchp = newx;
    447 		for (tp = lp; *x < win->maxx; tp++, (*x)++) {
    448 			tp->ch = (wchar_t) btowc((int) win->bch);
    449 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    450 				return ERR;
    451 			tp->attr = win->battr;
    452 			SET_WCOL(*tp, 1);
    453 		}
    454 		newx = win->maxx - 1 + win->ch_off;
    455 		if (newx > *(*lnp)->lastchp)
    456 			*(*lnp)->lastchp = newx;
    457 		__touchline(win, *y, sx, (int) win->maxx - 1);
    458 		sx = *x = 0;
    459 		if (*y == win->scr_b) {
    460 			if (!(win->flags & __SCROLLOK))
    461 				return ERR;
    462 			PSYNCH_OUT;
    463 			scroll(win);
    464 			PSYNCH_IN;
    465 		} else {
    466 			(*y)++;
    467 		}
    468 		lp = &win->lines[*y]->line[0];
    469 		(*lnp) = win->lines[*y];
    470 	}
    471 	win->cury = *y;
    472 
    473 	/* add spacing character */
    474 #ifdef DEBUG
    475 	__CTRACE(__CTRACE_INPUT,
    476 		 "_cursesi_addwchar: add character (%d,%d) 0x%x\n",
    477 		 *y, *x, wch->vals[0]);
    478 #endif /* DEBUG */
    479 	(*lnp)->flags |= __ISDIRTY;
    480 	newx = *x + win->ch_off;
    481 	if (newx < *(*lnp)->firstchp)
    482 		*(*lnp)->firstchp = newx;
    483 	if (lp->nsp) {
    484 		__cursesi_free_nsp(lp->nsp);
    485 		lp->nsp = NULL;
    486 	}
    487 
    488 	lp->ch = wch->vals[0];
    489 
    490 	attributes = (win->wattr | wch->attributes)
    491 		& (WA_ATTRIBUTES & ~__COLOR);
    492 	if (wch->attributes & __COLOR)
    493 		attributes |= wch->attributes & __COLOR;
    494 	else if (win->wattr & __COLOR)
    495 		attributes |= win->wattr & __COLOR;
    496 	if (attributes & __COLOR)
    497 		lp->attr = attributes | (win->battr & ~__COLOR);
    498 	else
    499 		lp->attr = attributes | win->battr;
    500 
    501 	SET_WCOL(*lp, cw);
    502 
    503 #ifdef DEBUG
    504 	__CTRACE(__CTRACE_INPUT,
    505 		 "_cursesi_addwchar: add spacing char 0x%x, attr 0x%x\n",
    506 		 lp->ch, lp->attr);
    507 #endif /* DEBUG */
    508 
    509 	if (wch->elements > 1) {
    510 		for (i = 1; i < wch->elements; i++) {
    511 			np = (nschar_t *)malloc(sizeof(nschar_t));
    512 			if (!np)
    513 				return ERR;;
    514 			np->ch = wch->vals[i];
    515 			np->next = lp->nsp;
    516 #ifdef DEBUG
    517 			__CTRACE(__CTRACE_INPUT,
    518 			    "_cursesi_addwchar: add non-spacing char 0x%x\n", np->ch);
    519 #endif /* DEBUG */
    520 			lp->nsp = np;
    521 		}
    522 	}
    523 #ifdef DEBUG
    524 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: non-spacing list header: %p\n",
    525 	    lp->nsp);
    526 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: add rest columns (%d:%d)\n",
    527 		sx + 1, sx + cw - 1);
    528 #endif /* DEBUG */
    529 	for (tp = lp + 1, *x = sx + 1; *x - sx <= cw - 1; tp++, (*x)++) {
    530 		if (tp->nsp) {
    531 			__cursesi_free_nsp(tp->nsp);
    532 			tp->nsp = NULL;
    533 		}
    534 		tp->ch = wch->vals[0];
    535 		tp->attr = lp->attr & WA_ATTRIBUTES;
    536 		/* Mark as "continuation" cell */
    537 		tp->attr |= __WCWIDTH;
    538 	}
    539 	if (*x == win->maxx) {
    540 		(*lnp)->flags |= __ISPASTEOL;
    541 		newx = win->maxx - 1 + win->ch_off;
    542 		if (newx > *(*lnp)->lastchp)
    543 			*(*lnp)->lastchp = newx;
    544 		__touchline(win, *y, sx, (int) win->maxx - 1);
    545 		win->curx = sx;
    546 	} else {
    547 		win->curx = *x;
    548 
    549 		/* clear the remining of the current characer */
    550 		if (*x && *x < win->maxx) {
    551 			ex = sx + cw;
    552 			tp = &win->lines[*y]->line[ex];
    553 			while (ex < win->maxx && WCOL(*tp) < 0) {
    554 #ifdef DEBUG
    555 				__CTRACE(__CTRACE_INPUT,
    556 					 "_cursesi_addwchar: clear "
    557 					 "remaining of current char (%d,%d)nn",
    558 					 *y, ex);
    559 #endif /* DEBUG */
    560 				tp->ch = (wchar_t) btowc((int) win->bch);
    561 				if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    562 					return ERR;
    563 				tp->attr = win->battr;
    564 				SET_WCOL(*tp, 1);
    565 				tp++, ex++;
    566 			}
    567 			newx = ex - 1 + win->ch_off;
    568 			if (newx > *(*lnp)->lastchp)
    569 				*(*lnp)->lastchp = newx;
    570 			__touchline(win, *y, sx, ex - 1);
    571 		}
    572 	}
    573 
    574 #ifdef DEBUG
    575 	__CTRACE(__CTRACE_INPUT, "add_wch: %d : 0x%x\n", lp->ch, lp->attr);
    576 #endif /* DEBUG */
    577 	return OK;
    578 #endif
    579 }
    580