diff options
| author | blymn <blymn@NetBSD.org> | 2007-05-28 15:01:53 +0000 |
|---|---|---|
| committer | blymn <blymn@NetBSD.org> | 2007-05-28 15:01:53 +0000 |
| commit | e124de36d8a3bb2fd90b77ec25eb7736f29ee44d (patch) | |
| tree | 0dac708fd51eee66b5194f8e69d6fe165e953031 /lib/libcurses/addbytes.c | |
| parent | 599840187d9b53fe3353daa7f2892b387a1c2f29 (diff) | |
Merge in wide curses code done as a Summer of Code project by
Ruibiao Qiu.
Diffstat (limited to 'lib/libcurses/addbytes.c')
| -rw-r--r-- | lib/libcurses/addbytes.c | 544 |
1 files changed, 441 insertions, 103 deletions
diff --git a/lib/libcurses/addbytes.c b/lib/libcurses/addbytes.c index 162c407fe65..11a43734150 100644 --- a/lib/libcurses/addbytes.c +++ b/lib/libcurses/addbytes.c @@ -1,4 +1,4 @@ -/* $NetBSD: addbytes.c,v 1.31 2007/01/21 13:25:36 jdc Exp $ */ +/* $NetBSD: addbytes.c,v 1.32 2007/05/28 15:01:53 blymn Exp $ */ /* * Copyright (c) 1987, 1993, 1994 @@ -34,10 +34,11 @@ #if 0 static char sccsid[] = "@(#)addbytes.c 8.4 (Berkeley) 5/4/94"; #else -__RCSID("$NetBSD: addbytes.c,v 1.31 2007/01/21 13:25:36 jdc Exp $"); +__RCSID("$NetBSD: addbytes.c,v 1.32 2007/05/28 15:01:53 blymn Exp $"); #endif #endif /* not lint */ +#include <stdlib.h> #include "curses.h" #include "curses_private.h" #ifdef DEBUG @@ -46,6 +47,8 @@ __RCSID("$NetBSD: addbytes.c,v 1.31 2007/01/21 13:25:36 jdc Exp $"); #define SYNCH_IN {y = win->cury; x = win->curx;} #define SYNCH_OUT {win->cury = y; win->curx = x;} +#define PSYNCH_IN {*y = win->cury; *x = win->curx;} +#define PSYNCH_OUT {win->cury = *y; win->curx = *x;} #ifndef _CURSES_USE_MACROS @@ -101,141 +104,476 @@ mvwaddbytes(WINDOW *win, int y, int x, const char *bytes, int count) int __waddbytes(WINDOW *win, const char *bytes, int count, attr_t attr) { - static char blanks[] = " "; - int c, newx, x, y; - attr_t attributes; + int x, y, err; __LINE *lp; +#ifdef HAVE_WCHAR + int n; + cchar_t cc; + wchar_t wc; +#else + int c; +#endif #ifdef DEBUG int i; for (i = 0; i < win->maxy; i++) { assert(win->lines[i]->sentinel == SENTINEL_VALUE); } + + __CTRACE(__CTRACE_INPUT, "ADDBYTES: add %d bytes\n", count); #endif - + + err = OK; SYNCH_IN; lp = win->lines[y]; - while (count--) { + while (count > 0) { +#ifndef HAVE_WCHAR c = *bytes++; #ifdef DEBUG __CTRACE(__CTRACE_INPUT, "ADDBYTES('%c', %x) at (%d, %d)\n", c, attr, y, x); #endif - switch (c) { - case '\t': - SYNCH_OUT; - if (waddbytes(win, blanks, 8 - (x % 8)) == ERR) - return (ERR); - SYNCH_IN; + err = _cursesi_addbyte(win, &lp, &y, &x, c, attr); + count--; +#else + /* + * For wide character support only, try and convert the + * given string into a wide character - we do this because + * this is how ncurses behaves (not that I think this is + * actually the correct thing to do but if we don't do it + * a lot of things that rely on this behaviour will break + * and we will be blamed). If the conversion succeeds + * then we eat the n characters used to make the wide char + * from the string. + */ + n = mbtowc(&wc, bytes, count); + if (n == 0) break; + else if (n < 0) { /* not a valid conversion just eat a char */ + wc = *bytes; + n = 1; + } + + +#ifdef DEBUG + __CTRACE(__CTRACE_INPUT, + "ADDBYTES WIDE(0x%x [%s], %x) at (%d, %d), ate %d bytes\n", + (unsigned) wc, unctrl((unsigned) wc), attr, y, x, n); +#endif + cc.vals[0] = wc; + cc.elements = 1; + cc.attributes = attr; + err = _cursesi_addwchar(win, &lp, &y, &x, &cc); + bytes += n; + count -= n; +#endif + } + + SYNCH_OUT; + +#ifdef DEBUG + for (i = 0; i < win->maxy; i++) { + assert(win->lines[i]->sentinel == SENTINEL_VALUE); + } +#endif + + return (err); +} - default: +/* + * _cursesi_addbyte - + * Internal function to add a byte and update the row and column + * positions as appropriate. This function is only used in the narrow + * character version of curses. + */ +int +_cursesi_addbyte(WINDOW *win, __LINE **lp, int *y, int *x, int c, + attr_t attr) +{ + static char blanks[] = " "; + int newx; + attr_t attributes; + + switch (c) { + case '\t': + PSYNCH_OUT; + if (waddbytes(win, blanks, 8 - (*x % 8)) == ERR) + return (ERR); + PSYNCH_IN; + break; + + default: #ifdef DEBUG - __CTRACE(__CTRACE_INPUT, "ADDBYTES(%p, %d, %d)\n", - win, y, x); + __CTRACE(__CTRACE_INPUT, "ADDBYTES(%p, %d, %d)\n", + win, *y, *x); #endif - if (lp->flags & __ISPASTEOL) { - newline: - x = 0; - lp->flags &= ~__ISPASTEOL; - if (y == win->scr_b) { + if ((*lp)->flags & __ISPASTEOL) { + newline: + *x = 0; + (*lp)->flags &= ~__ISPASTEOL; + if (*y == win->scr_b) { #ifdef DEBUG - __CTRACE(__CTRACE_INPUT, - "ADDBYTES - on bottom " - "of scrolling region\n"); + __CTRACE(__CTRACE_INPUT, + "ADDBYTES - on bottom " + "of scrolling region\n"); #endif - if (!(win->flags & __SCROLLOK)) - return ERR; - SYNCH_OUT; - scroll(win); - SYNCH_IN; - } else { - y++; - } - lp = win->lines[y]; - if (c == '\n') - break; + if (!(win->flags & __SCROLLOK)) + return ERR; + PSYNCH_OUT; + scroll(win); + PSYNCH_IN; + } else { + (*y)++; } + *lp = win->lines[*y]; + if (c == '\n') + break; + } - attributes = (win->wattr | attr) & - (__ATTRIBUTES & ~__COLOR); - if (attr & __COLOR) - attributes |= attr & __COLOR; - else if (win->wattr & __COLOR) - attributes |= win->wattr & __COLOR; + attributes = (win->wattr | attr) & + (__ATTRIBUTES & ~__COLOR); + if (attr & __COLOR) + attributes |= attr & __COLOR; + else if (win->wattr & __COLOR) + attributes |= win->wattr & __COLOR; #ifdef DEBUG - __CTRACE(__CTRACE_INPUT, - "ADDBYTES: 1: y = %d, x = %d, firstch = %d, " - "lastch = %d\n", - y, x, *win->lines[y]->firstchp, - *win->lines[y]->lastchp); + __CTRACE(__CTRACE_INPUT, + "ADDBYTES: 1: y = %d, x = %d, firstch = %d, " + "lastch = %d\n", + *y, *x, *win->lines[*y]->firstchp, + *win->lines[*y]->lastchp); #endif - /* - * Always update the change pointers. Otherwise, - * we could end up not displaying 'blank' characters - * when overlapping windows are displayed. - */ - newx = x + win->ch_off; - lp->flags |= __ISDIRTY; - /* - * firstchp/lastchp are shared between - * parent window and sub-window. - */ - if (newx < *lp->firstchp) - *lp->firstchp = newx; - if (newx > *lp->lastchp) - *lp->lastchp = newx; + /* + * Always update the change pointers. Otherwise, + * we could end up not displaying 'blank' characters + * when overlapping windows are displayed. + */ + newx = *x + win->ch_off; + (*lp)->flags |= __ISDIRTY; + /* + * firstchp/lastchp are shared between + * parent window and sub-window. + */ + if (newx < *(*lp)->firstchp) + *(*lp)->firstchp = newx; + if (newx > *(*lp)->lastchp) + *(*lp)->lastchp = newx; #ifdef DEBUG - __CTRACE(__CTRACE_INPUT, - "ADDBYTES: change gives f/l: %d/%d [%d/%d]\n", - *lp->firstchp, *lp->lastchp, - *lp->firstchp - win->ch_off, - *lp->lastchp - win->ch_off); + __CTRACE(__CTRACE_INPUT, + "ADDBYTES: change gives f/l: %d/%d [%d/%d]\n", + *(*lp)->firstchp, *(*lp)->lastchp, + *(*lp)->firstchp - win->ch_off, + *(*lp)->lastchp - win->ch_off); #endif - if (win->bch != ' ' && c == ' ') - lp->line[x].ch = win->bch; - else - lp->line[x].ch = c; - if (attributes & __COLOR) - lp->line[x].attr = - attributes | (win->battr & ~__COLOR); - else - lp->line[x].attr = attributes | win->battr; - if (x == win->maxx - 1) - lp->flags |= __ISPASTEOL; - else - x++; + if (win->bch != ' ' && c == ' ') + (*lp)->line[*x].ch = win->bch; + else + (*lp)->line[*x].ch = c; + + if (attributes & __COLOR) + (*lp)->line[*x].attr = + attributes | (win->battr & ~__COLOR); + else + (*lp)->line[*x].attr = attributes | win->battr; + + if (*x == win->maxx - 1) + (*lp)->flags |= __ISPASTEOL; + else + (*x)++; #ifdef DEBUG - __CTRACE(__CTRACE_INPUT, - "ADDBYTES: 2: y = %d, x = %d, firstch = %d, " - "lastch = %d\n", - y, x, *win->lines[y]->firstchp, - *win->lines[y]->lastchp); + __CTRACE(__CTRACE_INPUT, + "ADDBYTES: 2: y = %d, x = %d, firstch = %d, " + "lastch = %d\n", + *y, *x, *win->lines[*y]->firstchp, + *win->lines[*y]->lastchp); #endif - break; - case '\n': - SYNCH_OUT; - wclrtoeol(win); - SYNCH_IN; - goto newline; - case '\r': - x = 0; - continue; - case '\b': - if (--x < 0) - x = 0; - break; + break; + case '\n': + PSYNCH_OUT; + wclrtoeol(win); + PSYNCH_IN; + goto newline; + case '\r': + *x = 0; + break; + case '\b': + if (--(*x) < 0) + *x = 0; + break; + } + + return (OK); +} + +/* + * _cursesi_addwchar - + * Internal function to add a wide character and update the row + * and column positions. + */ +int +_cursesi_addwchar(WINDOW *win, __LINE **lnp, int *y, int *x, + const cchar_t *wch) +{ +#ifndef HAVE_WCHAR + return (ERR); +#else + int sx = 0, ex = 0, cw = 0, i = 0, newx = 0; + __LDATA *lp = &win->lines[*y]->line[*x], *tp = NULL; + nschar_t *np = NULL; + cchar_t cc; + attr_t attributes; + + /* special characters handling */ + switch (wch->vals[0]) { + case L'\b': + if (--*x < 0) + *x = 0; + win->curx = *x; + return OK; + case L'\r': + win->curx = 0; + return OK; + case L'\n': + wclrtoeol(win); + PSYNCH_IN; + *x = 0; + (*lnp)->flags &= ~__ISPASTEOL; + if (*y == win->scr_b) { + if (!(win->flags & __SCROLLOK)) + return ERR; + PSYNCH_OUT; + scroll(win); + PSYNCH_IN; + } else { + (*y)++; } + PSYNCH_OUT; + return OK; + case L'\t': + cc.vals[0] = L' '; + cc.elements = 1; + cc.attributes = win->wattr; + for (i = 0; i < 8 - (*x % 8); i++) { + if (wadd_wch(win, &cc) == ERR) + return ERR; + } + return OK; } - SYNCH_OUT; - + + /* check for non-spacing character */ + if (!wcwidth(wch->vals[0])) { #ifdef DEBUG - for (i = 0; i < win->maxy; i++) { - assert(win->lines[i]->sentinel == SENTINEL_VALUE); + __CTRACE(__CTRACE_INPUT, + "_cursesi_addwchar: char '%c' is non-spacing\n", + wch->vals[0]); +#endif /* DEBUG */ + cw = WCOL(*lp); + if (cw < 0) { + lp += cw; + *x += cw; + } + for (i = 0; i < wch->elements; i++) { + if (!(np = (nschar_t *) malloc(sizeof(nschar_t)))) + return ERR;; + np->ch = wch->vals[i]; + np->next = lp->nsp; + lp->nsp = np; + } + (*lnp)->flags |= __ISDIRTY; + newx = *x + win->ch_off; + if (newx < *(*lnp)->firstchp) + *(*lnp)->firstchp = newx; + if (newx > *(*lnp)->lastchp) + *(*lnp)->lastchp = newx; + __touchline(win, *y, *x, *x); + return OK; } -#endif + /* check for new line first */ + if ((*lnp)->flags & __ISPASTEOL) { + *x = 0; + (*lnp)->flags &= ~__ISPASTEOL; + if (*y == win->scr_b) { + if (!(win->flags & __SCROLLOK)) + return ERR; + PSYNCH_OUT; + scroll(win); + PSYNCH_IN; + } else { + (*y)++; + } + (*lnp) = win->lines[*y]; + lp = &win->lines[*y]->line[*x]; + } + /* clear out the current character */ + cw = WCOL(*lp); + if (cw >= 0) { + sx = *x; + } else { + for (sx = *x - 1; sx >= max(*x + cw, 0); sx--) { +#ifdef DEBUG + __CTRACE(__CTRACE_INPUT, + "_cursesi_addwchar: clear current char (%d,%d)\n", + *y, sx); +#endif /* DEBUG */ + tp = &win->lines[*y]->line[sx]; + tp->ch = (wchar_t) btowc((int) win->bch); + if (_cursesi_copy_nsp(win->bnsp, tp) == ERR) + return ERR; - return (OK); + tp->attr = win->battr; + SET_WCOL(*tp, 1); + } + sx = *x + cw; + (*lnp)->flags |= __ISDIRTY; + newx = sx + win->ch_off; + if (newx < *(*lnp)->firstchp) + *(*lnp)->firstchp = newx; + } + + /* check for enough space before the end of line */ + cw = wcwidth(wch->vals[0]); + if (cw > win->maxx - *x) { +#ifdef DEBUG + __CTRACE(__CTRACE_INPUT, + "_cursesi_addwchar: clear EOL (%d,%d)\n", + *y, *x); +#endif /* DEBUG */ + (*lnp)->flags |= __ISDIRTY; + newx = *x + win->ch_off; + if (newx < *(*lnp)->firstchp) + *(*lnp)->firstchp = newx; + for (tp = lp; *x < win->maxx; tp++, (*x)++) { + tp->ch = (wchar_t) btowc((int) win->bch); + if (_cursesi_copy_nsp(win->bnsp, tp) == ERR) + return ERR; + tp->attr = win->battr; + SET_WCOL(*tp, 1); + } + newx = win->maxx - 1 + win->ch_off; + if (newx > *(*lnp)->lastchp) + *(*lnp)->lastchp = newx; + __touchline(win, *y, sx, (int) win->maxx - 1); + sx = *x = 0; + if (*y == win->scr_b) { + if (!(win->flags & __SCROLLOK)) + return ERR; + PSYNCH_OUT; + scroll(win); + PSYNCH_IN; + } else { + (*y)++; + } + lp = &win->lines[*y]->line[0]; + (*lnp) = win->lines[*y]; + } + win->cury = *y; + + /* add spacing character */ +#ifdef DEBUG + __CTRACE(__CTRACE_INPUT, + "_cursesi_addwchar: add character (%d,%d) 0x%x\n", + *y, *x, wch->vals[0]); +#endif /* DEBUG */ + (*lnp)->flags |= __ISDIRTY; + newx = *x + win->ch_off; + if (newx < *(*lnp)->firstchp) + *(*lnp)->firstchp = newx; + if (lp->nsp) { + __cursesi_free_nsp(lp->nsp); + lp->nsp = NULL; + } + + lp->ch = wch->vals[0]; + + attributes = (win->wattr | wch->attributes) + & (WA_ATTRIBUTES & ~__COLOR); + if (wch->attributes & __COLOR) + attributes |= wch->attributes & __COLOR; + else if (win->wattr & __COLOR) + attributes |= win->wattr & __COLOR; + if (attributes & __COLOR) + lp->attr = attributes | (win->battr & ~__COLOR); + else + lp->attr = attributes | win->battr; + + SET_WCOL(*lp, cw); + +#ifdef DEBUG + __CTRACE(__CTRACE_INPUT, + "_cursesi_addwchar: add spacing char 0x%x, attr 0x%x\n", + lp->ch, lp->attr); +#endif /* DEBUG */ + + if (wch->elements > 1) { + for (i = 1; i < wch->elements; i++) { + np = (nschar_t *)malloc(sizeof(nschar_t)); + if (!np) + return ERR;; + np->ch = wch->vals[i]; + np->next = lp->nsp; +#ifdef DEBUG + __CTRACE(__CTRACE_INPUT, + "_cursesi_addwchar: add non-spacing char 0x%x\n", np->ch); +#endif /* DEBUG */ + lp->nsp = np; + } + } +#ifdef DEBUG + __CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: non-spacing list header: %p\n", + lp->nsp); + __CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: add rest columns (%d:%d)\n", + sx + 1, sx + cw - 1); +#endif /* DEBUG */ + for (tp = lp + 1, *x = sx + 1; *x - sx <= cw - 1; tp++, (*x)++) { + if (tp->nsp) { + __cursesi_free_nsp(tp->nsp); + tp->nsp = NULL; + } + tp->ch = wch->vals[0]; + tp->attr = lp->attr & WA_ATTRIBUTES; + /* Mark as "continuation" cell */ + tp->attr |= __WCWIDTH; + } + if (*x == win->maxx) { + (*lnp)->flags |= __ISPASTEOL; + newx = win->maxx - 1 + win->ch_off; + if (newx > *(*lnp)->lastchp) + *(*lnp)->lastchp = newx; + __touchline(win, *y, sx, (int) win->maxx - 1); + win->curx = sx; + } else { + win->curx = *x; + + /* clear the remining of the current characer */ + if (*x && *x < win->maxx) { + ex = sx + cw; + tp = &win->lines[*y]->line[ex]; + while (ex < win->maxx && WCOL(*tp) < 0) { +#ifdef DEBUG + __CTRACE(__CTRACE_INPUT, + "_cursesi_addwchar: clear " + "remaining of current char (%d,%d)nn", + *y, ex); +#endif /* DEBUG */ + tp->ch = (wchar_t) btowc((int) win->bch); + if (_cursesi_copy_nsp(win->bnsp, tp) == ERR) + return ERR; + tp->attr = win->battr; + SET_WCOL(*tp, 1); + tp++, ex++; + } + newx = ex - 1 + win->ch_off; + if (newx > *(*lnp)->lastchp) + *(*lnp)->lastchp = newx; + __touchline(win, *y, sx, ex - 1); + } + } + +#ifdef DEBUG + __CTRACE(__CTRACE_INPUT, "add_wch: %d : 0x%x\n", lp->ch, lp->attr); +#endif /* DEBUG */ + return OK; +#endif } |
