NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: lib/56224: libcurses: adding character to last line of non-scrolling window wraps instead of
The following reply was made to PR lib/56224; it has been noted by GNATS.
From: Michael Forney <mforney%mforney.org@localhost>
To: gnats-bugs%netbsd.org@localhost
Cc:
Subject: Re: lib/56224: libcurses: adding character to last line of
non-scrolling window wraps instead of
Date: Wed, 09 Jun 2021 20:54:03 -0700
Brett Lymn <blymn%internode.on.net@localhost> wrote:
> I have just committed a fix for this, please update libcurses, rebuild
> and reinstall it.
Thanks for the patch, I can confirm that this does solve the issue
for the application in question (catgirl).
However, I did a bit of investigation myself, and have a few comments:
1. It seems that now the string is truncated by one extra character
(the last column is empty). Since this last character doesn't extend
beyond the end of the line, my expectation is that it should not
be truncated. And indeed, this is how it behaves in ncurses.
2. I was thinking that this needed to be fixed in _cursesi_addwchar,
not _cursesi_addwbytes. Otherwise, addwstr and addch at the last
column still wrap to column 0 (though, addwstr already truncates
since it returns on the first ERR, whereas _curses_waddbytes ignores
all errors except for the last character).
3. This seems incorrect to me:
n =3D (int)mbrtowc(&wc, bytes, (size_t)count, &st);
...
/* if scrollok is false and we are at the bottom of
* screen and this character would take us past the
* end of the line then we are done.
*/
if ((win->curx + n >=3D win->maxx) &&
(!(win->flags & __SCROLLOK)) &&
(win->cury =3D=3D win->scr_b))
break;
Here, n is the number of bytes in a multi-byte character, *not* the
column width of that character. For example, consider this modified
test program:
#include <curses.h>
#include <locale.h>
=09
int main(void) {
setlocale(LC_ALL, "C.UTF-8");
initscr();
noecho();
raw();
do {
clear();
mvaddstr(LINES - 1, COLS - 7, "foo=E2=86=92=E2=86=92=E2=86=92");
refresh();
} while (getch() !=3D 'q');
endwin();
return 0;
}
The string gets truncated after the first '=E2=86=92' (U+2192, 3 bytes in
UTF-8), even though there are 3 more columns available in the line.
If you replace '=E2=86=92' with '=C2=B5' (U+03BC, 2 bytes in UTF-8), it get=
s
truncated after the second one. If you replace it with '*', it does
not get truncated.
Below is an alternative fix I've been testing that seems to solve
these problems. The first thing it does is make _cursesi_waddbytes
break from the loop and return ERR when any of the _cursesi_addwchar
calls returns ERR (not just the last one). This is consistent with
waddnwstr. The second thing it does is delay wrapping the cursor x
position back to zero until after we return ERR if scrolling is not
allowed.
diff --git a/lib/libcurses/addbytes.c b/lib/libcurses/addbytes.c
index 0a85ae76c3ad..8533a60ed752 100644
--- a/lib/libcurses/addbytes.c
+++ b/lib/libcurses/addbytes.c
@@ -141,7 +141,7 @@ _cursesi_waddbytes(WINDOW *win, const char *bytes, int =
count, attr_t attr,
#ifdef HAVE_WCHAR
(void)memset(&st, 0, sizeof(st));
#endif
- while (count > 0) {
+ while (count > 0 && err =3D=3D OK) {
#ifndef HAVE_WCHAR
c =3D *bytes++;
#ifdef DEBUG
@@ -241,7 +241,6 @@ _cursesi_addbyte(WINDOW *win, __LINE **lp, int *y, int =
*x, int c,
#endif
=20
if (char_interp && ((*lp)->flags & __ISPASTEOL)) {
- *x =3D 0;
(*lp)->flags &=3D ~__ISPASTEOL;
if (*y =3D=3D win->scr_b) {
#ifdef DEBUG
@@ -255,6 +254,7 @@ _cursesi_addbyte(WINDOW *win, __LINE **lp, int *y, int =
*x, int c,
} else {
(*y)++;
}
+ *x =3D 0;
*lp =3D win->alines[*y];
if (c =3D=3D '\n')
return OK;
@@ -350,7 +350,6 @@ _cursesi_addwchar(WINDOW *win, __LINE **lnp, int *y, in=
t *x,
return OK;
case L'\n':
wclrtoeol(win);
- *x =3D 0;
(*lnp)->flags &=3D ~__ISPASTEOL;
if (*y =3D=3D win->scr_b) {
if (!(win->flags & __SCROLLOK))
@@ -359,6 +358,7 @@ _cursesi_addwchar(WINDOW *win, __LINE **lnp, int *y, in=
t *x,
} else {
(*y)++;
}
+ *x =3D 0;
return OK;
case L'\t':
cc.vals[0] =3D L' ';
@@ -404,7 +404,6 @@ _cursesi_addwchar(WINDOW *win, __LINE **lnp, int *y, in=
t *x,
}
/* check for new line first */
if (char_interp && ((*lnp)->flags & __ISPASTEOL)) {
- *x =3D 0;
(*lnp)->flags &=3D ~__ISPASTEOL;
if (*y =3D=3D win->scr_b) {
if (!(win->flags & __SCROLLOK))
@@ -413,6 +412,7 @@ _cursesi_addwchar(WINDOW *win, __LINE **lnp, int *y, in=
t *x,
} else {
(*y)++;
}
+ *x =3D 0;
(*lnp) =3D win->alines[*y];
lp =3D &win->alines[*y]->line[*x];
}
@@ -468,7 +468,6 @@ _cursesi_addwchar(WINDOW *win, __LINE **lnp, int *y, in=
t *x,
if (newx > *(*lnp)->lastchp)
*(*lnp)->lastchp =3D newx;
__touchline(win, *y, sx, (int) win->maxx - 1);
- sx =3D *x =3D 0;
if (*y =3D=3D win->scr_b) {
if (!(win->flags & __SCROLLOK))
return ERR;
@@ -476,6 +475,7 @@ _cursesi_addwchar(WINDOW *win, __LINE **lnp, int *y, in=
t *x,
} else {
(*y)++;
}
+ sx =3D *x =3D 0;
lp =3D &win->alines[*y]->line[0];
(*lnp) =3D win->alines[*y];
}
@@ -556,14 +556,16 @@ _cursesi_addwchar(WINDOW *win, __LINE **lnp, int *y, =
int *x,
if (newx > *(*lnp)->lastchp)
*(*lnp)->lastchp =3D newx;
__touchline(win, *y, sx, (int) win->maxx - 1);
- *x =3D sx =3D 0;
if (*y =3D=3D win->scr_b) {
- if (!(win->flags & __SCROLLOK))
+ if (!(win->flags & __SCROLLOK)) {
+ *x =3D win->maxx - 1;
return ERR;
+ }
scroll(win);
} else {
(*y)++;
}
+ *x =3D sx =3D 0;
lp =3D &win->alines[*y]->line[0];
(*lnp) =3D win->alines[*y];
} else {
Home |
Main Index |
Thread Index |
Old Index