Patch 8.1.1727
Problem:    Code for viminfo support is spread out.
Solution:   Move to code to viminfo.c. (Yegappan Lakshmanan, closes #4686)
Files:      Filelist, src/Make_cyg_ming.mak, src/Make_morph.mak,
            src/Make_mvc.mak, src/Make_vms.mms, src/Makefile, src/buffer.c,
            src/eval.c, src/ex_cmds.c, src/ex_docmd.c, src/globals.h,
            src/proto.h, src/proto/buffer.pro, src/proto/eval.pro,
            src/proto/ex_cmds.pro, src/proto/viminfo.pro, src/structs.h,
            src/viminfo.c


*** ../vim-8.1.1726/Filelist    2019-07-14 21:29:04.554965965 +0200
--- Filelist    2019-07-21 18:56:45.345367795 +0200
***************
*** 110,115 ****
--- 110,116 ----
                src/version.c \
                src/version.h \
                src/vim.h \
+               src/viminfo.c \
                src/winclip.c \
                src/window.c \
                src/tee/tee.c \
***************
*** 234,239 ****
--- 235,241 ----
                src/proto/usercmd.pro \
                src/proto/userfunc.pro \
                src/proto/version.pro \
+               src/proto/viminfo.pro \
                src/proto/winclip.pro \
                src/proto/window.pro \
                src/libvterm/.bzrignore \
*** ../vim-8.1.1726/src/Make_cyg_ming.mak       2019-07-14 21:29:04.554965965 
+0200
--- src/Make_cyg_ming.mak       2019-07-21 18:56:45.345367795 +0200
***************
*** 772,777 ****
--- 772,778 ----
        $(OUTDIR)/usercmd.o \
        $(OUTDIR)/userfunc.o \
        $(OUTDIR)/version.o \
+       $(OUTDIR)/viminfo.o \
        $(OUTDIR)/winclip.o \
        $(OUTDIR)/window.o
  
*** ../vim-8.1.1726/src/Make_morph.mak  2019-07-14 21:29:04.554965965 +0200
--- src/Make_morph.mak  2019-07-21 18:56:45.345367795 +0200
***************
*** 89,94 ****
--- 89,95 ----
        usercmd.c                                               \
        userfunc.c                                              \
        version.c                                               \
+       viminfo.c                                               \
        window.c                                                \
  
  OBJ = $(SRC:.c=.o)
*** ../vim-8.1.1726/src/Make_mvc.mak    2019-07-15 21:15:02.218999423 +0200
--- src/Make_mvc.mak    2019-07-21 18:56:45.345367795 +0200
***************
*** 780,785 ****
--- 780,786 ----
        $(OUTDIR)\undo.obj \
        $(OUTDIR)\usercmd.obj \
        $(OUTDIR)\userfunc.obj \
+       $(OUTDIR)\viminfo.obj \
        $(OUTDIR)\winclip.obj \
        $(OUTDIR)\window.obj \
  
***************
*** 1643,1648 ****
--- 1644,1651 ----
  
  $(OUTDIR)/userfunc.obj:       $(OUTDIR) userfunc.c  $(INCL)
  
+ $(OUTDIR)/viminfo.obj:        $(OUTDIR) viminfo.c  $(INCL)
+ 
  $(OUTDIR)/window.obj: $(OUTDIR) window.c  $(INCL)
  
  $(OUTDIR)/xpm_w32.obj: $(OUTDIR) xpm_w32.c
***************
*** 1798,1803 ****
--- 1801,1807 ----
        proto/undo.pro \
        proto/usercmd.pro \
        proto/userfunc.pro \
+       proto/viminfo.pro \
        proto/window.pro \
        $(SOUND_PRO) \
        $(NETBEANS_PRO) \
*** ../vim-8.1.1726/src/Make_vms.mms    2019-07-14 21:29:04.554965965 +0200
--- src/Make_vms.mms    2019-07-21 18:56:45.345367795 +0200
***************
*** 316,323 ****
        misc2.c move.c normal.c ops.c option.c popupmnu.c popupwin.c \
        profiler.c quickfix.c regexp.c search.c sha256.c sign.c spell.c \
        spellfile.c syntax.c tag.c term.c termlib.c testing.c textprop.c ui.c \
!       undo.c usercmd.c userfunc.c version.c screen.c window.c os_unix.c \
!       os_vms.c pathdef.c \
        $(GUI_SRC) $(PERL_SRC) $(PYTHON_SRC) $(TCL_SRC) \
        $(RUBY_SRC) $(HANGULIN_SRC) $(MZSCH_SRC) $(XDIFF_SRC)
  
--- 316,323 ----
        misc2.c move.c normal.c ops.c option.c popupmnu.c popupwin.c \
        profiler.c quickfix.c regexp.c search.c sha256.c sign.c spell.c \
        spellfile.c syntax.c tag.c term.c termlib.c testing.c textprop.c ui.c \
!       undo.c usercmd.c userfunc.c version.c viminfo.c screen.c window.c \
!       os_unix.c os_vms.c pathdef.c \
        $(GUI_SRC) $(PERL_SRC) $(PYTHON_SRC) $(TCL_SRC) \
        $(RUBY_SRC) $(HANGULIN_SRC) $(MZSCH_SRC) $(XDIFF_SRC)
  
***************
*** 332,338 ****
        popupmnu.obj popupwin.obj profiler.obj quickfix.obj regexp.obj \
        search.obj sha256.obj sign.obj spell.obj spellfile.obj syntax.obj \
        tag.obj term.obj termlib.obj testing.obj textprop.obj ui.obj undo.obj \
!       usercmd.obj userfunc.obj screen.obj version.obj window.obj \
        os_unix.obj os_vms.obj pathdef.obj if_mzsch.obj \
        $(GUI_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(TCL_OBJ) \
        $(RUBY_OBJ) $(HANGULIN_OBJ) $(MZSCH_OBJ) $(XDIFF_OBJ)
--- 332,338 ----
        popupmnu.obj popupwin.obj profiler.obj quickfix.obj regexp.obj \
        search.obj sha256.obj sign.obj spell.obj spellfile.obj syntax.obj \
        tag.obj term.obj termlib.obj testing.obj textprop.obj ui.obj undo.obj \
!       usercmd.obj userfunc.obj screen.obj version.obj viminfo.obj window.obj \
        os_unix.obj os_vms.obj pathdef.obj if_mzsch.obj \
        $(GUI_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(TCL_OBJ) \
        $(RUBY_OBJ) $(HANGULIN_OBJ) $(MZSCH_OBJ) $(XDIFF_OBJ)
***************
*** 780,785 ****
--- 780,789 ----
   ascii.h keymap.h term.h macros.h structs.h regexp.h \
   gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
   globals.h version.h
+ viminfo.obj : viminfo.c vim.h [.auto]config.h feature.h os_unix.h \
+  ascii.h keymap.h term.h macros.h structs.h regexp.h \
+  gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+  globals.h version.h
  window.obj : window.c vim.h [.auto]config.h feature.h os_unix.h \
   ascii.h keymap.h term.h macros.h structs.h regexp.h \
   gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
*** ../vim-8.1.1726/src/Makefile        2019-07-14 21:29:04.554965965 +0200
--- src/Makefile        2019-07-21 18:56:45.345367795 +0200
***************
*** 1650,1655 ****
--- 1650,1656 ----
        usercmd.c \
        userfunc.c \
        version.c \
+       viminfo.c \
        window.c \
        $(OS_EXTRA_SRC)
  
***************
*** 1769,1774 ****
--- 1770,1776 ----
        objects/usercmd.o \
        objects/userfunc.o \
        objects/version.o \
+       objects/viminfo.o \
        objects/window.o \
        $(GUI_OBJ) \
        $(TERM_OBJ) \
***************
*** 1914,1919 ****
--- 1916,1922 ----
        usercmd.pro \
        userfunc.pro \
        version.pro \
+       viminfo.pro \
        window.pro \
        beval.pro \
        gui_beval.pro \
***************
*** 3298,3303 ****
--- 3301,3309 ----
  objects/userfunc.o: userfunc.c
        $(CCC) -o $@ userfunc.c
  
+ objects/viminfo.o: viminfo.c
+       $(CCC) -o $@ viminfo.c
+ 
  objects/window.o: window.c
        $(CCC) -o $@ window.c
  
***************
*** 3746,3751 ****
--- 3752,3761 ----
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
   proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
   proto.h globals.h version.h
+ objects/viminfo.o: viminfo.c vim.h protodef.h auto/config.h feature.h \
+  os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+  proto.h globals.h
  objects/window.o: window.c vim.h protodef.h auto/config.h feature.h os_unix.h 
\
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
   proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
*** ../vim-8.1.1726/src/buffer.c        2019-06-30 22:16:06.927821778 +0200
--- src/buffer.c        2019-07-21 18:56:45.345367795 +0200
***************
*** 29,35 ****
  
  static char_u *buflist_match(regmatch_T *rmp, buf_T *buf, int ignore_case);
  static char_u *fname_match(regmatch_T *rmp, char_u *name, int ignore_case);
- static void   buflist_setfpos(buf_T *buf, win_T *win, linenr_T lnum, colnr_T 
col, int copy_options);
  #ifdef UNIX
  static buf_T  *buflist_findname_stat(char_u *ffname, stat_T *st);
  static int    otherfile_buf(buf_T *buf, char_u *ffname, stat_T *stp);
--- 29,34 ----
***************
*** 449,455 ****
            }
      }
      if (!can_unload)
!       emsg(_("E937: Attempt to delete a buffer that is in use"));
      return can_unload;
  }
  
--- 448,455 ----
            }
      }
      if (!can_unload)
!       semsg(_("E937: Attempt to delete a buffer that is in use: %s"),
!                                                                buf->b_fname);
      return can_unload;
  }
  
***************
*** 2774,2780 ****
   * When "copy_options" is TRUE save the local window option values.
   * When "lnum" is 0 only do the options.
   */
!     static void
  buflist_setfpos(
      buf_T     *buf,
      win_T     *win,
--- 2774,2780 ----
   * When "copy_options" is TRUE save the local window option values.
   * When "lnum" is 0 only do the options.
   */
!     void
  buflist_setfpos(
      buf_T     *buf,
      win_T     *win,
***************
*** 5545,5656 ****
      return retval;
  }
  
- #if defined(FEAT_VIMINFO) || defined(PROTO)
-     int
- read_viminfo_bufferlist(
-     vir_T     *virp,
-     int               writing)
- {
-     char_u    *tab;
-     linenr_T  lnum;
-     colnr_T   col;
-     buf_T     *buf;
-     char_u    *sfname;
-     char_u    *xline;
- 
-     /* Handle long line and escaped characters. */
-     xline = viminfo_readstring(virp, 1, FALSE);
- 
-     /* don't read in if there are files on the command-line or if writing: */
-     if (xline != NULL && !writing && ARGCOUNT == 0
-                                      && find_viminfo_parameter('%') != NULL)
-     {
-       /* Format is: <fname> Tab <lnum> Tab <col>.
-        * Watch out for a Tab in the file name, work from the end. */
-       lnum = 0;
-       col = 0;
-       tab = vim_strrchr(xline, '\t');
-       if (tab != NULL)
-       {
-           *tab++ = '\0';
-           col = (colnr_T)atoi((char *)tab);
-           tab = vim_strrchr(xline, '\t');
-           if (tab != NULL)
-           {
-               *tab++ = '\0';
-               lnum = atol((char *)tab);
-           }
-       }
- 
-       /* Expand "~/" in the file name at "line + 1" to a full path.
-        * Then try shortening it by comparing with the current directory */
-       expand_env(xline, NameBuff, MAXPATHL);
-       sfname = shorten_fname1(NameBuff);
- 
-       buf = buflist_new(NameBuff, sfname, (linenr_T)0, BLN_LISTED);
-       if (buf != NULL)        /* just in case... */
-       {
-           buf->b_last_cursor.lnum = lnum;
-           buf->b_last_cursor.col = col;
-           buflist_setfpos(buf, curwin, lnum, col, FALSE);
-       }
-     }
-     vim_free(xline);
- 
-     return viminfo_readline(virp);
- }
- 
-     void
- write_viminfo_bufferlist(FILE *fp)
- {
-     buf_T     *buf;
-     win_T     *win;
-     tabpage_T *tp;
-     char_u    *line;
-     int               max_buffers;
- 
-     if (find_viminfo_parameter('%') == NULL)
-       return;
- 
-     /* Without a number -1 is returned: do all buffers. */
-     max_buffers = get_viminfo_parameter('%');
- 
-     /* Allocate room for the file name, lnum and col. */
- #define LINE_BUF_LEN (MAXPATHL + 40)
-     line = alloc(LINE_BUF_LEN);
-     if (line == NULL)
-       return;
- 
-     FOR_ALL_TAB_WINDOWS(tp, win)
-       set_last_cursor(win);
- 
-     fputs(_("\n# Buffer list:\n"), fp);
-     FOR_ALL_BUFFERS(buf)
-     {
-       if (buf->b_fname == NULL
-               || !buf->b_p_bl
- #ifdef FEAT_QUICKFIX
-               || bt_quickfix(buf)
- #endif
- #ifdef FEAT_TERMINAL
-               || bt_terminal(buf)
- #endif
-               || removable(buf->b_ffname))
-           continue;
- 
-       if (max_buffers-- == 0)
-           break;
-       putc('%', fp);
-       home_replace(NULL, buf->b_ffname, line, MAXPATHL, TRUE);
-       vim_snprintf_add((char *)line, LINE_BUF_LEN, "\t%ld\t%d",
-                       (long)buf->b_last_cursor.lnum,
-                       buf->b_last_cursor.col);
-       viminfo_writestring(fp, line);
-     }
-     vim_free(line);
- }
- #endif
- 
  /*
   * Return TRUE if "buf" is a normal buffer, 'buftype' is empty.
   */
--- 5545,5550 ----
*** ../vim-8.1.1726/src/eval.c  2019-07-21 14:14:22.796237688 +0200
--- src/eval.c  2019-07-21 18:56:45.349367775 +0200
***************
*** 36,42 ****
  #define NAMESPACE_CHAR        (char_u *)"abglstvw"
  
  static dictitem_T     globvars_var;           /* variable used for g: */
- #define globvarht globvardict.dv_hashtab
  
  /*
   * Old Vim variables such as "v:version" are also available without the "v:".
--- 36,41 ----
***************
*** 9321,9334 ****
  }
  
  #if defined(FEAT_VIMINFO) || defined(FEAT_SESSION)
! typedef enum
! {
!     VAR_FLAVOUR_DEFAULT,      /* doesn't start with uppercase */
!     VAR_FLAVOUR_SESSION,      /* starts with uppercase, some lower */
!     VAR_FLAVOUR_VIMINFO               /* all uppercase */
! } var_flavour_T;
! 
!     static var_flavour_T
  var_flavour(char_u *varname)
  {
      char_u *p = varname;
--- 9320,9326 ----
  }
  
  #if defined(FEAT_VIMINFO) || defined(FEAT_SESSION)
