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