Home | History | Annotate | Line # | Download | only in libcurses
add_wch.c revision 1.1.2.4
      1 /*   $NetBSD: add_wch.c,v 1.1.2.4 2007/01/22 10:43:28 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.2.4 2007/01/22 10:43:28 blymn Exp $");
     40 #endif /* not lint */
     41 
     42 #include <stdlib.h>
     43 #include <assert.h>
     44 #include "curses.h"
     45 #include "curses_private.h"
     46 #ifdef DEBUG
     47 #include <assert.h>
     48 #endif
     49 
     50 /*
     51  * add_wch --
     52  *	Add the wide character to the current position in stdscr.
     53  *
     54  */
     55 int
     56 add_wch(const cchar_t *wch)
     57 {
     58 #ifndef HAVE_WCHAR
     59 	return ERR;
     60 #else
     61 	return wadd_wch(stdscr, wch);
     62 #endif /* HAVE_WCHAR */
     63 }
     64 
     65 
     66 /*
     67  * mvadd_wch --
     68  *      Add the wide character to stdscr at the given location.
     69  */
     70 int
     71 mvadd_wch(int y, int x, const cchar_t *wch)
     72 {
     73 #ifndef HAVE_WCHAR
     74 	return ERR;
     75 #else
     76 	return mvwadd_wch(stdscr, y, x, wch);
     77 #endif /* HAVE_WCHAR */
     78 }
     79 
     80 
     81 /*
     82  * mvwadd_wch --
     83  *      Add the character to the given window at the given location.
     84  */
     85 int
     86 mvwadd_wch(WINDOW *win, int y, int x, const cchar_t *wch)
     87 {
     88 #ifndef HAVE_WCHAR
     89 	return ERR;
     90 #else
     91 	if (wmove(win, y, x) == ERR)
     92 		return ERR;
     93 
     94 	return wadd_wch(win, wch);
     95 #endif /* HAVE_WCHAR */
     96 }
     97 
     98 
     99 /*
    100  * wadd_wch --
    101  *	Add the wide character to the current position in the
    102  *	given window.
    103  *
    104  */
    105 int
    106 wadd_wch(WINDOW *win, const cchar_t *wch)
    107 {
    108 #ifndef HAVE_WCHAR
    109 	return ERR;
    110 #else
    111 	int x = win->curx, y = win->cury, sx = 0, ex = 0, cw = 0, i = 0,
    112 	    newx = 0;
    113 	__LDATA *lp = &win->lines[y]->line[x], *tp = NULL;
    114 	nschar_t *np = NULL, *tnp = NULL;
    115 	__LINE *lnp = NULL;
    116 	cchar_t cc;
    117 
    118 #ifdef DEBUG
    119 	for (i = 0; i < win->maxy; i++) {
    120 		assert(win->lines[i]->sentinel == SENTINEL_VALUE);
    121 	}
    122 	__CTRACE(__CTRACE_INPUT, "wadd_wch: win(%p)", win);
    123 #endif
    124 
    125 	/* special characters handling */
    126 	lnp = win->lines[y];
    127 	switch (wch->vals[0]) {
    128 	case L'\b':
    129 		if (--x < 0)
    130 			x = 0;
    131 		win->curx = x;
    132 		return OK;
    133 	case L'\r':
    134 		win->curx = 0;
    135 		return OK;
    136 	case L'\n':
    137 		wclrtoeol(win);
    138 		x = win->curx;
    139 		y = win->cury;
    140 		x = 0;
    141 		lnp->flags &= ~__ISPASTEOL;
    142 		if (y == win->scr_b) {
    143 			if (!(win->flags & __SCROLLOK))
    144 				return ERR;
    145 			win->cury = y;
    146 			win->curx = x;
    147 			scroll(win);
    148 			y = win->cury;
    149 			x = win->curx;
    150 		} else {
    151 			y++;
    152 		}
    153 		win->curx = x;
    154 		win->cury = y;
    155 		return OK;
    156 	case L'\t':
    157 		cc.vals[0] = L' ';
    158 		cc.elements = 1;
    159 		cc.attributes = win->wattr;
    160 		for (i = 0; i < 8 - (x % 8); i++) {
    161 			if (wadd_wch(win, &cc) == ERR)
    162 				return ERR;
    163 		}
    164 		return OK;
    165 	}
    166 
    167 	/* check for non-spacing character */
    168 	if (!wcwidth(wch->vals[0])) {
    169 		cw = WCOL(*lp);
    170 		if (cw < 0) {
    171 			lp += cw;
    172 			x += cw;
    173 		}
    174 		for (i = 0; i < wch->elements; i++) {
    175 			if (!(np = (nschar_t *) malloc(sizeof(nschar_t))))
    176 				return ERR;;
    177 			np->ch = wch->vals[i];
    178 			np->next = lp->nsp;
    179 			lp->nsp = np;
    180 		}
    181 		lnp->flags |= __ISDIRTY;
    182 		newx = x + win->ch_off;
    183 		if (newx < *lnp->firstchp)
    184 			*lnp->firstchp = newx;
    185 		if (newx > *lnp->lastchp)
    186 			*lnp->lastchp = newx;
    187 		__touchline(win, y, x, x);
    188 		return OK;
    189 	}
    190 	/* check for new line first */
    191 	if (lnp->flags & __ISPASTEOL) {
    192 		x = 0;
    193 		lnp->flags &= ~__ISPASTEOL;
    194 		if (y == win->scr_b) {
    195 			if (!(win->flags & __SCROLLOK))
    196 				return ERR;
    197 			win->cury = y;
    198 			win->curx = x;
    199 			scroll(win);
    200 			y = win->cury;
    201 			x = win->curx;
    202 		} else {
    203 			y++;
    204 		}
    205 		lnp = win->lines[y];
    206 		lp = &win->lines[y]->line[x];
    207 	}
    208 	/* clear out the current character */
    209 	cw = WCOL(*lp);
    210 	if (cw >= 0) {
    211 		sx = x;
    212 	} else {
    213 		for (sx = x - 1; sx >= max(x + cw, 0); sx--) {
    214 #ifdef DEBUG
    215 			__CTRACE(__CTRACE_INPUT,
    216 			    "wadd_wch: clear current char (%d,%d)", y, sx);
    217 #endif /* DEBUG */
    218 			tp = &win->lines[y]->line[sx];
    219 			tp->ch = (wchar_t) btowc((int) win->bch);
    220 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    221 				return ERR;
    222 
    223 			tp->attr = win->battr;
    224 			SET_WCOL(*tp, 1);
    225 		}
    226 		sx = x + cw;
    227 		lnp->flags |= __ISDIRTY;
    228 		newx = sx + win->ch_off;
    229 		if (newx < *lnp->firstchp)
    230 			*lnp->firstchp = newx;
    231 	}
    232 
    233 	/* check for enough space before the end of line */
    234 	cw = wcwidth(wch->vals[0]);
    235 	if (cw > win->maxx - x) {
    236 #ifdef DEBUG
    237 		__CTRACE(__CTRACE_INPUT, "wadd_wch: clear EOL (%d,%d)", y, x);
    238 #endif /* DEBUG */
    239 		lnp->flags |= __ISDIRTY;
    240 		newx = x + win->ch_off;
    241 		if (newx < *lnp->firstchp)
    242 			*lnp->firstchp = newx;
    243 		for (tp = lp; x < win->maxx; tp++, x++) {
    244 			tp->ch = (wchar_t) btowc((int) win->bch);
    245 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    246 				return ERR;
    247 			tp->attr = win->battr;
    248 			SET_WCOL(*tp, 1);
    249 		}
    250 		newx = win->maxx - 1 + win->ch_off;
    251 		if (newx > *lnp->lastchp)
    252 			*lnp->lastchp = newx;
    253 		__touchline(win, y, sx, (int) win->maxx - 1);
    254 		sx = x = 0;
    255 		if (y == win->scr_b) {
    256 			if (!(win->flags & __SCROLLOK))
    257 				return ERR;
    258 			win->curx = x;
    259 			win->cury = y;
    260 			scroll(win);
    261 			x = win->curx;
    262 			y = win->cury;
    263 		} else {
    264 			y++;
    265 		}
    266 		lp = &win->lines[y]->line[0];
    267 		lnp = win->lines[y];
    268 	}
    269 	win->cury = y;
    270 
    271 	/* add spacing character */
    272 #ifdef DEBUG
    273 	__CTRACE(__CTRACE_INPUT, "wadd_wch: add character (%d,%d)%x",
    274 		y, x, wch->vals[0]);
    275 #endif /* DEBUG */
    276 	lnp->flags |= __ISDIRTY;
    277 	newx = x + win->ch_off;
    278 	if (newx < *lnp->firstchp)
    279 		*lnp->firstchp = newx;
    280 	if (lp->nsp) {
    281 		np = lp->nsp;
    282 		while (np) {
    283 			tnp = np->next;
    284 			free(np);
    285 			np = tnp;
    286 		}
    287 		lp->nsp = NULL;
    288 	}
    289 	lp->ch = wch->vals[0];
    290 	lp->attr = wch->attributes & WA_ATTRIBUTES;
    291 	SET_WCOL(*lp, cw);
    292 	if (wch->elements > 1) {
    293 		for (i = 1; i < wch->elements; i++) {
    294 			np = (nschar_t *)malloc(sizeof(nschar_t));
    295 			if (!np)
    296 				return ERR;;
    297 			np->ch = wch->vals[i];
    298 			np->next = lp->nsp;
    299 #ifdef DEBUG
    300 			__CTRACE(__CTRACE_INPUT,
    301 			    "wadd_wch: add non-spacing char 0x%x", np->ch);
    302 #endif /* DEBUG */
    303 			lp->nsp = np;
    304 		}
    305 	}
    306 #ifdef DEBUG
    307 	__CTRACE(__CTRACE_INPUT, "wadd_wch: non-spacing list header: %p\n",
    308 	    lp->nsp);
    309 	__CTRACE(__CTRACE_INPUT, "wadd_wch: add rest columns (%d:%d)\n",
    310 		sx + 1, sx + cw - 1);
    311 #endif /* DEBUG */
    312 	for (tp = lp + 1, x = sx + 1; x - sx <= cw - 1; tp++, x++) {
    313 		if (tp->nsp) {
    314 			np = tp->nsp;
    315 			while (np) {
    316 				tnp = np->next;
    317 				free(np);
    318 				np = tnp;
    319 			}
    320 			tp->nsp = NULL;
    321 		}
    322 		tp->ch = wch->vals[0];
    323 		tp->attr = wch->attributes & WA_ATTRIBUTES;
    324 		SET_WCOL(*tp, sx - x);
    325 	}
    326 	if (x == win->maxx) {
    327 		lnp->flags |= __ISPASTEOL;
    328 		newx = win->maxx - 1 + win->ch_off;
    329 		if (newx > *lnp->lastchp)
    330 			*lnp->lastchp = newx;
    331 		__touchline(win, y, sx, (int) win->maxx - 1);
    332 		win->curx = sx;
    333 	} else {
    334 		win->curx = x;
    335 
    336 		/* clear the remining of the current characer */
    337 		if (x && x < win->maxx) {
    338 			ex = sx + cw;
    339 			tp = &win->lines[y]->line[ex];
    340 			while (ex < win->maxx && WCOL(*tp) < 0) {
    341 #ifdef DEBUG
    342 				__CTRACE(__CTRACE_INPUT, "wadd_wch: clear "
    343 				    "remaining of current char (%d,%d)",
    344 				    y, ex);
    345 #endif /* DEBUG */
    346 				tp->ch = (wchar_t) btowc((int) win->bch);
    347 				if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    348 					return ERR;
    349 				tp->attr = win->battr;
    350 				SET_WCOL(*tp, 1);
    351 				tp++, ex++;
    352 			}
    353 			newx = ex - 1 + win->ch_off;
    354 			if (newx > *lnp->lastchp)
    355 				*lnp->lastchp = newx;
    356 			__touchline(win, y, sx, ex - 1);
    357 		}
    358 	}
    359 
    360 #ifdef DEBUG
    361 	__CTRACE(__CTRACE_INPUT, "add_wch: %d : 0x%x\n", lp->ch, lp->attr);
    362 #endif /* DEBUG */
    363 	return OK;
    364 #endif /* HAVE_WCHAR */
    365 }
    366