!     var_flavour_T
  var_flavour(char_u *varname)
  {
      char_u *p = varname;
***************
*** 9345,9505 ****
  }
  #endif
  
- #if defined(FEAT_VIMINFO) || defined(PROTO)
- /*
-  * Restore global vars that start with a capital from the viminfo file
-  */
-     int
- read_viminfo_varlist(vir_T *virp, int writing)
- {
-     char_u    *tab;
-     int               type = VAR_NUMBER;
-     typval_T  tv;
-     funccal_entry_T funccal_entry;
- 
-     if (!writing && (find_viminfo_parameter('!') != NULL))
-     {
-       tab = vim_strchr(virp->vir_line + 1, '\t');
-       if (tab != NULL)
-       {
-           *tab++ = '\0';      /* isolate the variable name */
-           switch (*tab)
-           {
-               case 'S': type = VAR_STRING; break;
- #ifdef FEAT_FLOAT
-               case 'F': type = VAR_FLOAT; break;
- #endif
-               case 'D': type = VAR_DICT; break;
-               case 'L': type = VAR_LIST; break;
-               case 'B': type = VAR_BLOB; break;
-               case 'X': type = VAR_SPECIAL; break;
-           }
- 
-           tab = vim_strchr(tab, '\t');
-           if (tab != NULL)
-           {
-               tv.v_type = type;
-               if (type == VAR_STRING || type == VAR_DICT
-                       || type == VAR_LIST || type == VAR_BLOB)
-                   tv.vval.v_string = viminfo_readstring(virp,
-                                      (int)(tab - virp->vir_line + 1), TRUE);
- #ifdef FEAT_FLOAT
-               else if (type == VAR_FLOAT)
-                   (void)string2float(tab + 1, &tv.vval.v_float);
- #endif
-               else
-                   tv.vval.v_number = atol((char *)tab + 1);
-               if (type == VAR_DICT || type == VAR_LIST)
-               {
-                   typval_T *etv = eval_expr(tv.vval.v_string, NULL);
- 
-                   if (etv == NULL)
-                       /* Failed to parse back the dict or list, use it as a
-                        * string. */
-                       tv.v_type = VAR_STRING;
-                   else
-                   {
-                       vim_free(tv.vval.v_string);
-                       tv = *etv;
-                       vim_free(etv);
-                   }
-               }
-               else if (type == VAR_BLOB)
-               {
-                   blob_T *blob = string2blob(tv.vval.v_string);
- 
-                   if (blob == NULL)
-                       // Failed to parse back the blob, use it as a string.
-                       tv.v_type = VAR_STRING;
-                   else
-                   {
-                       vim_free(tv.vval.v_string);
-                       tv.v_type = VAR_BLOB;
-                       tv.vval.v_blob = blob;
-                   }
-               }
- 
-               /* when in a function use global variables */
-               save_funccal(&funccal_entry);
-               set_var(virp->vir_line + 1, &tv, FALSE);
-               restore_funccal();
- 
-               if (tv.v_type == VAR_STRING)
-                   vim_free(tv.vval.v_string);
-               else if (tv.v_type == VAR_DICT || tv.v_type == VAR_LIST ||
-                       tv.v_type == VAR_BLOB)
-                   clear_tv(&tv);
-           }
-       }
-     }
- 
-     return viminfo_readline(virp);
- }
- 
- /*
-  * Write global vars that start with a capital to the viminfo file
-  */
-     void
- write_viminfo_varlist(FILE *fp)
- {
-     hashitem_T        *hi;
-     dictitem_T        *this_var;
-     int               todo;
-     char      *s = "";
-     char_u    *p;
-     char_u    *tofree;
-     char_u    numbuf[NUMBUFLEN];
- 
-     if (find_viminfo_parameter('!') == NULL)
-       return;
- 
-     fputs(_("\n# global variables:\n"), fp);
- 
-     todo = (int)globvarht.ht_used;
-     for (hi = globvarht.ht_array; todo > 0; ++hi)
-     {
-       if (!HASHITEM_EMPTY(hi))
-       {
-           --todo;
-           this_var = HI2DI(hi);
-           if (var_flavour(this_var->di_key) == VAR_FLAVOUR_VIMINFO)
-           {
-               switch (this_var->di_tv.v_type)
-               {
-                   case VAR_STRING: s = "STR"; break;
-                   case VAR_NUMBER: s = "NUM"; break;
-                   case VAR_FLOAT:  s = "FLO"; break;
-                   case VAR_DICT:   s = "DIC"; break;
-                   case VAR_LIST:   s = "LIS"; break;
-                   case VAR_BLOB:   s = "BLO"; break;
-                   case VAR_SPECIAL: s = "XPL"; break;
- 
-                   case VAR_UNKNOWN:
-                   case VAR_FUNC:
-                   case VAR_PARTIAL:
-                   case VAR_JOB:
-                   case VAR_CHANNEL:
-                                    continue;
-               }
-               fprintf(fp, "!%s\t%s\t", this_var->di_key, s);
-               if (this_var->di_tv.v_type == VAR_SPECIAL)
-               {
-                   sprintf((char *)numbuf, "%ld",
-                                         (long)this_var->di_tv.vval.v_number);
-                   p = numbuf;
-                   tofree = NULL;
-               }
-               else
-                   p = echo_string(&this_var->di_tv, &tofree, numbuf, 0);
-               if (p != NULL)
-                   viminfo_writestring(fp, p);
-               vim_free(tofree);
-           }
-       }
-     }
- }
- #endif
- 
  #if defined(FEAT_SESSION) || defined(PROTO)
      int
  store_session_globals(FILE *fd)
--- 9337,9342 ----
*** ../vim-8.1.1726/src/ex_cmds.c       2019-07-18 21:42:45.963840541 +0200
--- src/ex_cmds.c       2019-07-21 19:08:03.006684233 +0200
***************
*** 20,31 ****
  
  static int linelen(int *has_tab);
  static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char_u 
*cmd, int do_in, int do_out);
- #ifdef FEAT_VIMINFO
- static char_u *viminfo_filename(char_u        *);
- static void do_viminfo(FILE *fp_in, FILE *fp_out, int flags);
- static int viminfo_encoding(vir_T *virp);
- static int read_viminfo_up_to_marks(vir_T *virp, int forceit, int writing);
- #endif
  
  static int check_readonly(int *forceit, buf_T *buf);
  static void delbuf_msg(char_u *name);
--- 20,25 ----
***************
*** 1849,2984 ****
                (char *)opt, (char *)fname);
  }
  
