Home | History | Annotate | Line # | Download | only in libcurses
add_wch.c revision 1.1
      1 /*   $NetBSD: add_wch.c,v 1.1 2007/01/21 11:38:59 blymn Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2005 The NetBSD Foundation Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from code donated to the NetBSD Foundation
      8  * by Ruibiao Qiu <ruibiao (at) arl.wustl.edu,ruibiao (at) gmail.com>.
      9  *
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. Neither the name of the NetBSD Foundation nor the names of its
     20  *    contributors may be used to endorse or promote products derived
     21  *    from this software without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
     24  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
     25  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  */
     36 
     37 #include <sys/cdefs.h>
     38 #ifndef lint
     39 __RCSID("$NetBSD: add_wch.c,v 1.1 2007/01/21 11:38:59 blymn Exp $");
     40 #endif /* not lint */
     41 
     42 #include <stdlib.h>
     43 #include "curses.h"
     44 #include "curses_private.h"
     45 
     46 /*
     47  * add_wch --
     48  *	Add the wide character to the current position in stdscr.
     49  *
     50  */
     51 int
     52 add_wch(const cchar_t *wch)
     53 {
     54 #ifndef HAVE_WCHAR
     55 	return ERR;
     56 #else
     57 	return wadd_wch(stdscr, wch);
     58 #endif /* HAVE_WCHAR */
     59 }
     60 
     61 
     62 /*
     63  * mvadd_wch --
     64  *      Add the wide character to stdscr at the given location.
     65  */
     66 int
     67 mvadd_wch(int y, int x, const cchar_t *wch)
     68 {
     69 #ifndef HAVE_WCHAR
     70 	return ERR;
     71 #else
     72 	return mvwadd_wch(stdscr, y, x, wch);
     73 #endif /* HAVE_WCHAR */
     74 }
     75 
     76 
     77 /*
     78  * mvwadd_wch --
     79  *      Add the character to the given window at the given location.
     80  */
     81 int
     82 mvwadd_wch(WINDOW *win, int y, int x, const cchar_t *wch)
     83 {
     84 #ifndef HAVE_WCHAR
     85 	return ERR;
     86 #else
     87 	if (wmove(win, y, x) == ERR)
     88 		return ERR;
     89 
     90 	return wadd_wch(win, wch);
     91 #endif /* HAVE_WCHAR */
     92 }
     93 
     94 
     95 /*
     96  * wadd_wch --
     97  *	Add the wide character to the current position in the
     98  *	given window.
     99  *
    100  */
    101 int
    102 wadd_wch(WINDOW *win, const cchar_t *wch)
    103 {
    104 #ifndef HAVE_WCHAR
    105 	return ERR;
    106 #else
    107 	int x = win->curx, y = win->cury, sx = 0, ex = 0, cw = 0, i = 0,
    108 	    newx = 0;
    109 	__LDATA *lp = &win->lines[y]->line[x], *tp = NULL;
    110 	nschar_t *np = NULL, *tnp = NULL;
    111 	__LINE *lnp = NULL;
    112 	cchar_t cc;
    113 
    114 #ifdef DEBUG
    115 	for (i = 0; i < win->maxy; i++) {
    116 		assert(win->lines[i]->sentinel == SENTINEL_VALUE);
    117 	}
    118 	__CTRACE("[wadd_wch]win(%p)", win);
    119 #endif
    120 
    121 	/* special characters handling */
    122 	lnp = win->lines[y];
    123 	switch (wch->vals[0]) {
    124 	case L'\b':
    125 		if (--x < 0)
    126 			x = 0;
    127 		win->curx = x;
    128 		return OK;
    129 	case L'\r':
    130 		win->curx = 0;
    131 		return OK;
    132 	case L'\n':
    133 		wclrtoeol(win);
    134 		x = win->curx;
    135 		y = win->cury;
    136 		x = 0;
    137 		lnp->flags &= ~__ISPASTEOL;
    138 		if (y == win->scr_b) {
    139 			if (!(win->flags & __SCROLLOK))
    140 				return ERR;
    141 			win->cury = y;
    142 			win->curx = x;
    143 			scroll(win);
    144 			y = win->cury;
    145 			x = win->curx;
    146 		} else {
    147 			y++;
    148 		}
    149 		win->curx = x;
    150 		win->cury = y;
    151 		return OK;
    152 	case L'\t':
    153 		cc.vals[0] = L' ';
    154 		cc.elements = 1;
    155 		cc.attributes = win->wattr;
    156 		for (i = 0; i < 8 - (x % 8); i++) {
    157 			if (wadd_wch(win, &cc) == ERR)
    158 				return ERR;
    159 		}
    160 		return OK;
    161 	}
    162 
    163 	/* check for non-spacing character */
    164 	if (!wcwidth(wch->vals[0])) {
    165 		cw = WCOL(*lp);
    166 		if (cw < 0) {
    167 			lp += cw;
    168 			x += cw;
    169 		}
    170 		for (i = 0; i < wch->elements; i++) {
    171 			if (!(np = (nschar_t *) malloc(sizeof(nschar_t))))
    172 				return ERR;;
    173 			np->ch = wch->vals[i];
    174 			np->next = lp->nsp;
    175 			lp->nsp = np;
    176 		}
    177 		lnp->flags |= __ISDIRTY;
    178 		newx = x + win->ch_off;
    179 		if (newx < *lnp->firstchp)
    180 			*lnp->firstchp = newx;
    181 		if (newx > *lnp->lastchp)
    182 			*lnp->lastchp = newx;
    183 		__touchline(win, y, x, x);
    184 		return OK;
    185 	}
    186 	/* check for new line first */
    187 	if (lnp->flags & __ISPASTEOL) {
    188 		x = 0;
    189 		lnp->flags &= ~__ISPASTEOL;
    190 		if (y == win->scr_b) {
    191 			if (!(win->flags & __SCROLLOK))
    192 				return ERR;
    193 			win->cury = y;
    194 			win->curx = x;
    195 			scroll(win);
    196 			y = win->cury;
    197 			x = win->curx;
    198 		} else {
    199 			y++;
    200 		}
    201 		lnp = win->lines[y];
    202 		lp = &win->lines[y]->line[x];
    203 	}
    204 	/* clear out the current character */
    205 	cw = WCOL(*lp);
    206 	if (cw >= 0) {
    207 		sx = x;
    208 	} else {
    209 		for (sx = x - 1; sx >= max(x + cw, 0); sx--) {
    210 #ifdef DEBUG
    211 			__CTRACE("[wadd_wch]clear current char (%d,%d)",
    212 				 y, sx);
    213 #endif /* DEBUG */
    214 			tp = &win->lines[y]->line[sx];
    215 			tp->ch = (wchar_t) btowc((int) win->bch);
    216 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    217 				return ERR;
    218 
    219 			tp->attr = win->battr;
    220 			SET_WCOL(*tp, 1);
    221 		}
    222 		sx = x + cw;
    223 		lnp->flags |= __ISDIRTY;
    224 		newx = sx + win->ch_off;
    225 		if (newx < *lnp->firstchp)
    226 			*lnp->firstchp = newx;
    227 	}
    228 
    229 	/* check for enough space before the end of line */
    230 	cw = wcwidth(wch->vals[0]);
    231 	if (cw > win->maxx - x) {
    232 #ifdef DEBUG
    233 		__CTRACE("[wadd_wch]clear EOL (%d,%d)", y, x);
    234 #endif /* DEBUG */
    235 		lnp->flags |= __ISDIRTY;
    236 		newx = x + win->ch_off;
    237 		if (newx < *lnp->firstchp)
    238 			*lnp->firstchp = newx;
    239 		for (tp = lp; x < win->maxx; tp++, x++) {
    240 			tp->ch = (wchar_t) btowc((int) win->bch);
    241 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    242 				return ERR;
    243 			tp->attr = win->battr;
    244 			SET_WCOL(*tp, 1);
    245 		}
    246 		newx = win->maxx - 1 + win->ch_off;
    247 		if (newx > *lnp->lastchp)
    248 			*lnp->lastchp = newx;
    249 		__touchline(win, y, sx, (int) win->maxx - 1);
    250 		sx = x = 0;
    251 		if (y == win->scr_b) {
    252 			if (!(win->flags & __SCROLLOK))
    253 				return ERR;
    254 			win->curx = x;
    255 			win->cury = y;
    256 			scroll(win);
    257 			x = win->curx;
    258 			y = win->cury;
    259 		} else {
    260 			y++;
    261 		}
    262 		lp = &win->lines[y]->line[0];
    263 		lnp = win->lines[y];
    264 	}
    265 	win->cury = y;
    266 
    267 	/* add spacing character */
    268 #ifdef DEBUG
    269 	__CTRACE("[wadd_wch]add character (%d,%d)%x",
    270 		y, x, wch->vals[0]);
    271 #endif /* DEBUG */
    272 	lnp->flags |= __ISDIRTY;
    273 	newx = x + win->ch_off;
    274 	if (newx < *lnp->firstchp)
    275 		*lnp->firstchp = newx;
    276 	if (lp->nsp) {
    277 		np = lp->nsp;
    278 		while (np) {
    279 			tnp = np->next;
    280 			free(np);
    281 			np = tnp;
    282 		}
    283 		lp->nsp = NULL;
    284 	}
    285 	lp->ch = wch->vals[0];
    286 	lp->attr = wch->attributes & WA_ATTRIBUTES;
    287 	SET_WCOL(*lp, cw);
    288 	if (wch->elements > 1) {
    289 		for (i = 1; i < wch->elements; i++) {
    290 			np = (nschar_t *)malloc(sizeof(nschar_t));
    291 			if (!np)
    292 				return ERR;;
    293 			np->ch = wch->vals[i];
    294 			np->next = lp->nsp;
    295 #ifdef DEBUG
    296 			__CTRACE("[wadd_wch]add non-spacing char 0x%x",
    297 			    np->ch);
    298 #endif /* DEBUG */
    299 			lp->nsp = np;
    300 		}
    301 	}
    302 #ifdef DEBUG
    303 	__CTRACE("[wadd_wch]non-spacing list header: %p\n", lp->nsp);
    304 	__CTRACE("[wadd_wch]add rest columns (%d:%d)\n",
    305 		sx + 1, sx + cw - 1);
    306 #endif /* DEBUG */
    307 	for (tp = lp + 1, x = sx + 1; x - sx <= cw - 1; tp++, x++) {
    308 		if (tp->nsp) {
    309 			np = tp->nsp;
    310 			while (np) {
    311 				tnp = np->next;
    312 				free(np);
    313 				np = tnp;
    314 			}
    315 			tp->nsp = NULL;
    316 		}
    317 		tp->ch = wch->vals[0];
    318 		tp->attr = wch->attributes & WA_ATTRIBUTES;
    319 		SET_WCOL(*tp, sx - x);
    320 	}
    321 	if (x == win->maxx) {
    322 		lnp->flags |= __ISPASTEOL;
    323 		newx = win->maxx - 1 + win->ch_off;
    324 		if (newx > *lnp->lastchp)
    325 			*lnp->lastchp = newx;
    326 		__touchline(win, y, sx, (int) win->maxx - 1);
    327 		win->curx = sx;
    328 	} else {
    329 		win->curx = x;
    330 
    331 		/* clear the remining of the current characer */
    332 		if (x && x < win->maxx) {
    333 			ex = sx + cw;
    334 			tp = &win->lines[y]->line[ex];
    335 			while (ex < win->maxx && WCOL(*tp) < 0) {
    336 #ifdef DEBUG
    337 				__CTRACE("[wadd_wch]clear remaining of current char (%d,%d)",
    338 				    y, ex);
    339 #endif /* DEBUG */
    340 				tp->ch = (wchar_t) btowc((int) win->bch);
    341 				if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    342 					return ERR;
    343 				tp->attr = win->battr;
    344 				SET_WCOL(*tp, 1);
    345 				tp++, ex++;
    346 			}
    347 			newx = ex - 1 + win->ch_off;
    348 			if (newx > *lnp->lastchp)
    349 				*lnp->lastchp = newx;
    350 			__touchline(win, y, sx, ex - 1);
    351 		}
    352 	}
    353 
    354 #ifdef DEBUG
    355 	__CTRACE("add_wch: %d : 0x%x\n", lp->ch, lp->attr);
    356 #endif /* DEBUG */
    357 	return OK;
    358 #endif /* HAVE_WCHAR */
    359 }
    360