aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZyX <kp-pav@yandex.ru>2015-04-25 18:47:31 +0300
committerZyX <kp-pav@yandex.ru>2015-10-08 21:59:51 +0300
commit244dbe3a77bf548f73d8781da7327f30e818b08a (patch)
tree8777a25447be219fe351106cfef37670e0278ddd /src
parent0fdaab995ed95250b13058a717d5bc562e1834c8 (diff)
downloadrneovim-244dbe3a77bf548f73d8781da7327f30e818b08a.tar.gz
rneovim-244dbe3a77bf548f73d8781da7327f30e818b08a.tar.bz2
rneovim-244dbe3a77bf548f73d8781da7327f30e818b08a.zip
viminfo: First version of ShaDa file dumping
What works: 1. ShaDa file dumping: header, registers, jump list, history, search patterns, substitute strings, variables. 2. ShaDa file reading: registers, global marks, variables. Most was not tested. TODO: 1. Merging. 2. Reading history, local marks, jump and buffer lists. 3. Documentation update. 4. Converting some data from &encoding. 5. Safer variant of dumping viminfo (dump to temporary file then rename). 6. Removing old viminfo code (currently masked with `#if 0` in a ShaDa file for reference).
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/private/helpers.h2
-rw-r--r--src/nvim/auevents.lua2
-rw-r--r--src/nvim/buffer.c94
-rw-r--r--src/nvim/buffer_defs.h19
-rw-r--r--src/nvim/edit.c6
-rw-r--r--src/nvim/eval.c143
-rw-r--r--src/nvim/ex_cmds.c609
-rw-r--r--src/nvim/ex_cmds.h14
-rw-r--r--src/nvim/ex_docmd.c11
-rw-r--r--src/nvim/ex_getln.c387
-rw-r--r--src/nvim/ex_getln.h9
-rw-r--r--src/nvim/fileio.c8
-rw-r--r--src/nvim/globals.h2
-rw-r--r--src/nvim/main.c23
-rw-r--r--src/nvim/mark.c710
-rw-r--r--src/nvim/mark.h16
-rw-r--r--src/nvim/mark_defs.h32
-rw-r--r--src/nvim/mbyte.c2
-rw-r--r--src/nvim/misc1.c5
-rw-r--r--src/nvim/normal.c4
-rw-r--r--src/nvim/ops.c315
-rw-r--r--src/nvim/ops.h20
-rw-r--r--src/nvim/os/time.c9
-rw-r--r--src/nvim/os/time.h2
-rw-r--r--src/nvim/os/unix_defs.h4
-rw-r--r--src/nvim/os/win_defs.h2
-rw-r--r--src/nvim/search.c194
-rw-r--r--src/nvim/search.h24
-rw-r--r--src/nvim/shada.c3454
-rw-r--r--src/nvim/shada.h18
-rw-r--r--src/nvim/tag.c2
-rw-r--r--src/nvim/undo.c30
-rw-r--r--src/nvim/undo_defs.h3
-rw-r--r--src/nvim/window.c2
34 files changed, 4361 insertions, 1816 deletions
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index f29deb53f9..a0f14ac7a4 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -69,6 +69,8 @@
#define ADD(array, item) \
kv_push(Object, array, item)
+#define STATIC_CSTR_AS_STRING(s) ((String) {.data = s, .size = sizeof(s) - 1})
+
// Helpers used by the generated msgpack-rpc api wrappers
#define api_init_boolean
#define api_init_integer
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index af801c6f1a..3d8a75febd 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -84,7 +84,7 @@ return {
'User', -- user defined autocommand
'VimEnter', -- after starting Vim
'VimLeave', -- before exiting Vim
- 'VimLeavePre', -- before exiting Vim and writing .viminfo
+ 'VimLeavePre', -- before exiting Vim and writing ShaDa file
'VimResized', -- after Vim window was resized
'WinEnter', -- after entering a window
'WinLeave', -- before leaving a window
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index b212e75283..5ebeec1b70 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -73,6 +73,7 @@
#include "nvim/undo.h"
#include "nvim/version.h"
#include "nvim/window.h"
+#include "nvim/shada.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
#include "nvim/os/input.h"
@@ -555,6 +556,12 @@ static void free_buffer(buf_T *buf)
free_buffer_stuff(buf, TRUE);
unref_var_dict(buf->b_vars);
aubuflocal_remove(buf);
+ free_fmark(buf->b_last_cursor);
+ free_fmark(buf->b_last_insert);
+ free_fmark(buf->b_last_change);
+ for (size_t i = 0; i < NMARKS; i++) {
+ free_fmark(buf->b_namedm[i]);
+ }
if (autocmd_busy) {
// Do not free the buffer structure while autocommands are executing,
// it's still needed. Free it when autocmd_busy is reset.
@@ -4164,93 +4171,6 @@ chk_modeline (
return retval;
}
-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 = path_shorten_fname_if_possible(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);
- }
- }
- xfree(xline);
-
- return viminfo_readline(virp);
-}
-
-void write_viminfo_bufferlist(FILE *fp)
-{
- 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 = xmalloc(LINE_BUF_LEN);
-
- 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
- || bt_quickfix(buf)
- || 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%" PRId64 "\t%d",
- (int64_t)buf->b_last_cursor.lnum,
- buf->b_last_cursor.col);
- viminfo_writestring(fp, line);
- }
- xfree(line);
-}
-
-
/*
* Return special buffer name.
* Returns NULL when the buffer has a normal file name.
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 98fbef9c87..6fbdea2c62 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -327,15 +327,6 @@ typedef struct {
bool vc_fail; /* fail for invalid char, don't use '?' */
} vimconv_T;
-/*
- * Structure used for reading from the viminfo file.
- */
-typedef struct {
- char_u *vir_line; /* text of the current line */
- FILE *vir_fd; /* file descriptor */
- vimconv_T vir_conv; /* encoding conversion */
-} vir_T;
-
#define CONV_NONE 0
#define CONV_TO_UTF8 1
#define CONV_9_TO_UTF8 2
@@ -515,16 +506,16 @@ struct file_buffer {
uint64_t b_orig_size; /* size of original file in bytes */
int b_orig_mode; /* mode of original file */
- pos_T b_namedm[NMARKS]; /* current named marks (mark.c) */
+ fmark_T b_namedm[NMARKS]; /* current named marks (mark.c) */
/* These variables are set when VIsual_active becomes FALSE */
visualinfo_T b_visual;
int b_visual_mode_eval; /* b_visual.vi_mode for visualmode() */
- pos_T b_last_cursor; /* cursor position when last unloading this
+ fmark_T b_last_cursor; /* cursor position when last unloading this
buffer */
- pos_T b_last_insert; /* where Insert mode was left */
- pos_T b_last_change; /* position of last change: '. mark */
+ fmark_T b_last_insert; /* where Insert mode was left */
+ fmark_T b_last_change; /* position of last change: '. mark */
/*
* the changelist contains old change positions
@@ -553,7 +544,7 @@ struct file_buffer {
pos_T b_op_start_orig; // used for Insstart_orig
pos_T b_op_end;
- bool b_marks_read; /* Have we read viminfo marks yet? */
+ bool b_marks_read; /* Have we read ShaDa marks yet? */
/*
* The following only used in undo.c.
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 427623e052..310191ba06 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -60,6 +60,7 @@
#include "nvim/undo.h"
#include "nvim/window.h"
#include "nvim/event/loop.h"
+#include "nvim/mark.h"
#include "nvim/os/input.h"
#include "nvim/os/time.h"
@@ -6991,8 +6992,9 @@ ins_esc (
curwin->w_set_curswant = TRUE;
/* Remember the last Insert position in the '^ mark. */
- if (!cmdmod.keepjumps)
- curbuf->b_last_insert = curwin->w_cursor;
+ if (!cmdmod.keepjumps) {
+ RESET_FMARK(&curbuf->b_last_insert, curwin->w_cursor, curbuf->b_fnum);
+ }
/*
* The cursor should end up on the last inserted character.
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 65afd19bbe..5a7d4702d2 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -354,7 +354,7 @@ typedef struct {
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_SHADA /* all uppercase */
} var_flavour_T;
/* values for vv_flags: */
@@ -10482,6 +10482,7 @@ static void f_has(typval_T *argvars, typval_T *rettv)
"scrollbind",
"showcmd",
"cmdline_info",
+ "shada",
"signs",
"smartindent",
"startuptime",
@@ -10498,7 +10499,6 @@ static void f_has(typval_T *argvars, typval_T *rettv)
"title",
"user-commands", /* was accidentally included in 5.4 */
"user_commands",
- "viminfo",
"vertsplit",
"virtualedit",
"visual",
@@ -20712,107 +20712,62 @@ static var_flavour_T var_flavour(char_u *varname)
while (*(++p))
if (ASCII_ISLOWER(*p))
return VAR_FLAVOUR_SESSION;
- return VAR_FLAVOUR_VIMINFO;
+ return VAR_FLAVOUR_SHADA;
} else
return VAR_FLAVOUR_DEFAULT;
}
-/*
- * 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;
-
- if (!writing && (find_viminfo_parameter('!') != NULL)) {
- tab = vim_strchr(virp->vir_line + 1, '\t');
- if (tab != NULL) {
- *tab++ = NUL; /* isolate the variable name */
- switch (*tab) {
- case 'S': type = VAR_STRING; break;
- case 'F': type = VAR_FLOAT; break;
- case 'D': type = VAR_DICT; break;
- case 'L': type = VAR_LIST; break;
- }
-
- tab = vim_strchr(tab, '\t');
- if (tab != NULL) {
- tv.v_type = type;
- if (type == VAR_STRING || type == VAR_DICT || type == VAR_LIST)
- tv.vval.v_string = viminfo_readstring(virp,
- (int)(tab - virp->vir_line + 1), TRUE);
- else if (type == VAR_FLOAT)
- (void)string2float(tab + 1, &tv.vval.v_float);
- 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 {
- xfree(tv.vval.v_string);
- tv = *etv;
- xfree(etv);
- }
- }
-
- set_var(virp->vir_line + 1, &tv, FALSE);
-
- if (tv.v_type == VAR_STRING)
- xfree(tv.vval.v_string);
- else if (tv.v_type == VAR_DICT || tv.v_type == VAR_LIST)
- clear_tv(&tv);
- }
+/// Iterate over global variables
+///
+/// @warning No modifications to global variable dictionary must be performed
+/// while iteration is in progress.
+///
+/// @param[in] iter Iterator. Pass NULL to start iteration.
+/// @param[out] name Variable name.
+/// @param[out] rettv Variable value.
+///
+/// @return Pointer that needs to be passed to next `var_shada_iter` invocation
+/// or NULL to indicate that iteration is over.
+const void *var_shada_iter(const void *const iter, const char **const name,
+ typval_T *rettv)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(2, 3)
+{
+ const hashitem_T *hi;
+ const hashitem_T *hifirst = globvarht.ht_array;
+ const size_t hinum = (size_t) globvarht.ht_mask + 1;
+ *name = NULL;
+ if (iter == NULL) {
+ hi = globvarht.ht_array;
+ while ((HASHITEM_EMPTY(hi)
+ || var_flavour(HI2DI(hi)->di_key) != VAR_FLAVOUR_SHADA)
+ && (size_t) (hi - hifirst) < hinum) {
+ hi++;
+ }
+ if (HASHITEM_EMPTY(hi)
+ || var_flavour(HI2DI(hi)->di_key) != VAR_FLAVOUR_SHADA) {
+ *rettv = (typval_T) {.v_type = VAR_UNKNOWN};
+ return NULL;
}
+ } else {
+ hi = (const hashitem_T *) iter;
}
-
- return viminfo_readline(virp);
+ *name = (char *) HI2DI(hi)->di_key;
+ copy_tv(&(HI2DI(hi)->di_tv), rettv);
+ while ((size_t) (++hi - hifirst) < hinum) {
+ if (!HASHITEM_EMPTY(hi)
+ && var_flavour(HI2DI(hi)->di_key) == VAR_FLAVOUR_SHADA) {
+ return hi;
+ }
+ }
+ return NULL;
}
-/*
- * Write global vars that start with a capital to the viminfo file
- */
-void write_viminfo_varlist(FILE *fp)
+void var_set_global(const char *const name, typval_T vartv)
{
- hashitem_T *hi;
- dictitem_T *this_var;
- int todo;
- char *s;
- char_u *p;
-
- 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;
- default: continue;
- }
- fprintf(fp, "!%s\t%s\t", this_var->di_key, s);
- p = (char_u *) echo_string(&this_var->di_tv, NULL);
- if (p != NULL) {
- viminfo_writestring(fp, p);
- }
- xfree(p);
- }
- }
- }
+ funccall_T *const saved_current_funccal = current_funccal;
+ current_funccal = NULL;
+ set_var((char_u *) name, &vartv, false);
+ current_funccal = saved_current_funccal;
}
int store_session_globals(FILE *fd)
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 81abf2fa63..262150a8c0 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -67,6 +67,9 @@
#include "nvim/os/os.h"
#include "nvim/os/shell.h"
#include "nvim/os/input.h"
+#include "nvim/os/time.h"
+#include "nvim/api/private/defs.h"
+#include "nvim/api/private/helpers.h"
/*
* Struct to hold the sign properties.
@@ -1391,550 +1394,6 @@ void append_redir(char_u *buf, int buflen, char_u *opt, char_u *fname)
(char *)opt, (char *)fname);
}
-
-static int viminfo_errcnt;
-
-static int no_viminfo(void)
-{
- /* "vim -i NONE" does not read or write a viminfo file */
- return use_viminfo != NULL && STRCMP(use_viminfo, "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(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 */
- 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();
- }
-
- xfree(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 */
- char_u *wp;
-#if defined(UNIX)
- mode_t umask_save;
-#endif
-
- if (no_viminfo())
- return;
-
- fname = viminfo_filename(file); /* may set to default if NULL */
-
- fp_in = mch_fopen((char *)fname, READBIN);
- if (fp_in == NULL) {
- /* if it does exist, but we can't read it, don't try writing */
- if (os_file_exists(fname))
- goto end;
-#if defined(UNIX)
- /*
- * For Unix we create the .viminfo non-accessible for others,
- * because it may contain text from non-accessible documents.
- */
- umask_save = umask(077);
-#endif
- fp_out = mch_fopen((char *)fname, WRITEBIN);
-#if defined(UNIX)
- (void)umask(umask_save);
-#endif
- } 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 later.
- */
-#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.
- */
-
- FileInfo old_info; // FileInfo of existing viminfo file
- if (os_fileinfo((char *)fname, &old_info)
- && getuid() != ROOT_UID
- && !(old_info.stat.st_uid == getuid()
- ? (old_info.stat.st_mode & 0200)
- : (old_info.stat.st_gid == getgid()
- ? (old_info.stat.st_mode & 0020)
- : (old_info.stat.st_mode & 0002)))) {
- int tt = msg_didany;
-
- /* avoid a wait_return for this message, it's annoying */
- EMSG2(_("E137: Viminfo file is not writable: %s"), fname);
- msg_didany = tt;
- fclose(fp_in);
- goto end;
- }
-#endif
-
- // Make tempname
- tempname = (char_u *)modname((char *)fname, ".tmp", FALSE);
- if (tempname != NULL) {
- /*
- * Check if tempfile already exists. Never overwrite an
- * existing file!
- */
- if (os_file_exists(tempname)) {
- /*
- * Try another name. Change one character, just before
- * the extension.
- */
- wp = tempname + STRLEN(tempname) - 5;
- if (wp < path_tail(tempname)) /* empty file name? */
- wp = path_tail(tempname);
- for (*wp = 'z'; os_file_exists(tempname); --*wp) {
- /*
- * They all exist? Must be something wrong! Don't
- * write the viminfo file then.
- */
- if (*wp == 'a') {
- xfree(tempname);
- tempname = NULL;
- break;
- }
- }
- }
- }
-
- if (tempname != NULL) {
- int fd;
-
- /* Use os_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 = os_open((char *)tempname,
- O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW,
- (int)((old_info.stat.st_mode & 0777) | 0600));
- (void)umask(umask_save);
-# else
- fd = os_open((char *)tempname,
- O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
-# endif
- if (fd < 0)
- fp_out = NULL;
- else
- fp_out = fdopen(fd, WRITEBIN);
-
- /*
- * If we can't create in the same directory, try creating a
- * "normal" temp file.
- */
- if (fp_out == NULL) {
- xfree(tempname);
- if ((tempname = vim_tempname()) != NULL)
- fp_out = mch_fopen((char *)tempname, WRITEBIN);
- }
-
-#ifdef UNIX
- /*
- * Make sure the owner can read/write it. This only works for
- * root.
- */
- if (fp_out != NULL) {
- os_fchown(fileno(fp_out), old_info.stat.st_uid, old_info.stat.st_gid);
- }
-#endif
- }
- }
-
- /*
- * Check if the new viminfo file can be written to.
- */
- if (fp_out == NULL) {
- EMSG2(_("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));
-
- fclose(fp_out); /* errors are ignored !? */
- 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 && vim_rename(tempname, fname) == -1) {
- viminfo_errcnt++;
- EMSG2(_("E886: Can't rename viminfo file to %s!"), fname);
- }
- if (viminfo_errcnt > 0) {
- os_remove((char *)tempname);
- }
- }
-
-end:
- xfree(fname);
- xfree(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.
- */
-static char_u *viminfo_filename(char_u *file)
-{
- if (file == NULL || *file == NUL) {
- if (use_viminfo != NULL)
- file = use_viminfo;
- else if ((file = find_viminfo_parameter('n')) == NULL || *file == NUL) {
-#ifdef VIMINFO_FILE2
- // don't use $HOME when not defined (turned into "c:/"!).
- if (!os_env_exists("HOME")) {
- // 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 count = 0;
- int eof = FALSE;
- vir_T vir;
- int merge = FALSE;
-
- vir.vir_line = xmalloc(LSIZE);
- vir.vir_fd = fp_in;
- vir.vir_conv.vc_type = CONV_NONE;
-
- if (fp_in != NULL) {
- if (flags & VIF_WANT_INFO) {
- 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] != '>')
- ;
- }
- if (fp_out != NULL) {
- /* Write the info: */
- fprintf(fp_out, _("# This viminfo file was generated by Nvim %s.\n"),
- mediumVersion);
- fputs(_("# You may edit it if you're careful!\n\n"), 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);
- write_viminfo_history(fp_out, merge);
- write_viminfo_registers(fp_out);
- write_viminfo_varlist(fp_out);
- write_viminfo_filemarks(fp_out);
- write_viminfo_bufferlist(fp_out);
- count = write_viminfo_marks(fp_out);
- }
- if (fp_in != NULL
- && (flags & (VIF_WANT_MARKS | VIF_GET_OLDFILES | VIF_FORCEIT)))
- copy_viminfo_marks(&vir, fp_out, count, eof, flags);
-
- xfree(vir.vir_line);
- if (vir.vir_conv.vc_type != CONV_NONE)
- convert_setup(&vir.vir_conv, NULL, NULL);
-}
-
-/*
- * 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;
-
- prepare_viminfo_history(forceit ? 9999 : 0, writing);
- 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 '^': /* 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 '*': /* "*encoding=value" */
- eof = viminfo_encoding(virp);
- break;
- case '!': /* global variable */
- eof = read_viminfo_varlist(virp, writing);
- break;
- case '%': /* entry for buffer list */
- eof = read_viminfo_bufferlist(virp, writing);
- break;
- case '"':
- eof = read_viminfo_register(virp, forceit);
- 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;</