- #if defined(FEAT_VIMINFO) || defined(PROTO)
- 
- static int read_viminfo_barline(vir_T *virp, int got_encoding, int force, int 
writing);
- static void write_viminfo_version(FILE *fp_out);
- static void write_viminfo_barlines(vir_T *virp, FILE *fp_out);
- static int  viminfo_errcnt;
- 
-     static int
- no_viminfo(void)
- {
-     /* "vim -i NONE" does not read or write a viminfo file */
-     return STRCMP(p_viminfofile, "NONE") == 0;
- }
- 
- /*
-  * Report an error for reading a viminfo file.
-  * Count the number of errors.        When there are more than 10, return 
TRUE.
-  */
-     int
- viminfo_error(char *errnum, char *message, char_u *line)
- {
-     vim_snprintf((char *)IObuff, IOSIZE, _("%sviminfo: %s in line: "),
-                                                            errnum, message);
-     STRNCAT(IObuff, line, IOSIZE - STRLEN(IObuff) - 1);
-     if (IObuff[STRLEN(IObuff) - 1] == '\n')
-       IObuff[STRLEN(IObuff) - 1] = NUL;
-     emsg((char *)IObuff);
-     if (++viminfo_errcnt >= 10)
-     {
-       emsg(_("E136: viminfo: Too many errors, skipping rest of file"));
-       return TRUE;
-     }
-     return FALSE;
- }
- 
- /*
-  * read_viminfo() -- Read the viminfo file.  Registers etc. which are already
-  * set are not over-written unless "flags" includes VIF_FORCEIT. -- webb
-  */
-     int
- read_viminfo(
-     char_u    *file,      /* file name or NULL to use default name */
-     int               flags)      /* VIF_WANT_INFO et al. */
- {
-     FILE      *fp;
-     char_u    *fname;
- 
-     if (no_viminfo())
-       return FAIL;
- 
-     fname = viminfo_filename(file);   /* get file name in allocated buffer */
-     if (fname == NULL)
-       return FAIL;
-     fp = mch_fopen((char *)fname, READBIN);
- 
-     if (p_verbose > 0)
-     {
-       verbose_enter();
-       smsg(_("Reading viminfo file \"%s\"%s%s%s"),
-               fname,
-               (flags & VIF_WANT_INFO) ? _(" info") : "",
-               (flags & VIF_WANT_MARKS) ? _(" marks") : "",
-               (flags & VIF_GET_OLDFILES) ? _(" oldfiles") : "",
-               fp == NULL ? _(" FAILED") : "");
-       verbose_leave();
-     }
- 
-     vim_free(fname);
-     if (fp == NULL)
-       return FAIL;
- 
-     viminfo_errcnt = 0;
-     do_viminfo(fp, NULL, flags);
- 
-     fclose(fp);
-     return OK;
- }
- 
- /*
-  * Write the viminfo file.  The old one is read in first so that effectively a
-  * merge of current info and old info is done.  This allows multiple vims to
-  * run simultaneously, without losing any marks etc.
-  * If "forceit" is TRUE, then the old file is not read in, and only internal
-  * info is written to the file.
-  */
-     void
- write_viminfo(char_u *file, int forceit)
- {
-     char_u    *fname;
-     FILE      *fp_in = NULL;  /* input viminfo file, if any */
-     FILE      *fp_out = NULL; /* output viminfo file */
-     char_u    *tempname = NULL;       /* name of temp viminfo file */
-     stat_T    st_new;         /* mch_stat() of potential new file */
- #if defined(UNIX) || defined(VMS)
-     mode_t    umask_save;
- #endif
- #ifdef UNIX
-     int               shortname = FALSE;      /* use 8.3 file name */
-     stat_T    st_old;         /* mch_stat() of existing viminfo file */
- #endif
- #ifdef MSWIN
-     int               hidden = FALSE;
- #endif
- 
-     if (no_viminfo())
-       return;
- 
-     fname = viminfo_filename(file);   /* may set to default if NULL */
-     if (fname == NULL)
-       return;
- 
-     fp_in = mch_fopen((char *)fname, READBIN);
-     if (fp_in == NULL)
-     {
-       int fd;
- 
-       /* if it does exist, but we can't read it, don't try writing */
-       if (mch_stat((char *)fname, &st_new) == 0)
-           goto end;
- 
-       /* Create the new .viminfo non-accessible for others, because it may
-        * contain text from non-accessible documents. It is up to the user to
-        * widen access (e.g. to a group). This may also fail if there is a
-        * race condition, then just give up. */
-       fd = mch_open((char *)fname,
-                           O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
-       if (fd < 0)
-           goto end;
-       fp_out = fdopen(fd, WRITEBIN);
-     }
-     else
-     {
-       /*
-        * There is an existing viminfo file.  Create a temporary file to
-        * write the new viminfo into, in the same directory as the
-        * existing viminfo file, which will be renamed once all writing is
-        * successful.
-        */
- #ifdef UNIX
-       /*
-        * For Unix we check the owner of the file.  It's not very nice to
-        * overwrite a user's viminfo file after a "su root", with a
-        * viminfo file that the user can't read.
-        */
-       st_old.st_dev = (dev_t)0;
-       st_old.st_ino = 0;
-       st_old.st_mode = 0600;
-       if (mch_stat((char *)fname, &st_old) == 0
-               && getuid() != ROOT_UID
-               && !(st_old.st_uid == getuid()
-                       ? (st_old.st_mode & 0200)
-                       : (st_old.st_gid == getgid()
-                               ? (st_old.st_mode & 0020)
-                               : (st_old.st_mode & 0002))))
-       {
-           int tt = msg_didany;
- 
-           /* avoid a wait_return for this message, it's annoying */
-           semsg(_("E137: Viminfo file is not writable: %s"), fname);
-           msg_didany = tt;
-           fclose(fp_in);
-           goto end;
-       }
- #endif
- #ifdef MSWIN
-       /* Get the file attributes of the existing viminfo file. */
-       hidden = mch_ishidden(fname);
- #endif
- 
-       /*
-        * Make tempname, find one that does not exist yet.
-        * Beware of a race condition: If someone logs out and all Vim
-        * instances exit at the same time a temp file might be created between
-        * stat() and open().  Use mch_open() with O_EXCL to avoid that.
-        * May try twice: Once normal and once with shortname set, just in
-        * case somebody puts his viminfo file in an 8.3 filesystem.
-        */
-       for (;;)
-       {
-           int         next_char = 'z';
-           char_u      *wp;
- 
-           tempname = buf_modname(
- #ifdef UNIX
-                                   shortname,
- #else
-                                   FALSE,
- #endif
-                                   fname,
- #ifdef VMS
-                                   (char_u *)"-tmp",
- #else
-                                   (char_u *)".tmp",
- #endif
-                                   FALSE);
-           if (tempname == NULL)               /* out of memory */
-               break;
- 
-           /*
-            * Try a series of names.  Change one character, just before
-            * the extension.  This should also work for an 8.3
-            * file name, when after adding the extension it still is
-            * the same file as the original.
-            */
-           wp = tempname + STRLEN(tempname) - 5;
-           if (wp < gettail(tempname))     /* empty file name? */
-               wp = gettail(tempname);
-           for (;;)
-           {
-               /*
-                * Check if tempfile already exists.  Never overwrite an
-                * existing file!
-                */
-               if (mch_stat((char *)tempname, &st_new) == 0)
-               {
- #ifdef UNIX
-                   /*
-                    * Check if tempfile is same as original file.  May happen
-                    * when modname() gave the same file back.  E.g.  silly
-                    * link, or file name-length reached.  Try again with
-                    * shortname set.
-                    */
-                   if (!shortname && st_new.st_dev == st_old.st_dev
-                                               && st_new.st_ino == 
st_old.st_ino)
-                   {
-                       VIM_CLEAR(tempname);
-                       shortname = TRUE;
-                       break;
-                   }
- #endif
-               }
-               else
-               {
-                   /* Try creating the file exclusively.  This may fail if
-                    * another Vim tries to do it at the same time. */
- #ifdef VMS
-                   /* fdopen() fails for some reason */
-                   umask_save = umask(077);
-                   fp_out = mch_fopen((char *)tempname, WRITEBIN);
-                   (void)umask(umask_save);
- #else
-                   int fd;
- 
-                   /* Use mch_open() to be able to use O_NOFOLLOW and set file
-                    * protection:
-                    * Unix: same as original file, but strip s-bit.  Reset
-                    * umask to avoid it getting in the way.
-                    * Others: r&w for user only. */
- # ifdef UNIX
-                   umask_save = umask(0);
-                   fd = mch_open((char *)tempname,
-                           O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW,
-                                       (int)((st_old.st_mode & 0777) | 0600));
-                   (void)umask(umask_save);
- # else
-                   fd = mch_open((char *)tempname,
-                            O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
- # endif
-                   if (fd < 0)
-                   {
-                       fp_out = NULL;
- # ifdef EEXIST
-                       /* Avoid trying lots of names while the problem is lack
-                        * of permission, only retry if the file already
-                        * exists. */
-                       if (errno != EEXIST)
-                           break;
- # endif
-                   }
-                   else
-                       fp_out = fdopen(fd, WRITEBIN);
- #endif /* VMS */
-                   if (fp_out != NULL)
-                       break;
-               }
- 
-               /* Assume file exists, try again with another name. */
-               if (next_char == 'a' - 1)
-               {
-                   /* They all exist?  Must be something wrong! Don't write
-                    * the viminfo file then. */
-                   semsg(_("E929: Too many viminfo temp files, like %s!"),
-                                                                    tempname);
-                   break;
-               }
-               *wp = next_char;
-               --next_char;
-           }
- 
-           if (tempname != NULL)
-               break;
-           /* continue if shortname was set */
-       }
- 
- #if defined(UNIX) && defined(HAVE_FCHOWN)
-       if (tempname != NULL && fp_out != NULL)
-       {
-               stat_T  tmp_st;
- 
-           /*
-            * Make sure the original owner can read/write the tempfile and
-            * otherwise preserve permissions, making sure the group matches.
-            */
-           if (mch_stat((char *)tempname, &tmp_st) >= 0)
-           {
-               if (st_old.st_uid != tmp_st.st_uid)
-                   /* Changing the owner might fail, in which case the
-                    * file will now owned by the current user, oh well. */
-                   vim_ignored = fchown(fileno(fp_out), st_old.st_uid, -1);
-               if (st_old.st_gid != tmp_st.st_gid
-                       && fchown(fileno(fp_out), -1, st_old.st_gid) == -1)
-                   /* can't set the group to what it should be, remove
-                    * group permissions */
-                   (void)mch_setperm(tempname, 0600);
-           }
-           else
-               /* can't stat the file, set conservative permissions */
-               (void)mch_setperm(tempname, 0600);
-       }
- #endif
-     }
- 
-     /*
-      * Check if the new viminfo file can be written to.
-      */
-     if (fp_out == NULL)
-     {
-       semsg(_("E138: Can't write viminfo file %s!"),
-                      (fp_in == NULL || tempname == NULL) ? fname : tempname);
-       if (fp_in != NULL)
-           fclose(fp_in);
-       goto end;
-     }
- 
-     if (p_verbose > 0)
-     {
-       verbose_enter();
-       smsg(_("Writing viminfo file \"%s\""), fname);
-       verbose_leave();
-     }
- 
-     viminfo_errcnt = 0;
-     do_viminfo(fp_in, fp_out, forceit ? 0 : (VIF_WANT_INFO | VIF_WANT_MARKS));
- 
-     if (fclose(fp_out) == EOF)
-       ++viminfo_errcnt;
- 
-     if (fp_in != NULL)
-     {
-       fclose(fp_in);
- 
-       /* In case of an error keep the original viminfo file.  Otherwise
-        * rename the newly written file.  Give an error if that fails. */
-       if (viminfo_errcnt == 0)
-       {
-           if (vim_rename(tempname, fname) == -1)
-           {
-               ++viminfo_errcnt;
-               semsg(_("E886: Can't rename viminfo file to %s!"), fname);
-           }
- # ifdef MSWIN
-           /* If the viminfo file was hidden then also hide the new file. */
-           else if (hidden)
-               mch_hide(fname);
- # endif
-       }
-       if (viminfo_errcnt > 0)
-           mch_remove(tempname);
-     }
- 
- end:
-     vim_free(fname);
-     vim_free(tempname);
- }
- 
- /*
-  * Get the viminfo file name to use.
-  * If "file" is given and not empty, use it (has already been expanded by
-  * cmdline functions).
-  * Otherwise use "-i file_name", value from 'viminfo' or the default, and
-  * expand environment variables.
-  * Returns an allocated string.  NULL when out of memory.
-  */
-     static char_u *
- viminfo_filename(char_u *file)
- {
-     if (file == NULL || *file == NUL)
-     {
-       if (*p_viminfofile != NUL)
-           file = p_viminfofile;
-       else if ((file = find_viminfo_parameter('n')) == NULL || *file == NUL)
-       {
- #ifdef VIMINFO_FILE2
- # ifdef VMS
-           if (mch_getenv((char_u *)"SYS$LOGIN") == NULL)
- # else
- #  ifdef MSWIN
-           /* Use $VIM only if $HOME is the default "C:/". */
-           if (STRCMP(vim_getenv((char_u *)"HOME", NULL), "C:/") == 0
-                   && mch_getenv((char_u *)"HOME") == NULL)
- #  else
-           if (mch_getenv((char_u *)"HOME") == NULL)
- #  endif
- # endif
-           {
-               /* don't use $VIM when not available. */
-               expand_env((char_u *)"$VIM", NameBuff, MAXPATHL);
-               if (STRCMP("$VIM", NameBuff) != 0)  /* $VIM was expanded */
-                   file = (char_u *)VIMINFO_FILE2;
-               else
-                   file = (char_u *)VIMINFO_FILE;
-           }
-           else
- #endif
-               file = (char_u *)VIMINFO_FILE;
-       }
-       expand_env(file, NameBuff, MAXPATHL);
-       file = NameBuff;
-     }
-     return vim_strsave(file);
- }
- 
- /*
-  * do_viminfo() -- Should only be called from read_viminfo() & 
write_viminfo().
-  */
-     static void
- do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
- {
-     int               eof = FALSE;
-     vir_T     vir;
-     int               merge = FALSE;
-     int               do_copy_marks = FALSE;
-     garray_T  buflist;
- 
-     if ((vir.vir_line = alloc(LSIZE)) == NULL)
-       return;
-     vir.vir_fd = fp_in;
-     vir.vir_conv.vc_type = CONV_NONE;
-     ga_init2(&vir.vir_barlines, (int)sizeof(char_u *), 100);
-     vir.vir_version = -1;
- 
-     if (fp_in != NULL)
-     {
-       if (flags & VIF_WANT_INFO)
-       {
-           if (fp_out != NULL)
-           {
-               /* Registers and marks are read and kept separate from what
-                * this Vim is using.  They are merged when writing. */
-               prepare_viminfo_registers();
-               prepare_viminfo_marks();
-           }
- 
-           eof = read_viminfo_up_to_marks(&vir,
-                                        flags & VIF_FORCEIT, fp_out != NULL);
-           merge = TRUE;
-       }
-       else if (flags != 0)
-           /* Skip info, find start of marks */
-           while (!(eof = viminfo_readline(&vir))
-                   && vir.vir_line[0] != '>')
-               ;
- 
-       do_copy_marks = (flags &
-                          (VIF_WANT_MARKS | VIF_GET_OLDFILES | VIF_FORCEIT));
-     }
- 
-     if (fp_out != NULL)
-     {
-       /* Write the info: */
-       fprintf(fp_out, _("# This viminfo file was generated by Vim %s.\n"),
-                                                         VIM_VERSION_MEDIUM);
-       fputs(_("# You may edit it if you're careful!\n\n"), fp_out);
-       write_viminfo_version(fp_out);
-       fputs(_("# Value of 'encoding' when this file was written\n"), fp_out);
-       fprintf(fp_out, "*encoding=%s\n\n", p_enc);
-       write_viminfo_search_pattern(fp_out);
-       write_viminfo_sub_string(fp_out);
- #ifdef FEAT_CMDHIST
-       write_viminfo_history(fp_out, merge);
- #endif
-       write_viminfo_registers(fp_out);
-       finish_viminfo_registers();
- #ifdef FEAT_EVAL
-       write_viminfo_varlist(fp_out);
- #endif
-       write_viminfo_filemarks(fp_out);
-       finish_viminfo_marks();
-       write_viminfo_bufferlist(fp_out);
-       write_viminfo_barlines(&vir, fp_out);
- 
-       if (do_copy_marks)
-           ga_init2(&buflist, sizeof(buf_T *), 50);
-       write_viminfo_marks(fp_out, do_copy_marks ? &buflist : NULL);
-     }
- 
-     if (do_copy_marks)
-     {
-       copy_viminfo_marks(&vir, fp_out, &buflist, eof, flags);
-       if (fp_out != NULL)
-           ga_clear(&buflist);
-     }
- 
-     vim_free(vir.vir_line);
-     if (vir.vir_conv.vc_type != CONV_NONE)
-       convert_setup(&vir.vir_conv, NULL, NULL);
-     ga_clear_strings(&vir.vir_barlines);
- }
- 
- /*
-  * read_viminfo_up_to_marks() -- Only called from do_viminfo().  Reads in the
-  * first part of the viminfo file which contains everything but the marks that
-  * are local to a file.  Returns TRUE when end-of-file is reached. -- webb
-  */
-     static int
- read_viminfo_up_to_marks(
-     vir_T     *virp,
-     int               forceit,
-     int               writing)
- {
-     int               eof;
-     buf_T     *buf;
-     int               got_encoding = FALSE;
- 
- #ifdef FEAT_CMDHIST
-     prepare_viminfo_history(forceit ? 9999 : 0, writing);
- #endif
- 
-     eof = viminfo_readline(virp);
-     while (!eof && virp->vir_line[0] != '>')
-     {
-       switch (virp->vir_line[0])
-       {
-               /* Characters reserved for future expansion, ignored now */
-           case '+': /* "+40 /path/dir file", for running vim without args */
-           case '^': /* to be defined */
-           case '<': /* long line - ignored */
-               /* A comment or empty line. */
-           case NUL:
-           case '\r':
-           case '\n':
-           case '#':
-               eof = viminfo_readline(virp);
-               break;
-           case '|':
-               eof = read_viminfo_barline(virp, got_encoding,
-                                                           forceit, writing);
-               break;
-           case '*': /* "*encoding=value" */
-               got_encoding = TRUE;
-               eof = viminfo_encoding(virp);
-               break;
-           case '!': /* global variable */
- #ifdef FEAT_EVAL
-               eof = read_viminfo_varlist(virp, writing);
- #else
-               eof = viminfo_readline(virp);
- #endif
-               break;
-           case '%': /* entry for buffer list */
-               eof = read_viminfo_bufferlist(virp, writing);
-               break;
-           case '"':
-               /* When registers are in bar lines skip the old style register
-                * lines. */
-               if (virp->vir_version < VIMINFO_VERSION_WITH_REGISTERS)
-                   eof = read_viminfo_register(virp, forceit);
-               else
-                   do {
-                       eof = viminfo_readline(virp);
-                   } while (!eof && (virp->vir_line[0] == TAB
-                                               || virp->vir_line[0] == '<'));
-               break;
-           case '/':       /* Search string */
-           case '&':       /* Substitute search string */
-           case '~':       /* Last search string, followed by '/' or '&' */
-               eof = read_viminfo_search_pattern(virp, forceit);
-               break;
-           case '$':
-               eof = read_viminfo_sub_string(virp, forceit);
-               break;
-           case ':':
-           case '?':
-           case '=':
-           case '@':
- #ifdef FEAT_CMDHIST
-               /* When history is in bar lines skip the old style history
-                * lines. */
-               if (virp->vir_version < VIMINFO_VERSION_WITH_HISTORY)
-                   eof = read_viminfo_history(virp, writing);
-               else
- #endif
-                   eof = viminfo_readline(virp);
-               break;
-           case '-':
-           case '\'':
-               /* When file marks are in bar lines skip the old style lines. */
-               if (virp->vir_version < VIMINFO_VERSION_WITH_MARKS)
-                   eof = read_viminfo_filemark(virp, forceit);
-               else
-                   eof = viminfo_readline(virp);
-               break;
-           default:
-               if (viminfo_error("E575: ", _("Illegal starting char"),
-                           virp->vir_line))
-                   eof = TRUE;
-               else
-                   eof = viminfo_readline(virp);
-               break;
-       }
-     }
- 
- #ifdef FEAT_CMDHIST
-     /* Finish reading history items. */
-     if (!writing)
-       finish_viminfo_history(virp);
- #endif
- 
-     /* Change file names to buffer numbers for fmarks. */
-     FOR_ALL_BUFFERS(buf)
-       fmarks_check_names(buf);
- 
-     return eof;
- }
- 
- /*
-  * Compare the 'encoding' value in the viminfo file with the current value of
-  * 'encoding'.  If different and the 'c' flag is in 'viminfo', setup for
-  * conversion of text with iconv() in viminfo_readstring().
-  */
-     static int
- viminfo_encoding(vir_T *virp)
- {
-     char_u    *p;
-     int               i;
- 
-     if (get_viminfo_parameter('c') != 0)
-     {
-       p = vim_strchr(virp->vir_line, '=');
-       if (p != NULL)
-       {
-           /* remove trailing newline */
-           ++p;
-           for (i = 0; vim_isprintc(p[i]); ++i)
-               ;
-           p[i] = NUL;
- 
-           convert_setup(&virp->vir_conv, p, p_enc);
-       }
-     }
-     return viminfo_readline(virp);
- }
- 
- /*
-  * Read a line from the viminfo file.
-  * Returns TRUE for end-of-file;
-  */
-     int
- viminfo_readline(vir_T *virp)
- {
-     return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
- }
- 
- /*
-  * Check string read from viminfo file.
-  * Remove '\n' at the end of the line.
-  * - replace CTRL-V CTRL-V with CTRL-V
-  * - replace CTRL-V 'n'    with '\n'
-  *
-  * Check for a long line as written by viminfo_writestring().
-  *
-  * Return the string in allocated memory (NULL when out of memory).
-  */
-     char_u *
- viminfo_readstring(
-     vir_T     *virp,
-     int               off,                /* offset for virp->vir_line */
-     int               convert UNUSED)     /* convert the string */
- {
-     char_u    *retval;
-     char_u    *s, *d;
-     long      len;
- 
-     if (virp->vir_line[off] == Ctrl_V && vim_isdigit(virp->vir_line[off + 1]))
-     {
-       len = atol((char *)virp->vir_line + off + 1);
-       retval = alloc(len);
-       if (retval == NULL)
-       {
-           /* Line too long?  File messed up?  Skip next line. */
-           (void)vim_fgets(virp->vir_line, 10, virp->vir_fd);
-           return NULL;
-       }
-       (void)vim_fgets(retval, (int)len, virp->vir_fd);
-       s = retval + 1;     /* Skip the leading '<' */
-     }
-     else
-     {
-       retval = vim_strsave(virp->vir_line + off);
-       if (retval == NULL)
-           return NULL;
-       s = retval;
-     }
- 
-     /* Change CTRL-V CTRL-V to CTRL-V and CTRL-V n to \n in-place. */
-     d = retval;
-     while (*s != NUL && *s != '\n')
-     {
-       if (s[0] == Ctrl_V && s[1] != NUL)
-       {
-           if (s[1] == 'n')
-               *d++ = '\n';
-           else
-               *d++ = Ctrl_V;
-           s += 2;
-       }
-       else
-           *d++ = *s++;
-     }
-     *d = NUL;
- 
-     if (convert && virp->vir_conv.vc_type != CONV_NONE && *retval != NUL)
-     {
-       d = string_convert(&virp->vir_conv, retval, NULL);
-       if (d != NULL)
-       {
-           vim_free(retval);
-           retval = d;
-       }
-     }
- 
-     return retval;
- }
- 
- /*
-  * write string to viminfo file
-  * - replace CTRL-V with CTRL-V CTRL-V
-  * - replace '\n'   with CTRL-V 'n'
-  * - add a '\n' at the end
-  *
-  * For a long line:
-  * - write " CTRL-V <length> \n " in first line
-  * - write " < <string> \n "    in second line
-  */
-     void
- viminfo_writestring(FILE *fd, char_u *p)
- {
-     int               c;
-     char_u    *s;
-     int               len = 0;
- 
-     for (s = p; *s != NUL; ++s)
-     {
-       if (*s == Ctrl_V || *s == '\n')
-           ++len;
-       ++len;
-     }
- 
-     /* If the string will be too long, write its length and put it in the next
-      * line.  Take into account that some room is needed for what comes before
-      * the string (e.g., variable name).  Add something to the length for the
-      * '<', NL and trailing NUL. */
-     if (len > LSIZE / 2)
-       fprintf(fd, IF_EB("\026%d\n<", CTRL_V_STR "%d\n<"), len + 3);
- 
-     while ((c = *p++) != NUL)
-     {
-       if (c == Ctrl_V || c == '\n')
-       {
-           putc(Ctrl_V, fd);
-           if (c == '\n')
-               c = 'n';
-       }
-       putc(c, fd);
-     }
-     putc('\n', fd);
- }
- 
- /*
-  * Write a string in quotes that barline_parse() can read back.
-  * Breaks the line in less than LSIZE pieces when needed.
-  * Returns remaining characters in the line.
-  */
-     int
- barline_writestring(FILE *fd, char_u *s, int remaining_start)
- {
-     char_u *p;
-     int           remaining = remaining_start;
-     int           len = 2;
- 
-     /* Count the number of characters produced, including quotes. */
-     for (p = s; *p != NUL; ++p)
-     {
-       if (*p == NL)
-           len += 2;
-       else if (*p == '"' || *p == '\\')
-           len += 2;
-       else
-           ++len;
-     }
-     if (len > remaining - 2)
-     {
-       fprintf(fd, ">%d\n|<", len);
-       remaining = LSIZE - 20;
-     }
- 
-     putc('"', fd);
-     for (p = s; *p != NUL; ++p)
-     {
-       if (*p == NL)
-       {
-           putc('\\', fd);
-           putc('n', fd);
-           --remaining;
-       }
-       else if (*p == '"' || *p == '\\')
-       {
-           putc('\\', fd);
-           putc(*p, fd);
-           --remaining;
-       }
-       else
-           putc(*p, fd);
-       --remaining;
- 
-       if (remaining < 3)
-       {
-           putc('\n', fd);
-           putc('|', fd);
-           putc('<', fd);
-           /* Leave enough space for another continuation. */
-           remaining = LSIZE - 20;
-       }
-     }
-     putc('"', fd);
-     return remaining - 2;
- }
- 
- /*
-  * Parse a viminfo line starting with '|'.
-  * Add each decoded value to "values".
-  * Returns TRUE if the next line is to be read after using the parsed values.
-  */
-     static int
- barline_parse(vir_T *virp, char_u *text, garray_T *values)
- {
-     char_u  *p = text;
-     char_u  *nextp = NULL;
-     char_u  *buf = NULL;
-     bval_T  *value;
-     int           i;
-     int           allocated = FALSE;
-     int           eof;
-     char_u  *sconv;
-     int           converted;
- 
-     while (*p == ',')
-     {
-       ++p;
-       if (ga_grow(values, 1) == FAIL)
-           break;
-       value = (bval_T *)(values->ga_data) + values->ga_len;
- 
-       if (*p == '>')
-       {
-           /* Need to read a continuation line.  Put strings in allocated
-            * memory, because virp->vir_line is overwritten. */
-           if (!allocated)
-           {
-               for (i = 0; i < values->ga_len; ++i)
-               {
-                   bval_T  *vp = (bval_T *)(values->ga_data) + i;
- 
-                   if (vp->bv_type == BVAL_STRING && !vp->bv_allocated)
-                   {
-                       vp->bv_string = vim_strnsave(vp->bv_string, vp->bv_len);
-                       vp->bv_allocated = TRUE;
-                   }
-               }
-               allocated = TRUE;
-           }
- 
-           if (vim_isdigit(p[1]))
-           {
-               size_t len;
-               size_t todo;
-               size_t n;
- 
-               /* String value was split into lines that are each shorter
-                * than LSIZE:
-                *     |{bartype},>{length of "{text}{text2}"}
-                *     |<"{text1}
-                *     |<{text2}",{value}
-                * Length includes the quotes.
-                */
-               ++p;
-               len = getdigits(&p);
-               buf = alloc(len + 1);
-               if (buf == NULL)
-                   return TRUE;
-               p = buf;
-               for (todo = len; todo > 0; todo -= n)
-               {
-                   eof = viminfo_readline(virp);
-                   if (eof || virp->vir_line[0] != '|'
-                                                 || virp->vir_line[1] != '<')
-                   {
-                       /* File was truncated or garbled. Read another line if
-                        * this one starts with '|'. */
-                       vim_free(buf);
-                       return eof || virp->vir_line[0] == '|';
-                   }
-                   /* Get length of text, excluding |< and NL chars. */
-                   n = STRLEN(virp->vir_line);
-                   while (n > 0 && (virp->vir_line[n - 1] == NL
-                                            || virp->vir_line[n - 1] == CAR))
-                       --n;
-                   n -= 2;
-                   if (n > todo)
-                   {
-                       /* more values follow after the string */
-                       nextp = virp->vir_line + 2 + todo;
-                       n = todo;
-                   }
-                   mch_memmove(p, virp->vir_line + 2, n);
-                   p += n;
-               }
-               *p = NUL;
-               p = buf;
-           }
-           else
-           {
-               /* Line ending in ">" continues in the next line:
-                *     |{bartype},{lots of values},>
-                *     |<{value},{value}
-                */
-               eof = viminfo_readline(virp);
-               if (eof || virp->vir_line[0] != '|'
-                                             || virp->vir_line[1] != '<')
-                   /* File was truncated or garbled. Read another line if
-                    * this one starts with '|'. */
-                   return eof || virp->vir_line[0] == '|';
-               p = virp->vir_line + 2;
-           }
-       }
- 
-       if (isdigit(*p))
-       {
-           value->bv_type = BVAL_NR;
-           value->bv_nr = getdigits(&p);
-           ++values->ga_len;
-       }
-       else if (*p == '"')
-       {
-           int     len = 0;
-           char_u  *s = p;
- 
-           /* Unescape special characters in-place. */
-           ++p;
-           while (*p != '"')
-           {
-               if (*p == NL || *p == NUL)
-                   return TRUE;  /* syntax error, drop the value */
-               if (*p == '\\')
-               {
-                   ++p;
-                   if (*p == 'n')
-                       s[len++] = '\n';
-                   else
-                       s[len++] = *p;
-                   ++p;
-               }
-               else
-                   s[len++] = *p++;
-           }
-           ++p;
-           s[len] = NUL;
- 
-           converted = FALSE;
-           if (virp->vir_conv.vc_type != CONV_NONE && *s != NUL)
-           {
-               sconv = string_convert(&virp->vir_conv, s, NULL);
-               if (sconv != NULL)
-               {
-                   if (s == buf)
-                       vim_free(s);
-                   s = sconv;
-                   buf = s;
-                   converted = TRUE;
-               }
-           }
- 
-           /* Need to copy in allocated memory if the string wasn't allocated
-            * above and we did allocate before, thus vir_line may change. */
-           if (s != buf && allocated)
-               s = vim_strsave(s);
-           value->bv_string = s;
-           value->bv_type = BVAL_STRING;
-           value->bv_len = len;
-           value->bv_allocated = allocated || converted;
-           ++values->ga_len;
-           if (nextp != NULL)
-           {
-               /* values following a long string */
-               p = nextp;
-               nextp = NULL;
-           }
-       }
-       else if (*p == ',')
-       {
-           value->bv_type = BVAL_EMPTY;
-           ++values->ga_len;
-       }
-       else
-           break;
-     }
-     return TRUE;
- }
- 
-     static int
- read_viminfo_barline(vir_T *virp, int got_encoding, int force, int writing)
- {
-     char_u    *p = virp->vir_line + 1;
-     int               bartype;
-     garray_T  values;
-     bval_T    *vp;
-     int               i;
-     int               read_next = TRUE;
- 
-     /* The format is: |{bartype},{value},...
-      * For a very long string:
-      *     |{bartype},>{length of "{text}{text2}"}
-      *     |<{text1}
-      *     |<{text2},{value}
-      * For a long line not using a string
-      *     |{bartype},{lots of values},>
-      *     |<{value},{value}
-      */
-     if (*p == '<')
-     {
-       /* Continuation line of an unrecognized item. */
-       if (writing)
-           ga_add_string(&virp->vir_barlines, virp->vir_line);
-     }
-     else
-     {
-       ga_init2(&values, sizeof(bval_T), 20);
-       bartype = getdigits(&p);
-       switch (bartype)
-       {
-           case BARTYPE_VERSION:
-               /* Only use the version when it comes before the encoding.
-                * If it comes later it was copied by a Vim version that
-                * doesn't understand the version. */
-               if (!got_encoding)
-               {
-                   read_next = barline_parse(virp, p, &values);
-                   vp = (bval_T *)values.ga_data;
-                   if (values.ga_len > 0 && vp->bv_type == BVAL_NR)
-                       virp->vir_version = vp->bv_nr;
-               }
-               break;
- 
-           case BARTYPE_HISTORY:
-               read_next = barline_parse(virp, p, &values);
-               handle_viminfo_history(&values, writing);
-               break;
- 
-           case BARTYPE_REGISTER:
-               read_next = barline_parse(virp, p, &values);
-               handle_viminfo_register(&values, force);
-               break;
- 
-           case BARTYPE_MARK:
-               read_next = barline_parse(virp, p, &values);
-               handle_viminfo_mark(&values, force);
-               break;
- 
-           default:
-               /* copy unrecognized line (for future use) */
-               if (writing)
-                   ga_add_string(&virp->vir_barlines, virp->vir_line);
-       }
-       for (i = 0; i < values.ga_len; ++i)
-       {
-           vp = (bval_T *)values.ga_data + i;
-           if (vp->bv_type == BVAL_STRING && vp->bv_allocated)
-               vim_free(vp->bv_string);
-       }
-       ga_clear(&values);
-     }
- 
-     if (read_next)
-       return viminfo_readline(virp);
-     return FALSE;
- }
- 
-     static void
- write_viminfo_version(FILE *fp_out)
- {
-     fprintf(fp_out, "# Viminfo version\n|%d,%d\n\n",
-                                           BARTYPE_VERSION, VIMINFO_VERSION);
- }
- 
-     static void
- write_viminfo_barlines(vir_T *virp, FILE *fp_out)
- {
-     int               i;
-     garray_T  *gap = &virp->vir_barlines;
-     int               seen_useful = FALSE;
-     char      *line;
- 
-     if (gap->ga_len > 0)
-     {
-       fputs(_("\n# Bar lines, copied verbatim:\n"), fp_out);
- 
-       /* Skip over continuation lines until seeing a useful line. */
-       for (i = 0; i < gap->ga_len; ++i)
-       {
-           line = ((char **)(gap->ga_data))[i];
-           if (seen_useful || line[1] != '<')
-           {
-               fputs(line, fp_out);
-               seen_useful = TRUE;
-           }
-       }
-     }
- }
- #endif /* FEAT_VIMINFO */
- 
  /*
   * Return the current time in seconds.  Calls time(), unless test_settime()
   * was used.
--- 1843,1848 ----
***************
*** 6240,6246 ****
        viminfo_writestring(fp, old_sub);
      }
  }
! #endif /* FEAT_VIMINFO */
  
  #if defined(EXITFREE) || defined(PROTO)
      void
--- 5104,5110 ----
        viminfo_writestring(fp, old_sub);
      }
  }
