diff options
38 files changed, 4485 insertions, 1822 deletions
diff --git a/contrib/YouCompleteMe/ycm_extra_conf.py b/contrib/YouCompleteMe/ycm_extra_conf.py index 7c54677c8f..12ad080143 100644 --- a/contrib/YouCompleteMe/ycm_extra_conf.py +++ b/contrib/YouCompleteMe/ycm_extra_conf.py @@ -9,7 +9,7 @@ def DirectoryOfThisScript(): def GetDatabase(): compilation_database_folder = os.path.join(DirectoryOfThisScript(), - '..', 'build') + '..', '..', 'build') if os.path.exists(compilation_database_folder): return ycm_core.CompilationDatabase(compilation_database_folder) return None diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 897137ff42..085f6f21a8 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -6770,10 +6770,14 @@ A jump table for the options with a short description can be found at |Q_op|. e.g., for Unix: "r/tmp". Case is ignored. Maximum length of each 'r' argument is 50 characters. *viminfo-s* - s Maximum size of an item in Kbyte. If zero then registers are - not saved. Currently only applies to registers. The default - "s10" will exclude registers with more than 10 Kbyte of text. - Also see the '<' item above: line count limit. + s Maximum size of an item contents in KiB. If zero then nothing + is saved. Unlike Vim this applies to all items, except for + the buffer list and header. Full item size is off by three + unsigned integers: with `s10` maximum item size may be 1 byte + (type: 7-bit integer) + 9 bytes (timestamp: up to 64-bit + integer) + 3 bytes (item size: up to 16-bit integer because + 2^8 < 10240 < 2^16) + 10240 bytes (requested maximum item + contents size) = 10253 bytes. Example: > :set viminfo='50,<1000,s100,:0,n~/vim/viminfo @@ -6782,7 +6786,8 @@ A jump table for the options with a short description can be found at |Q_op|. edited. <1000 Contents of registers (up to 1000 lines each) will be remembered. - s100 Registers with more than 100 Kbyte text are skipped. + s100 Items with contents occupying more then 100 KiB are + skipped. :0 Command-line history will not be saved. n~/vim/viminfo The name of the file to use is "~/vim/viminfo". no / Since '/' is not specified, the default will be used, diff --git a/scripts/shadacat.py b/scripts/shadacat.py new file mode 100755 index 0000000000..8f5ed276f8 --- /dev/null +++ b/scripts/shadacat.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3.4 + +import sys +import codecs + +from enum import Enum +from datetime import datetime +from functools import reduce + +import msgpack + + +class EntryTypes(Enum): + Unknown = -1 + Missing = 0 + Header = 1 + SearchPattern = 2 + SubString = 3 + HistoryEntry = 4 + Register = 5 + Variable = 6 + GlobalMark = 7 + Jump = 8 + BufferList = 9 + LocalMark = 10 + + +def strtrans_errors(e): + if not isinstance(e, UnicodeDecodeError): + raise NotImplementedError('don’t know how to handle {0} error'.format( + e.__class__.__name__)) + return '<{0:x}>'.format(reduce((lambda a, b: a*0x100+b), + list(e.object[e.start:e.end]))), e.end + + +codecs.register_error('strtrans', strtrans_errors) + + +def idfunc(o): + return o + + +class CharInt(int): + def __repr__(self): + return super(CharInt, self).__repr__() + ' (\'%s\')' % chr(self) + + +ctable = { + bytes: lambda s: s.decode('utf-8', 'strtrans'), + dict: lambda d: dict((mnormalize(k), mnormalize(v)) for k, v in d.items()), + list: lambda l: list(mnormalize(i) for i in l), + int: lambda n: CharInt(n) if 0x20 <= n <= 0x7E else n, +} + + +def mnormalize(o): + return ctable.get(type(o), idfunc)(o) + + +with open(sys.argv[1], 'rb') as fp: + unpacker = msgpack.Unpacker(file_like=fp) + while True: + try: + typ = EntryTypes(unpacker.unpack()) + except msgpack.OutOfData: + break + else: + timestamp = unpacker.unpack() + time = datetime.fromtimestamp(timestamp) + length = unpacker.unpack() + entry = unpacker.unpack() + print('{0:13} {1} {2:5} {3!r}'.format( + typ.name, time.isoformat(), length, mnormalize(entry))) 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; - e |