Module Name: src Committed By: blymn Date: Mon Nov 15 06:27:06 UTC 2021
Modified Files: src/lib/libcurses: ins_wstr.c Log Message: Fix for PR lib/55433 Correct the behaviour for ins_wstr: * Properly check the string will fit by processing any special characters present when preforming the check. * Simplify the routine by removing code that duplicates the code in _cursesi_addwchar and just call _cursesi_addwchar. To generate a diff of this commit: cvs rdiff -u -r1.17 -r1.18 src/lib/libcurses/ins_wstr.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libcurses/ins_wstr.c diff -u src/lib/libcurses/ins_wstr.c:1.17 src/lib/libcurses/ins_wstr.c:1.18 --- src/lib/libcurses/ins_wstr.c:1.17 Mon Sep 6 07:45:48 2021 +++ src/lib/libcurses/ins_wstr.c Mon Nov 15 06:27:06 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: ins_wstr.c,v 1.17 2021/09/06 07:45:48 rin Exp $ */ +/* $NetBSD: ins_wstr.c,v 1.18 2021/11/15 06:27:06 blymn Exp $ */ /* * Copyright (c) 2005 The NetBSD Foundation Inc. @@ -36,7 +36,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: ins_wstr.c,v 1.17 2021/09/06 07:45:48 rin Exp $"); +__RCSID("$NetBSD: ins_wstr.c,v 1.18 2021/11/15 06:27:06 blymn Exp $"); #endif /* not lint */ #include <string.h> @@ -133,8 +133,9 @@ wins_nwstr(WINDOW *win, const wchar_t *w __LDATA *start, *temp1, *temp2; __LINE *lnp; const wchar_t *scp; - int width, len, sx, x, y, cw, pcw, newx; - nschar_t *np; + cchar_t cc; + wchar_t *lstr, *slstr; + int i, width, len, lx, sx, x, y, tx, ty, cw, pcw, newx, tn, w; wchar_t ws[] = L" "; /* check for leading non-spacing character */ @@ -146,171 +147,259 @@ wins_nwstr(WINDOW *win, const wchar_t *w if (!cw) return ERR; + lstr = malloc(sizeof(wchar_t) * win->maxx); + if (lstr == NULL) + return ERR; + scp = wstr + 1; width = cw; len = 1; n--; + y = win->cury; + x = win->curx; + tn = n; + + /* + * Firstly, make sure the string will fit... + */ while (*scp) { - int w; - if (!n) + if (!tn) break; + switch (*scp) { + case L'\b': + if (--x < 0) + x = 0; + cw = wcwidth(*(scp - 1)); + if (cw < 0) + cw = 1; + width -= cw; + scp++; + continue;; + + case L'\r': + width = 0; + x = 0; + scp++; + continue; + + case L'\n': + if (y == win->scr_b) { + if (!(win->flags & __SCROLLOK)) { + free(lstr); + return ERR; + } + } + y++; + scp++; + continue; + + case L'\t': + w = min(win->maxx - x, TABSIZE - (x % TABSIZE)); + width += w * wcwidth(ws[0]); + x += w * wcwidth(ws[0]); + scp++; + continue; + } w = wcwidth(*scp); if (w < 0) w = 1; - n--, len++, width += w; + tn--, width += w; scp++; } __CTRACE(__CTRACE_INPUT, "wins_nwstr: width=%d,len=%d\n", width, len); - if (cw > win->maxx - win->curx + 1) + if (width > win->maxx - win->curx + 1) { + free(lstr); return ERR; - start = &win->alines[win->cury]->line[win->curx]; - sx = win->curx; - lnp = win->alines[win->cury]; - pcw = WCOL(*start); - if (pcw < 0) { - sx += pcw; - start += pcw; } - __CTRACE(__CTRACE_INPUT, "wins_nwstr: start@(%d)\n", sx); - pcw = WCOL(*start); - lnp->flags |= __ISDIRTY; - newx = sx + win->ch_off; - if (newx < *lnp->firstchp) - *lnp->firstchp = newx; + + scp = wstr; + x = win->curx; + y = win->cury; + len = 0; + width = 0; + slstr = lstr; + + while (*scp && n) { + lstr = slstr; + lx = x; + while (*scp) { + if (!n) + break; + switch (*scp) { + case L'\b': + if (--x < 0) + x = 0; + if (--len < 0) + len = 0; + cw = wcwidth(*(scp - 1)); + if (cw < 0) + cw = 1; + width -= cw; + scp++; + if (lstr != slstr) + lstr--; + continue;; + + case L'\r': + width = 0; + len = 0; + x = 0; + scp++; + lstr = slstr; + continue; + + case L'\n': + goto loopdone; + break; + + case L'\t': + w = min(win->maxx - x, + TABSIZE - (x % TABSIZE)); + width += w * wcwidth(ws[0]); + x += w * wcwidth(ws[0]); + len += w; + scp++; + for (i = 0; i < w; i++ ) { + *lstr = *ws; + lstr++; + } + continue; + } + w = wcwidth(*scp); + if (w < 0) + w = 1; + *lstr = *scp; + n--, len++, width += w; + scp++, lstr++; + } + +loopdone: + start = &win->alines[y]->line[x]; + sx = x; + lnp = win->alines[y]; + pcw = WCOL(*start); + if (pcw < 0) { + sx += pcw; + start += pcw; + } + __CTRACE(__CTRACE_INPUT, "wins_nwstr: start@(%d)\n", sx); + pcw = WCOL(*start); + lnp->flags |= __ISDIRTY; + newx = sx + win->ch_off; + if (newx < *lnp->firstchp) + *lnp->firstchp = newx; #ifdef DEBUG - { - __CTRACE(__CTRACE_INPUT, "========before=======\n"); - for (x = 0; x < win->maxx; x++) + { + __CTRACE(__CTRACE_INPUT, "========before=======\n"); + for (i = 0; i < win->maxx; i++) __CTRACE(__CTRACE_INPUT, - "wins_nwstr: (%d,%d)=(%x,%x,%p)\n", - win->cury, x, - win->alines[win->cury]->line[x].ch, - win->alines[win->cury]->line[x].attr, - win->alines[win->cury]->line[x].nsp); - } + "wins_nwstr: (%d,%d)=(%x,%x,%p)\n", + y, i, win->alines[y]->line[i].ch, + win->alines[y]->line[i].attr, + win->alines[y]->line[i].nsp); + } #endif /* DEBUG */ - /* shift all complete characters */ - if (sx + width + pcw <= win->maxx) { - __CTRACE(__CTRACE_INPUT, "wins_nwstr: shift all characters\n"); - temp1 = &win->alines[win->cury]->line[win->maxx - 1]; - temp2 = temp1 - width; - pcw = WCOL(*(temp2 + 1)); - if (pcw < 0) { - __CTRACE(__CTRACE_INPUT, - "wins_nwstr: clear from %d to EOL(%d)\n", - win->maxx + pcw, win->maxx - 1); - temp2 += pcw; - while (temp1 > temp2 + width) { - temp1->ch = (wchar_t)btowc((int) win->bch); - if (_cursesi_copy_nsp(win->bnsp, temp1) == ERR) - return ERR; - temp1->attr = win->battr; - SET_WCOL(*temp1, 1); + /* shift all complete characters */ + if (sx + width + pcw <= win->maxx) { + __CTRACE(__CTRACE_INPUT, "wins_nwstr: shift all characters by %d\n", width); + temp1 = &win->alines[y]->line[win->maxx - 1]; + temp2 = temp1 - width; + pcw = WCOL(*(temp2 + 1)); + if (pcw < 0) { __CTRACE(__CTRACE_INPUT, - "wins_nwstr: empty cell(%p)\n", temp1); - temp1--; + "wins_nwstr: clear from %d to EOL(%d)\n", + win->maxx + pcw, win->maxx - 1); + temp2 += pcw; + while (temp1 > temp2 + width) { + temp1->ch = (wchar_t)btowc((int) win->bch); + if (_cursesi_copy_nsp(win->bnsp, temp1) == ERR) { + free(lstr); + return ERR; + } + temp1->attr = win->battr; + SET_WCOL(*temp1, 1); + __CTRACE(__CTRACE_INPUT, + "wins_nwstr: empty cell(%p)\n", temp1); + temp1--; + } + } + while (temp2 >= start) { + (void)memcpy(temp1, temp2, sizeof(__LDATA)); + temp1--, temp2--; + } +#ifdef DEBUG + { + __CTRACE(__CTRACE_INPUT, "=====after shift====\n"); + for (i = 0; i < win->maxx; i++) + __CTRACE(__CTRACE_INPUT, + "wins_nwstr: (%d,%d)=(%x,%x,%p)\n", + y, i, + win->alines[y]->line[i].ch, + win->alines[y]->line[i].attr, + win->alines[y]->line[i].nsp); + __CTRACE(__CTRACE_INPUT, "=====lstr====\n"); + for (i = 0; i < len; i++) + __CTRACE(__CTRACE_INPUT, + "wins_nwstr: lstr[%d]= %x,\n", + i, (unsigned) slstr[i]); } +#endif /* DEBUG */ } - while (temp2 >= start) { - (void)memcpy(temp1, temp2, sizeof(__LDATA)); - temp1--, temp2--; + + /* update string columns */ + x = lx; + for (lstr = slstr, temp1 = start; len; len--, lstr++) { + lnp = win->alines[y]; + cc.vals[0] = *lstr; + cc.elements = 1; + cc.attributes = win->wattr; + _cursesi_addwchar(win, &lnp, &y, &x, &cc, 0); } + #ifdef DEBUG { - __CTRACE(__CTRACE_INPUT, "=====after shift====\n"); - for (x = 0; x < win->maxx; x++) + __CTRACE(__CTRACE_INPUT, "lx = %d, x = %x\n", lx, x); + __CTRACE(__CTRACE_INPUT, "========after=======\n"); + for (i = 0; i < win->maxx; i++) __CTRACE(__CTRACE_INPUT, "wins_nwstr: (%d,%d)=(%x,%x,%p)\n", - win->cury, x, - win->alines[win->cury]->line[x].ch, - win->alines[win->cury]->line[x].attr, - win->alines[win->cury]->line[x].nsp); + y, i, + win->alines[y]->line[i].ch, + win->alines[y]->line[i].attr, + win->alines[y]->line[i].nsp); } #endif /* DEBUG */ - } - /* update string columns */ - x = win->curx; - y = win->cury; - for (scp = wstr, temp1 = start; len; len--, scp++) { - switch (*scp) { - case L'\b': - if (--x < 0) - x = 0; - win->curx = x; - continue;; - case L'\r': - win->curx = 0; - continue; - case L'\n': - wclrtoeol(win); - if (y == win->scr_b) { - if (!(win->flags & __SCROLLOK)) - return ERR; - scroll(win); - } - continue; - case L'\t': - if (wins_nwstr(win, ws, - min(win->maxx - x, TABSIZE - (x % TABSIZE))) - == ERR) - return ERR; - continue; - } - cw = wcwidth(*scp); - if (cw < 0) - cw = 1; - if (cw) { - /* 1st column */ - temp1->ch = (wchar_t)*scp; - temp1->attr = win->wattr; - SET_WCOL(*temp1, cw); - temp1->nsp = NULL; - __CTRACE(__CTRACE_INPUT, - "wins_nwstr: add spacing char(%x)\n", temp1->ch); - temp2 = temp1++; - if (cw > 1) { - x = -1; - while (temp1 < temp2 + cw) { - /* the rest columns */ - temp1->ch = (wchar_t)*scp; - temp1->attr = win->wattr; - temp1->nsp = NULL; - SET_WCOL(*temp1, x); - temp1++, x--; - } - temp1--; - } - } else { - /* non-spacing character */ - np = malloc(sizeof(nschar_t)); - if (!np) - return ERR; - np->ch = *scp; - np->next = temp1->nsp; - temp1->nsp = np; - __CTRACE(__CTRACE_INPUT, - "wins_nstr: add non-spacing char(%x)\n", np->ch); + __touchline(win, (int) y, lx, (int) win->maxx - 1); + + /* + * Handle the newline here - we don't need to check + * if we are allowed to scroll because this was checked + * already. + */ + if (*scp == '\n') { + tx = win->curx; + ty = win->cury; + win->curx = x; + win->cury = y; + wclrtoeol(win); + win->curx = tx; + win->cury = ty; + if (y == win->scr_b) + scroll(win); + else + y++; + scp++; + } + + newx = win->maxx - 1 + win->ch_off; + if (newx > *lnp->lastchp) + *lnp->lastchp = newx; } -#ifdef DEBUG - { - __CTRACE(__CTRACE_INPUT, "========after=======\n"); - for (x = 0; x < win->maxx; x++) - __CTRACE(__CTRACE_INPUT, - "wins_nwstr: (%d,%d)=(%x,%x,%p)\n", - win->cury, x, - win->alines[win->cury]->line[x].ch, - win->alines[win->cury]->line[x].attr, - win->alines[win->cury]->line[x].nsp); - } -#endif /* DEBUG */ - newx = win->maxx - 1 + win->ch_off; - if (newx > *lnp->lastchp) - *lnp->lastchp = newx; - __touchline(win, (int) win->cury, sx, (int) win->maxx - 1); + free(lstr); __sync(win); return OK; }