! #endif // FEAT_VIMINFO
  
  #if defined(EXITFREE) || defined(PROTO)
      void
*** ../vim-8.1.1726/src/ex_docmd.c      2019-07-18 21:42:45.963840541 +0200
--- src/ex_docmd.c      2019-07-21 18:56:45.349367775 +0200
***************
*** 318,326 ****
  #ifndef FEAT_EVAL
  # define ex_compiler          ex_ni
  #endif
! #ifdef FEAT_VIMINFO
! static void   ex_viminfo(exarg_T *eap);
! #else
  # define ex_viminfo           ex_ni
  #endif
  static void   ex_behave(exarg_T *eap);
--- 318,324 ----
  #ifndef FEAT_EVAL
  # define ex_compiler          ex_ni
  #endif
! #ifndef FEAT_VIMINFO
  # define ex_viminfo           ex_ni
  #endif
  static void   ex_behave(exarg_T *eap);
***************
*** 10713,10743 ****
      return OK;
  }
  
- #ifdef FEAT_VIMINFO
- /*
-  * ":rviminfo" and ":wviminfo".
-  */
-     static void
- ex_viminfo(
-     exarg_T   *eap)
- {
-     char_u    *save_viminfo;
- 
-     save_viminfo = p_viminfo;
-     if (*p_viminfo == NUL)
-       p_viminfo = (char_u *)"'100";
-     if (eap->cmdidx == CMD_rviminfo)
-     {
-       if (read_viminfo(eap->arg, VIF_WANT_INFO | VIF_WANT_MARKS
-                                 | (eap->forceit ? VIF_FORCEIT : 0)) == FAIL)
-           emsg(_("E195: Cannot open viminfo file for reading"));
-     }
-     else
-       write_viminfo(eap->arg, eap->forceit);
-     p_viminfo = save_viminfo;
- }
- #endif
- 
  #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
  /*
   * Make a dialog message in "buff[DIALOG_MSG_SIZE]".
--- 10711,10716 ----
*** ../vim-8.1.1726/src/globals.h       2019-07-15 22:40:19.061741740 +0200
--- src/globals.h       2019-07-21 18:56:45.353367758 +0200
***************
*** 190,195 ****
--- 190,196 ----
  EXTERN int    did_endif INIT(= FALSE);    /* just had ":endif" */
  EXTERN dict_T vimvardict;                 /* Dictionary with v: variables */
  EXTERN dict_T globvardict;                /* Dictionary with g: variables */
