fix for PR 55496

* Fix bkgrndset so that it actually sets the background character in
   in line with the SUSv2 specification.

 * Add an internal function to copy a complex character

 * Make the previously static celleq function into a libcurses private
   function so that it can be called in other files.
This commit is contained in:
blymn 2022-04-19 22:26:57 +00:00
parent 43941b9834
commit 881239103e
4 changed files with 100 additions and 56 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: background.c,v 1.29 2022/04/12 07:03:04 blymn Exp $ */
/* $NetBSD: background.c,v 1.30 2022/04/19 22:26:57 blymn Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: background.c,v 1.29 2022/04/12 07:03:04 blymn Exp $");
__RCSID("$NetBSD: background.c,v 1.30 2022/04/19 22:26:57 blymn Exp $");
#endif /* not lint */
#include <stdlib.h>
@ -160,7 +160,9 @@ wbkgrndset(WINDOW *win, const cchar_t *wch)
{
attr_t battr;
nschar_t *np, *tnp;
int i;
int i, wy, wx;
__LDATA obkgrnd, nbkgrnd;
__LINE *wlp;
__CTRACE(__CTRACE_ATTR, "wbkgrndset: (%p), '%s', %x\n",
win, (const char *)wunctrl(wch), wch->attributes);
@ -169,6 +171,14 @@ wbkgrndset(WINDOW *win, const cchar_t *wch)
if (!wch->elements || wcwidth(wch->vals[0]) > 1)
return;
/* get a copy of the old background, we will need it. */
obkgrnd.ch = win->bch;
obkgrnd.attr = win->battr;
obkgrnd.wflags = 0;
obkgrnd.wcols = win->wcols;
obkgrnd.nsp = NULL;
_cursesi_copy_nsp(win->bnsp, &obkgrnd);
/* Background character. */
tnp = np = win->bnsp;
if (wcwidth( wch->vals[0]))
@ -204,11 +214,7 @@ wbkgrndset(WINDOW *win, const cchar_t *wch)
}
}
/* clear the old non-spacing characters */
while (np) {
tnp = np->next;
free(np);
np = tnp;
}
__cursesi_free_nsp(np);
/* Background attributes (check colour). */
battr = wch->attributes & WA_ATTRIBUTES;
@ -216,6 +222,29 @@ wbkgrndset(WINDOW *win, const cchar_t *wch)
battr |= __default_color;
win->battr = battr;
win->wcols = 1;
/*
* Now do the dirty work of updating all the locations
* that have the old background character with the new.
*/
nbkgrnd.ch = win->bch;
nbkgrnd.attr = win->battr;
nbkgrnd.wflags = 0;
nbkgrnd.wcols = win->wcols;
nbkgrnd.nsp = NULL;
_cursesi_copy_nsp(win->bnsp, &nbkgrnd);
for (wy = 0; wy < win->maxy; wy++) {
wlp = win->alines[wy];
for (wx = 0; wx < win->maxx; wx++) {
if (_cursesi_celleq(&obkgrnd, &wlp->line[wx])) {
_cursesi_copy_wchar(&nbkgrnd, &wlp->line[wx]);
}
}
}
__touchwin(win, 1);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: curses.c,v 1.28 2017/01/31 09:17:53 roy Exp $ */
/* $NetBSD: curses.c,v 1.29 2022/04/19 22:26:57 blymn Exp $ */
/*
* Copyright (c) 1981, 1993, 1994
@ -35,7 +35,7 @@
#if 0
static char sccsid[] = "@(#)curses.c 8.3 (Berkeley) 5/4/94";
#else
__RCSID("$NetBSD: curses.c,v 1.28 2017/01/31 09:17:53 roy Exp $");
__RCSID("$NetBSD: curses.c,v 1.29 2022/04/19 22:26:57 blymn Exp $");
#endif
#endif /* not lint */
@ -77,7 +77,55 @@ char __GT; /* Gtty indicates tabs. */
char __NONL; /* Term can't hack LF doing a CR. */
char __UPPERCASE; /* Terminal is uppercase only. */
/* compare two cells on screen, must have the same foreground/background,
* and for wide characters the same sequence of non-spacing characters
*/
int
_cursesi_celleq(__LDATA *x, __LDATA *y)
{
#ifdef HAVE_WCHAR
nschar_t *xnp = x->nsp, *ynp = y->nsp;
#endif /* HAVE_WCHAR */
int ret = ( x->ch == y->ch ) && ( x->attr == y->attr );
#ifdef HAVE_WCHAR
if (!ret)
return 0;
if (!xnp && !ynp)
return 1;
if ((xnp && !ynp) || (!xnp && ynp))
return 0;
while (xnp && ynp) {
if (xnp->ch != ynp->ch)
return 0;
xnp = xnp->next;
ynp = ynp->next;
}
return !xnp && !ynp;
#else
return ret;
#endif /* HAVE_WCHAR */
}
#ifdef HAVE_WCHAR
/*
* Copy a complex character from source to destination.
*
*/
void
_cursesi_copy_wchar(__LDATA *src, __LDATA *dest)
{
dest->ch = src->ch;
dest->attr = src->attr;
dest->wflags = src->wflags;
dest->wcols = src->wcols;
_cursesi_copy_nsp(src->nsp, dest);
}
/*
* Copy the non-spacing character list (src_nsp) to the given character,
* allocate or free storage as required.

View File

@ -1,4 +1,4 @@
/* $NetBSD: curses_private.h,v 1.78 2022/04/12 07:03:04 blymn Exp $ */
/* $NetBSD: curses_private.h,v 1.79 2022/04/19 22:26:57 blymn Exp $ */
/*-
* Copyright (c) 1998-2000 Brett Lymn
@ -361,10 +361,12 @@ unsigned int __hash_line(const __LDATA *, int);
void __id_subwins(WINDOW *);
void __init_getch(SCREEN *);
void __init_acs(SCREEN *);
int _cursesi_celleq(__LDATA *, __LDATA *);
#ifdef HAVE_WCHAR
void __init_get_wch(SCREEN *);
void __init_wacs(SCREEN *);
int __cputwchar_args( wchar_t, void * );
void _cursesi_copy_wchar(__LDATA *, __LDATA *);
int _cursesi_copy_nsp(nschar_t *, struct __ldata *);
void __cursesi_free_nsp(nschar_t *);
void __cursesi_win_free_nsp(WINDOW *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: refresh.c,v 1.121 2022/04/13 19:17:09 pgoyette Exp $ */
/* $NetBSD: refresh.c,v 1.122 2022/04/19 22:26:57 blymn Exp $ */
/*
* Copyright (c) 1981, 1993, 1994
@ -34,7 +34,7 @@
#if 0
static char sccsid[] = "@(#)refresh.c 8.7 (Berkeley) 8/13/94";
#else
__RCSID("$NetBSD: refresh.c,v 1.121 2022/04/13 19:17:09 pgoyette Exp $");
__RCSID("$NetBSD: refresh.c,v 1.122 2022/04/19 22:26:57 blymn Exp $");
#endif
#endif /* not lint */
@ -57,7 +57,6 @@ static void scrolln(int, int, int, int, int);
static int _wnoutrefresh(WINDOW *, int, int, int, int, int, int);
static int celleq(__LDATA *, __LDATA *);
static int lineeq(__LDATA *, __LDATA *, size_t);
#define CHECK_INTERVAL 5 /* Change N lines before checking typeahead */
@ -1174,7 +1173,7 @@ makech(int wy)
|| (__using_color && back_color_erase))) {
cp = &win->alines[wy]->line[win->maxx - 1];
#ifdef HAVE_WCHAR
while ((celleq(cp, &space) == 1) &&
while ((_cursesi_celleq(cp, &space) == 1) &&
#else
while (cp->ch == space.ch &&
#endif /* HAVE_WCHAR */
@ -1200,7 +1199,7 @@ makech(int wy)
__CTRACE(__CTRACE_REFRESH, "makech: wx=%d,lch=%d\n", wx, lch);
#ifdef HAVE_WCHAR
__CTRACE(__CTRACE_REFRESH, "makech: farnarkle: flags 0x%x, wflags 0x%x, color_init %d, celleq %d\n",
wlp->flags, nsp->wflags, __do_color_init, celleq(nsp, csp));
wlp->flags, nsp->wflags, __do_color_init, _cursesi_celleq(nsp, csp));
__CTRACE(__CTRACE_REFRESH, "makech: nsp=(%x,%x,%d,%x,%x,%d,%p)\n",
nsp->ch, nsp->attr, nsp->wcols, win->bch, win->battr,
win->wcols, nsp->nsp);
@ -1212,10 +1211,10 @@ makech(int wy)
#ifdef HAVE_WCHAR
((nsp->wflags & WCA_CONTINUATION) != WCA_CONTINUATION) &&
#endif
celleq(nsp, csp))
_cursesi_celleq(nsp, csp))
{
if (wx <= lch) {
while (wx <= lch && celleq(nsp, csp)) {
while (wx <= lch && _cursesi_celleq(nsp, csp)) {
#ifdef HAVE_WCHAR
wx += nsp->wcols;
#else
@ -1239,7 +1238,7 @@ makech(int wy)
_cursesi_screen->lx = wx;
owx = wx;
while (wx <= lch &&
((wlp->flags & __ISFORCED) || !celleq(nsp, csp)))
((wlp->flags & __ISFORCED) || !_cursesi_celleq(nsp, csp)))
{
if ((ce != NULL) && (wx >= nlsp) &&
(nsp->ch == space.ch) &&
@ -1346,7 +1345,7 @@ makech(int wy)
!(win->flags & __SCROLLWIN))
{
tld = nsp;
if (celleq(&blank, nsp))
if (_cursesi_celleq(&blank, nsp))
tld = &blank;
if (putch(tld, csp, wy, wx) == ERR)
@ -1711,7 +1710,7 @@ done:
if (clp->hash != blank_hash ||
!lineeq(clp->line, clp->line + 1,
(__virtscr->maxx - 1)) ||
!celleq(clp->line, buf))
!_cursesi_celleq(clp->line, buf))
{
for (i = __virtscr->maxx;
i > BLANKSIZE;
@ -1990,40 +1989,6 @@ __unsetattr(int checkms)
__unset_color(curscr);
}
/* compare two cells on screen, must have the same foreground/background,
* and for wide characters the same sequence of non-spacing characters
*/
static int
celleq(__LDATA *x, __LDATA *y)
{
#ifdef HAVE_WCHAR
nschar_t *xnp = x->nsp, *ynp = y->nsp;
#endif /* HAVE_WCHAR */
int ret = ( x->ch == y->ch ) && ( x->attr == y->attr );
#ifdef HAVE_WCHAR
if (!ret)
return 0;
if (!xnp && !ynp)
return 1;
if ((xnp && !ynp) || (!xnp && ynp))
return 0;
while (xnp && ynp) {
if (xnp->ch != ynp->ch)
return 0;
xnp = xnp->next;
ynp = ynp->next;
}
return !xnp && !ynp;
#else
return ret;
#endif /* HAVE_WCHAR */
}
/* compare two line segments */
static int
lineeq(__LDATA *xl, __LDATA *yl, size_t len)
@ -2032,7 +1997,7 @@ lineeq(__LDATA *xl, __LDATA *yl, size_t len)
__LDATA *xp = xl, *yp = yl;
for (i = 0; i < len; i++, xp++, yp++) {
if (!celleq(xp, yp))
if (!_cursesi_celleq(xp, yp))
return 0;
}
return 1;