Tue Nov 21 06:35:22 2017 UTC ()
Fix screen corruption by rewriting only a part of a multi-width character.


(rin)
diff -r1.4 -r1.5 src/external/bsd/nvi/dist/vi/v_txt.c

cvs diff -r1.4 -r1.5 src/external/bsd/nvi/dist/vi/v_txt.c (expand / switch to unified diff)

--- src/external/bsd/nvi/dist/vi/v_txt.c 2014/01/26 21:43:45 1.4
+++ src/external/bsd/nvi/dist/vi/v_txt.c 2017/11/21 06:35:22 1.5
@@ -1,32 +1,32 @@ @@ -1,32 +1,32 @@
1/* $NetBSD: v_txt.c,v 1.4 2014/01/26 21:43:45 christos Exp $ */ 1/* $NetBSD: v_txt.c,v 1.5 2017/11/21 06:35:22 rin Exp $ */
2/*- 2/*-
3 * Copyright (c) 1993, 1994 3 * Copyright (c) 1993, 1994
4 * The Regents of the University of California. All rights reserved. 4 * The Regents of the University of California. All rights reserved.
5 * Copyright (c) 1992, 1993, 1994, 1995, 1996 5 * Copyright (c) 1992, 1993, 1994, 1995, 1996
6 * Keith Bostic. All rights reserved. 6 * Keith Bostic. All rights reserved.
7 * 7 *
8 * See the LICENSE file for redistribution information. 8 * See the LICENSE file for redistribution information.
9 */ 9 */
10 10
11#include "config.h" 11#include "config.h"
12 12
13#include <sys/cdefs.h> 13#include <sys/cdefs.h>
14#if 0 14#if 0
15#ifndef lint 15#ifndef lint
16static const char sccsid[] = "Id: v_txt.c,v 10.108 2003/07/18 21:27:42 skimo Exp (Berkeley) Date: 2003/07/18 21:27:42 "; 16static const char sccsid[] = "Id: v_txt.c,v 10.108 2003/07/18 21:27:42 skimo Exp (Berkeley) Date: 2003/07/18 21:27:42 ";
17#endif /* not lint */ 17#endif /* not lint */
18#else 18#else
19__RCSID("$NetBSD: v_txt.c,v 1.4 2014/01/26 21:43:45 christos Exp $"); 19__RCSID("$NetBSD: v_txt.c,v 1.5 2017/11/21 06:35:22 rin Exp $");
20#endif 20#endif
21 21
22#include <sys/types.h> 22#include <sys/types.h>
23#include <sys/queue.h> 23#include <sys/queue.h>
24#include <sys/stat.h> 24#include <sys/stat.h>
25#include <sys/time.h> 25#include <sys/time.h>
26 26
27#include <bitstring.h> 27#include <bitstring.h>
28#include <ctype.h> 28#include <ctype.h>
29#include <errno.h> 29#include <errno.h>
30#include <limits.h> 30#include <limits.h>
31#include <stdio.h> 31#include <stdio.h>
32#include <stdlib.h> 32#include <stdlib.h>
@@ -2265,51 +2265,63 @@ static int @@ -2265,51 +2265,63 @@ static int
2265txt_emark(SCR *sp, TEXT *tp, size_t cno) 2265txt_emark(SCR *sp, TEXT *tp, size_t cno)
2266{ 2266{
2267 CHAR_T ch; 2267 CHAR_T ch;
2268 unsigned char *kp; 2268 unsigned char *kp;
2269 size_t chlen, nlen, olen; 2269 size_t chlen, nlen, olen;
2270 CHAR_T *p; 2270 CHAR_T *p;
2271 2271
2272 ch = CH_ENDMARK; 2272 ch = CH_ENDMARK;
2273 2273
2274 /* 2274 /*
2275 * The end mark may not be the same size as the current character. 2275 * The end mark may not be the same size as the current character.
2276 * Don't let the line shift. 2276 * Don't let the line shift.
2277 */ 2277 */
2278 nlen = KEY_LEN(sp, ch); 2278 nlen = KEY_COL(sp, ch);
2279 if (tp->lb[cno] == '\t') 2279 if (tp->lb[cno] == '\t')
2280 (void)vs_columns(sp, tp->lb, tp->lno, &cno, &olen); 2280 (void)vs_columns(sp, tp->lb, tp->lno, &cno, &olen);
2281 else 2281 else
2282 olen = KEY_LEN(sp, tp->lb[cno]); 2282 olen = KEY_COL(sp, tp->lb[cno]);
2283 2283
2284 /* 2284 /*
2285 * If the line got longer, well, it's weird, but it's easy. If 2285 * If the line got longer, well, it's weird, but it's easy. If
2286 * it's the same length, it's easy. If it got shorter, we have 2286 * it's the same length, it's easy. If it got shorter, we have
2287 * to fix it up. 2287 * to fix it up.
2288 */ 2288 */
2289 if (olen > nlen) { 2289 if (olen > nlen) {
2290 BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + olen); 2290 BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + olen);
2291 chlen = olen - nlen; 2291 chlen = olen - nlen;
2292 if (tp->insert != 0) 2292 if (tp->insert != 0)
2293 MEMMOVEW(tp->lb + cno + 1 + chlen, 2293 MEMMOVEW(tp->lb + cno + 1 + chlen,
2294 tp->lb + cno + 1, tp->insert); 2294 tp->lb + cno + 1, tp->insert);
2295 2295
2296 tp->len += chlen; 2296 tp->len += chlen;
2297 tp->owrite += chlen; 2297 tp->owrite += chlen;
2298 p = tp->lb + cno; 2298 p = tp->lb + cno;
2299 if (tp->lb[cno] == '\t') 2299 if (tp->lb[cno] == '\t')
2300 for (cno += chlen; chlen--;) 2300 for (cno += chlen; chlen--;)
2301 *p++ = ' '; 2301 *p++ = ' ';
2302 else 2302 else if (INTISWIDE(tp->lb[cno])) {
 2303 /*
 2304 * Do not put the end mark on a part of a multi-width
 2305 * char, which results in screen corruption.
 2306 */
 2307 for (; chlen >= nlen; chlen -= nlen) {
 2308 cno++;
 2309 *p++ = ch;
 2310 }
 2311 /* Paranoia: nlen is usually 1. */
 2312 for (cno += chlen; chlen--;)
 2313 *p++ = ' ';
 2314 } else
2303 for (kp = KEY_NAME(sp, tp->lb[cno]), 2315 for (kp = KEY_NAME(sp, tp->lb[cno]),
2304 cno += chlen; chlen--;) 2316 cno += chlen; chlen--;)
2305 *p++ = *kp++; 2317 *p++ = *kp++;
2306 } 2318 }
2307 tp->lb[cno] = ch; 2319 tp->lb[cno] = ch;
2308 return (vs_change(sp, tp->lno, LINE_RESET)); 2320 return (vs_change(sp, tp->lno, LINE_RESET));
2309} 2321}
2310 2322
2311/* 2323/*
2312 * txt_err -- 2324 * txt_err --
2313 * Handle an error during input processing. 2325 * Handle an error during input processing.
2314 */ 2326 */
2315static void 2327static void
@@ -2447,61 +2459,66 @@ txt_insch(SCR *sp, TEXT *tp, ARG_CHAR_T  @@ -2447,61 +2459,66 @@ txt_insch(SCR *sp, TEXT *tp, ARG_CHAR_T
2447 cno = tp->cno; 2459 cno = tp->cno;
2448 2460
2449 /* 2461 /*
2450 * If the old or new characters are tabs, then the length of the 2462 * If the old or new characters are tabs, then the length of the
2451 * display depends on the character position in the display. We 2463 * display depends on the character position in the display. We
2452 * don't even try to handle this here, just ask the screen. 2464 * don't even try to handle this here, just ask the screen.
2453 */ 2465 */
2454 if (*chp == '\t') { 2466 if (*chp == '\t') {
2455 savech = tp->lb[cno]; 2467 savech = tp->lb[cno];
2456 tp->lb[cno] = '\t'; 2468 tp->lb[cno] = '\t';
2457 (void)vs_columns(sp, tp->lb, tp->lno, &cno, &nlen); 2469 (void)vs_columns(sp, tp->lb, tp->lno, &cno, &nlen);
2458 tp->lb[cno] = savech; 2470 tp->lb[cno] = savech;
2459 } else 2471 } else
2460 nlen = KEY_LEN(sp, *chp); 2472 nlen = KEY_COL(sp, *chp);
2461 2473
2462 /* 2474 /*
2463 * Eat overwrite characters until we run out of them or we've 2475 * Eat overwrite characters until we run out of them or we've
2464 * handled the length of the new character. If we only eat 2476 * handled the length of the new character. If we only eat
2465 * part of an overwrite character, break it into its component 2477 * part of an overwrite character, break it into its component
2466 * elements and display the remaining components. 2478 * elements and display the remaining components.
2467 */ 2479 */
2468 for (copydown = 0; nlen != 0 && tp->owrite != 0;) { 2480 for (copydown = 0; nlen != 0 && tp->owrite != 0;) {
2469 --tp->owrite; 2481 --tp->owrite;
2470 2482
2471 if (tp->lb[cno] == '\t') 2483 if (tp->lb[cno] == '\t')
2472 (void)vs_columns(sp, 2484 (void)vs_columns(sp,
2473 tp->lb, tp->lno, &cno, &olen); 2485 tp->lb, tp->lno, &cno, &olen);
2474 else 2486 else
2475 olen = KEY_LEN(sp, tp->lb[cno]); 2487 olen = KEY_COL(sp, tp->lb[cno]);
2476 2488
2477 if (olen == nlen) { 2489 if (olen == nlen) {
2478 nlen = 0; 2490 nlen = 0;
2479 break; 2491 break;
2480 } 2492 }
2481 if (olen < nlen) { 2493 if (olen < nlen) {
2482 ++copydown; 2494 ++copydown;
2483 nlen -= olen; 2495 nlen -= olen;
2484 } else { 2496 } else {
2485 BINC_RETW(sp, 2497 BINC_RETW(sp,
2486 tp->lb, tp->lb_len, tp->len + olen); 2498 tp->lb, tp->lb_len, tp->len + olen);
2487 chlen = olen - nlen; 2499 chlen = olen - nlen;
2488 MEMMOVEW(tp->lb + cno + 1 + chlen, 2500 MEMMOVEW(tp->lb + cno + 1 + chlen,
2489 tp->lb + cno + 1,  2501 tp->lb + cno + 1,
2490 tp->owrite + tp->insert); 2502 tp->owrite + tp->insert);
2491 2503
2492 tp->len += chlen; 2504 tp->len += chlen;
2493 tp->owrite += chlen; 2505 tp->owrite += chlen;
2494 if (tp->lb[cno] == '\t') 2506 /*
 2507 * Do not rewrite a part of a multi-width char,
 2508 * which results in screen corruption.
 2509 */
 2510 if (tp->lb[cno] == '\t'
 2511 || INTISWIDE(tp->lb[cno]))
2495 for (p = tp->lb + cno + 1; chlen--;) 2512 for (p = tp->lb + cno + 1; chlen--;)
2496 *p++ = ' '; 2513 *p++ = ' ';
2497 else 2514 else
2498 for (kp = 2515 for (kp =
2499 KEY_NAME(sp, tp->lb[cno]) + nlen, 2516 KEY_NAME(sp, tp->lb[cno]) + nlen,
2500 p = tp->lb + cno + 1; chlen--;) 2517 p = tp->lb + cno + 1; chlen--;)
2501 *p++ = *kp++; 2518 *p++ = *kp++;
2502 nlen = 0; 2519 nlen = 0;
2503 break; 2520 break;
2504 } 2521 }
2505 } 2522 }
2506 2523
2507 /* 2524 /*