+ #define globvarht globvardict.dv_hashtab
  #endif
  EXTERN int    did_emsg;                   /* set by emsg() when the message
                                               is displayed or thrown */
*** ../vim-8.1.1726/src/proto.h 2019-07-14 21:29:04.558965949 +0200
--- src/proto.h 2019-07-21 18:56:45.353367758 +0200
***************
*** 107,112 ****
--- 107,115 ----
  # ifdef FEAT_ARABIC
  #  include "arabic.pro"
  # endif
+ # ifdef FEAT_VIMINFO
+ # include "viminfo.pro"
+ # endif
  
  /* These prototypes cannot be produced automatically. */
  int smsg(const char *, ...)
*** ../vim-8.1.1726/src/proto/buffer.pro        2019-06-30 22:16:06.927821778 
+0200
--- src/proto/buffer.pro        2019-07-21 18:56:45.353367758 +0200
***************
*** 27,32 ****
--- 27,33 ----
  int ExpandBufnames(char_u *pat, int *num_file, char_u ***file, int options);
  buf_T *buflist_findnr(int nr);
  char_u *buflist_nr2name(int n, int fullname, int helptail);
+ void buflist_setfpos(buf_T *buf, win_T *win, linenr_T lnum, colnr_T col, int 
copy_options);
  void get_winopts(buf_T *buf);
  pos_T *buflist_findfpos(buf_T *buf);
  linenr_T buflist_findlnum(buf_T *buf);
***************
*** 55,62 ****
  void do_arg_all(int count, int forceit, int keep_tabs);
  void ex_buffer_all(exarg_T *eap);
  void do_modelines(int flags);
- int read_viminfo_bufferlist(vir_T *virp, int writing);
- void write_viminfo_bufferlist(FILE *fp);
  int bt_normal(buf_T *buf);
  int bt_quickfix(buf_T *buf);
  int bt_terminal(buf_T *buf);
--- 56,61 ----
*** ../vim-8.1.1726/src/proto/eval.pro  2019-07-14 14:55:20.368881426 +0200
--- src/proto/eval.pro  2019-07-21 18:56:45.353367758 +0200
***************
*** 126,133 ****
  void setwinvar(typval_T *argvars, typval_T *rettv, int off);
  char_u *autoload_name(char_u *name);
  int script_autoload(char_u *name, int reload);
! int read_viminfo_varlist(vir_T *virp, int writing);
! void write_viminfo_varlist(FILE *fp);
  int store_session_globals(FILE *fd);
  void last_set_msg(sctx_T script_ctx);
  void reset_v_option_vars(void);
--- 126,132 ----
  void setwinvar(typval_T *argvars, typval_T *rettv, int off);
  char_u *autoload_name(char_u *name);
  int script_autoload(char_u *name, int reload);
! var_flavour_T var_flavour(char_u *varname);
  int store_session_globals(FILE *fd);
  void last_set_msg(sctx_T script_ctx);
  void reset_v_option_vars(void);
*** ../vim-8.1.1726/src/proto/ex_cmds.pro       2019-01-01 13:20:05.940711222 
+0100
--- src/proto/ex_cmds.pro       2019-07-21 18:56:45.353367758 +0200
***************
*** 10,22 ****
  void do_shell(char_u *cmd, int flags);
  char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp);
  void append_redir(char_u *buf, int buflen, char_u *opt, char_u *fname);
- int viminfo_error(char *errnum, char *message, char_u *line);
- int read_viminfo(char_u *file, int flags);
- void write_viminfo(char_u *file, int forceit);
- int viminfo_readline(vir_T *virp);
- char_u *viminfo_readstring(vir_T *virp, int off, int convert);
- void viminfo_writestring(FILE *fd, char_u *p);
- int barline_writestring(FILE *fd, char_u *s, int remaining_start);
  time_T vim_time(void);
  void do_fixdel(exarg_T *eap);
  void print_line_no_prefix(linenr_T lnum, int use_number, int list);
--- 10,15 ----
*** ../vim-8.1.1726/src/proto/viminfo.pro       2019-07-21 19:24:20.498845384 
+0200
--- src/proto/viminfo.pro       2019-07-21 19:14:22.241283589 +0200
***************
*** 0 ****
--- 1,10 ----
+ /* viminfo.c */
+ int viminfo_error(char *errnum, char *message, char_u *line);
+ int read_viminfo(char_u *file, int flags);
+ void write_viminfo(char_u *file, int forceit);
+ int viminfo_readline(vir_T *virp);
+ char_u *viminfo_readstring(vir_T *virp, int off, int convert);
+ void viminfo_writestring(FILE *fd, char_u *p);
+ int barline_writestring(FILE *fd, char_u *s, int remaining_start);
+ void ex_viminfo(exarg_T *eap);
+ /* vim: set ft=c : */
*** ../vim-8.1.1726/src/structs.h       2019-07-15 22:40:19.061741740 +0200
--- src/structs.h       2019-07-21 18:56:45.353367758 +0200
***************
*** 3725,3730 ****
--- 3725,3738 ----
      CDSCOPE_WINDOW    // :lcd
  } cdscope_T;
  
