diff options
-rw-r--r-- | Filelist | 2 | ||||
-rw-r--r-- | src/Make_cyg_ming.mak | 1 | ||||
-rw-r--r-- | src/Make_morph.mak | 1 | ||||
-rw-r--r-- | src/Make_mvc.mak | 4 | ||||
-rw-r--r-- | src/Make_vms.mms | 10 | ||||
-rw-r--r-- | src/Makefile | 10 | ||||
-rw-r--r-- | src/buffer.c | 112 | ||||
-rw-r--r-- | src/eval.c | 165 | ||||
-rw-r--r-- | src/ex_cmds.c | 1138 | ||||
-rw-r--r-- | src/ex_docmd.c | 29 | ||||
-rw-r--r-- | src/globals.h | 1 | ||||
-rw-r--r-- | src/proto.h | 3 | ||||
-rw-r--r-- | src/proto/buffer.pro | 3 | ||||
-rw-r--r-- | src/proto/eval.pro | 3 | ||||
-rw-r--r-- | src/proto/ex_cmds.pro | 7 | ||||
-rw-r--r-- | src/proto/viminfo.pro | 10 | ||||
-rw-r--r-- | src/structs.h | 8 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/viminfo.c | 1424 |
19 files changed, 1481 insertions, 1452 deletions
@@ -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_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_encodin |