Home | History | Annotate | Line # | Download | only in libcurses
addbytes.c revision 1.30.6.6
      1 /*	$NetBSD: addbytes.c,v 1.30.6.6 2007/02/26 09:49:28 blymn 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.6 2007/02/26 09:49:28 blymn 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		 c, x, y, err;
    108 	__LINE		*lp;
    109 #ifdef HAVE_WCHAR
    110 	int		n;
    111 	cchar_t		cc;
    112 	wchar_t		wc;
    113 #endif
    114 #ifdef DEBUG
    115 	int             i;
    116 
    117 	for (i = 0; i < win->maxy; i++) {
    118 		assert(win->lines[i]->sentinel == SENTINEL_VALUE);
    119 	}
    120 
    121 	__CTRACE(__CTRACE_INPUT, "ADDBYTES: add %d bytes\n", count);
    122 #endif
    123 
    124 	err = OK;
    125 	SYNCH_IN;
    126 	lp = win->lines[y];
    127 
    128 	while (count > 0) {
    129 #ifndef HAVE_WCHAR
    130 		c = *bytes++;
    131 #ifdef DEBUG
    132 	__CTRACE(__CTRACE_INPUT, "ADDBYTES('%c', %x) at (%d, %d)\n",
    133 		 c, attr, y, x);
    134 #endif
    135 		err = _cursesi_addbyte(win, &lp, &y, &x, c, attr);
    136 		count--;
    137 #else
    138 		/*
    139 		 * For wide character support only, try and convert the
    140 		 * given string into a wide character - we do this because
    141 		 * this is how ncurses behaves (not that I think this is
    142 		 * actually the correct thing to do but if we don't do it
    143 		 * a lot of things that rely on this behaviour will break
    144 		 * and we will be blamed).  If the conversion succeeds
    145 		 * then we eat the n characters used to make the wide char
    146 		 * from the string.
    147 		 */
    148 		n = mbtowc(&wc, bytes, count);
    149 		if (n == 0)
    150 			break;
    151 		else if (n < 0) { /* not a valid conversion just eat a char */
    152 			wc = *bytes;
    153 			n = 1;
    154 		}
    155 
    156 
    157 #ifdef DEBUG
    158 	__CTRACE(__CTRACE_INPUT,
    159 		 "ADDBYTES WIDE(0x%x, %x) at (%d, %d), ate %d bytes\n",
    160 		 (unsigned) wc, attr, y, x, n);
    161 #endif
    162 		cc.vals[0] = wc;
    163 		cc.elements = 1;
    164 		cc.attributes = attr;
    165 		err = _cursesi_addwchar(win, &lp, &y, &x, &cc);
    166 		bytes += n;
    167 		count -= n;
    168 #endif
    169 	}
    170 
    171 	SYNCH_OUT;
    172 
    173 #ifdef DEBUG
    174 	for (i = 0; i < win->maxy; i++) {
    175 		assert(win->lines[i]->sentinel == SENTINEL_VALUE);
    176 	}
    177 #endif
    178 
    179 	return (err);
    180 }
    181 
    182 /*
    183  * _cursesi_addbyte -
    184  *	Internal function to add a byte and update the row and column
    185  * positions as appropriate.  This function is only used in the narrow
    186  * character version of curses.
    187  */
    188 int
    189 _cursesi_addbyte(WINDOW *win, __LINE **lp, int *y, int *x, int c,
    190 		 attr_t attr)
    191 {
    192 	static char	 blanks[] = "        ";
    193 	int		 newx;
    194 	attr_t		 attributes;
    195 
    196 	switch (c) {
    197 	case '\t':
    198 		PSYNCH_OUT;
    199 		if (waddbytes(win, blanks, 8 - (*x % 8)) == ERR)
    200 			return (ERR);
    201 		PSYNCH_IN;
    202 		break;
    203 
    204 	default:
    205 #ifdef DEBUG
    206 		__CTRACE(__CTRACE_INPUT, "ADDBYTES(%p, %d, %d)\n",
    207 			 win, *y, *x);
    208 #endif
    209 
    210 		if ((*lp)->flags & __ISPASTEOL) {
    211 		  newline:
    212 			*x = 0;
    213 			(*lp)->flags &= ~__ISPASTEOL;
    214 			if (*y == win->scr_b) {
    215 #ifdef DEBUG
    216 				__CTRACE(__CTRACE_INPUT,
    217 					 "ADDBYTES - on bottom "
    218 					 "of scrolling region\n");
    219 #endif
    220 				if (!(win->flags & __SCROLLOK))
    221 					return ERR;
    222 				PSYNCH_OUT;
    223 				scroll(win);
    224 				PSYNCH_IN;
    225 			} else {
    226 				(*y)++;
    227 			}
    228 			*lp = win->lines[*y];
    229 			if (c == '\n')
    230 				break;
    231 		}
    232 
    233 		attributes = (win->wattr | attr) &
    234 			(__ATTRIBUTES & ~__COLOR);
    235 		if (attr & __COLOR)
    236 			attributes |= attr & __COLOR;
    237 		else if (win->wattr & __COLOR)
    238 			attributes |= win->wattr & __COLOR;
    239 #ifdef DEBUG
    240 		__CTRACE(__CTRACE_INPUT,
    241 			 "ADDBYTES: 1: y = %d, x = %d, firstch = %d, "
    242 			 "lastch = %d\n",
    243 			 *y, *x, *win->lines[*y]->firstchp,
    244 			 *win->lines[*y]->lastchp);
    245 #endif
    246 		/*
    247 		 * Always update the change pointers.  Otherwise,
    248 		 * we could end up not displaying 'blank' characters
    249 		 * when overlapping windows are displayed.
    250 		 */
    251 		newx = *x + win->ch_off;
    252 		(*lp)->flags |= __ISDIRTY;
    253 		/*
    254 		 * firstchp/lastchp are shared between
    255 		 * parent window and sub-window.
    256 		 */
    257 		if (newx < *(*lp)->firstchp)
    258 			*(*lp)->firstchp = newx;
    259 		if (newx > *(*lp)->lastchp)
    260 			*(*lp)->lastchp = newx;
    261 #ifdef DEBUG
    262 		__CTRACE(__CTRACE_INPUT,
    263 			 "ADDBYTES: change gives f/l: %d/%d [%d/%d]\n",
    264 			 *(*lp)->firstchp, *(*lp)->lastchp,
    265 			 *(*lp)->firstchp - win->ch_off,
    266 			 *(*lp)->lastchp - win->ch_off);
    267 #endif
    268 		if (win->bch != ' ' && c == ' ')
    269 			(*lp)->line[*x].ch = win->bch;
    270 		else
    271 			(*lp)->line[*x].ch = c;
    272 
    273 		if (attributes & __COLOR)
    274 			(*lp)->line[*x].attr =
    275 				attributes | (win->battr & ~__COLOR);
    276 		else
    277 			(*lp)->line[*x].attr = attributes | win->battr;
    278 
    279 		if (*x == win->maxx - 1)
    280 			(*lp)->flags |= __ISPASTEOL;
    281 		else
    282 			(*x)++;
    283 #ifdef DEBUG
    284 		__CTRACE(__CTRACE_INPUT,
    285 			 "ADDBYTES: 2: y = %d, x = %d, firstch = %d, "
    286 			 "lastch = %d\n",
    287 			 *y, *x, *win->lines[*y]->firstchp,
    288 			 *win->lines[*y]->lastchp);
    289 #endif
    290 		break;
    291 	case '\n':
    292 		PSYNCH_OUT;
    293 		wclrtoeol(win);
    294 		PSYNCH_IN;
    295 		goto newline;
    296 	case '\r':
    297 		*x = 0;
    298 		break;
    299 	case '\b':
    300 		if (--(*x) < 0)
    301 			*x = 0;
    302 		break;
    303 	}
    304 
    305 	return (OK);
    306 }
    307 
    308 /*
    309  * _cursesi_addwchar -
    310  *	Internal function to add a wide character and update the row
    311  * and column positions.
    312  */
    313 int
    314 _cursesi_addwchar(WINDOW *win, __LINE **lnp, int *y, int *x,
    315 		  const cchar_t *wch)
    316 {
    317 #ifndef HAVE_WCHAR
    318 	return (ERR);
    319 #else
    320 	int sx = 0, ex = 0, cw = 0, i = 0, newx = 0;
    321 	__LDATA *lp = &win->lines[*y]->line[*x], *tp = NULL;
    322 	nschar_t *np = NULL, *tnp = NULL;
    323 	cchar_t cc;
    324 	attr_t attributes;
    325 
    326 	/* special characters handling */
    327 	switch (wch->vals[0]) {
    328 	case L'\b':
    329 		if (--*x < 0)
    330 			*x = 0;
    331 		win->curx = *x;
    332 		return OK;
    333 	case L'\r':
    334 		win->curx = 0;
    335 		return OK;
    336 	case L'\n':
    337 		wclrtoeol(win);
    338 		PSYNCH_IN;
    339 		*x = 0;
    340 		(*lnp)->flags &= ~__ISPASTEOL;
    341 		if (*y == win->scr_b) {
    342 			if (!(win->flags & __SCROLLOK))
    343 				return ERR;
    344 			PSYNCH_OUT;
    345 			scroll(win);
    346 			PSYNCH_IN;
    347 		} else {
    348 			(*y)++;
    349 		}
    350 		PSYNCH_OUT;
    351 		return OK;
    352 	case L'\t':
    353 		cc.vals[0] = L' ';
    354 		cc.elements = 1;
    355 		cc.attributes = win->wattr;
    356 		for (i = 0; i < 8 - (*x % 8); i++) {
    357 			if (wadd_wch(win, &cc) == ERR)
    358 				return ERR;
    359 		}
    360 		return OK;
    361 	}
    362 
    363 	/* check for non-spacing character */
    364 	if (!wcwidth(wch->vals[0])) {
    365 #ifdef DEBUG
    366 		__CTRACE(__CTRACE_INPUT,
    367 			 "_cursesi_addwchar: char '%c' is non-spacing\n",
    368 			 wch->vals[0]);
    369 #endif /* DEBUG */
    370 		cw = WCOL(*lp);
    371 		if (cw < 0) {
    372 			lp += cw;
    373 			*x += cw;
    374 		}
    375 		for (i = 0; i < wch->elements; i++) {
    376 			if (!(np = (nschar_t *) malloc(sizeof(nschar_t))))
    377 				return ERR;;
    378 			np->ch = wch->vals[i];
    379 			np->next = lp->nsp;
    380 			lp->nsp = np;
    381 		}
    382 		(*lnp)->flags |= __ISDIRTY;
    383 		newx = *x + win->ch_off;
    384 		if (newx < *(*lnp)->firstchp)
    385 			*(*lnp)->firstchp = newx;
    386 		if (newx > *(*lnp)->lastchp)
    387 			*(*lnp)->lastchp = newx;
    388 		__touchline(win, *y, *x, *x);
    389 		return OK;
    390 	}
    391 	/* check for new line first */
    392 	if ((*lnp)->flags & __ISPASTEOL) {
    393 		*x = 0;
    394 		(*lnp)->flags &= ~__ISPASTEOL;
    395 		if (*y == win->scr_b) {
    396 			if (!(win->flags & __SCROLLOK))
    397 				return ERR;
    398 			PSYNCH_OUT;
    399 			scroll(win);
    400 			PSYNCH_IN;
    401 		} else {
    402 			(*y)++;
    403 		}
    404 		(*lnp) = win->lines[*y];
    405 		lp = &win->lines[*y]->line[*x];
    406 	}
    407 	/* clear out the current character */
    408 	cw = WCOL(*lp);
    409 	if (cw >= 0) {
    410 		sx = *x;
    411 	} else {
    412 		for (sx = *x - 1; sx >= max(*x + cw, 0); sx--) {
    413 #ifdef DEBUG
    414 			__CTRACE(__CTRACE_INPUT,
    415 				 "_cursesi_addwchar: clear current char (%d,%d)\n",
    416 				 *y, sx);
    417 #endif /* DEBUG */
    418 			tp = &win->lines[*y]->line[sx];
    419 			tp->ch = (wchar_t) btowc((int) win->bch);
    420 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    421 				return ERR;
    422 
    423 			tp->attr = win->battr;
    424 			SET_WCOL(*tp, 1);
    425 		}
    426 		sx = *x + cw;
    427 		(*lnp)->flags |= __ISDIRTY;
    428 		newx = sx + win->ch_off;
    429 		if (newx < *(*lnp)->firstchp)
    430 			*(*lnp)->firstchp = newx;
    431 	}
    432 
    433 	/* check for enough space before the end of line */
    434 	cw = wcwidth(wch->vals[0]);
    435 	if (cw > win->maxx - *x) {
    436 #ifdef DEBUG
    437 		__CTRACE(__CTRACE_INPUT,
    438 			 "_cursesi_addwchar: clear EOL (%d,%d)\n",
    439 			 *y, *x);
    440 #endif /* DEBUG */
    441 		(*lnp)->flags |= __ISDIRTY;
    442 		newx = *x + win->ch_off;
    443 		if (newx < *(*lnp)->firstchp)
    444 			*(*lnp)->firstchp = newx;
    445 		for (tp = lp; *x < win->maxx; tp++, (*x)++) {
    446 			tp->ch = (wchar_t) btowc((int) win->bch);
    447 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    448 				return ERR;
    449 			tp->attr = win->battr;
    450 			SET_WCOL(*tp, 1);
    451 		}
    452 		newx = win->maxx - 1 + win->ch_off;
    453 		if (newx > *(*lnp)->lastchp)
    454 			*(*lnp)->lastchp = newx;
    455 		__touchline(win, *y, sx, (int) win->maxx - 1);
    456 		sx = *x = 0;
    457 		if (*y == win->scr_b) {
    458 			if (!(win->flags & __SCROLLOK))
    459 				return ERR;
    460 			PSYNCH_OUT;
    461 			scroll(win);
    462 			PSYNCH_IN;
    463 		} else {
    464 			(*y)++;
    465 		}
    466 		lp = &win->lines[*y]->line[0];
    467 		(*lnp) = win->lines[*y];
    468 	}
    469 	win->cury = *y;
    470 
    471 	/* add spacing character */
    472 #ifdef DEBUG
    473 	__CTRACE(__CTRACE_INPUT,
    474 		 "_cursesi_addwchar: add character (%d,%d) 0x%x\n",
    475 		 *y, *x, wch->vals[0]);
    476 #endif /* DEBUG */
    477 	(*lnp)->flags |= __ISDIRTY;
    478 	newx = *x + win->ch_off;
    479 	if (newx < *(*lnp)->firstchp)
    480 		*(*lnp)->firstchp = newx;
    481 	if (lp->nsp) {
    482 		__cursesi_free_nsp(lp->nsp);
    483 		lp->nsp = NULL;
    484 	}
    485 
    486 	lp->ch = wch->vals[0];
    487 
    488 	attributes = (win->wattr | wch->attributes)
    489 		& (WA_ATTRIBUTES & ~__COLOR);
    490 	if (wch->attributes & __COLOR)
    491 		attributes |= wch->attributes & __COLOR;
    492 	else if (win->wattr & __COLOR)
    493 		attributes |= win->wattr & __COLOR;
    494 	if (attributes & __COLOR)
    495 		lp->attr = attributes | (win->battr & ~__COLOR);
    496 	else
    497 		lp->attr = attributes | win->battr;
    498 
    499 	SET_WCOL(*lp, cw);
    500 
    501 #ifdef DEBUG
    502 	__CTRACE(__CTRACE_INPUT,
    503 		 "_cursesi_addwchar: add spacing char 0x%x, attr 0x%x\n",
    504 		 lp->ch, lp->attr);
    505 #endif /* DEBUG */
    506 
    507 	if (wch->elements > 1) {
    508 		for (i = 1; i < wch->elements; i++) {
    509 			np = (nschar_t *)malloc(sizeof(nschar_t));
    510 			if (!np)
    511 				return ERR;;
    512 			np->ch = wch->vals[i];
    513 			np->next = lp->nsp;
    514 #ifdef DEBUG
    515 			__CTRACE(__CTRACE_INPUT,
    516 			    "_cursesi_addwchar: add non-spacing char 0x%x\n", np->ch);
    517 #endif /* DEBUG */
    518 			lp->nsp = np;
    519 		}
    520 	}
    521 #ifdef DEBUG
    522 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: non-spacing list header: %p\n",
    523 	    lp->nsp);
    524 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: add rest columns (%d:%d)\n",
    525 		sx + 1, sx + cw - 1);
    526 #endif /* DEBUG */
    527 	for (tp = lp + 1, *x = sx + 1; *x - sx <= cw - 1; tp++, (*x)++) {
    528 		if (tp->nsp) {
    529 			__cursesi_free_nsp(tp->nsp);
    530 			tp->nsp = NULL;
    531 		}
    532 		tp->ch = wch->vals[0];
    533 		tp->attr = wch->attributes & WA_ATTRIBUTES;
    534 		SET_WCOL(*tp, sx - *x);
    535 	}
    536 	if (*x == win->maxx) {
    537 		(*lnp)->flags |= __ISPASTEOL;
    538 		newx = win->maxx - 1 + win->ch_off;
    539 		if (newx > *(*lnp)->lastchp)
    540 			*(*lnp)->lastchp = newx;
    541 		__touchline(win, *y, sx, (int) win->maxx - 1);
    542 		win->curx = sx;
    543 	} else {
    544 		win->curx = *x;
    545 
    546 		/* clear the remining of the current characer */
    547 		if (*x && *x < win->maxx) {
    548 			ex = sx + cw;
    549 			tp = &win->lines[*y]->line[ex];
    550 			while (ex < win->maxx && WCOL(*tp) < 0) {
    551 #ifdef DEBUG
    552 				__CTRACE(__CTRACE_INPUT,
    553 					 "_cursesi_addwchar: clear "
    554 					 "remaining of current char (%d,%d)nn",
    555 					 *y, ex);
    556 #endif /* DEBUG */
    557 				tp->ch = (wchar_t) btowc((int) win->bch);
    558 				if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    559 					return ERR;
    560 				tp->attr = win->battr;
    561 				SET_WCOL(*tp, 1);
    562 				tp++, ex++;
    563 			}
    564 			newx = ex - 1 + win->ch_off;
    565 			if (newx > *(*lnp)->lastchp)
    566 				*(*lnp)->lastchp = newx;
    567 			__touchline(win, *y, sx, ex - 1);
    568 		}
    569 	}
    570 
    571 #ifdef DEBUG
    572 	__CTRACE(__CTRACE_INPUT, "add_wch: %d : 0x%x\n", lp->ch, lp->attr);
    573 #endif /* DEBUG */
    574 	return OK;
    575 #endif
    576 }
    577