+ // Variable flavor
+ typedef enum
+ {
+     VAR_FLAVOUR_DEFAULT,      /* doesn't start with uppercase */
+     VAR_FLAVOUR_SESSION,      /* starts with uppercase, some lower */
+     VAR_FLAVOUR_VIMINFO               /* all uppercase */
+ } var_flavour_T;
+ 
  // argument for mouse_find_win()
  typedef enum {
      IGNORE_POPUP,     // only check non-popup windows
*** ../vim-8.1.1726/src/viminfo.c       2019-07-21 19:24:20.506845351 +0200
--- src/viminfo.c       2019-07-21 19:15:22.817045906 +0200
***************
*** 0 ****
--- 1,1424 ----
+ /* vi:set ts=8 sts=4 sw=4 noet:
+  *
+  * VIM - Vi IMproved  by Bram Moolenaar
+  *
+  * Do ":help uganda"  in Vim to read copying and usage conditions.
+  * Do ":help credits" in Vim to see a list of people who contributed.
+  * See README.txt for an overview of the Vim source code.
+  */
+ 
+ /*
+  * viminfo.c: viminfo related functions
+  */
+ 
+ #include "vim.h"
+ #include "version.h"
+ 
+ #if defined(FEAT_VIMINFO) || defined(PROTO)
+ 
+ static int  viminfo_errcnt;
+ 
+ /*
+  * Get the viminfo file name to use.
+  * If "file" is given and not empty, use it (has already been expanded by
+  * cmdline functions).
+  * Otherwise use "-i file_name", value from 'viminfo' or the default, and
+  * expand environment variables.
+  * Returns an allocated string.  NULL when out of memory.
+  */
+     static char_u *
+ viminfo_filename(char_u *file)
+ {
+     if (file == NULL || *file == NUL)
+     {
+       if (*p_viminfofile != NUL)
+           file = p_viminfofile;
+       else if ((file = find_viminfo_parameter('n')) == NULL || *file == NUL)
+       {
+ #ifdef VIMINFO_FILE2
+ # ifdef VMS
+           if (mch_getenv((char_u *)"SYS$LOGIN") == NULL)
+ # else
+ #  ifdef MSWIN
+           // Use $VIM only if $HOME is the default "C:/".
+           if (STRCMP(vim_getenv((char_u *)"HOME", NULL), "C:/") == 0
+                   && mch_getenv((char_u *)"HOME") == NULL)
+ #  else
+           if (mch_getenv((char_u *)"HOME") == NULL)
+ #  endif
+ # endif
+           {
+               // don't use $VIM when not available.
+               expand_env((char_u *)"$VIM", NameBuff, MAXPATHL);
+               if (STRCMP("$VIM", NameBuff) != 0)  // $VIM was expanded
+                   file = (char_u *)VIMINFO_FILE2;
+               else
+                   file = (char_u *)VIMINFO_FILE;
+           }
+           else
+ #endif
+               file = (char_u *)VIMINFO_FILE;
+       }
+       expand_env(file, NameBuff, MAXPATHL);
+       file = NameBuff;
+     }
+     return vim_strsave(file);
+ }
+ 
+     static int
+ read_viminfo_bufferlist(
+     vir_T     *virp,
+     int               writing)
+ {
+     char_u    *tab;
+     linenr_T  lnum;
+     colnr_T   col;
+     buf_T     *buf;
+     char_u    *sfname;
+     char_u    *xline;
+ 
+     // Handle long line and escaped characters.
+     xline = viminfo_readstring(virp, 1, FALSE);
+ 
+     // don't read in if there are files on the command-line or if writing:
+     if (xline != NULL && !writing && ARGCOUNT == 0
+                                      && find_viminfo_parameter('%') != NULL)
+     {
+       // Format is: <fname> Tab <lnum> Tab <col>.
+       // Watch out for a Tab in the file name, work from the end.
+       lnum = 0;
+       col = 0;
+       tab = vim_strrchr(xline, '\t');
+       if (tab != NULL)
+       {
+           *tab++ = '\0';
+           col = (colnr_T)atoi((char *)tab);
+           tab = vim_strrchr(xline, '\t');
+           if (tab != NULL)
+           {
+               *tab++ = '\0';
+               lnum = atol((char *)tab);
+           }
+       }
+ 
+       // Expand "~/" in the file name at "line + 1" to a full path.
+       // Then try shortening it by comparing with the current directory
+       expand_env(xline, NameBuff, MAXPATHL);
+       sfname = shorten_fname1(NameBuff);
+ 
+       buf = buflist_new(NameBuff, sfname, (linenr_T)0, BLN_LISTED);
+       if (buf != NULL)        // just in case...
+       {
+           buf->b_last_cursor.lnum = lnum;
+           buf->b_last_cursor.col = col;
+           buflist_setfpos(buf, curwin, lnum, col, FALSE);
+       }
+     }
+     vim_free(xline);
+ 
+     return viminfo_readline(virp);
+ }
+ 
+     static void
+ write_viminfo_bufferlist(FILE *fp)
+ {
+     buf_T     *buf;
+     win_T     *win;
+     tabpage_T *tp;
+     char_u    *line;
+     int               max_buffers;
+ 
+     if (find_viminfo_parameter('%') == NULL)
+       return;
+ 
+     // Without a number -1 is returned: do all buffers.
+     max_buffers = get_viminfo_parameter('%');
+ 
+     // Allocate room for the file name, lnum and col.
+ #define LINE_BUF_LEN (MAXPATHL + 40)
+     line = alloc(LINE_BUF_LEN);
+     if (line == NULL)
+       return;
+ 
+     FOR_ALL_TAB_WINDOWS(tp, win)
+       set_last_cursor(win);
+ 
+     fputs(_("\n# Buffer list:\n"), fp);
+     FOR_ALL_BUFFERS(buf)
+     {
+       if (buf->b_fname == NULL
+               || !buf->b_p_bl
+ #ifdef FEAT_QUICKFIX
+               || bt_quickfix(buf)
+ #endif
+ #ifdef FEAT_TERMINAL
+               || bt_terminal(buf)
+ #endif
+               || removable(buf->b_ffname))
+           continue;
+ 
+       if (max_buffers-- == 0)
+           break;
+       putc('%', fp);
+       home_replace(NULL, buf->b_ffname, line, MAXPATHL, TRUE);
+       vim_snprintf_add((char *)line, LINE_BUF_LEN, "\t%ld\t%d",
+                       (long)buf->b_last_cursor.lnum,
+                       buf->b_last_cursor.col);
+       viminfo_writestring(fp, line);
+     }
+     vim_free(line);
+ }
+ 
+     static void
+ write_viminfo_barlines(vir_T *virp, FILE *fp_out)
+ {
+     int               i;
+     garray_T  *gap = &virp->vir_barlines;
+     int               seen_useful = FALSE;
+     char      *line;
+ 
+     if (gap->ga_len > 0)
+     {
+       fputs(_("\n# Bar lines, copied verbatim:\n"), fp_out);
+ 
+       // Skip over continuation lines until seeing a useful line.
+       for (i = 0; i < gap->ga_len; ++i)
+       {
+           line = ((char **)(gap->ga_data))[i];
+           if (seen_useful || line[1] != '<')
+           {
+               fputs(line, fp_out);
+               seen_useful = TRUE;
+           }
+       }
+     }
+ }
+ 
+ /*
+  * Parse a viminfo line starting with '|'.
+  * Add each decoded value to "values".
+  * Returns TRUE if the next line is to be read after using the parsed values.
+  */
+     static int
+ barline_parse(vir_T *virp, char_u *text, garray_T *values)
+ {
+     char_u  *p = text;
+     char_u  *nextp = NULL;
+     char_u  *buf = NULL;
+     bval_T  *value;
+     int           i;
+     int           allocated = FALSE;
+     int           eof;
+     char_u  *sconv;
+     int           converted;
+ 
+     while (*p == ',')
+     {
+       ++p;
+       if (ga_grow(values, 1) == FAIL)
+           break;
+       value = (bval_T *)(values->ga_data) + values->ga_len;
+ 
+       if (*p == '>')
+       {
+           // Need to read a continuation line.  Put strings in allocated
+           // memory, because virp->vir_line is overwritten.
+           if (!allocated)
+           {
+               for (i = 0; i < values->ga_len; ++i)
+               {
+                   bval_T  *vp = (bval_T *)(values->ga_data) + i;
+ 
+                   if (vp->bv_type == BVAL_STRING && !vp->bv_allocated)
+                   {
+                       vp->bv_string = vim_strnsave(vp->bv_string, vp->bv_len);
+                       vp->bv_allocated = TRUE;
+                   }
+               }
+               allocated = TRUE;
+           }
+ 
+           if (vim_isdigit(p[1]))
+           {
+               size_t len;
+               size_t todo;
+               size_t n;
+ 
+               // String value was split into lines that are each shorter
+               // than LSIZE:
+               //     |{bartype},>{length of "{text}{text2}"}
+               //     |<"{text1}
+               //     |<{text2}",{value}
+               // Length includes the quotes.
+               ++p;
+               len = getdigits(&p);
+               buf = alloc((int)(len + 1));
+               if (buf == NULL)
+                   return TRUE;
+               p = buf;
+               for (todo = len; todo > 0; todo -= n)
+               {
+                   eof = viminfo_readline(virp);
+                   if (eof || virp->vir_line[0] != '|'
+                                                 || virp->vir_line[1] != '<')
+                   {
+                       // File was truncated or garbled. Read another line if
+                       // this one starts with '|'.
+                       vim_free(buf);
+                       return eof || virp->vir_line[0] == '|';
+                   }
+                   // Get length of text, excluding |< and NL chars.
+                   n = STRLEN(virp->vir_line);
+                   while (n > 0 && (virp->vir_line[n - 1] == NL
+                                            || virp->vir_line[n - 1] == CAR))
+                       --n;
+                   n -= 2;
+                   if (n > todo)
+                   {
+                       // more values follow after the string
+                       nextp = virp->vir_line + 2 + todo;
+                       n = todo;
+                   }
+                   mch_memmove(p, virp->vir_line + 2, n);
+                   p += n;
+               }
+               *p = NUL;
+               p = buf;
+           }
+           else
+           {
+               // Line ending in ">" continues in the next line:
+               //     |{bartype},{lots of values},>
+               //     |<{value},{value}
+               eof = viminfo_readline(virp);
+               if (eof || virp->vir_line[0] != '|'
+                                             || virp->vir_line[1] != '<')
+                   // File was truncated or garbled. Read another line if
+                   // this one starts with '|'.
+                   return eof || virp->vir_line[0] == '|';
+               p = virp->vir_line + 2;
+           }
+       }
+ 
+       if (isdigit(*p))
+       {
+           value->bv_type = BVAL_NR;
+           value->bv_nr = getdigits(&p);
+           ++values->ga_len;
+       }
+       else if (*p == '"')
+       {
+           int     len = 0;
+           char_u  *s = p;
+ 
+           // Unescape special characters in-place.
+           ++p;
+           while (*p != '"')
+           {
+               if (*p == NL || *p == NUL)
+                   return TRUE;  // syntax error, drop the value
+               if (*p == '\\')
+               {
+                   ++p;
+                   if (*p == 'n')
+                       s[len++] = '\n';
+                   else
+                       s[len++] = *p;
+                   ++p;
+               }
+               else
+                   s[len++] = *p++;
+           }
+           ++p;
+           s[len] = NUL;
+ 
+           converted = FALSE;
+           if (virp->vir_conv.vc_type != CONV_NONE && *s != NUL)
+           {
+               sconv = string_convert(&virp->vir_conv, s, NULL);
+               if (sconv != NULL)
+               {
+                   if (s == buf)
+                       vim_free(s);
+                   s = sconv;
+                   buf = s;
+                   converted = TRUE;
+               }
+           }
+ 
+           // Need to copy in allocated memory if the string wasn't allocated
+           // above and we did allocate before, thus vir_line may change.
+           if (s != buf && allocated)
+               s = vim_strsave(s);
+           value->bv_string = s;
+           value->bv_type = BVAL_STRING;
+           value->bv_len = len;
+           value->bv_allocated = allocated || converted;
+           ++values->ga_len;
+           if (nextp != NULL)
+           {
+               // values following a long string
+               p = nextp;
+               nextp = NULL;
+           }
+       }
+       else if (*p == ',')
+       {
+           value->bv_type = BVAL_EMPTY;
+           ++values->ga_len;
+       }
+       else
+           break;
+     }
+     return TRUE;
+ }
+ 
+     static int
+ read_viminfo_barline(vir_T *virp, int got_encoding, int force, int writing)
+ {
+     char_u    *p = virp->vir_line + 1;
+     int               bartype;
+     garray_T  values;
+     bval_T    *vp;
+     int               i;
+     int               read_next = TRUE;
+ 
+     /*
+      * The format is: |{bartype},{value},...
+      * For a very long string:
+      *     |{bartype},>{length of "{text}{text2}"}
+      *     |<{text1}
+      *     |<{text2},{value}
+      * For a long line not using a string
+      *     |{bartype},{lots of values},>
+      *     |<{value},{value}
+      */
+     if (*p == '<')
+     {
+       // Continuation line of an unrecognized item.
+       if (writing)
+           ga_add_string(&virp->vir_barlines, virp->vir_line);
+     }
+     else
+     {
+       ga_init2(&values, sizeof(bval_T), 20);
+       bartype = getdigits(&p);
+       switch (bartype)
+       {
+           case BARTYPE_VERSION:
+               // Only use the version when it comes before the encoding.
+               // If it comes later it was copied by a Vim version that
+               // doesn't understand the version.
+               if (!got_encoding)
+               {
+                   read_next = barline_parse(virp, p, &values);
+                   vp = (bval_T *)values.ga_data;
+                   if (values.ga_len > 0 && vp->bv_type == BVAL_NR)
+                       virp->vir_version = vp->bv_nr;
+               }
+               break;
+ 
+           case BARTYPE_HISTORY:
+               read_next = barline_parse(virp, p, &values);
+               handle_viminfo_history(&values, writing);
+               break;
+ 
+           case BARTYPE_REGISTER:
+               read_next = barline_parse(virp, p, &values);
+               handle_viminfo_register(&values, force);
+               break;
+ 
+           case BARTYPE_MARK:
+               read_next = barline_parse(virp, p, &values);
+               handle_viminfo_mark(&values, force);
+               break;
+ 
+           default:
+               // copy unrecognized line (for future use)
+               if (writing)
+                   ga_add_string(&virp->vir_barlines, virp->vir_line);
+       }
+       for (i = 0; i < values.ga_len; ++i)
+       {
+           vp = (bval_T *)values.ga_data + i;
+           if (vp->bv_type == BVAL_STRING && vp->bv_allocated)
+               vim_free(vp->bv_string);
+       }
+       ga_clear(&values);
+     }
+ 
+     if (read_next)
+       return viminfo_readline(virp);
+     return FALSE;
+ }
+ 
+     static void
+ write_viminfo_version(FILE *fp_out)
+ {
+     fprintf(fp_out, "# Viminfo version\n|%d,%d\n\n",
+                                           BARTYPE_VERSION, VIMINFO_VERSION);
+ }
+ 
+     static int
+ no_viminfo(void)
+ {
+     // "vim -i NONE" does not read or write a viminfo file
+     return STRCMP(p_viminfofile, "NONE") == 0;
+ }
+ 
+ /*
+  * Report an error for reading a viminfo file.
+  * Count the number of errors.        When there are more than 10, return 
TRUE.
+  */
+     int
+ viminfo_error(char *errnum, char *message, char_u *line)
+ {
+     vim_snprintf((char *)IObuff, IOSIZE, _("%sviminfo: %s in line: "),
+                                                            errnum, message);
+     STRNCAT(IObuff, line, IOSIZE - STRLEN(IObuff) - 1);
+     if (IObuff[STRLEN(IObuff) - 1] == '\n')
+       IObuff[STRLEN(IObuff) - 1] = NUL;
+     emsg((char *)IObuff);
+     if (++viminfo_errcnt >= 10)
+     {
+       emsg(_("E136: viminfo: Too many errors, skipping rest of file"));
+       return TRUE;
+     }
+     return FALSE;
+ }
+ 
+ /*
+  * Compare the 'encoding' value in the viminfo file with the current value of
+  * 'encoding'.  If different and the 'c' flag is in 'viminfo', setup for
+  * conversion of text with iconv() in viminfo_readstring().
+  */
+     static int
+ viminfo_encoding(vir_T *virp)
+ {
+     char_u    *p;
+     int               i;
+ 
+     if (get_viminfo_parameter('c') != 0)
+     {
+       p = vim_strchr(virp->vir_line, '=');
+       if (p != NULL)
+       {
+           // remove trailing newline
+           ++p;
+           for (i = 0; vim_isprintc(p[i]); ++i)
+               ;
+           p[i] = NUL;
+ 
+           convert_setup(&virp->vir_conv, p, p_enc);
+       }
+     }
+     return viminfo_readline(virp);
+ }
+ 
+ #if defined(FEAT_EVAL) || defined(PROTO)
+ /*
+  * Restore global vars that start with a capital from the viminfo file
+  */
+     static int
+ read_viminfo_varlist(vir_T *virp, int writing)
+ {
+     char_u    *tab;
+     int               type = VAR_NUMBER;
+     typval_T  tv;
+     funccal_entry_T funccal_entry;
+ 
+     if (!writing && (find_viminfo_parameter('!') != NULL))
+     {
+       tab = vim_strchr(virp->vir_line + 1, '\t');
+       if (tab != NULL)
+       {
+           *tab++ = '\0';      // isolate the variable name
+           switch (*tab)
+           {
+               case 'S': type = VAR_STRING; break;
+ #ifdef FEAT_FLOAT
+               case 'F': type = VAR_FLOAT; break;
+ #endif
+               case 'D': type = VAR_DICT; break;
+               case 'L': type = VAR_LIST; break;
+               case 'B': type = VAR_BLOB; break;
+               case 'X': type = VAR_SPECIAL; break;
+           }
+ 
+           tab = vim_strchr(tab, '\t');
+           if (tab != NULL)
+           {
+               tv.v_type = type;
+               if (type == VAR_STRING || type == VAR_DICT
+                       || type == VAR_LIST || type == VAR_BLOB)
+                   tv.vval.v_string = viminfo_readstring(virp,
+                                      (int)(tab - virp->vir_line + 1), TRUE);
+ #ifdef FEAT_FLOAT
+               else if (type == VAR_FLOAT)
+                   (void)string2float(tab + 1, &tv.vval.v_float);
+ #endif
+               else
+                   tv.vval.v_number = atol((char *)tab + 1);
+               if (type == VAR_DICT || type == VAR_LIST)
+               {
+                   typval_T *etv = eval_expr(tv.vval.v_string, NULL);
+ 
+                   if (etv == NULL)
+                       // Failed to parse back the dict or list, use it as a
+                       // string.
+                       tv.v_type = VAR_STRING;
+                   else
+                   {
+                       vim_free(tv.vval.v_string);
+                       tv = *etv;
+                       vim_free(etv);
+                   }
+               }
+               else if (type == VAR_BLOB)
+               {
+                   blob_T *blob = string2blob(tv.vval.v_string);
+ 
+                   if (blob == NULL)
+                       // Failed to parse back the blob, use it as a string.
+                       tv.v_type = VAR_STRING;
+                   else
+                   {
+                       vim_free(tv.vval.v_string);
+                       tv.v_type = VAR_BLOB;
+                       tv.vval.v_blob = blob;
+                   }
+               }
+ 
+               // when in a function use global variables
+               save_funccal(&funccal_entry);
+               set_var(virp->vir_line + 1, &tv, FALSE);
+               restore_funccal();
+ 
+               if (tv.v_type == VAR_STRING)
+                   vim_free(tv.vval.v_string);
+               else if (tv.v_type == VAR_DICT || tv.v_type == VAR_LIST ||
+                       tv.v_type == VAR_BLOB)
+                   clear_tv(&tv);
+           }
+       }
+     }
+ 
+     return viminfo_readline(virp);
+ }
+ 
+ /*
+  * Write global vars that start with a capital to the viminfo file
+  */
+     static void
+ write_viminfo_varlist(FILE *fp)
+ {
+     hashitem_T        *hi;
+     dictitem_T        *this_var;
+     int               todo;
+     char      *s = "";
+     char_u    *p;
+     char_u    *tofree;
+     char_u    numbuf[NUMBUFLEN];
+ 
+     if (find_viminfo_parameter('!') == NULL)
+       return;
+ 
+     fputs(_("\n# global variables:\n"), fp);
+ 
+     todo = (int)globvarht.ht_used;
+     for (hi = globvarht.ht_array; todo > 0; ++hi)
+     {
+       if (!HASHITEM_EMPTY(hi))
+       {
+           --todo;
+           this_var = HI2DI(hi);
+           if (var_flavour(this_var->di_key) == VAR_FLAVOUR_VIMINFO)
+           {
+               switch (this_var->di_tv.v_type)
+               {
+                   case VAR_STRING: s = "STR"; break;
+                   case VAR_NUMBER: s = "NUM"; break;
+                   case VAR_FLOAT:  s = "FLO"; break;
+                   case VAR_DICT:   s = "DIC"; break;
+                   case VAR_LIST:   s = "LIS"; break;
+                   case VAR_BLOB:   s = "BLO"; break;
+                   case VAR_SPECIAL: s = "XPL"; break;
+ 
+                   case VAR_UNKNOWN:
+                   case VAR_FUNC:
+                   case VAR_PARTIAL:
+                   case VAR_JOB:
+                   case VAR_CHANNEL:
+                                    continue;
+               }
+               fprintf(fp, "!%s\t%s\t", this_var->di_key, s);
+               if (this_var->di_tv.v_type == VAR_SPECIAL)
+               {
+                   sprintf((char *)numbuf, "%ld",
+                                         (long)this_var->di_tv.vval.v_number);
+                   p = numbuf;
+                   tofree = NULL;
+               }
+               else
+                   p = echo_string(&this_var->di_tv, &tofree, numbuf, 0);
+               if (p != NULL)
+                   viminfo_writestring(fp, p);
+               vim_free(tofree);
+           }
+       }
+     }
+ }
+ #endif // FEAT_EVAL
+ 
+ /*
+  * read_viminfo_up_to_marks() -- Only called from do_viminfo().  Reads in the
+  * first part of the viminfo file which contains everything but the marks that
+  * are local to a file.  Returns TRUE when end-of-file is reached. -- webb
+  */
+     static int
+ read_viminfo_up_to_marks(
+     vir_T     *virp,
+     int               forceit,
+     int               writing)
+ {
+     int               eof;
+     buf_T     *buf;
+     int               got_encoding = FALSE;
+ 
+ #ifdef FEAT_CMDHIST
+     prepare_viminfo_history(forceit ? 9999 : 0, writing);
+ #endif
+ 
+     eof = viminfo_readline(virp);
+     while (!eof && virp->vir_line[0] != '>')
+     {
+       switch (virp->vir_line[0])
+       {
+               // Characters reserved for future expansion, ignored now
+           case '+': // "+40 /path/dir file", for running vim without args
+           case '^': // to be defined
+           case '<': // long line - ignored
+               // A comment or empty line.
+           case NUL:
+           case '\r':
+           case '\n':
+           case '#':
+               eof = viminfo_readline(virp);
+               break;
+           case '|':
+               eof = read_viminfo_barline(virp, got_encoding,
+                                                           forceit, writing);
+               break;
+           case '*': // "*encoding=value"
+               got_encoding = TRUE;
+               eof = viminfo_encoding(virp);
+               break;
+           case '!': // global variable
+ #ifdef FEAT_EVAL
+               eof = read_viminfo_varlist(virp, writing);
+ #else
+               eof = viminfo_readline(virp);
+ #endif
+               break;
+           case '%': // entry for buffer list
+               eof = read_viminfo_bufferlist(virp, writing);
+               break;
+           case '"':
+               // When registers are in bar lines skip the old style register
+               // lines.
+               if (virp->vir_version < VIMINFO_VERSION_WITH_REGISTERS)
+                   eof = read_viminfo_register(virp, forceit);
+               else
+                   do {
+                       eof = viminfo_readline(virp);
+                   } while (!eof && (virp->vir_line[0] == TAB
+                                               || virp->vir_line[0] == '<'));
+               break;
+           case '/':       // Search string
+           case '&':       // Substitute search string
+           case '~':       // Last search string, followed by '/' or '&'
+               eof = read_viminfo_search_pattern(virp, forceit);
+               break;
+           case '$':
+               eof = read_viminfo_sub_string(virp, forceit);
+               break;
+           case ':':
+           case '?':
+           case '=':
+           case '@':
+ #ifdef FEAT_CMDHIST
+               // When history is in bar lines skip the old style history
+               // lines.
+               if (virp->vir_version < VIMINFO_VERSION_WITH_HISTORY)
+                   eof = read_viminfo_history(virp, writing);
+               else
+ #endif
+                   eof = viminfo_readline(virp);
+               break;
+           case '-':
+           case '\'':
+               // When file marks are in bar lines skip the old style lines.
+               if (virp->vir_version < VIMINFO_VERSION_WITH_MARKS)
+                   eof = read_viminfo_filemark(virp, forceit);
+               else
+                   eof = viminfo_readline(virp);
+               break;
+           default:
+               if (viminfo_error("E575: ", _("Illegal starting char"),
+                           virp->vir_line))
+                   eof = TRUE;
+               else
+                   eof = viminfo_readline(virp);
+               break;
+       }
+     }
+ 
+ #ifdef FEAT_CMDHIST
+     // Finish reading history items.
+     if (!writing)
+       finish_viminfo_history(virp);
+ #endif
+ 
+     // Change file names to buffer numbers for fmarks.
+     FOR_ALL_BUFFERS(buf)
+       fmarks_check_names(buf);
+ 
+     return eof;
+ }
+ 
+ /*
+  * do_viminfo() -- Should only be called from read_viminfo() & 
write_viminfo().
+  */
+     static void
+ do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
+ {
+     int               eof = FALSE;
+     vir_T     vir;
+     int               merge = FALSE;
+     int               do_copy_marks = FALSE;
+     garray_T  buflist;
+ 
+     if ((vir.vir_line = alloc(LSIZE)) == NULL)
+       return;
+     vir.vir_fd = fp_in;
+     vir.vir_conv.vc_type = CONV_NONE;
+     ga_init2(&vir.vir_barlines, (int)sizeof(char_u *), 100);
+     vir.vir_version = -1;
+ 
+     if (fp_in != NULL)
+     {
+       if (flags & VIF_WANT_INFO)
+       {
+           if (fp_out != NULL)
+           {
+               // Registers and marks are read and kept separate from what
+               // this Vim is using.  They are merged when writing.
+               prepare_viminfo_registers();
+               prepare_viminfo_marks();
+           }
+ 
+           eof = read_viminfo_up_to_marks(&vir,
+                                        flags & VIF_FORCEIT, fp_out != NULL);
+           merge = TRUE;
+       }
+       else if (flags != 0)
+           // Skip info, find start of marks
+           while (!(eof = viminfo_readline(&vir))
+                   && vir.vir_line[0] != '>')
+               ;
+ 
+       do_copy_marks = (flags &
+                          (VIF_WANT_MARKS | VIF_GET_OLDFILES | VIF_FORCEIT));
+     }
+ 
+     if (fp_out != NULL)
+     {
+       // Write the info:
+       fprintf(fp_out, _("# This viminfo file was generated by Vim %s.\n"),
+                                                         VIM_VERSION_MEDIUM);
+       fputs(_("# You may edit it if you're careful!\n\n"), fp_out);
+       write_viminfo_version(fp_out);
+       fputs(_("# Value of 'encoding' when this file was written\n"), fp_out);
+       fprintf(fp_out, "*encoding=%s\n\n", p_enc);
+       write_viminfo_search_pattern(fp_out);
+       write_viminfo_sub_string(fp_out);
+ #ifdef FEAT_CMDHIST
+       write_viminfo_history(fp_out, merge);
+ #endif
+       write_viminfo_registers(fp_out);
+       finish_viminfo_registers();
+ #ifdef FEAT_EVAL
+       write_viminfo_varlist(fp_out);
+ #endif
+       write_viminfo_filemarks(fp_out);
+       finish_viminfo_marks();
+       write_viminfo_bufferlist(fp_out);
+       write_viminfo_barlines(&vir, fp_out);
+ 
+       if (do_copy_marks)
+           ga_init2(&buflist, sizeof(buf_T *), 50);
+       write_viminfo_marks(fp_out, do_copy_marks ? &buflist : NULL);
+     }
+ 
+     if (do_copy_marks)
+     {
+       copy_viminfo_marks(&vir, fp_out, &buflist, eof, flags);
+       if (fp_out != NULL)
+           ga_clear(&buflist);
+     }
+ 
+     vim_free(vir.vir_line);
+     if (vir.vir_conv.vc_type != CONV_NONE)
+       convert_setup(&vir.vir_conv, NULL, NULL);
+     ga_clear_strings(&vir.vir_barlines);
+ }
+ 
+ /*
+  * read_viminfo() -- Read the viminfo file.  Registers etc. which are already
+  * set are not over-written unless "flags" includes VIF_FORCEIT. -- webb
+  */
+     int
+ read_viminfo(
+     char_u    *file,      // file name or NULL to use default name
+     int               flags)      // VIF_WANT_INFO et al.
+ {
+     FILE      *fp;
+     char_u    *fname;
+ 
+     if (no_viminfo())
+       return FAIL;
+ 
+     fname = viminfo_filename(file);   // get file name in allocated buffer
+     if (fname == NULL)
+       return FAIL;
+     fp = mch_fopen((char *)fname, READBIN);
+ 
+     if (p_verbose > 0)
+     {
+       verbose_enter();
+       smsg(_("Reading viminfo file \"%s\"%s%s%s"),
+               fname,
+               (flags & VIF_WANT_INFO) ? _(" info") : "",
+               (flags & VIF_WANT_MARKS) ? _(" marks") : "",
+               (flags & VIF_GET_OLDFILES) ? _(" oldfiles") : "",
+               fp == NULL ? _(" FAILED") : "");
+       verbose_leave();
+     }
+ 
+     vim_free(fname);
+     if (fp == NULL)
+       return FAIL;
+ 
+     viminfo_errcnt = 0;
+     do_viminfo(fp, NULL, flags);
+ 
+     fclose(fp);
+     return OK;
+ }
+ 
+ /*
+  * Write the viminfo file.  The old one is read in first so that effectively a
+  * merge of current info and old info is done.  This allows multiple vims to
+  * run simultaneously, without losing any marks etc.
+  * If "forceit" is TRUE, then the old file is not read in, and only internal
+  * info is written to the file.
+  */
+     void
+ write_viminfo(char_u *file, int forceit)
+ {
+     char_u    *fname;
+     FILE      *fp_in = NULL;  // input viminfo file, if any
+     FILE      *fp_out = NULL; // output viminfo file
+     char_u    *tempname = NULL;       // name of temp viminfo file
+     stat_T    st_new;         // mch_stat() of potential new file
+ #if defined(UNIX) || defined(VMS)
+     mode_t    umask_save;
+ #endif
+ #ifdef UNIX
+     int               shortname = FALSE;      // use 8.3 file name
+     stat_T    st_old;         // mch_stat() of existing viminfo file
+ #endif
+ #ifdef MSWIN
+     int               hidden = FALSE;
+ #endif
+ 
+     if (no_viminfo())
+       return;
+ 
+     fname = viminfo_filename(file);   // may set to default if NULL
+     if (fname == NULL)
+       return;
+ 
+     fp_in = mch_fopen((char *)fname, READBIN);
+     if (fp_in == NULL)
+     {
+       int fd;
+ 
+       // if it does exist, but we can't read it, don't try writing
+       if (mch_stat((char *)fname, &st_new) == 0)
+           goto end;
+ 
+       // Create the new .viminfo non-accessible for others, because it may
+       // contain text from non-accessible documents. It is up to the user to
+       // widen access (e.g. to a group). This may also fail if there is a
+       // race condition, then just give up.
+       fd = mch_open((char *)fname,
+                           O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
+       if (fd < 0)
+           goto end;
+       fp_out = fdopen(fd, WRITEBIN);
+     }
+     else
+     {
+       /*
+        * There is an existing viminfo file.  Create a temporary file to
+        * write the new viminfo into, in the same directory as the
+        * existing viminfo file, which will be renamed once all writing is
+        * successful.
+        */
+ #ifdef UNIX
+       /*
+        * For Unix we check the owner of the file.  It's not very nice to
+        * overwrite a user's viminfo file after a "su root", with a
+        * viminfo file that the user can't read.
+        */
+       st_old.st_dev = (dev_t)0;
+       st_old.st_ino = 0;
+       st_old.st_mode = 0600;
+       if (mch_stat((char *)fname, &st_old) == 0
+               && getuid() != ROOT_UID
+               && !(st_old.st_uid == getuid()
+                       ? (st_old.st_mode & 0200)
+                       : (st_old.st_gid == getgid()
+                               ? (st_old.st_mode & 0020)
+                               : (st_old.st_mode & 0002))))
+       {
+           int tt = msg_didany;
+ 
+           // avoid a wait_return for this message, it's annoying
+           semsg(_("E137: Viminfo file is not writable: %s"), fname);
+           msg_didany = tt;
+           fclose(fp_in);
+           goto end;
+       }
+ #endif
+ #ifdef MSWIN
+       // Get the file attributes of the existing viminfo file.
+       hidden = mch_ishidden(fname);
+ #endif
+ 
+       /*
+        * Make tempname, find one that does not exist yet.
+        * Beware of a race condition: If someone logs out and all Vim
+        * instances exit at the same time a temp file might be created between
+        * stat() and open().  Use mch_open() with O_EXCL to avoid that.
+        * May try twice: Once normal and once with shortname set, just in
+        * case somebody puts his viminfo file in an 8.3 filesystem.
+        */
+       for (;;)
+       {
+           int         next_char = 'z';
+           char_u      *wp;
+ 
+           tempname = buf_modname(
+ #ifdef UNIX
+                                   shortname,
+ #else
+                                   FALSE,
+ #endif
+                                   fname,
+ #ifdef VMS
+                                   (char_u *)"-tmp",
+ #else
+                                   (char_u *)".tmp",
+ #endif
+                                   FALSE);
+           if (tempname == NULL)               // out of memory
+               break;
+ 
+           /*
+            * Try a series of names.  Change one character, just before
+            * the extension.  This should also work for an 8.3
+            * file name, when after adding the extension it still is
+            * the same file as the original.
+            */
+           wp = tempname + STRLEN(tempname) - 5;
+           if (wp < gettail(tempname))     // empty file name?
+               wp = gettail(tempname);
+           for (;;)
+           {
+               /*
+                * Check if tempfile already exists.  Never overwrite an
+                * existing file!
+                */
+               if (mch_stat((char *)tempname, &st_new) == 0)
+               {
+ #ifdef UNIX
+                   /*
+                    * Check if tempfile is same as original file.  May happen
+                    * when modname() gave the same file back.  E.g.  silly
+                    * link, or file name-length reached.  Try again with
+                    * shortname set.
+                    */
+                   if (!shortname && st_new.st_dev == st_old.st_dev
+                                               && st_new.st_ino == 
st_old.st_ino)
+                   {
+                       VIM_CLEAR(tempname);
+                       shortname = TRUE;
+                       break;
+                   }
+ #endif
+               }
+               else
+               {
+                   // Try creating the file exclusively.  This may fail if
+                   // another Vim tries to do it at the same time.
+ #ifdef VMS
+                   // fdopen() fails for some reason
+                   umask_save = umask(077);
+                   fp_out = mch_fopen((char *)tempname, WRITEBIN);
+                   (void)umask(umask_save);
+ #else
+                   int fd;
+ 
+                   // Use mch_open() to be able to use O_NOFOLLOW and set file
+                   // protection:
+                   // Unix: same as original file, but strip s-bit.  Reset
+                   // umask to avoid it getting in the way.
+                   // Others: r&w for user only.
+ # ifdef UNIX
+                   umask_save = umask(0);
+                   fd = mch_open((char *)tempname,
+                           O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW,
+                                       (int)((st_old.st_mode & 0777) | 0600));
+                   (void)umask(umask_save);
+ # else
+                   fd = mch_open((char *)tempname,
+                            O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
+ # endif
+                   if (fd < 0)
+                   {
+                       fp_out = NULL;
+ # ifdef EEXIST
+                       // Avoid trying lots of names while the problem is lack
+                       // of permission, only retry if the file already
+                       // exists.
+                       if (errno != EEXIST)
+                           break;
+ # endif
+                   }
+                   else
+                       fp_out = fdopen(fd, WRITEBIN);
+ #endif // VMS
+                   if (fp_out != NULL)
+                       break;
+               }
+ 
+               // Assume file exists, try again with another name.
+               if (next_char == 'a' - 1)
+               {
+                   // They all exist?  Must be something wrong! Don't write
+                   // the viminfo file then.
+                   semsg(_("E929: Too many viminfo temp files, like %s!"),
+                                                                    tempname);
+                   break;
+               }
+               *wp = next_char;
+               --next_char;
+           }
+ 
+           if (tempname != NULL)
+               break;
+           // continue if shortname was set
+       }
+ 
+ #if defined(UNIX) && defined(HAVE_FCHOWN)
+       if (tempname != NULL && fp_out != NULL)
+       {
+               stat_T  tmp_st;
+ 
+           /*
+            * Make sure the original owner can read/write the tempfile and
+            * otherwise preserve permissions, making sure the group matches.
+            */
+           if (mch_stat((char *)tempname, &tmp_st) >= 0)
+           {
+               if (st_old.st_uid != tmp_st.st_uid)
+                   // Changing the owner might fail, in which case the
+                   // file will now owned by the current user, oh well.
+                   vim_ignored = fchown(fileno(fp_out), st_old.st_uid, -1);
+               if (st_old.st_gid != tmp_st.st_gid
+                       && fchown(fileno(fp_out), -1, st_old.st_gid) == -1)
+                   // can't set the group to what it should be, remove
+                   // group permissions
+                   (void)mch_setperm(tempname, 0600);
+           }
+           else
+               // can't stat the file, set conservative permissions
+               (void)mch_setperm(tempname, 0600);
+       }
+ #endif
+     }
+ 
+     /*
+      * Check if the new viminfo file can be written to.
+      */
+     if (fp_out == NULL)
+     {
+       semsg(_("E138: Can't write viminfo file %s!"),
+                      (fp_in == NULL || tempname == NULL) ? fname : tempname);
+       if (fp_in != NULL)
+           fclose(fp_in);
+       goto end;
+     }
+ 
+     if (p_verbose > 0)
+     {
+       verbose_enter();
+       smsg(_("Writing viminfo file \"%s\""), fname);
+       verbose_leave();
+     }
+ 
+     viminfo_errcnt = 0;
+     do_viminfo(fp_in, fp_out, forceit ? 0 : (VIF_WANT_INFO | VIF_WANT_MARKS));
+ 
+     if (fclose(fp_out) == EOF)
+       ++viminfo_errcnt;
+ 
+     if (fp_in != NULL)
+     {
+       fclose(fp_in);
+ 
+       // In case of an error keep the original viminfo file.  Otherwise
+       // rename the newly written file.  Give an error if that fails.
+       if (viminfo_errcnt == 0)
+       {
+           if (vim_rename(tempname, fname) == -1)
+           {
+               ++viminfo_errcnt;
+               semsg(_("E886: Can't rename viminfo file to %s!"), fname);
+           }
+ # ifdef MSWIN
+           // If the viminfo file was hidden then also hide the new file.
+           else if (hidden)
+               mch_hide(fname);
+ # endif
+       }
+       if (viminfo_errcnt > 0)
+           mch_remove(tempname);
+     }
+ 
+ end:
+     vim_free(fname);
+     vim_free(tempname);
+ }
+ 
+ /*
+  * Read a line from the viminfo file.
+  * Returns TRUE for end-of-file;
+  */
+     int
+ viminfo_readline(vir_T *virp)
+ {
+     return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
+ }
+ 
+ /*
+  * Check string read from viminfo file.
+  * Remove '\n' at the end of the line.
+  * - replace CTRL-V CTRL-V with CTRL-V
+  * - replace CTRL-V 'n'    with '\n'
+  *
+  * Check for a long line as written by viminfo_writestring().
+  *
+  * Return the string in allocated memory (NULL when out of memory).
+  */
+     char_u *
+ viminfo_readstring(
+     vir_T     *virp,
+     int               off,                // offset for virp->vir_line
+     int               convert UNUSED)     // convert the string
+ {
+     char_u    *retval;
+     char_u    *s, *d;
+     long      len;
+ 
+     if (virp->vir_line[off] == Ctrl_V && vim_isdigit(virp->vir_line[off + 1]))
+     {
+       len = atol((char *)virp->vir_line + off + 1);
+       retval = lalloc(len, TRUE);
+       if (retval == NULL)
+       {
+           // Line too long?  File messed up?  Skip next line.
+           (void)vim_fgets(virp->vir_line, 10, virp->vir_fd);
+           return NULL;
+       }
+       (void)vim_fgets(retval, (int)len, virp->vir_fd);
+       s = retval + 1;     // Skip the leading '<'
+     }
+     else
+     {
+       retval = vim_strsave(virp->vir_line + off);
+       if (retval == NULL)
+           return NULL;
+       s = retval;
+     }
+ 
+     // Change CTRL-V CTRL-V to CTRL-V and CTRL-V n to \n in-place.
+     d = retval;
+     while (*s != NUL && *s != '\n')
+     {
+       if (s[0] == Ctrl_V && s[1] != NUL)
+       {
+           if (s[1] == 'n')
+               *d++ = '\n';
+           else
+               *d++ = Ctrl_V;
+           s += 2;
+       }
+       else
+           *d++ = *s++;
+     }
+     *d = NUL;
+ 
+     if (convert && virp->vir_conv.vc_type != CONV_NONE && *retval != NUL)
+     {
+       d = string_convert(&virp->vir_conv, retval, NULL);
+       if (d != NULL)
+       {
+           vim_free(retval);
+           retval = d;
+       }
+     }
+ 
+     return retval;
+ }
+ 
+ /*
+  * write string to viminfo file
+  * - replace CTRL-V with CTRL-V CTRL-V
+  * - replace '\n'   with CTRL-V 'n'
+  * - add a '\n' at the end
+  *
+  * For a long line:
+  * - write " CTRL-V <length> \n " in first line
+  * - write " < <string> \n "    in second line
+  */
+     void
+ viminfo_writestring(FILE *fd, char_u *p)
+ {
+     int               c;
+     char_u    *s;
+     int               len = 0;
+ 
+     for (s = p; *s != NUL; ++s)
+     {
+       if (*s == Ctrl_V || *s == '\n')
+           ++len;
+       ++len;
+     }
+ 
+     // If the string will be too long, write its length and put it in the next
+     // line.  Take into account that some room is needed for what comes before
+     // the string (e.g., variable name).  Add something to the length for the
+     // '<', NL and trailing NUL.
+     if (len > LSIZE / 2)
+       fprintf(fd, IF_EB("\026%d\n<", CTRL_V_STR "%d\n<"), len + 3);
+ 
+     while ((c = *p++) != NUL)
+     {
+       if (c == Ctrl_V || c == '\n')
+       {
+           putc(Ctrl_V, fd);
+           if (c == '\n')
+               c = 'n';
+       }
+       putc(c, fd);
+     }
+     putc('\n', fd);
+ }
+ 
+ /*
+  * Write a string in quotes that barline_parse() can read back.
+  * Breaks the line in less than LSIZE pieces when needed.
+  * Returns remaining characters in the line.
+  */
+     int
+ barline_writestring(FILE *fd, char_u *s, int remaining_start)
+ {
+     char_u *p;
+     int           remaining = remaining_start;
+     int           len = 2;
+ 
+     // Count the number of characters produced, including quotes.
+     for (p = s; *p != NUL; ++p)
+     {
+       if (*p == NL)
+           len += 2;
+       else if (*p == '"' || *p == '\\')
+           len += 2;
+       else
+           ++len;
+     }
+     if (len > remaining - 2)
+     {
+       fprintf(fd, ">%d\n|<", len);
+       remaining = LSIZE - 20;
+     }
+ 
+     putc('"', fd);
+     for (p = s; *p != NUL; ++p)
+     {
+       if (*p == NL)
+       {
+           putc('\\', fd);
+           putc('n', fd);
+           --remaining;
+       }
+       else if (*p == '"' || *p == '\\')
+       {
+           putc('\\', fd);
+           putc(*p, fd);
+           --remaining;
+       }
+       else
+           putc(*p, fd);
+       --remaining;
+ 
+       if (remaining < 3)
+       {
+           putc('\n', fd);
+           putc('|', fd);
+           putc('<', fd);
+           // Leave enough space for another continuation.
+           remaining = LSIZE - 20;
+       }
+     }
+     putc('"', fd);
+     return remaining - 2;
+ }
+ 
+ /*
+  * ":rviminfo" and ":wviminfo".
+  */
+     void
+ ex_viminfo(
+     exarg_T   *eap)
+ {
+     char_u    *save_viminfo;
+ 
+     save_viminfo = p_viminfo;
+     if (*p_viminfo == NUL)
+       p_viminfo = (char_u *)"'100";
+     if (eap->cmdidx == CMD_rviminfo)
+     {
+       if (read_viminfo(eap->arg, VIF_WANT_INFO | VIF_WANT_MARKS
+                                 | (eap->forceit ? VIF_FORCEIT : 0)) == FAIL)
+           emsg(_("E195: Cannot open viminfo file for reading"));
+     }
+     else
+       write_viminfo(eap->arg, eap->forceit);
+     p_viminfo = save_viminfo;
+ }
+ 
+ #endif // FEAT_VIMINFO
*** ../vim-8.1.1726/src/version.c       2019-07-21 16:39:56.200095876 +0200
--- src/version.c       2019-07-21 18:58:26.660910830 +0200
***************
*** 779,780 ****
--- 779,782 ----
  {   /* Add new patch number below this line */
+ /**/
+     1727,
  /**/

-- 
The chat program is in public domain.  This is not the GNU public license.
If it breaks then you get to keep both pieces.
                -- Copyright notice for the chat program

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201907211727.x6LHRi6K009032%40masaka.moolenaar.net.

Raspunde prin e-mail lui