summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-07-21 19:25:37 +0200
committerBram Moolenaar <Bram@vim.org>2019-07-21 19:25:37 +0200
commitdefa067c54874dd987121dd7252c62755e0aebfa (patch)
tree4734b054e299ab86a5141b29a5305f7782edd81a
parented997adaa1e9bd057ce732a73d933b739e9d0c30 (diff)
patch 8.1.1727: code for viminfo support is spread outv8.1.1727
Problem: Code for viminfo support is spread out. Solution: Move to code to viminfo.c. (Yegappan Lakshmanan, closes #4686)
-rw-r--r--Filelist2
-rw-r--r--src/Make_cyg_ming.mak1
-rw-r--r--src/Make_morph.mak1
-rw-r--r--src/Make_mvc.mak4
-rw-r--r--src/Make_vms.mms10
-rw-r--r--src/Makefile10
-rw-r--r--src/buffer.c112
-rw-r--r--src/eval.c165
-rw-r--r--src/ex_cmds.c1138
-rw-r--r--src/ex_docmd.c29
-rw-r--r--src/globals.h1
-rw-r--r--src/proto.h3
-rw-r--r--src/proto/buffer.pro3
-rw-r--r--src/proto/eval.pro3
-rw-r--r--src/proto/ex_cmds.pro7
-rw-r--r--src/proto/viminfo.pro10
-rw-r--r--src/structs.h8
-rw-r--r--src/version.c2
-rw-r--r--src/viminfo.c1424
19 files changed, 1481 insertions, 1452 deletions
diff --git a/Filelist b/Filelist
index 73f842fd4b..c04eda603f 100644
--- a/Filelist
+++ b/Filelist
@@ -110,6 +110,7 @@ SRC_ALL = \
src/version.c \
src/version.h \
src/vim.h \
+ src/viminfo.c \
src/winclip.c \
src/window.c \
src/tee/tee.c \
@@ -234,6 +235,7 @@ SRC_ALL = \
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 \
diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak
index a54730b796..4ceaa91177 100644
--- a/src/Make_cyg_ming.mak
+++ b/src/Make_cyg_ming.mak
@@ -772,6 +772,7 @@ OBJ = \
$(OUTDIR)/usercmd.o \
$(OUTDIR)/userfunc.o \
$(OUTDIR)/version.o \
+ $(OUTDIR)/viminfo.o \
$(OUTDIR)/winclip.o \
$(OUTDIR)/window.o
diff --git a/src/Make_morph.mak b/src/Make_morph.mak
index 6990a04274..8d93d7efec 100644
--- a/src/Make_morph.mak
+++ b/src/Make_morph.mak
@@ -89,6 +89,7 @@ SRC = arabic.c \
usercmd.c \
userfunc.c \
version.c \
+ viminfo.c \
window.c \
OBJ = $(SRC:.c=.o)
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak
index 4292b91820..10fcb74040 100644
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -780,6 +780,7 @@ OBJ = \
$(OUTDIR)\undo.obj \
$(OUTDIR)\usercmd.obj \
$(OUTDIR)\userfunc.obj \
+ $(OUTDIR)\viminfo.obj \
$(OUTDIR)\winclip.obj \
$(OUTDIR)\window.obj \
@@ -1643,6 +1644,8 @@ $(OUTDIR)/usercmd.obj: $(OUTDIR) usercmd.c $(INCL)
$(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,6 +1801,7 @@ proto.h: \
proto/undo.pro \
proto/usercmd.pro \
proto/userfunc.pro \
+ proto/viminfo.pro \
proto/window.pro \
$(SOUND_PRO) \
$(NETBEANS_PRO) \
diff --git a/src/Make_vms.mms b/src/Make_vms.mms
index 92c078b822..73f4998b9a 100644
--- a/src/Make_vms.mms
+++ b/src/Make_vms.mms
@@ -316,8 +316,8 @@ SRC = arabic.c autocmd.c beval.c blob.c blowfish.c buffer.c change.c charset.c \
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 \
+ 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,7 +332,7 @@ OBJ = arabic.obj autocmd.obj beval.obj blob.obj blowfish.obj buffer.obj change.
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 \
+ 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,6 +780,10 @@ version.obj : version.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
+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 \
diff --git a/src/Makefile b/src/Makefile
index f4f8cc31da..c6c528d63c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1650,6 +1650,7 @@ BASIC_SRC = \
usercmd.c \
userfunc.c \
version.c \
+ viminfo.c \
window.c \
$(OS_EXTRA_SRC)
@@ -1769,6 +1770,7 @@ OBJ_COMMON = \
objects/usercmd.o \
objects/userfunc.o \
objects/version.o \
+ objects/viminfo.o \
objects/window.o \
$(GUI_OBJ) \
$(TERM_OBJ) \
@@ -1914,6 +1916,7 @@ PRO_AUTO = \
usercmd.pro \
userfunc.pro \
version.pro \
+ viminfo.pro \
window.pro \
beval.pro \
gui_beval.pro \
@@ -3298,6 +3301,9 @@ objects/usercmd.o: usercmd.c
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,6 +3752,10 @@ objects/version.o: version.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 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 \
diff --git a/src/buffer.c b/src/buffer.c
index 74e0ea6d01..55bcc829ab 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -29,7 +29,6 @@
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);
@@ -449,7 +448,8 @@ can_unload_buffer(buf_T *buf)
}
}
if (!can_unload)
- emsg(_("E937: Attempt to delete a buffer that is in use"));
+ semsg(_("E937: Attempt to delete a buffer that is in use: %s"),
+ buf->b_fname);
return can_unload;
}
@@ -2774,7 +2774,7 @@ buflist_nr2name(
* When "copy_options" is TRUE save the local window option values.
* When "lnum" is 0 only do the options.
*/
- static void
+ void
buflist_setfpos(
buf_T *buf,
win_T *win,
@@ -5545,112 +5545,6 @@ chk_modeline(
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.
*/
diff --git a/src/eval.c b/src/eval.c
index 5a4ed677d5..a2d3d97688 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -36,7 +36,6 @@ static char *e_float_as_string = N_("E806: using Float as a String");
#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:".
@@ -9321,14 +9320,7 @@ script_autoload(
}
#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_T
var_flavour(char_u *varname)
{
char_u *p = varname;
@@ -9345,161 +9337,6 @@ var_flavour(char_u *varname)
}
#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)
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index e262da1d59..47d1998e8a 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -20,12 +20,6 @@
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);
@@ -1849,1136 +1843,6 @@ append_redir(
(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_co