The diff below includes a change that shouldn't be there.  The following
is wrong:

        /* Flush the cache, update line count, before screen update. */
  -     if (lno >= ep->c_lno)
  +     if (lno <= ep->c_lno)


That's from something I wrongly changed at some point and forgot to
undo, and slipped in the final diff.  At bottom I include the updated
version of this diff.


On Fri, May 22, 2026 at 09:26:00AM +0200, Walter Alejandro Iglesias wrote:
> DEEPER SOLUTION:
> 
> The diff at bottom is extensive, but a deeper solution.  It uses realloc
> and memcpy to create a private copy of the data.  This is somewhat
> closer to what nvi2 from ports does, where this bug is fixed
> (accidentally?) by this intermediate translation layer for wide chars
> support:
> 
>       if (FILE2INT(sp, data.data, data.size, wp, wlen)) {
>           if (!F_ISSET(sp, SC_CONV_ERROR)) {
>               F_SET(sp, SC_CONV_ERROR);
>               msgq(sp, M_ERR, "324|Conversion error on line %d", lno);
>           }
>           goto err3;
>       }
> 
>       /* Reset the cache. */
>       if (wp != data.data) {
>           BINC_GOTOW(sp, sp->c_lp, sp->c_blen, wlen);
>           MEMCPYW(sp->c_lp, wp, wlen);
>       }
>       sp->c_lno = lno;
>       sp->c_len = wlen;
> 
> 
> Index: common/exf.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/vi/common/exf.c,v
> diff -u -p -u -p -r1.51 exf.c
> --- common/exf.c      20 Apr 2026 10:30:02 -0000      1.51
> +++ common/exf.c      4 May 2026 13:25:07 -0000
> @@ -434,6 +434,11 @@ oerr:    if (F_ISSET(ep, F_RCV_ON))
>       ep->rcv_path = NULL;
>       if (ep->db != NULL)
>               (void)ep->db->close(ep->db);
> +
> +     /* Free the private cache buffer. */
> +     if (ep->c_buf != NULL)
> +             free(ep->c_buf);
> +
>       free(ep);
>  
>       return (open_err ?
> @@ -715,6 +720,11 @@ file_end(SCR *sp, EXF *ep, int force)
>               (void)close(ep->rcv_fd);
>       free(ep->rcv_path);
>       free(ep->rcv_mpath);
> +
> +     /* Free the private cache buffer. */
> +     if (ep->c_buf != NULL)
> +             free(ep->c_buf);
> +
>       free(ep);
>       return (0);
>  }
> Index: common/exf.h
> ===================================================================
> RCS file: /cvs/src/usr.bin/vi/common/exf.h,v
> diff -u -p -u -p -r1.6 exf.h
> --- common/exf.h      20 Feb 2022 19:45:51 -0000      1.6
> +++ common/exf.h      4 May 2026 13:25:07 -0000
> @@ -24,7 +24,8 @@ struct _exf {
>       size_t   c_len;                 /* Cached line length. */
>       recno_t  c_lno;                 /* Cached line number. */
>       recno_t  c_nlines;              /* Cached lines in the file. */
> -
> +     char    *c_buf;                 /* Buffer used to reset cache */
> +     size_t   c_buf_len;             /* Length of buffer used to reset cache 
> */
>       DB      *log;                   /* Log db structure. */
>       char    *l_lp;                  /* Log buffer. */
>       size_t   l_len;                 /* Log buffer length. */
> Index: common/line.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/vi/common/line.c,v
> diff -u -p -u -p -r1.18 line.c
> --- common/line.c     20 Apr 2026 10:30:02 -0000      1.18
> +++ common/line.c     4 May 2026 13:25:07 -0000
> @@ -19,6 +19,7 @@
>  #include <errno.h>
>  #include <limits.h>
>  #include <stdio.h>
> +#include <stdlib.h>
>  #include <string.h>
>  
>  #include "common.h"
> @@ -156,9 +157,8 @@ err3:             if (lenp != NULL)
>       }
>  
>       /* Reset the cache. */
> -     ep->c_lno = lno;
> -     ep->c_len = data.size;
> -     ep->c_lp = data.data;
> +     if (db_cache_update(sp, ep, lno, data.data, data.size))
> +             goto err3;
>  
>  #if defined(DEBUG) && 0
>       TRACE(sp, "retrieve DB line %lu\n", (u_long)lno);
> @@ -326,7 +326,7 @@ db_insert(SCR *sp, recno_t lno, char *p,
>       }
>  
>       /* Flush the cache, update line count, before screen update. */
> -     if (lno >= ep->c_lno)
> +     if (lno <= ep->c_lno)
>               ep->c_lno = OOBLNO;
>       if (ep->c_nlines != OOBLNO)
>               ++ep->c_nlines;
> @@ -484,9 +484,9 @@ db_last(SCR *sp, recno_t *lnop)
>  
>       /* Fill the cache. */
>       memcpy(&lno, key.data, sizeof(lno));
> +     if (db_cache_update(sp, ep, lno, data.data, data.size))
> +             return (1);
>       ep->c_nlines = ep->c_lno = lno;
> -     ep->c_len = data.size;
> -     ep->c_lp = data.data;
>  
>       /* Return the value. */
>       *lnop = (F_ISSET(sp, SC_TINPUT) &&
> @@ -529,4 +529,30 @@ scr_update(SCR *sp, recno_t lno, lnop_t 
>                               if (vs_change(tsp, lno, op))
>                                       return (1);
>       return (current ? vs_change(sp, lno, op) : 0);
> +}
> +
> +/*
> + * db_cache_update --
> + *   Update the line cache with a private copy of the data.
> + */
> +int
> +db_cache_update(SCR *sp, EXF *ep, recno_t lno, void *data, size_t size)
> +{
> +     if (size > ep->c_buf_len) {
> +             REALLOC(sp, ep->c_buf, size);
> +             if (ep->c_buf == NULL) {
> +                     ep->c_buf_len = 0;
> +                     ep->c_lp = NULL;
> +                     ep->c_lno = OOBLNO;
> +                     return (1);
> +             }
> +             ep->c_buf_len = size;
> +     }
> +     if (size > 0)
> +             memcpy(ep->c_buf, data, size);
> +
> +     ep->c_lno = lno;
> +     ep->c_len = size;
> +     ep->c_lp = ep->c_buf;
> +     return (0);
>  }
> Index: include/com_extern.h
> ===================================================================
> RCS file: /cvs/src/usr.bin/vi/include/com_extern.h,v
> diff -u -p -u -p -r1.17 com_extern.h
> --- include/com_extern.h      23 Aug 2025 21:02:10 -0000      1.17
> +++ include/com_extern.h      4 May 2026 13:25:07 -0000
> @@ -34,6 +34,7 @@ int db_insert(SCR *, recno_t, char *, si
>  int db_set(SCR *, recno_t, char *, size_t);
>  int db_exist(SCR *, recno_t);
>  int db_last(SCR *, recno_t *);
> +int db_cache_update(SCR *, EXF *, recno_t, void *, size_t);
>  void db_err(SCR *, recno_t);
>  int log_init(SCR *, EXF *);
>  int log_end(SCR *, EXF *);
> 
> 


Corrected version:

Index: common/exf.c
===================================================================
RCS file: /cvs/src/usr.bin/vi/common/exf.c,v
diff -u -p -u -p -r1.51 exf.c
--- common/exf.c        20 Apr 2026 10:30:02 -0000      1.51
+++ common/exf.c        17 Jun 2026 12:21:11 -0000
@@ -434,6 +434,11 @@ oerr:      if (F_ISSET(ep, F_RCV_ON))
        ep->rcv_path = NULL;
        if (ep->db != NULL)
                (void)ep->db->close(ep->db);
+
+       /* Free the private cache buffer. */
+       if (ep->c_buf != NULL)
+               free(ep->c_buf);
+
        free(ep);
 
        return (open_err ?
@@ -715,6 +720,11 @@ file_end(SCR *sp, EXF *ep, int force)
                (void)close(ep->rcv_fd);
        free(ep->rcv_path);
        free(ep->rcv_mpath);
+
+       /* Free the private cache buffer. */
+       if (ep->c_buf != NULL)
+               free(ep->c_buf);
+
        free(ep);
        return (0);
 }
Index: common/exf.h
===================================================================
RCS file: /cvs/src/usr.bin/vi/common/exf.h,v
diff -u -p -u -p -r1.6 exf.h
--- common/exf.h        20 Feb 2022 19:45:51 -0000      1.6
+++ common/exf.h        17 Jun 2026 12:21:11 -0000
@@ -24,7 +24,8 @@ struct _exf {
        size_t   c_len;                 /* Cached line length. */
        recno_t  c_lno;                 /* Cached line number. */
        recno_t  c_nlines;              /* Cached lines in the file. */
-
+       char    *c_buf;                 /* Buffer used to reset cache */
+       size_t   c_buf_len;             /* Length of buffer used to reset cache 
*/
        DB      *log;                   /* Log db structure. */
        char    *l_lp;                  /* Log buffer. */
        size_t   l_len;                 /* Log buffer length. */
Index: common/line.c
===================================================================
RCS file: /cvs/src/usr.bin/vi/common/line.c,v
diff -u -p -u -p -r1.18 line.c
--- common/line.c       20 Apr 2026 10:30:02 -0000      1.18
+++ common/line.c       17 Jun 2026 12:21:11 -0000
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "common.h"
@@ -156,9 +157,8 @@ err3:               if (lenp != NULL)
        }
 
        /* Reset the cache. */
-       ep->c_lno = lno;
-       ep->c_len = data.size;
-       ep->c_lp = data.data;
+       if (db_cache_update(sp, ep, lno, data.data, data.size))
+               goto err3;
 
 #if defined(DEBUG) && 0
        TRACE(sp, "retrieve DB line %lu\n", (u_long)lno);
@@ -484,9 +484,9 @@ db_last(SCR *sp, recno_t *lnop)
 
        /* Fill the cache. */
        memcpy(&lno, key.data, sizeof(lno));
+       if (db_cache_update(sp, ep, lno, data.data, data.size))
+               return (1);
        ep->c_nlines = ep->c_lno = lno;
-       ep->c_len = data.size;
-       ep->c_lp = data.data;
 
        /* Return the value. */
        *lnop = (F_ISSET(sp, SC_TINPUT) &&
@@ -529,4 +529,30 @@ scr_update(SCR *sp, recno_t lno, lnop_t 
                                if (vs_change(tsp, lno, op))
                                        return (1);
        return (current ? vs_change(sp, lno, op) : 0);
+}
+
+/*
+ * db_cache_update --
+ *     Update the line cache with a private copy of the data.
+ */
+int
+db_cache_update(SCR *sp, EXF *ep, recno_t lno, void *data, size_t size)
+{
+       if (size > ep->c_buf_len) {
+               REALLOC(sp, ep->c_buf, size);
+               if (ep->c_buf == NULL) {
+                       ep->c_buf_len = 0;
+                       ep->c_lp = NULL;
+                       ep->c_lno = OOBLNO;
+                       return (1);
+               }
+               ep->c_buf_len = size;
+       }
+       if (size > 0)
+               memcpy(ep->c_buf, data, size);
+
+       ep->c_lno = lno;
+       ep->c_len = size;
+       ep->c_lp = ep->c_buf;
+       return (0);
 }
Index: include/com_extern.h
===================================================================
RCS file: /cvs/src/usr.bin/vi/include/com_extern.h,v
diff -u -p -u -p -r1.17 com_extern.h
--- include/com_extern.h        23 Aug 2025 21:02:10 -0000      1.17
+++ include/com_extern.h        17 Jun 2026 12:21:11 -0000
@@ -34,6 +34,7 @@ int db_insert(SCR *, recno_t, char *, si
 int db_set(SCR *, recno_t, char *, size_t);
 int db_exist(SCR *, recno_t);
 int db_last(SCR *, recno_t *);
+int db_cache_update(SCR *, EXF *, recno_t, void *, size_t);
 void db_err(SCR *, recno_t);
 int log_init(SCR *, EXF *);
 int log_end(SCR *, EXF *);



-- 
Walter

Reply via email to