1defa067cSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2defa067cSBram Moolenaar *
3defa067cSBram Moolenaar * VIM - Vi IMproved by Bram Moolenaar
4defa067cSBram Moolenaar *
5defa067cSBram Moolenaar * Do ":help uganda" in Vim to read copying and usage conditions.
6defa067cSBram Moolenaar * Do ":help credits" in Vim to see a list of people who contributed.
7defa067cSBram Moolenaar * See README.txt for an overview of the Vim source code.
8defa067cSBram Moolenaar */
9defa067cSBram Moolenaar
10defa067cSBram Moolenaar /*
11defa067cSBram Moolenaar * viminfo.c: viminfo related functions
12defa067cSBram Moolenaar */
13defa067cSBram Moolenaar
14defa067cSBram Moolenaar #include "vim.h"
15defa067cSBram Moolenaar #include "version.h"
16defa067cSBram Moolenaar
176bd1d770SBram Moolenaar /*
186bd1d770SBram Moolenaar * Structure used for reading from the viminfo file.
196bd1d770SBram Moolenaar */
206bd1d770SBram Moolenaar typedef struct
216bd1d770SBram Moolenaar {
226bd1d770SBram Moolenaar char_u *vir_line; // text of the current line
236bd1d770SBram Moolenaar FILE *vir_fd; // file descriptor
246bd1d770SBram Moolenaar vimconv_T vir_conv; // encoding conversion
256bd1d770SBram Moolenaar int vir_version; // viminfo version detected or -1
266bd1d770SBram Moolenaar garray_T vir_barlines; // lines starting with |
276bd1d770SBram Moolenaar } vir_T;
286bd1d770SBram Moolenaar
29408030e8SBram Moolenaar typedef enum {
30408030e8SBram Moolenaar BVAL_NR,
31408030e8SBram Moolenaar BVAL_STRING,
32408030e8SBram Moolenaar BVAL_EMPTY
33408030e8SBram Moolenaar } btype_T;
34408030e8SBram Moolenaar
35408030e8SBram Moolenaar typedef struct {
36408030e8SBram Moolenaar btype_T bv_type;
37408030e8SBram Moolenaar long bv_nr;
38408030e8SBram Moolenaar char_u *bv_string;
39408030e8SBram Moolenaar char_u *bv_tofree; // free later when not NULL
40408030e8SBram Moolenaar int bv_len; // length of bv_string
41408030e8SBram Moolenaar int bv_allocated; // bv_string was allocated
42408030e8SBram Moolenaar } bval_T;
43408030e8SBram Moolenaar
44defa067cSBram Moolenaar #if defined(FEAT_VIMINFO) || defined(PROTO)
45defa067cSBram Moolenaar
46defa067cSBram Moolenaar static int viminfo_errcnt;
47defa067cSBram Moolenaar
48defa067cSBram Moolenaar /*
49c3328169SBram Moolenaar * Find the parameter represented by the given character (eg ''', ':', '"', or
50c3328169SBram Moolenaar * '/') in the 'viminfo' option and return a pointer to the string after it.
51c3328169SBram Moolenaar * Return NULL if the parameter is not specified in the string.
52c3328169SBram Moolenaar */
53c3328169SBram Moolenaar static char_u *
find_viminfo_parameter(int type)54c3328169SBram Moolenaar find_viminfo_parameter(int type)
55c3328169SBram Moolenaar {
56c3328169SBram Moolenaar char_u *p;
57c3328169SBram Moolenaar
58c3328169SBram Moolenaar for (p = p_viminfo; *p; ++p)
59c3328169SBram Moolenaar {
60c3328169SBram Moolenaar if (*p == type)
61c3328169SBram Moolenaar return p + 1;
62c3328169SBram Moolenaar if (*p == 'n') // 'n' is always the last one
63c3328169SBram Moolenaar break;
64c3328169SBram Moolenaar p = vim_strchr(p, ','); // skip until next ','
65c3328169SBram Moolenaar if (p == NULL) // hit the end without finding parameter
66c3328169SBram Moolenaar break;
67c3328169SBram Moolenaar }
68c3328169SBram Moolenaar return NULL;
69c3328169SBram Moolenaar }
70c3328169SBram Moolenaar
71c3328169SBram Moolenaar /*
72c3328169SBram Moolenaar * Find the parameter represented by the given character (eg ', :, ", or /),
73c3328169SBram Moolenaar * and return its associated value in the 'viminfo' string.
74c3328169SBram Moolenaar * Only works for number parameters, not for 'r' or 'n'.
75c3328169SBram Moolenaar * If the parameter is not specified in the string or there is no following
76c3328169SBram Moolenaar * number, return -1.
77c3328169SBram Moolenaar */
78c3328169SBram Moolenaar int
get_viminfo_parameter(int type)79c3328169SBram Moolenaar get_viminfo_parameter(int type)
80c3328169SBram Moolenaar {
81c3328169SBram Moolenaar char_u *p;
82c3328169SBram Moolenaar
83c3328169SBram Moolenaar p = find_viminfo_parameter(type);
84c3328169SBram Moolenaar if (p != NULL && VIM_ISDIGIT(*p))
85c3328169SBram Moolenaar return atoi((char *)p);
86c3328169SBram Moolenaar return -1;
87c3328169SBram Moolenaar }
88c3328169SBram Moolenaar
89c3328169SBram Moolenaar /*
90defa067cSBram Moolenaar * Get the viminfo file name to use.
91defa067cSBram Moolenaar * If "file" is given and not empty, use it (has already been expanded by
92defa067cSBram Moolenaar * cmdline functions).
93defa067cSBram Moolenaar * Otherwise use "-i file_name", value from 'viminfo' or the default, and
94defa067cSBram Moolenaar * expand environment variables.
95defa067cSBram Moolenaar * Returns an allocated string. NULL when out of memory.
96defa067cSBram Moolenaar */
97defa067cSBram Moolenaar static char_u *
viminfo_filename(char_u * file)98defa067cSBram Moolenaar viminfo_filename(char_u *file)
99defa067cSBram Moolenaar {
100defa067cSBram Moolenaar if (file == NULL || *file == NUL)
101defa067cSBram Moolenaar {
102defa067cSBram Moolenaar if (*p_viminfofile != NUL)
103defa067cSBram Moolenaar file = p_viminfofile;
104defa067cSBram Moolenaar else if ((file = find_viminfo_parameter('n')) == NULL || *file == NUL)
105defa067cSBram Moolenaar {
106defa067cSBram Moolenaar #ifdef VIMINFO_FILE2
107defa067cSBram Moolenaar # ifdef VMS
108defa067cSBram Moolenaar if (mch_getenv((char_u *)"SYS$LOGIN") == NULL)
109defa067cSBram Moolenaar # else
110defa067cSBram Moolenaar # ifdef MSWIN
111defa067cSBram Moolenaar // Use $VIM only if $HOME is the default "C:/".
112defa067cSBram Moolenaar if (STRCMP(vim_getenv((char_u *)"HOME", NULL), "C:/") == 0
113defa067cSBram Moolenaar && mch_getenv((char_u *)"HOME") == NULL)
114defa067cSBram Moolenaar # else
115defa067cSBram Moolenaar if (mch_getenv((char_u *)"HOME") == NULL)
116defa067cSBram Moolenaar # endif
117defa067cSBram Moolenaar # endif
118defa067cSBram Moolenaar {
119defa067cSBram Moolenaar // don't use $VIM when not available.
120defa067cSBram Moolenaar expand_env((char_u *)"$VIM", NameBuff, MAXPATHL);
121defa067cSBram Moolenaar if (STRCMP("$VIM", NameBuff) != 0) // $VIM was expanded
122defa067cSBram Moolenaar file = (char_u *)VIMINFO_FILE2;
123defa067cSBram Moolenaar else
124defa067cSBram Moolenaar file = (char_u *)VIMINFO_FILE;
125defa067cSBram Moolenaar }
126defa067cSBram Moolenaar else
127defa067cSBram Moolenaar #endif
128defa067cSBram Moolenaar file = (char_u *)VIMINFO_FILE;
129defa067cSBram Moolenaar }
130defa067cSBram Moolenaar expand_env(file, NameBuff, MAXPATHL);
131defa067cSBram Moolenaar file = NameBuff;
132defa067cSBram Moolenaar }
133defa067cSBram Moolenaar return vim_strsave(file);
134defa067cSBram Moolenaar }
135defa067cSBram Moolenaar
136c3328169SBram Moolenaar /*
137c3328169SBram Moolenaar * write string to viminfo file
138c3328169SBram Moolenaar * - replace CTRL-V with CTRL-V CTRL-V
139c3328169SBram Moolenaar * - replace '\n' with CTRL-V 'n'
140c3328169SBram Moolenaar * - add a '\n' at the end
141c3328169SBram Moolenaar *
142c3328169SBram Moolenaar * For a long line:
143c3328169SBram Moolenaar * - write " CTRL-V <length> \n " in first line
144c3328169SBram Moolenaar * - write " < <string> \n " in second line
145c3328169SBram Moolenaar */
146c3328169SBram Moolenaar static void
viminfo_writestring(FILE * fd,char_u * p)147c3328169SBram Moolenaar viminfo_writestring(FILE *fd, char_u *p)
148c3328169SBram Moolenaar {
149c3328169SBram Moolenaar int c;
150c3328169SBram Moolenaar char_u *s;
151c3328169SBram Moolenaar int len = 0;
152c3328169SBram Moolenaar
153c3328169SBram Moolenaar for (s = p; *s != NUL; ++s)
154c3328169SBram Moolenaar {
155c3328169SBram Moolenaar if (*s == Ctrl_V || *s == '\n')
156c3328169SBram Moolenaar ++len;
157c3328169SBram Moolenaar ++len;
158c3328169SBram Moolenaar }
159c3328169SBram Moolenaar
160c3328169SBram Moolenaar // If the string will be too long, write its length and put it in the next
161c3328169SBram Moolenaar // line. Take into account that some room is needed for what comes before
162c3328169SBram Moolenaar // the string (e.g., variable name). Add something to the length for the
163c3328169SBram Moolenaar // '<', NL and trailing NUL.
164c3328169SBram Moolenaar if (len > LSIZE / 2)
165c3328169SBram Moolenaar fprintf(fd, IF_EB("\026%d\n<", CTRL_V_STR "%d\n<"), len + 3);
166c3328169SBram Moolenaar
167c3328169SBram Moolenaar while ((c = *p++) != NUL)
168c3328169SBram Moolenaar {
169c3328169SBram Moolenaar if (c == Ctrl_V || c == '\n')
170c3328169SBram Moolenaar {
171c3328169SBram Moolenaar putc(Ctrl_V, fd);
172c3328169SBram Moolenaar if (c == '\n')
173c3328169SBram Moolenaar c = 'n';
174c3328169SBram Moolenaar }
175c3328169SBram Moolenaar putc(c, fd);
176c3328169SBram Moolenaar }
177c3328169SBram Moolenaar putc('\n', fd);
178c3328169SBram Moolenaar }
179c3328169SBram Moolenaar
180c3328169SBram Moolenaar /*
181c3328169SBram Moolenaar * Write a string in quotes that barline_parse() can read back.
182c3328169SBram Moolenaar * Breaks the line in less than LSIZE pieces when needed.
183c3328169SBram Moolenaar * Returns remaining characters in the line.
184c3328169SBram Moolenaar */
185c3328169SBram Moolenaar static int
barline_writestring(FILE * fd,char_u * s,int remaining_start)186c3328169SBram Moolenaar barline_writestring(FILE *fd, char_u *s, int remaining_start)
187c3328169SBram Moolenaar {
188c3328169SBram Moolenaar char_u *p;
189c3328169SBram Moolenaar int remaining = remaining_start;
190c3328169SBram Moolenaar int len = 2;
191c3328169SBram Moolenaar
192c3328169SBram Moolenaar // Count the number of characters produced, including quotes.
193c3328169SBram Moolenaar for (p = s; *p != NUL; ++p)
194c3328169SBram Moolenaar {
195c3328169SBram Moolenaar if (*p == NL)
196c3328169SBram Moolenaar len += 2;
197c3328169SBram Moolenaar else if (*p == '"' || *p == '\\')
198c3328169SBram Moolenaar len += 2;
199c3328169SBram Moolenaar else
200c3328169SBram Moolenaar ++len;
201c3328169SBram Moolenaar }
202c3328169SBram Moolenaar if (len > remaining - 2)
203c3328169SBram Moolenaar {
204c3328169SBram Moolenaar fprintf(fd, ">%d\n|<", len);
205c3328169SBram Moolenaar remaining = LSIZE - 20;
206c3328169SBram Moolenaar }
207c3328169SBram Moolenaar
208c3328169SBram Moolenaar putc('"', fd);
209c3328169SBram Moolenaar for (p = s; *p != NUL; ++p)
210c3328169SBram Moolenaar {
211c3328169SBram Moolenaar if (*p == NL)
212c3328169SBram Moolenaar {
213c3328169SBram Moolenaar putc('\\', fd);
214c3328169SBram Moolenaar putc('n', fd);
215c3328169SBram Moolenaar --remaining;
216c3328169SBram Moolenaar }
217c3328169SBram Moolenaar else if (*p == '"' || *p == '\\')
218c3328169SBram Moolenaar {
219c3328169SBram Moolenaar putc('\\', fd);
220c3328169SBram Moolenaar putc(*p, fd);
221c3328169SBram Moolenaar --remaining;
222c3328169SBram Moolenaar }
223c3328169SBram Moolenaar else
224c3328169SBram Moolenaar putc(*p, fd);
225c3328169SBram Moolenaar --remaining;
226c3328169SBram Moolenaar
227c3328169SBram Moolenaar if (remaining < 3)
228c3328169SBram Moolenaar {
229c3328169SBram Moolenaar putc('\n', fd);
230c3328169SBram Moolenaar putc('|', fd);
231c3328169SBram Moolenaar putc('<', fd);
232c3328169SBram Moolenaar // Leave enough space for another continuation.
233c3328169SBram Moolenaar remaining = LSIZE - 20;
234c3328169SBram Moolenaar }
235c3328169SBram Moolenaar }
236c3328169SBram Moolenaar putc('"', fd);
237c3328169SBram Moolenaar return remaining - 2;
238c3328169SBram Moolenaar }
239c3328169SBram Moolenaar
240c3328169SBram Moolenaar /*
241c3328169SBram Moolenaar * Check string read from viminfo file.
242c3328169SBram Moolenaar * Remove '\n' at the end of the line.
243c3328169SBram Moolenaar * - replace CTRL-V CTRL-V with CTRL-V
244c3328169SBram Moolenaar * - replace CTRL-V 'n' with '\n'
245c3328169SBram Moolenaar *
246c3328169SBram Moolenaar * Check for a long line as written by viminfo_writestring().
247c3328169SBram Moolenaar *
248c3328169SBram Moolenaar * Return the string in allocated memory (NULL when out of memory).
249c3328169SBram Moolenaar */
250c3328169SBram Moolenaar static char_u *
viminfo_readstring(vir_T * virp,int off,int convert UNUSED)251c3328169SBram Moolenaar viminfo_readstring(
252c3328169SBram Moolenaar vir_T *virp,
253c3328169SBram Moolenaar int off, // offset for virp->vir_line
254c3328169SBram Moolenaar int convert UNUSED) // convert the string
255c3328169SBram Moolenaar {
256*ed7cb2dfSBram Moolenaar char_u *retval = NULL;
257c3328169SBram Moolenaar char_u *s, *d;
258c3328169SBram Moolenaar long len;
259c3328169SBram Moolenaar
260c3328169SBram Moolenaar if (virp->vir_line[off] == Ctrl_V && vim_isdigit(virp->vir_line[off + 1]))
261c3328169SBram Moolenaar {
262c3328169SBram Moolenaar len = atol((char *)virp->vir_line + off + 1);
263*ed7cb2dfSBram Moolenaar if (len > 0 && len < 1000000)
264c3328169SBram Moolenaar retval = lalloc(len, TRUE);
265c3328169SBram Moolenaar if (retval == NULL)
266c3328169SBram Moolenaar {
267*ed7cb2dfSBram Moolenaar // Invalid length, line too long, out of memory? Skip next line.
268c3328169SBram Moolenaar (void)vim_fgets(virp->vir_line, 10, virp->vir_fd);
269c3328169SBram Moolenaar return NULL;
270c3328169SBram Moolenaar }
271c3328169SBram Moolenaar (void)vim_fgets(retval, (int)len, virp->vir_fd);
272c3328169SBram Moolenaar s = retval + 1; // Skip the leading '<'
273c3328169SBram Moolenaar }
274c3328169SBram Moolenaar else
275c3328169SBram Moolenaar {
276c3328169SBram Moolenaar retval = vim_strsave(virp->vir_line + off);
277c3328169SBram Moolenaar if (retval == NULL)
278c3328169SBram Moolenaar return NULL;
279c3328169SBram Moolenaar s = retval;
280c3328169SBram Moolenaar }
281c3328169SBram Moolenaar
282c3328169SBram Moolenaar // Change CTRL-V CTRL-V to CTRL-V and CTRL-V n to \n in-place.
283c3328169SBram Moolenaar d = retval;
284c3328169SBram Moolenaar while (*s != NUL && *s != '\n')
285c3328169SBram Moolenaar {
286c3328169SBram Moolenaar if (s[0] == Ctrl_V && s[1] != NUL)
287c3328169SBram Moolenaar {
288c3328169SBram Moolenaar if (s[1] == 'n')
289c3328169SBram Moolenaar *d++ = '\n';
290c3328169SBram Moolenaar else
291c3328169SBram Moolenaar *d++ = Ctrl_V;
292c3328169SBram Moolenaar s += 2;
293c3328169SBram Moolenaar }
294c3328169SBram Moolenaar else
295c3328169SBram Moolenaar *d++ = *s++;
296c3328169SBram Moolenaar }
297c3328169SBram Moolenaar *d = NUL;
298c3328169SBram Moolenaar
299c3328169SBram Moolenaar if (convert && virp->vir_conv.vc_type != CONV_NONE && *retval != NUL)
300c3328169SBram Moolenaar {
301c3328169SBram Moolenaar d = string_convert(&virp->vir_conv, retval, NULL);
302c3328169SBram Moolenaar if (d != NULL)
303c3328169SBram Moolenaar {
304c3328169SBram Moolenaar vim_free(retval);
305c3328169SBram Moolenaar retval = d;
306c3328169SBram Moolenaar }
307c3328169SBram Moolenaar }
308c3328169SBram Moolenaar
309c3328169SBram Moolenaar return retval;
310c3328169SBram Moolenaar }
311c3328169SBram Moolenaar
312c3328169SBram Moolenaar /*
313c3328169SBram Moolenaar * Read a line from the viminfo file.
314c3328169SBram Moolenaar * Returns TRUE for end-of-file;
315c3328169SBram Moolenaar */
316c3328169SBram Moolenaar static int
viminfo_readline(vir_T * virp)317c3328169SBram Moolenaar viminfo_readline(vir_T *virp)
318c3328169SBram Moolenaar {
319c3328169SBram Moolenaar return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
320c3328169SBram Moolenaar }
321c3328169SBram Moolenaar
322defa067cSBram Moolenaar static int
read_viminfo_bufferlist(vir_T * virp,int writing)323defa067cSBram Moolenaar read_viminfo_bufferlist(
324defa067cSBram Moolenaar vir_T *virp,
325defa067cSBram Moolenaar int writing)
326defa067cSBram Moolenaar {
327defa067cSBram Moolenaar char_u *tab;
328defa067cSBram Moolenaar linenr_T lnum;
329defa067cSBram Moolenaar colnr_T col;
330defa067cSBram Moolenaar buf_T *buf;
331defa067cSBram Moolenaar char_u *sfname;
332defa067cSBram Moolenaar char_u *xline;
333defa067cSBram Moolenaar
334defa067cSBram Moolenaar // Handle long line and escaped characters.
335defa067cSBram Moolenaar xline = viminfo_readstring(virp, 1, FALSE);
336defa067cSBram Moolenaar
337defa067cSBram Moolenaar // don't read in if there are files on the command-line or if writing:
338defa067cSBram Moolenaar if (xline != NULL && !writing && ARGCOUNT == 0
339defa067cSBram Moolenaar && find_viminfo_parameter('%') != NULL)
340defa067cSBram Moolenaar {
341defa067cSBram Moolenaar // Format is: <fname> Tab <lnum> Tab <col>.
342defa067cSBram Moolenaar // Watch out for a Tab in the file name, work from the end.
343defa067cSBram Moolenaar lnum = 0;
344defa067cSBram Moolenaar col = 0;
345defa067cSBram Moolenaar tab = vim_strrchr(xline, '\t');
346defa067cSBram Moolenaar if (tab != NULL)
347defa067cSBram Moolenaar {
348defa067cSBram Moolenaar *tab++ = '\0';
349defa067cSBram Moolenaar col = (colnr_T)atoi((char *)tab);
350defa067cSBram Moolenaar tab = vim_strrchr(xline, '\t');
351defa067cSBram Moolenaar if (tab != NULL)
352defa067cSBram Moolenaar {
353defa067cSBram Moolenaar *tab++ = '\0';
354defa067cSBram Moolenaar lnum = atol((char *)tab);
355defa067cSBram Moolenaar }
356defa067cSBram Moolenaar }
357defa067cSBram Moolenaar
358defa067cSBram Moolenaar // Expand "~/" in the file name at "line + 1" to a full path.
359defa067cSBram Moolenaar // Then try shortening it by comparing with the current directory
360defa067cSBram Moolenaar expand_env(xline, NameBuff, MAXPATHL);
361defa067cSBram Moolenaar sfname = shorten_fname1(NameBuff);
362defa067cSBram Moolenaar
363defa067cSBram Moolenaar buf = buflist_new(NameBuff, sfname, (linenr_T)0, BLN_LISTED);
364defa067cSBram Moolenaar if (buf != NULL) // just in case...
365defa067cSBram Moolenaar {
366defa067cSBram Moolenaar buf->b_last_cursor.lnum = lnum;
367defa067cSBram Moolenaar buf->b_last_cursor.col = col;
368defa067cSBram Moolenaar buflist_setfpos(buf, curwin, lnum, col, FALSE);
369defa067cSBram Moolenaar }
370defa067cSBram Moolenaar }
371defa067cSBram Moolenaar vim_free(xline);
372defa067cSBram Moolenaar
373defa067cSBram Moolenaar return viminfo_readline(virp);
374defa067cSBram Moolenaar }
375defa067cSBram Moolenaar
376c3328169SBram Moolenaar /*
377c3328169SBram Moolenaar * Return TRUE if "name" is on removable media (depending on 'viminfo').
378c3328169SBram Moolenaar */
379c3328169SBram Moolenaar static int
removable(char_u * name)380c3328169SBram Moolenaar removable(char_u *name)
381c3328169SBram Moolenaar {
382c3328169SBram Moolenaar char_u *p;
383c3328169SBram Moolenaar char_u part[51];
384c3328169SBram Moolenaar int retval = FALSE;
385c3328169SBram Moolenaar size_t n;
386c3328169SBram Moolenaar
387c3328169SBram Moolenaar name = home_replace_save(NULL, name);
388c3328169SBram Moolenaar if (name != NULL)
389c3328169SBram Moolenaar {
390c3328169SBram Moolenaar for (p = p_viminfo; *p; )
391c3328169SBram Moolenaar {
392c3328169SBram Moolenaar copy_option_part(&p, part, 51, ", ");
393c3328169SBram Moolenaar if (part[0] == 'r')
394c3328169SBram Moolenaar {
395c3328169SBram Moolenaar n = STRLEN(part + 1);
396c3328169SBram Moolenaar if (MB_STRNICMP(part + 1, name, n) == 0)
397c3328169SBram Moolenaar {
398c3328169SBram Moolenaar retval = TRUE;
399c3328169SBram Moolenaar break;
400c3328169SBram Moolenaar }
401c3328169SBram Moolenaar }
402c3328169SBram Moolenaar }
403c3328169SBram Moolenaar vim_free(name);
404c3328169SBram Moolenaar }
405c3328169SBram Moolenaar return retval;
406c3328169SBram Moolenaar }
407c3328169SBram Moolenaar
408defa067cSBram Moolenaar static void
write_viminfo_bufferlist(FILE * fp)409defa067cSBram Moolenaar write_viminfo_bufferlist(FILE *fp)
410defa067cSBram Moolenaar {
411defa067cSBram Moolenaar buf_T *buf;
412defa067cSBram Moolenaar win_T *win;
413defa067cSBram Moolenaar tabpage_T *tp;
414defa067cSBram Moolenaar char_u *line;
415defa067cSBram Moolenaar int max_buffers;
416defa067cSBram Moolenaar
417defa067cSBram Moolenaar if (find_viminfo_parameter('%') == NULL)
418defa067cSBram Moolenaar return;
419defa067cSBram Moolenaar
420defa067cSBram Moolenaar // Without a number -1 is returned: do all buffers.
421defa067cSBram Moolenaar max_buffers = get_viminfo_parameter('%');
422defa067cSBram Moolenaar
423defa067cSBram Moolenaar // Allocate room for the file name, lnum and col.
424defa067cSBram Moolenaar #define LINE_BUF_LEN (MAXPATHL + 40)
425defa067cSBram Moolenaar line = alloc(LINE_BUF_LEN);
426defa067cSBram Moolenaar if (line == NULL)
427defa067cSBram Moolenaar return;
428defa067cSBram Moolenaar
429defa067cSBram Moolenaar FOR_ALL_TAB_WINDOWS(tp, win)
430defa067cSBram Moolenaar set_last_cursor(win);
431defa067cSBram Moolenaar
432defa067cSBram Moolenaar fputs(_("\n# Buffer list:\n"), fp);
433defa067cSBram Moolenaar FOR_ALL_BUFFERS(buf)
434defa067cSBram Moolenaar {
435defa067cSBram Moolenaar if (buf->b_fname == NULL
436defa067cSBram Moolenaar || !buf->b_p_bl
437defa067cSBram Moolenaar #ifdef FEAT_QUICKFIX
438defa067cSBram Moolenaar || bt_quickfix(buf)
439defa067cSBram Moolenaar #endif
440defa067cSBram Moolenaar #ifdef FEAT_TERMINAL
441defa067cSBram Moolenaar || bt_terminal(buf)
442defa067cSBram Moolenaar #endif
443defa067cSBram Moolenaar || removable(buf->b_ffname))
444defa067cSBram Moolenaar continue;
445defa067cSBram Moolenaar
446defa067cSBram Moolenaar if (max_buffers-- == 0)
447defa067cSBram Moolenaar break;
448defa067cSBram Moolenaar putc('%', fp);
449defa067cSBram Moolenaar home_replace(NULL, buf->b_ffname, line, MAXPATHL, TRUE);
450defa067cSBram Moolenaar vim_snprintf_add((char *)line, LINE_BUF_LEN, "\t%ld\t%d",
451defa067cSBram Moolenaar (long)buf->b_last_cursor.lnum,
452defa067cSBram Moolenaar buf->b_last_cursor.col);
453defa067cSBram Moolenaar viminfo_writestring(fp, line);
454defa067cSBram Moolenaar }
455defa067cSBram Moolenaar vim_free(line);
456defa067cSBram Moolenaar }
457defa067cSBram Moolenaar
4585f32ece4SBram Moolenaar /*
4595f32ece4SBram Moolenaar * Buffers for history read from a viminfo file. Only valid while reading.
4605f32ece4SBram Moolenaar */
4615f32ece4SBram Moolenaar static histentry_T *viminfo_history[HIST_COUNT] =
4625f32ece4SBram Moolenaar {NULL, NULL, NULL, NULL, NULL};
4635f32ece4SBram Moolenaar static int viminfo_hisidx[HIST_COUNT] = {0, 0, 0, 0, 0};
4645f32ece4SBram Moolenaar static int viminfo_hislen[HIST_COUNT] = {0, 0, 0, 0, 0};
4655f32ece4SBram Moolenaar static int viminfo_add_at_front = FALSE;
4665f32ece4SBram Moolenaar
4675f32ece4SBram Moolenaar /*
4685f32ece4SBram Moolenaar * Translate a history type number to the associated character.
4695f32ece4SBram Moolenaar */
4705f32ece4SBram Moolenaar static int
hist_type2char(int type,int use_question)4715f32ece4SBram Moolenaar hist_type2char(
4725f32ece4SBram Moolenaar int type,
4735f32ece4SBram Moolenaar int use_question) // use '?' instead of '/'
4745f32ece4SBram Moolenaar {
4755f32ece4SBram Moolenaar if (type == HIST_CMD)
4765f32ece4SBram Moolenaar return ':';
4775f32ece4SBram Moolenaar if (type == HIST_SEARCH)
4785f32ece4SBram Moolenaar {
4795f32ece4SBram Moolenaar if (use_question)
4805f32ece4SBram Moolenaar return '?';
4815f32ece4SBram Moolenaar else
4825f32ece4SBram Moolenaar return '/';
4835f32ece4SBram Moolenaar }
4845f32ece4SBram Moolenaar if (type == HIST_EXPR)
4855f32ece4SBram Moolenaar return '=';
4865f32ece4SBram Moolenaar return '@';
4875f32ece4SBram Moolenaar }
4885f32ece4SBram Moolenaar
4895f32ece4SBram Moolenaar /*
4905f32ece4SBram Moolenaar * Prepare for reading the history from the viminfo file.
4915f32ece4SBram Moolenaar * This allocates history arrays to store the read history lines.
4925f32ece4SBram Moolenaar */
4935f32ece4SBram Moolenaar static void
prepare_viminfo_history(int asklen,int writing)4945f32ece4SBram Moolenaar prepare_viminfo_history(int asklen, int writing)
4955f32ece4SBram Moolenaar {
4965f32ece4SBram Moolenaar int i;
4975f32ece4SBram Moolenaar int num;
4985f32ece4SBram Moolenaar int type;
4995f32ece4SBram Moolenaar int len;
50026b654a5SBram Moolenaar int hislen;
5015f32ece4SBram Moolenaar
5025f32ece4SBram Moolenaar init_history();
50326b654a5SBram Moolenaar hislen = get_hislen();
5045f32ece4SBram Moolenaar viminfo_add_at_front = (asklen != 0 && !writing);
5055f32ece4SBram Moolenaar if (asklen > hislen)
5065f32ece4SBram Moolenaar asklen = hislen;
5075f32ece4SBram Moolenaar
5085f32ece4SBram Moolenaar for (type = 0; type < HIST_COUNT; ++type)
5095f32ece4SBram Moolenaar {
5105f32ece4SBram Moolenaar histentry_T *histentry = get_histentry(type);
5115f32ece4SBram Moolenaar
5125f32ece4SBram Moolenaar // Count the number of empty spaces in the history list. Entries read
5135f32ece4SBram Moolenaar // from viminfo previously are also considered empty. If there are
5145f32ece4SBram Moolenaar // more spaces available than we request, then fill them up.
5155f32ece4SBram Moolenaar for (i = 0, num = 0; i < hislen; i++)
5165f32ece4SBram Moolenaar if (histentry[i].hisstr == NULL || histentry[i].viminfo)
5175f32ece4SBram Moolenaar num++;
5185f32ece4SBram Moolenaar len = asklen;
5195f32ece4SBram Moolenaar if (num > len)
5205f32ece4SBram Moolenaar len = num;
5215f32ece4SBram Moolenaar if (len <= 0)
5225f32ece4SBram Moolenaar viminfo_history[type] = NULL;
5235f32ece4SBram Moolenaar else
5245f32ece4SBram Moolenaar viminfo_history[type] = LALLOC_MULT(histentry_T, len);
5255f32ece4SBram Moolenaar if (viminfo_history[type] == NULL)
5265f32ece4SBram Moolenaar len = 0;
5275f32ece4SBram Moolenaar viminfo_hislen[type] = len;
5285f32ece4SBram Moolenaar viminfo_hisidx[type] = 0;
5295f32ece4SBram Moolenaar }
5305f32ece4SBram Moolenaar }
5315f32ece4SBram Moolenaar
5325f32ece4SBram Moolenaar /*
5335f32ece4SBram Moolenaar * Accept a line from the viminfo, store it in the history array when it's
5345f32ece4SBram Moolenaar * new.
5355f32ece4SBram Moolenaar */
5365f32ece4SBram Moolenaar static int
read_viminfo_history(vir_T * virp,int writing)5375f32ece4SBram Moolenaar read_viminfo_history(vir_T *virp, int writing)
5385f32ece4SBram Moolenaar {
5395f32ece4SBram Moolenaar int type;
5405f32ece4SBram Moolenaar long_u len;
5415f32ece4SBram Moolenaar char_u *val;
5425f32ece4SBram Moolenaar char_u *p;
5435f32ece4SBram Moolenaar
5445f32ece4SBram Moolenaar type = hist_char2type(virp->vir_line[0]);
5455f32ece4SBram Moolenaar if (viminfo_hisidx[type] < viminfo_hislen[type])
5465f32ece4SBram Moolenaar {
5475f32ece4SBram Moolenaar val = viminfo_readstring(virp, 1, TRUE);
5485f32ece4SBram Moolenaar if (val != NULL && *val != NUL)
5495f32ece4SBram Moolenaar {
5505f32ece4SBram Moolenaar int sep = (*val == ' ' ? NUL : *val);
5515f32ece4SBram Moolenaar
5525f32ece4SBram Moolenaar if (!in_history(type, val + (type == HIST_SEARCH),
5535f32ece4SBram Moolenaar viminfo_add_at_front, sep, writing))
5545f32ece4SBram Moolenaar {
5555f32ece4SBram Moolenaar // Need to re-allocate to append the separator byte.
5565f32ece4SBram Moolenaar len = STRLEN(val);
5575f32ece4SBram Moolenaar p = alloc(len + 2);
5585f32ece4SBram Moolenaar if (p != NULL)
5595f32ece4SBram Moolenaar {
5605f32ece4SBram Moolenaar if (type == HIST_SEARCH)
5615f32ece4SBram Moolenaar {
5625f32ece4SBram Moolenaar // Search entry: Move the separator from the first
5635f32ece4SBram Moolenaar // column to after the NUL.
5645f32ece4SBram Moolenaar mch_memmove(p, val + 1, (size_t)len);
5655f32ece4SBram Moolenaar p[len] = sep;
5665f32ece4SBram Moolenaar }
5675f32ece4SBram Moolenaar else
5685f32ece4SBram Moolenaar {
5695f32ece4SBram Moolenaar // Not a search entry: No separator in the viminfo
5705f32ece4SBram Moolenaar // file, add a NUL separator.
5715f32ece4SBram Moolenaar mch_memmove(p, val, (size_t)len + 1);
5725f32ece4SBram Moolenaar p[len + 1] = NUL;
5735f32ece4SBram Moolenaar }
5745f32ece4SBram Moolenaar viminfo_history[type][viminfo_hisidx[type]].hisstr = p;
5755f32ece4SBram Moolenaar viminfo_history[type][viminfo_hisidx[type]].time_set = 0;
5765f32ece4SBram Moolenaar viminfo_history[type][viminfo_hisidx[type]].viminfo = TRUE;
5775f32ece4SBram Moolenaar viminfo_history[type][viminfo_hisidx[type]].hisnum = 0;
5785f32ece4SBram Moolenaar viminfo_hisidx[type]++;
5795f32ece4SBram Moolenaar }
5805f32ece4SBram Moolenaar }
5815f32ece4SBram Moolenaar }
5825f32ece4SBram Moolenaar vim_free(val);
5835f32ece4SBram Moolenaar }
5845f32ece4SBram Moolenaar return viminfo_readline(virp);
5855f32ece4SBram Moolenaar }
5865f32ece4SBram Moolenaar
5875f32ece4SBram Moolenaar /*
5885f32ece4SBram Moolenaar * Accept a new style history line from the viminfo, store it in the history
5895f32ece4SBram Moolenaar * array when it's new.
5905f32ece4SBram Moolenaar */
5915f32ece4SBram Moolenaar static void
handle_viminfo_history(garray_T * values,int writing)5925f32ece4SBram Moolenaar handle_viminfo_history(
5935f32ece4SBram Moolenaar garray_T *values,
5945f32ece4SBram Moolenaar int writing)
5955f32ece4SBram Moolenaar {
5965f32ece4SBram Moolenaar int type;
5975f32ece4SBram Moolenaar long_u len;
5985f32ece4SBram Moolenaar char_u *val;
5995f32ece4SBram Moolenaar char_u *p;
6005f32ece4SBram Moolenaar bval_T *vp = (bval_T *)values->ga_data;
6015f32ece4SBram Moolenaar
6025f32ece4SBram Moolenaar // Check the format:
6035f32ece4SBram Moolenaar // |{bartype},{histtype},{timestamp},{separator},"text"
6045f32ece4SBram Moolenaar if (values->ga_len < 4
6055f32ece4SBram Moolenaar || vp[0].bv_type != BVAL_NR
6065f32ece4SBram Moolenaar || vp[1].bv_type != BVAL_NR
6075f32ece4SBram Moolenaar || (vp[2].bv_type != BVAL_NR && vp[2].bv_type != BVAL_EMPTY)
6085f32ece4SBram Moolenaar || vp[3].bv_type != BVAL_STRING)
6095f32ece4SBram Moolenaar return;
6105f32ece4SBram Moolenaar
6115f32ece4SBram Moolenaar type = vp[0].bv_nr;
6125f32ece4SBram Moolenaar if (type >= HIST_COUNT)
6135f32ece4SBram Moolenaar return;
6145f32ece4SBram Moolenaar if (viminfo_hisidx[type] < viminfo_hislen[type])
6155f32ece4SBram Moolenaar {
6165f32ece4SBram Moolenaar val = vp[3].bv_string;
6175f32ece4SBram Moolenaar if (val != NULL && *val != NUL)
6185f32ece4SBram Moolenaar {
6195f32ece4SBram Moolenaar int sep = type == HIST_SEARCH && vp[2].bv_type == BVAL_NR
6205f32ece4SBram Moolenaar ? vp[2].bv_nr : NUL;
6215f32ece4SBram Moolenaar int idx;
6225f32ece4SBram Moolenaar int overwrite = FALSE;
6235f32ece4SBram Moolenaar
6245f32ece4SBram Moolenaar if (!in_history(type, val, viminfo_add_at_front, sep, writing))
6255f32ece4SBram Moolenaar {
6265f32ece4SBram Moolenaar // If lines were written by an older Vim we need to avoid
6275f32ece4SBram Moolenaar // getting duplicates. See if the entry already exists.
6285f32ece4SBram Moolenaar for (idx = 0; idx < viminfo_hisidx[type]; ++idx)
6295f32ece4SBram Moolenaar {
6305f32ece4SBram Moolenaar p = viminfo_history[type][idx].hisstr;
6315f32ece4SBram Moolenaar if (STRCMP(val, p) == 0
6325f32ece4SBram Moolenaar && (type != HIST_SEARCH || sep == p[STRLEN(p) + 1]))
6335f32ece4SBram Moolenaar {
6345f32ece4SBram Moolenaar overwrite = TRUE;
6355f32ece4SBram Moolenaar break;
6365f32ece4SBram Moolenaar }
6375f32ece4SBram Moolenaar }
6385f32ece4SBram Moolenaar
6395f32ece4SBram Moolenaar if (!overwrite)
6405f32ece4SBram Moolenaar {
6415f32ece4SBram Moolenaar // Need to re-allocate to append the separator byte.
6425f32ece4SBram Moolenaar len = vp[3].bv_len;
6435f32ece4SBram Moolenaar p = alloc(len + 2);
6445f32ece4SBram Moolenaar }
6455f32ece4SBram Moolenaar else
6465f32ece4SBram Moolenaar len = 0; // for picky compilers
6475f32ece4SBram Moolenaar if (p != NULL)
6485f32ece4SBram Moolenaar {
6495f32ece4SBram Moolenaar viminfo_history[type][idx].time_set = vp[1].bv_nr;
6505f32ece4SBram Moolenaar if (!overwrite)
6515f32ece4SBram Moolenaar {
6525f32ece4SBram Moolenaar mch_memmove(p, val, (size_t)len + 1);
6535f32ece4SBram Moolenaar // Put the separator after the NUL.
6545f32ece4SBram Moolenaar p[len + 1] = sep;
6555f32ece4SBram Moolenaar viminfo_history[type][idx].hisstr = p;
6565f32ece4SBram Moolenaar viminfo_history[type][idx].hisnum = 0;
6575f32ece4SBram Moolenaar viminfo_history[type][idx].viminfo = TRUE;
6585f32ece4SBram Moolenaar viminfo_hisidx[type]++;
6595f32ece4SBram Moolenaar }
6605f32ece4SBram Moolenaar }
6615f32ece4SBram Moolenaar }
6625f32ece4SBram Moolenaar }
6635f32ece4SBram Moolenaar }
6645f32ece4SBram Moolenaar }
6655f32ece4SBram Moolenaar
6665f32ece4SBram Moolenaar /*
6675f32ece4SBram Moolenaar * Concatenate history lines from viminfo after the lines typed in this Vim.
6685f32ece4SBram Moolenaar */
6695f32ece4SBram Moolenaar static void
concat_history(int type)6705f32ece4SBram Moolenaar concat_history(int type)
6715f32ece4SBram Moolenaar {
6725f32ece4SBram Moolenaar int idx;
6735f32ece4SBram Moolenaar int i;
6745f32ece4SBram Moolenaar int hislen = get_hislen();
6755f32ece4SBram Moolenaar histentry_T *histentry = get_histentry(type);
6765f32ece4SBram Moolenaar int *hisidx = get_hisidx(type);
6775f32ece4SBram Moolenaar int *hisnum = get_hisnum(type);
6785f32ece4SBram Moolenaar
6795f32ece4SBram Moolenaar idx = *hisidx + viminfo_hisidx[type];
6805f32ece4SBram Moolenaar if (idx >= hislen)
6815f32ece4SBram Moolenaar idx -= hislen;
6825f32ece4SBram Moolenaar else if (idx < 0)
6835f32ece4SBram Moolenaar idx = hislen - 1;
6845f32ece4SBram Moolenaar if (viminfo_add_at_front)
6855f32ece4SBram Moolenaar *hisidx = idx;
6865f32ece4SBram Moolenaar else
6875f32ece4SBram Moolenaar {
6885f32ece4SBram Moolenaar if (*hisidx == -1)
6895f32ece4SBram Moolenaar *hisidx = hislen - 1;
6905f32ece4SBram Moolenaar do
6915f32ece4SBram Moolenaar {
6925f32ece4SBram Moolenaar if (histentry[idx].hisstr != NULL || histentry[idx].viminfo)
6935f32ece4SBram Moolenaar break;
6945f32ece4SBram Moolenaar if (++idx == hislen)
6955f32ece4SBram Moolenaar idx = 0;
6965f32ece4SBram Moolenaar } while (idx != *hisidx);
6975f32ece4SBram Moolenaar if (idx != *hisidx && --idx < 0)
6985f32ece4SBram Moolenaar idx = hislen - 1;
6995f32ece4SBram Moolenaar }
7005f32ece4SBram Moolenaar for (i = 0; i < viminfo_hisidx[type]; i++)
7015f32ece4SBram Moolenaar {
7025f32ece4SBram Moolenaar vim_free(histentry[idx].hisstr);
7035f32ece4SBram Moolenaar histentry[idx].hisstr = viminfo_history[type][i].hisstr;
7045f32ece4SBram Moolenaar histentry[idx].viminfo = TRUE;
7055f32ece4SBram Moolenaar histentry[idx].time_set = viminfo_history[type][i].time_set;
7065f32ece4SBram Moolenaar if (--idx < 0)
7075f32ece4SBram Moolenaar idx = hislen - 1;
7085f32ece4SBram Moolenaar }
7095f32ece4SBram Moolenaar idx += 1;
7105f32ece4SBram Moolenaar idx %= hislen;
7115f32ece4SBram Moolenaar for (i = 0; i < viminfo_hisidx[type]; i++)
7125f32ece4SBram Moolenaar {
7135f32ece4SBram Moolenaar histentry[idx++].hisnum = ++*hisnum;
7145f32ece4SBram Moolenaar idx %= hislen;
7155f32ece4SBram Moolenaar }
7165f32ece4SBram Moolenaar }
7175f32ece4SBram Moolenaar
7185f32ece4SBram Moolenaar static int
sort_hist(const void * s1,const void * s2)7195f32ece4SBram Moolenaar sort_hist(const void *s1, const void *s2)
7205f32ece4SBram Moolenaar {
7215f32ece4SBram Moolenaar histentry_T *p1 = *(histentry_T **)s1;
7225f32ece4SBram Moolenaar histentry_T *p2 = *(histentry_T **)s2;
7235f32ece4SBram Moolenaar
7245f32ece4SBram Moolenaar if (p1->time_set < p2->time_set) return -1;
7255f32ece4SBram Moolenaar if (p1->time_set > p2->time_set) return 1;
7265f32ece4SBram Moolenaar return 0;
7275f32ece4SBram Moolenaar }
7285f32ece4SBram Moolenaar
7295f32ece4SBram Moolenaar /*
7305f32ece4SBram Moolenaar * Merge history lines from viminfo and lines typed in this Vim based on the
7315f32ece4SBram Moolenaar * timestamp;
7325f32ece4SBram Moolenaar */
7335f32ece4SBram Moolenaar static void
merge_history(int type)7345f32ece4SBram Moolenaar merge_history(int type)
7355f32ece4SBram Moolenaar {
7365f32ece4SBram Moolenaar int max_len;
7375f32ece4SBram Moolenaar histentry_T **tot_hist;
7385f32ece4SBram Moolenaar histentry_T *new_hist;
7395f32ece4SBram Moolenaar int i;
7405f32ece4SBram Moolenaar int len;
7415f32ece4SBram Moolenaar int hislen = get_hislen();
7425f32ece4SBram Moolenaar histentry_T *histentry = get_histentry(type);
7435f32ece4SBram Moolenaar int *hisidx = get_hisidx(type);
7445f32ece4SBram Moolenaar int *hisnum = get_hisnum(type);
7455f32ece4SBram Moolenaar
7465f32ece4SBram Moolenaar // Make one long list with all entries.
7475f32ece4SBram Moolenaar max_len = hislen + viminfo_hisidx[type];
7485f32ece4SBram Moolenaar tot_hist = ALLOC_MULT(histentry_T *, max_len);
7495f32ece4SBram Moolenaar new_hist = ALLOC_MULT(histentry_T, hislen);
7505f32ece4SBram Moolenaar if (tot_hist == NULL || new_hist == NULL)
7515f32ece4SBram Moolenaar {
7525f32ece4SBram Moolenaar vim_free(tot_hist);
7535f32ece4SBram Moolenaar vim_free(new_hist);
7545f32ece4SBram Moolenaar return;
7555f32ece4SBram Moolenaar }
7565f32ece4SBram Moolenaar for (i = 0; i < viminfo_hisidx[type]; i++)
7575f32ece4SBram Moolenaar tot_hist[i] = &viminfo_history[type][i];
7585f32ece4SBram Moolenaar len = i;
7595f32ece4SBram Moolenaar for (i = 0; i < hislen; i++)
7605f32ece4SBram Moolenaar if (histentry[i].hisstr != NULL)
7615f32ece4SBram Moolenaar tot_hist[len++] = &histentry[i];
7625f32ece4SBram Moolenaar
7635f32ece4SBram Moolenaar // Sort the list on timestamp.
7645f32ece4SBram Moolenaar qsort((void *)tot_hist, (size_t)len, sizeof(histentry_T *), sort_hist);
7655f32ece4SBram Moolenaar
7665f32ece4SBram Moolenaar // Keep the newest ones.
7675f32ece4SBram Moolenaar for (i = 0; i < hislen; i++)
7685f32ece4SBram Moolenaar {
7695f32ece4SBram Moolenaar if (i < len)
7705f32ece4SBram Moolenaar {
7715f32ece4SBram Moolenaar new_hist[i] = *tot_hist[i];
7725f32ece4SBram Moolenaar tot_hist[i]->hisstr = NULL;
7735f32ece4SBram Moolenaar if (new_hist[i].hisnum == 0)
7745f32ece4SBram Moolenaar new_hist[i].hisnum = ++*hisnum;
7755f32ece4SBram Moolenaar }
7765f32ece4SBram Moolenaar else
7775f32ece4SBram Moolenaar clear_hist_entry(&new_hist[i]);
7785f32ece4SBram Moolenaar }
7795f32ece4SBram Moolenaar *hisidx = (i < len ? i : len) - 1;
7805f32ece4SBram Moolenaar
7815f32ece4SBram Moolenaar // Free what is not kept.
7825f32ece4SBram Moolenaar for (i = 0; i < viminfo_hisidx[type]; i++)
7835f32ece4SBram Moolenaar vim_free(viminfo_history[type][i].hisstr);
7845f32ece4SBram Moolenaar for (i = 0; i < hislen; i++)
7855f32ece4SBram Moolenaar vim_free(histentry[i].hisstr);
7865f32ece4SBram Moolenaar vim_free(histentry);
7875f32ece4SBram Moolenaar set_histentry(type, new_hist);
7885f32ece4SBram Moolenaar vim_free(tot_hist);
7895f32ece4SBram Moolenaar }
7905f32ece4SBram Moolenaar
7915f32ece4SBram Moolenaar /*
7925f32ece4SBram Moolenaar * Finish reading history lines from viminfo. Not used when writing viminfo.
7935f32ece4SBram Moolenaar */
7945f32ece4SBram Moolenaar static void
finish_viminfo_history(vir_T * virp)7955f32ece4SBram Moolenaar finish_viminfo_history(vir_T *virp)
7965f32ece4SBram Moolenaar {
7975f32ece4SBram Moolenaar int type;
7985f32ece4SBram Moolenaar int merge = virp->vir_version >= VIMINFO_VERSION_WITH_HISTORY;
7995f32ece4SBram Moolenaar
8005f32ece4SBram Moolenaar for (type = 0; type < HIST_COUNT; ++type)
8015f32ece4SBram Moolenaar {
8025f32ece4SBram Moolenaar if (get_histentry(type) == NULL)
8035f32ece4SBram Moolenaar continue;
8045f32ece4SBram Moolenaar
8055f32ece4SBram Moolenaar if (merge)
8065f32ece4SBram Moolenaar merge_history(type);
8075f32ece4SBram Moolenaar else
8085f32ece4SBram Moolenaar concat_history(type);
8095f32ece4SBram Moolenaar
8105f32ece4SBram Moolenaar VIM_CLEAR(viminfo_history[type]);
8115f32ece4SBram Moolenaar viminfo_hisidx[type] = 0;
8125f32ece4SBram Moolenaar }
8135f32ece4SBram Moolenaar }
8145f32ece4SBram Moolenaar
8155f32ece4SBram Moolenaar /*
8165f32ece4SBram Moolenaar * Write history to viminfo file in "fp".
8175f32ece4SBram Moolenaar * When "merge" is TRUE merge history lines with a previously read viminfo
8185f32ece4SBram Moolenaar * file, data is in viminfo_history[].
8195f32ece4SBram Moolenaar * When "merge" is FALSE just write all history lines. Used for ":wviminfo!".
8205f32ece4SBram Moolenaar */
8215f32ece4SBram Moolenaar static void
write_viminfo_history(FILE * fp,int merge)8225f32ece4SBram Moolenaar write_viminfo_history(FILE *fp, int merge)
8235f32ece4SBram Moolenaar {
8245f32ece4SBram Moolenaar int i;
8255f32ece4SBram Moolenaar int type;
8265f32ece4SBram Moolenaar int num_saved;
8275f32ece4SBram Moolenaar int round;
8285f32ece4SBram Moolenaar int hislen;
8295f32ece4SBram Moolenaar
8305f32ece4SBram Moolenaar init_history();
8315f32ece4SBram Moolenaar hislen = get_hislen();
8325f32ece4SBram Moolenaar if (hislen == 0)
8335f32ece4SBram Moolenaar return;
8345f32ece4SBram Moolenaar for (type = 0; type < HIST_COUNT; ++type)
8355f32ece4SBram Moolenaar {
8365f32ece4SBram Moolenaar histentry_T *histentry = get_histentry(type);
8375f32ece4SBram Moolenaar int *hisidx = get_hisidx(type);
8385f32ece4SBram Moolenaar
8395f32ece4SBram Moolenaar num_saved = get_viminfo_parameter(hist_type2char(type, FALSE));
8405f32ece4SBram Moolenaar if (num_saved == 0)
8415f32ece4SBram Moolenaar continue;
8425f32ece4SBram Moolenaar if (num_saved < 0) // Use default
8435f32ece4SBram Moolenaar num_saved = hislen;
8445f32ece4SBram Moolenaar fprintf(fp, _("\n# %s History (newest to oldest):\n"),
8455f32ece4SBram Moolenaar type == HIST_CMD ? _("Command Line") :
8465f32ece4SBram Moolenaar type == HIST_SEARCH ? _("Search String") :
8475f32ece4SBram Moolenaar type == HIST_EXPR ? _("Expression") :
8485f32ece4SBram Moolenaar type == HIST_INPUT ? _("Input Line") :
8495f32ece4SBram Moolenaar _("Debug Line"));
8505f32ece4SBram Moolenaar if (num_saved > hislen)
8515f32ece4SBram Moolenaar num_saved = hislen;
8525f32ece4SBram Moolenaar
8536bd1d770SBram Moolenaar // Merge typed and viminfo history:
8546bd1d770SBram Moolenaar // round 1: history of typed commands.
8556bd1d770SBram Moolenaar // round 2: history from recently read viminfo.
8565f32ece4SBram Moolenaar for (round = 1; round <= 2; ++round)
8575f32ece4SBram Moolenaar {
8585f32ece4SBram Moolenaar if (round == 1)
8595f32ece4SBram Moolenaar // start at newest entry, somewhere in the list
8605f32ece4SBram Moolenaar i = *hisidx;
8615f32ece4SBram Moolenaar else if (viminfo_hisidx[type] > 0)
8625f32ece4SBram Moolenaar // start at newest entry, first in the list
8635f32ece4SBram Moolenaar i = 0;
8645f32ece4SBram Moolenaar else
8655f32ece4SBram Moolenaar // empty list
8665f32ece4SBram Moolenaar i = -1;
8675f32ece4SBram Moolenaar if (i >= 0)
8685f32ece4SBram Moolenaar while (num_saved > 0
8695f32ece4SBram Moolenaar && !(round == 2 && i >= viminfo_hisidx[type]))
8705f32ece4SBram Moolenaar {
8715f32ece4SBram Moolenaar char_u *p;
8725f32ece4SBram Moolenaar time_t timestamp;
8735f32ece4SBram Moolenaar int c = NUL;
8745f32ece4SBram Moolenaar
8755f32ece4SBram Moolenaar if (round == 1)
8765f32ece4SBram Moolenaar {
8775f32ece4SBram Moolenaar p = histentry[i].hisstr;
8785f32ece4SBram Moolenaar timestamp = histentry[i].time_set;
8795f32ece4SBram Moolenaar }
8805f32ece4SBram Moolenaar else
8815f32ece4SBram Moolenaar {
8825f32ece4SBram Moolenaar p = viminfo_history[type] == NULL ? NULL
8835f32ece4SBram Moolenaar : viminfo_history[type][i].hisstr;
8845f32ece4SBram Moolenaar timestamp = viminfo_history[type] == NULL ? 0
8855f32ece4SBram Moolenaar : viminfo_history[type][i].time_set;
8865f32ece4SBram Moolenaar }
8875f32ece4SBram Moolenaar
8885f32ece4SBram Moolenaar if (p != NULL && (round == 2
8895f32ece4SBram Moolenaar || !merge
8905f32ece4SBram Moolenaar || !histentry[i].viminfo))
8915f32ece4SBram Moolenaar {
8925f32ece4SBram Moolenaar --num_saved;
8935f32ece4SBram Moolenaar fputc(hist_type2char(type, TRUE), fp);
8945f32ece4SBram Moolenaar // For the search history: put the separator in the
8955f32ece4SBram Moolenaar // second column; use a space if there isn't one.
8965f32ece4SBram Moolenaar if (type == HIST_SEARCH)
8975f32ece4SBram Moolenaar {
8985f32ece4SBram Moolenaar c = p[STRLEN(p) + 1];
8995f32ece4SBram Moolenaar putc(c == NUL ? ' ' : c, fp);
9005f32ece4SBram Moolenaar }
9015f32ece4SBram Moolenaar viminfo_writestring(fp, p);
9025f32ece4SBram Moolenaar
9035f32ece4SBram Moolenaar {
9045f32ece4SBram Moolenaar char cbuf[NUMBUFLEN];
9055f32ece4SBram Moolenaar
9065f32ece4SBram Moolenaar // New style history with a bar line. Format:
9075f32ece4SBram Moolenaar // |{bartype},{histtype},{timestamp},{separator},"text"
9085f32ece4SBram Moolenaar if (c == NUL)
9095f32ece4SBram Moolenaar cbuf[0] = NUL;
9105f32ece4SBram Moolenaar else
9115f32ece4SBram Moolenaar sprintf(cbuf, "%d", c);
9125f32ece4SBram Moolenaar fprintf(fp, "|%d,%d,%ld,%s,", BARTYPE_HISTORY,
9135f32ece4SBram Moolenaar type, (long)timestamp, cbuf);
9145f32ece4SBram Moolenaar barline_writestring(fp, p, LSIZE - 20);
9155f32ece4SBram Moolenaar putc('\n', fp);
9165f32ece4SBram Moolenaar }
9175f32ece4SBram Moolenaar }
9185f32ece4SBram Moolenaar if (round == 1)
9195f32ece4SBram Moolenaar {
9205f32ece4SBram Moolenaar // Decrement index, loop around and stop when back at
9215f32ece4SBram Moolenaar // the start.
9225f32ece4SBram Moolenaar if (--i < 0)
9235f32ece4SBram Moolenaar i = hislen - 1;
9245f32ece4SBram Moolenaar if (i == *hisidx)
9255f32ece4SBram Moolenaar break;
9265f32ece4SBram Moolenaar }
9275f32ece4SBram Moolenaar else
9285f32ece4SBram Moolenaar {
9295f32ece4SBram Moolenaar // Increment index. Stop at the end in the while.
9305f32ece4SBram Moolenaar ++i;
9315f32ece4SBram Moolenaar }
9325f32ece4SBram Moolenaar }
9335f32ece4SBram Moolenaar }
9345f32ece4SBram Moolenaar for (i = 0; i < viminfo_hisidx[type]; ++i)
9355f32ece4SBram Moolenaar if (viminfo_history[type] != NULL)
9365f32ece4SBram Moolenaar vim_free(viminfo_history[type][i].hisstr);
9375f32ece4SBram Moolenaar VIM_CLEAR(viminfo_history[type]);
9385f32ece4SBram Moolenaar viminfo_hisidx[type] = 0;
9395f32ece4SBram Moolenaar }
9405f32ece4SBram Moolenaar }
9415f32ece4SBram Moolenaar
942defa067cSBram Moolenaar static void
write_viminfo_barlines(vir_T * virp,FILE * fp_out)943defa067cSBram Moolenaar write_viminfo_barlines(vir_T *virp, FILE *fp_out)
944defa067cSBram Moolenaar {
945defa067cSBram Moolenaar int i;
946defa067cSBram Moolenaar garray_T *gap = &virp->vir_barlines;
947defa067cSBram Moolenaar int seen_useful = FALSE;
948defa067cSBram Moolenaar char *line;
949defa067cSBram Moolenaar
950defa067cSBram Moolenaar if (gap->ga_len > 0)
951defa067cSBram Moolenaar {
952defa067cSBram Moolenaar fputs(_("\n# Bar lines, copied verbatim:\n"), fp_out);
953defa067cSBram Moolenaar
954defa067cSBram Moolenaar // Skip over continuation lines until seeing a useful line.
955defa067cSBram Moolenaar for (i = 0; i < gap->ga_len; ++i)
956defa067cSBram Moolenaar {
957defa067cSBram Moolenaar line = ((char **)(gap->ga_data))[i];
958defa067cSBram Moolenaar if (seen_useful || line[1] != '<')
959defa067cSBram Moolenaar {
960defa067cSBram Moolenaar fputs(line, fp_out);
961defa067cSBram Moolenaar seen_useful = TRUE;
962defa067cSBram Moolenaar }
963defa067cSBram Moolenaar }
964defa067cSBram Moolenaar }
965defa067cSBram Moolenaar }
966defa067cSBram Moolenaar
967defa067cSBram Moolenaar /*
968defa067cSBram Moolenaar * Parse a viminfo line starting with '|'.
969defa067cSBram Moolenaar * Add each decoded value to "values".
970defa067cSBram Moolenaar * Returns TRUE if the next line is to be read after using the parsed values.
971defa067cSBram Moolenaar */
972defa067cSBram Moolenaar static int
barline_parse(vir_T * virp,char_u * text,garray_T * values)973defa067cSBram Moolenaar barline_parse(vir_T *virp, char_u *text, garray_T *values)
974defa067cSBram Moolenaar {
975defa067cSBram Moolenaar char_u *p = text;
976defa067cSBram Moolenaar char_u *nextp = NULL;
977defa067cSBram Moolenaar char_u *buf = NULL;
978defa067cSBram Moolenaar bval_T *value;
979defa067cSBram Moolenaar int i;
980defa067cSBram Moolenaar int allocated = FALSE;
981defa067cSBram Moolenaar int eof;
982defa067cSBram Moolenaar char_u *sconv;
983defa067cSBram Moolenaar int converted;
984defa067cSBram Moolenaar
985defa067cSBram Moolenaar while (*p == ',')
986defa067cSBram Moolenaar {
987defa067cSBram Moolenaar ++p;
988defa067cSBram Moolenaar if (ga_grow(values, 1) == FAIL)
989defa067cSBram Moolenaar break;
990defa067cSBram Moolenaar value = (bval_T *)(values->ga_data) + values->ga_len;
991defa067cSBram Moolenaar
992defa067cSBram Moolenaar if (*p == '>')
993defa067cSBram Moolenaar {
994defa067cSBram Moolenaar // Need to read a continuation line. Put strings in allocated
995defa067cSBram Moolenaar // memory, because virp->vir_line is overwritten.
996defa067cSBram Moolenaar if (!allocated)
997defa067cSBram Moolenaar {
998defa067cSBram Moolenaar for (i = 0; i < values->ga_len; ++i)
999defa067cSBram Moolenaar {
1000defa067cSBram Moolenaar bval_T *vp = (bval_T *)(values->ga_data) + i;
1001defa067cSBram Moolenaar
1002defa067cSBram Moolenaar if (vp->bv_type == BVAL_STRING && !vp->bv_allocated)
1003defa067cSBram Moolenaar {
1004defa067cSBram Moolenaar vp->bv_string = vim_strnsave(vp->bv_string, vp->bv_len);
1005defa067cSBram Moolenaar vp->bv_allocated = TRUE;
1006defa067cSBram Moolenaar }
1007defa067cSBram Moolenaar }
1008defa067cSBram Moolenaar allocated = TRUE;
1009defa067cSBram Moolenaar }
1010defa067cSBram Moolenaar
1011defa067cSBram Moolenaar if (vim_isdigit(p[1]))
1012defa067cSBram Moolenaar {
1013defa067cSBram Moolenaar size_t len;
1014defa067cSBram Moolenaar size_t todo;
1015defa067cSBram Moolenaar size_t n;
1016defa067cSBram Moolenaar
1017defa067cSBram Moolenaar // String value was split into lines that are each shorter
1018defa067cSBram Moolenaar // than LSIZE:
1019defa067cSBram Moolenaar // |{bartype},>{length of "{text}{text2}"}
1020defa067cSBram Moolenaar // |<"{text1}
1021defa067cSBram Moolenaar // |<{text2}",{value}
1022defa067cSBram Moolenaar // Length includes the quotes.
1023defa067cSBram Moolenaar ++p;
1024defa067cSBram Moolenaar len = getdigits(&p);
1025defa067cSBram Moolenaar buf = alloc((int)(len + 1));
1026defa067cSBram Moolenaar if (buf == NULL)
1027defa067cSBram Moolenaar return TRUE;
1028defa067cSBram Moolenaar p = buf;
1029defa067cSBram Moolenaar for (todo = len; todo > 0; todo -= n)
1030defa067cSBram Moolenaar {
1031defa067cSBram Moolenaar eof = viminfo_readline(virp);
1032defa067cSBram Moolenaar if (eof || virp->vir_line[0] != '|'
1033defa067cSBram Moolenaar || virp->vir_line[1] != '<')
1034defa067cSBram Moolenaar {
1035defa067cSBram Moolenaar // File was truncated or garbled. Read another line if
1036defa067cSBram Moolenaar // this one starts with '|'.
1037defa067cSBram Moolenaar vim_free(buf);
1038defa067cSBram Moolenaar return eof || virp->vir_line[0] == '|';
1039defa067cSBram Moolenaar }
1040defa067cSBram Moolenaar // Get length of text, excluding |< and NL chars.
1041defa067cSBram Moolenaar n = STRLEN(virp->vir_line);
1042defa067cSBram Moolenaar while (n > 0 && (virp->vir_line[n - 1] == NL
1043defa067cSBram Moolenaar || virp->vir_line[n - 1] == CAR))
1044defa067cSBram Moolenaar --n;
1045defa067cSBram Moolenaar n -= 2;
1046defa067cSBram Moolenaar if (n > todo)
1047defa067cSBram Moolenaar {
1048defa067cSBram Moolenaar // more values follow after the string
1049defa067cSBram Moolenaar nextp = virp->vir_line + 2 + todo;
1050defa067cSBram Moolenaar n = todo;
1051defa067cSBram Moolenaar }
1052defa067cSBram Moolenaar mch_memmove(p, virp->vir_line + 2, n);
1053defa067cSBram Moolenaar p += n;
1054defa067cSBram Moolenaar }
1055defa067cSBram Moolenaar *p = NUL;
1056defa067cSBram Moolenaar p = buf;
1057defa067cSBram Moolenaar }
1058defa067cSBram Moolenaar else
1059defa067cSBram Moolenaar {
1060defa067cSBram Moolenaar // Line ending in ">" continues in the next line:
1061defa067cSBram Moolenaar // |{bartype},{lots of values},>
1062defa067cSBram Moolenaar // |<{value},{value}
1063defa067cSBram Moolenaar eof = viminfo_readline(virp);
1064defa067cSBram Moolenaar if (eof || virp->vir_line[0] != '|'
1065defa067cSBram Moolenaar || virp->vir_line[1] != '<')
1066defa067cSBram Moolenaar // File was truncated or garbled. Read another line if
1067defa067cSBram Moolenaar // this one starts with '|'.
1068defa067cSBram Moolenaar return eof || virp->vir_line[0] == '|';
1069defa067cSBram Moolenaar p = virp->vir_line + 2;
1070defa067cSBram Moolenaar }
1071defa067cSBram Moolenaar }
1072defa067cSBram Moolenaar
1073defa067cSBram Moolenaar if (isdigit(*p))
1074defa067cSBram Moolenaar {
1075defa067cSBram Moolenaar value->bv_type = BVAL_NR;
1076defa067cSBram Moolenaar value->bv_nr = getdigits(&p);
1077defa067cSBram Moolenaar ++values->ga_len;
1078defa067cSBram Moolenaar }
1079defa067cSBram Moolenaar else if (*p == '"')
1080defa067cSBram Moolenaar {
1081defa067cSBram Moolenaar int len = 0;
1082defa067cSBram Moolenaar char_u *s = p;
1083defa067cSBram Moolenaar
1084defa067cSBram Moolenaar // Unescape special characters in-place.
1085defa067cSBram Moolenaar ++p;
1086defa067cSBram Moolenaar while (*p != '"')
1087defa067cSBram Moolenaar {
1088defa067cSBram Moolenaar if (*p == NL || *p == NUL)
1089defa067cSBram Moolenaar return TRUE; // syntax error, drop the value
1090defa067cSBram Moolenaar if (*p == '\\')
1091defa067cSBram Moolenaar {
1092defa067cSBram Moolenaar ++p;
1093defa067cSBram Moolenaar if (*p == 'n')
1094defa067cSBram Moolenaar s[len++] = '\n';
1095defa067cSBram Moolenaar else
1096defa067cSBram Moolenaar s[len++] = *p;
1097defa067cSBram Moolenaar ++p;
1098defa067cSBram Moolenaar }
1099defa067cSBram Moolenaar else
1100defa067cSBram Moolenaar s[len++] = *p++;
1101defa067cSBram Moolenaar }
1102defa067cSBram Moolenaar ++p;
1103defa067cSBram Moolenaar s[len] = NUL;
1104defa067cSBram Moolenaar
1105defa067cSBram Moolenaar converted = FALSE;
1106408030e8SBram Moolenaar value->bv_tofree = NULL;
1107defa067cSBram Moolenaar if (virp->vir_conv.vc_type != CONV_NONE && *s != NUL)
1108defa067cSBram Moolenaar {
1109defa067cSBram Moolenaar sconv = string_convert(&virp->vir_conv, s, NULL);
1110defa067cSBram Moolenaar if (sconv != NULL)
1111defa067cSBram Moolenaar {
1112defa067cSBram Moolenaar if (s == buf)
1113408030e8SBram Moolenaar // the converted string is stored in bv_string and
1114408030e8SBram Moolenaar // freed later, also need to free "buf" later
1115408030e8SBram Moolenaar value->bv_tofree = buf;
1116defa067cSBram Moolenaar s = sconv;
1117defa067cSBram Moolenaar converted = TRUE;
1118defa067cSBram Moolenaar }
1119defa067cSBram Moolenaar }
1120defa067cSBram Moolenaar
1121defa067cSBram Moolenaar // Need to copy in allocated memory if the string wasn't allocated
1122defa067cSBram Moolenaar // above and we did allocate before, thus vir_line may change.
1123408030e8SBram Moolenaar if (s != buf && allocated && !converted)
1124defa067cSBram Moolenaar s = vim_strsave(s);
1125defa067cSBram Moolenaar value->bv_string = s;
1126defa067cSBram Moolenaar value->bv_type = BVAL_STRING;
1127defa067cSBram Moolenaar value->bv_len = len;
1128defa067cSBram Moolenaar value->bv_allocated = allocated || converted;
1129defa067cSBram Moolenaar ++values->ga_len;
1130defa067cSBram Moolenaar if (nextp != NULL)
1131defa067cSBram Moolenaar {
1132defa067cSBram Moolenaar // values following a long string
1133defa067cSBram Moolenaar p = nextp;
1134defa067cSBram Moolenaar nextp = NULL;
1135defa067cSBram Moolenaar }
1136defa067cSBram Moolenaar }
1137defa067cSBram Moolenaar else if (*p == ',')
1138defa067cSBram Moolenaar {
1139defa067cSBram Moolenaar value->bv_type = BVAL_EMPTY;
1140defa067cSBram Moolenaar ++values->ga_len;
1141defa067cSBram Moolenaar }
1142defa067cSBram Moolenaar else
1143defa067cSBram Moolenaar break;
1144defa067cSBram Moolenaar }
1145defa067cSBram Moolenaar return TRUE;
1146defa067cSBram Moolenaar }
1147defa067cSBram Moolenaar
1148defa067cSBram Moolenaar static void
write_viminfo_version(FILE * fp_out)1149defa067cSBram Moolenaar write_viminfo_version(FILE *fp_out)
1150defa067cSBram Moolenaar {
1151defa067cSBram Moolenaar fprintf(fp_out, "# Viminfo version\n|%d,%d\n\n",
1152defa067cSBram Moolenaar BARTYPE_VERSION, VIMINFO_VERSION);
1153defa067cSBram Moolenaar }
1154defa067cSBram Moolenaar
1155defa067cSBram Moolenaar static int
no_viminfo(void)1156defa067cSBram Moolenaar no_viminfo(void)
1157defa067cSBram Moolenaar {
1158defa067cSBram Moolenaar // "vim -i NONE" does not read or write a viminfo file
1159defa067cSBram Moolenaar return STRCMP(p_viminfofile, "NONE") == 0;
1160defa067cSBram Moolenaar }
1161defa067cSBram Moolenaar
1162defa067cSBram Moolenaar /*
1163defa067cSBram Moolenaar * Report an error for reading a viminfo file.
1164defa067cSBram Moolenaar * Count the number of errors. When there are more than 10, return TRUE.
1165defa067cSBram Moolenaar */
1166c3328169SBram Moolenaar static int
viminfo_error(char * errnum,char * message,char_u * line)1167defa067cSBram Moolenaar viminfo_error(char *errnum, char *message, char_u *line)
1168defa067cSBram Moolenaar {
1169defa067cSBram Moolenaar vim_snprintf((char *)IObuff, IOSIZE, _("%sviminfo: %s in line: "),
1170defa067cSBram Moolenaar errnum, message);
1171defa067cSBram Moolenaar STRNCAT(IObuff, line, IOSIZE - STRLEN(IObuff) - 1);
1172defa067cSBram Moolenaar if (IObuff[STRLEN(IObuff) - 1] == '\n')
1173defa067cSBram Moolenaar IObuff[STRLEN(IObuff) - 1] = NUL;
1174defa067cSBram Moolenaar emsg((char *)IObuff);
1175defa067cSBram Moolenaar if (++viminfo_errcnt >= 10)
1176defa067cSBram Moolenaar {
1177defa067cSBram Moolenaar emsg(_("E136: viminfo: Too many errors, skipping rest of file"));
1178defa067cSBram Moolenaar return TRUE;
1179defa067cSBram Moolenaar }
1180defa067cSBram Moolenaar return FALSE;
1181defa067cSBram Moolenaar }
1182defa067cSBram Moolenaar
1183defa067cSBram Moolenaar /*
1184defa067cSBram Moolenaar * Compare the 'encoding' value in the viminfo file with the current value of
1185defa067cSBram Moolenaar * 'encoding'. If different and the 'c' flag is in 'viminfo', setup for
1186defa067cSBram Moolenaar * conversion of text with iconv() in viminfo_readstring().
1187defa067cSBram Moolenaar */
1188defa067cSBram Moolenaar static int
viminfo_encoding(vir_T * virp)1189defa067cSBram Moolenaar viminfo_encoding(vir_T *virp)
1190defa067cSBram Moolenaar {
1191defa067cSBram Moolenaar char_u *p;
1192defa067cSBram Moolenaar int i;
1193defa067cSBram Moolenaar
1194defa067cSBram Moolenaar if (get_viminfo_parameter('c') != 0)
1195defa067cSBram Moolenaar {
1196defa067cSBram Moolenaar p = vim_strchr(virp->vir_line, '=');
1197defa067cSBram Moolenaar if (p != NULL)
1198defa067cSBram Moolenaar {
1199defa067cSBram Moolenaar // remove trailing newline
1200defa067cSBram Moolenaar ++p;
1201defa067cSBram Moolenaar for (i = 0; vim_isprintc(p[i]); ++i)
1202defa067cSBram Moolenaar ;
1203defa067cSBram Moolenaar p[i] = NUL;
1204defa067cSBram Moolenaar
1205defa067cSBram Moolenaar convert_setup(&virp->vir_conv, p, p_enc);
1206defa067cSBram Moolenaar }
1207defa067cSBram Moolenaar }
1208defa067cSBram Moolenaar return viminfo_readline(virp);
1209defa067cSBram Moolenaar }
1210defa067cSBram Moolenaar
1211defa067cSBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
1212defa067cSBram Moolenaar /*
1213defa067cSBram Moolenaar * Restore global vars that start with a capital from the viminfo file
1214defa067cSBram Moolenaar */
1215defa067cSBram Moolenaar static int
read_viminfo_varlist(vir_T * virp,int writing)1216defa067cSBram Moolenaar read_viminfo_varlist(vir_T *virp, int writing)
1217defa067cSBram Moolenaar {
1218defa067cSBram Moolenaar char_u *tab;
1219defa067cSBram Moolenaar int type = VAR_NUMBER;
1220defa067cSBram Moolenaar typval_T tv;
1221defa067cSBram Moolenaar funccal_entry_T funccal_entry;
1222defa067cSBram Moolenaar
1223defa067cSBram Moolenaar if (!writing && (find_viminfo_parameter('!') != NULL))
1224defa067cSBram Moolenaar {
1225defa067cSBram Moolenaar tab = vim_strchr(virp->vir_line + 1, '\t');
1226defa067cSBram Moolenaar if (tab != NULL)
1227defa067cSBram Moolenaar {
1228defa067cSBram Moolenaar *tab++ = '\0'; // isolate the variable name
1229defa067cSBram Moolenaar switch (*tab)
1230defa067cSBram Moolenaar {
1231defa067cSBram Moolenaar case 'S': type = VAR_STRING; break;
1232defa067cSBram Moolenaar #ifdef FEAT_FLOAT
1233defa067cSBram Moolenaar case 'F': type = VAR_FLOAT; break;
1234defa067cSBram Moolenaar #endif
1235defa067cSBram Moolenaar case 'D': type = VAR_DICT; break;
1236defa067cSBram Moolenaar case 'L': type = VAR_LIST; break;
1237defa067cSBram Moolenaar case 'B': type = VAR_BLOB; break;
1238defa067cSBram Moolenaar case 'X': type = VAR_SPECIAL; break;
1239defa067cSBram Moolenaar }
1240defa067cSBram Moolenaar
1241defa067cSBram Moolenaar tab = vim_strchr(tab, '\t');
1242defa067cSBram Moolenaar if (tab != NULL)
1243defa067cSBram Moolenaar {
1244defa067cSBram Moolenaar tv.v_type = type;
1245defa067cSBram Moolenaar if (type == VAR_STRING || type == VAR_DICT
1246defa067cSBram Moolenaar || type == VAR_LIST || type == VAR_BLOB)
1247defa067cSBram Moolenaar tv.vval.v_string = viminfo_readstring(virp,
1248defa067cSBram Moolenaar (int)(tab - virp->vir_line + 1), TRUE);
1249defa067cSBram Moolenaar #ifdef FEAT_FLOAT
1250defa067cSBram Moolenaar else if (type == VAR_FLOAT)
12512950065eSBram Moolenaar (void)string2float(tab + 1, &tv.vval.v_float, FALSE);
1252defa067cSBram Moolenaar #endif
1253defa067cSBram Moolenaar else
12549b4a15d5SBram Moolenaar {
1255defa067cSBram Moolenaar tv.vval.v_number = atol((char *)tab + 1);
12569b4a15d5SBram Moolenaar if (type == VAR_SPECIAL && (tv.vval.v_number == VVAL_FALSE
12579b4a15d5SBram Moolenaar || tv.vval.v_number == VVAL_TRUE))
12589b4a15d5SBram Moolenaar tv.v_type = VAR_BOOL;
12599b4a15d5SBram Moolenaar }
1260defa067cSBram Moolenaar if (type == VAR_DICT || type == VAR_LIST)
1261defa067cSBram Moolenaar {
1262defa067cSBram Moolenaar typval_T *etv = eval_expr(tv.vval.v_string, NULL);
1263defa067cSBram Moolenaar
1264defa067cSBram Moolenaar if (etv == NULL)
1265defa067cSBram Moolenaar // Failed to parse back the dict or list, use it as a
1266defa067cSBram Moolenaar // string.
1267defa067cSBram Moolenaar tv.v_type = VAR_STRING;
1268defa067cSBram Moolenaar else
1269defa067cSBram Moolenaar {
1270defa067cSBram Moolenaar vim_free(tv.vval.v_string);
1271defa067cSBram Moolenaar tv = *etv;
1272defa067cSBram Moolenaar vim_free(etv);
1273defa067cSBram Moolenaar }
1274defa067cSBram Moolenaar }
1275defa067cSBram Moolenaar else if (type == VAR_BLOB)
1276defa067cSBram Moolenaar {
1277defa067cSBram Moolenaar blob_T *blob = string2blob(tv.vval.v_string);
1278defa067cSBram Moolenaar
1279defa067cSBram Moolenaar if (blob == NULL)
1280defa067cSBram Moolenaar // Failed to parse back the blob, use it as a string.
1281defa067cSBram Moolenaar tv.v_type = VAR_STRING;
1282defa067cSBram Moolenaar else
1283defa067cSBram Moolenaar {
1284defa067cSBram Moolenaar vim_free(tv.vval.v_string);
1285defa067cSBram Moolenaar tv.v_type = VAR_BLOB;
1286defa067cSBram Moolenaar tv.vval.v_blob = blob;
1287defa067cSBram Moolenaar }
1288defa067cSBram Moolenaar }
1289defa067cSBram Moolenaar
1290defa067cSBram Moolenaar // when in a function use global variables
1291defa067cSBram Moolenaar save_funccal(&funccal_entry);
1292defa067cSBram Moolenaar set_var(virp->vir_line + 1, &tv, FALSE);
1293defa067cSBram Moolenaar restore_funccal();
1294defa067cSBram Moolenaar
1295defa067cSBram Moolenaar if (tv.v_type == VAR_STRING)
1296defa067cSBram Moolenaar vim_free(tv.vval.v_string);
1297defa067cSBram Moolenaar else if (tv.v_type == VAR_DICT || tv.v_type == VAR_LIST ||
1298defa067cSBram Moolenaar tv.v_type == VAR_BLOB)
1299defa067cSBram Moolenaar clear_tv(&tv);
1300defa067cSBram Moolenaar }
1301defa067cSBram Moolenaar }
1302defa067cSBram Moolenaar }
1303defa067cSBram Moolenaar
1304defa067cSBram Moolenaar return viminfo_readline(virp);
1305defa067cSBram Moolenaar }
1306defa067cSBram Moolenaar
1307defa067cSBram Moolenaar /*
1308defa067cSBram Moolenaar * Write global vars that start with a capital to the viminfo file
1309defa067cSBram Moolenaar */
1310defa067cSBram Moolenaar static void
write_viminfo_varlist(FILE * fp)1311defa067cSBram Moolenaar write_viminfo_varlist(FILE *fp)
1312defa067cSBram Moolenaar {
1313da6c0334SBram Moolenaar hashtab_T *gvht = get_globvar_ht();
1314defa067cSBram Moolenaar hashitem_T *hi;
1315defa067cSBram Moolenaar dictitem_T *this_var;
1316defa067cSBram Moolenaar int todo;
1317defa067cSBram Moolenaar char *s = "";
1318defa067cSBram Moolenaar char_u *p;
1319defa067cSBram Moolenaar char_u *tofree;
1320defa067cSBram Moolenaar char_u numbuf[NUMBUFLEN];
1321defa067cSBram Moolenaar
1322defa067cSBram Moolenaar if (find_viminfo_parameter('!') == NULL)
1323defa067cSBram Moolenaar return;
1324defa067cSBram Moolenaar
1325defa067cSBram Moolenaar fputs(_("\n# global variables:\n"), fp);
1326defa067cSBram Moolenaar
1327da6c0334SBram Moolenaar todo = (int)gvht->ht_used;
1328da6c0334SBram Moolenaar for (hi = gvht->ht_array; todo > 0; ++hi)
1329defa067cSBram Moolenaar {
1330defa067cSBram Moolenaar if (!HASHITEM_EMPTY(hi))
1331defa067cSBram Moolenaar {
1332defa067cSBram Moolenaar --todo;
1333defa067cSBram Moolenaar this_var = HI2DI(hi);
1334defa067cSBram Moolenaar if (var_flavour(this_var->di_key) == VAR_FLAVOUR_VIMINFO)
1335defa067cSBram Moolenaar {
1336defa067cSBram Moolenaar switch (this_var->di_tv.v_type)
1337defa067cSBram Moolenaar {
1338defa067cSBram Moolenaar case VAR_STRING: s = "STR"; break;
1339defa067cSBram Moolenaar case VAR_NUMBER: s = "NUM"; break;
1340defa067cSBram Moolenaar case VAR_FLOAT: s = "FLO"; break;
13415b157fe2SBram Moolenaar case VAR_DICT:
13425b157fe2SBram Moolenaar {
13435b157fe2SBram Moolenaar dict_T *di = this_var->di_tv.vval.v_dict;
13445b157fe2SBram Moolenaar int copyID = get_copyID();
13455b157fe2SBram Moolenaar
13465b157fe2SBram Moolenaar s = "DIC";
13475b157fe2SBram Moolenaar if (di != NULL && !set_ref_in_ht(
13485b157fe2SBram Moolenaar &di->dv_hashtab, copyID, NULL)
13495b157fe2SBram Moolenaar && di->dv_copyID == copyID)
13505b157fe2SBram Moolenaar // has a circular reference, can't turn the
13515b157fe2SBram Moolenaar // value into a string
13525b157fe2SBram Moolenaar continue;
13535b157fe2SBram Moolenaar break;
13545b157fe2SBram Moolenaar }
13555b157fe2SBram Moolenaar case VAR_LIST:
13565b157fe2SBram Moolenaar {
13575b157fe2SBram Moolenaar list_T *l = this_var->di_tv.vval.v_list;
13585b157fe2SBram Moolenaar int copyID = get_copyID();
13595b157fe2SBram Moolenaar
13605b157fe2SBram Moolenaar s = "LIS";
13615b157fe2SBram Moolenaar if (l != NULL && !set_ref_in_list_items(
13625b157fe2SBram Moolenaar l, copyID, NULL)
13635b157fe2SBram Moolenaar && l->lv_copyID == copyID)
13645b157fe2SBram Moolenaar // has a circular reference, can't turn the
13655b157fe2SBram Moolenaar // value into a string
13665b157fe2SBram Moolenaar continue;
13675b157fe2SBram Moolenaar break;
13685b157fe2SBram Moolenaar }
1369defa067cSBram Moolenaar case VAR_BLOB: s = "BLO"; break;
13709b4a15d5SBram Moolenaar case VAR_BOOL: s = "XPL"; break; // backwards compat.
1371defa067cSBram Moolenaar case VAR_SPECIAL: s = "XPL"; break;
1372defa067cSBram Moolenaar
1373defa067cSBram Moolenaar case VAR_UNKNOWN:
13744c683750SBram Moolenaar case VAR_ANY:
13758a7d6542SBram Moolenaar case VAR_VOID:
1376defa067cSBram Moolenaar case VAR_FUNC:
1377defa067cSBram Moolenaar case VAR_PARTIAL:
1378defa067cSBram Moolenaar case VAR_JOB:
1379defa067cSBram Moolenaar case VAR_CHANNEL:
1380f18332fbSBram Moolenaar case VAR_INSTR:
1381defa067cSBram Moolenaar continue;
1382defa067cSBram Moolenaar }
1383defa067cSBram Moolenaar fprintf(fp, "!%s\t%s\t", this_var->di_key, s);
13849b4a15d5SBram Moolenaar if (this_var->di_tv.v_type == VAR_BOOL
13859b4a15d5SBram Moolenaar || this_var->di_tv.v_type == VAR_SPECIAL)
1386defa067cSBram Moolenaar {
13879b4a15d5SBram Moolenaar // do not use "v:true" but "1"
1388defa067cSBram Moolenaar sprintf((char *)numbuf, "%ld",
1389defa067cSBram Moolenaar (long)this_var->di_tv.vval.v_number);
1390defa067cSBram Moolenaar p = numbuf;
1391defa067cSBram Moolenaar tofree = NULL;
1392defa067cSBram Moolenaar }
1393defa067cSBram Moolenaar else
1394defa067cSBram Moolenaar p = echo_string(&this_var->di_tv, &tofree, numbuf, 0);
1395defa067cSBram Moolenaar if (p != NULL)
1396defa067cSBram Moolenaar viminfo_writestring(fp, p);
1397defa067cSBram Moolenaar vim_free(tofree);
1398defa067cSBram Moolenaar }
1399defa067cSBram Moolenaar }
1400defa067cSBram Moolenaar }
1401defa067cSBram Moolenaar }
1402defa067cSBram Moolenaar #endif // FEAT_EVAL
1403defa067cSBram Moolenaar
1404c3328169SBram Moolenaar static int
read_viminfo_sub_string(vir_T * virp,int force)1405c3328169SBram Moolenaar read_viminfo_sub_string(vir_T *virp, int force)
1406c3328169SBram Moolenaar {
1407c3328169SBram Moolenaar if (force || get_old_sub() == NULL)
1408c3328169SBram Moolenaar set_old_sub(viminfo_readstring(virp, 1, TRUE));
1409c3328169SBram Moolenaar return viminfo_readline(virp);
1410c3328169SBram Moolenaar }
1411c3328169SBram Moolenaar
1412c3328169SBram Moolenaar static void
write_viminfo_sub_string(FILE * fp)1413c3328169SBram Moolenaar write_viminfo_sub_string(FILE *fp)
1414c3328169SBram Moolenaar {
1415c3328169SBram Moolenaar char_u *old_sub = get_old_sub();
1416c3328169SBram Moolenaar
1417c3328169SBram Moolenaar if (get_viminfo_parameter('/') != 0 && old_sub != NULL)
1418c3328169SBram Moolenaar {
1419c3328169SBram Moolenaar fputs(_("\n# Last Substitute String:\n$"), fp);
1420c3328169SBram Moolenaar viminfo_writestring(fp, old_sub);
1421c3328169SBram Moolenaar }
1422c3328169SBram Moolenaar }
1423c3328169SBram Moolenaar
1424c3328169SBram Moolenaar /*
1425c3328169SBram Moolenaar * Functions relating to reading/writing the search pattern from viminfo
1426c3328169SBram Moolenaar */
1427c3328169SBram Moolenaar
1428c3328169SBram Moolenaar static int
read_viminfo_search_pattern(vir_T * virp,int force)1429c3328169SBram Moolenaar read_viminfo_search_pattern(vir_T *virp, int force)
1430c3328169SBram Moolenaar {
1431c3328169SBram Moolenaar char_u *lp;
1432c3328169SBram Moolenaar int idx = -1;
1433c3328169SBram Moolenaar int magic = FALSE;
1434c3328169SBram Moolenaar int no_scs = FALSE;
1435c3328169SBram Moolenaar int off_line = FALSE;
1436c3328169SBram Moolenaar int off_end = 0;
1437c3328169SBram Moolenaar long off = 0;
1438c3328169SBram Moolenaar int setlast = FALSE;
1439c3328169SBram Moolenaar #ifdef FEAT_SEARCH_EXTRA
1440c3328169SBram Moolenaar static int hlsearch_on = FALSE;
1441c3328169SBram Moolenaar #endif
1442c3328169SBram Moolenaar char_u *val;
1443c3328169SBram Moolenaar spat_T *spat;
1444c3328169SBram Moolenaar
1445c3328169SBram Moolenaar // Old line types:
1446c3328169SBram Moolenaar // "/pat", "&pat": search/subst. pat
1447c3328169SBram Moolenaar // "~/pat", "~&pat": last used search/subst. pat
1448c3328169SBram Moolenaar // New line types:
1449c3328169SBram Moolenaar // "~h", "~H": hlsearch highlighting off/on
1450c3328169SBram Moolenaar // "~<magic><smartcase><line><end><off><last><which>pat"
1451c3328169SBram Moolenaar // <magic>: 'm' off, 'M' on
1452c3328169SBram Moolenaar // <smartcase>: 's' off, 'S' on
1453c3328169SBram Moolenaar // <line>: 'L' line offset, 'l' char offset
1454c3328169SBram Moolenaar // <end>: 'E' from end, 'e' from start
1455c3328169SBram Moolenaar // <off>: decimal, offset
1456c3328169SBram Moolenaar // <last>: '~' last used pattern
1457c3328169SBram Moolenaar // <which>: '/' search pat, '&' subst. pat
1458c3328169SBram Moolenaar lp = virp->vir_line;
1459c3328169SBram Moolenaar if (lp[0] == '~' && (lp[1] == 'm' || lp[1] == 'M')) // new line type
1460c3328169SBram Moolenaar {
1461c3328169SBram Moolenaar if (lp[1] == 'M') // magic on
1462c3328169SBram Moolenaar magic = TRUE;
1463c3328169SBram Moolenaar if (lp[2] == 's')
1464c3328169SBram Moolenaar no_scs = TRUE;
1465c3328169SBram Moolenaar if (lp[3] == 'L')
1466c3328169SBram Moolenaar off_line = TRUE;
1467c3328169SBram Moolenaar if (lp[4] == 'E')
1468c3328169SBram Moolenaar off_end = SEARCH_END;
1469c3328169SBram Moolenaar lp += 5;
1470c3328169SBram Moolenaar off = getdigits(&lp);
1471c3328169SBram Moolenaar }
1472c3328169SBram Moolenaar if (lp[0] == '~') // use this pattern for last-used pattern
1473c3328169SBram Moolenaar {
1474c3328169SBram Moolenaar setlast = TRUE;
1475c3328169SBram Moolenaar lp++;
1476c3328169SBram Moolenaar }
1477c3328169SBram Moolenaar if (lp[0] == '/')
1478c3328169SBram Moolenaar idx = RE_SEARCH;
1479c3328169SBram Moolenaar else if (lp[0] == '&')
1480c3328169SBram Moolenaar idx = RE_SUBST;
1481c3328169SBram Moolenaar #ifdef FEAT_SEARCH_EXTRA
1482c3328169SBram Moolenaar else if (lp[0] == 'h') // ~h: 'hlsearch' highlighting off
1483c3328169SBram Moolenaar hlsearch_on = FALSE;
1484c3328169SBram Moolenaar else if (lp[0] == 'H') // ~H: 'hlsearch' highlighting on
1485c3328169SBram Moolenaar hlsearch_on = TRUE;
1486c3328169SBram Moolenaar #endif
1487c3328169SBram Moolenaar if (idx >= 0)
1488c3328169SBram Moolenaar {
1489736cd2cfSBram Moolenaar spat = get_spat(idx);
1490c3328169SBram Moolenaar if (force || spat->pat == NULL)
1491c3328169SBram Moolenaar {
1492c3328169SBram Moolenaar val = viminfo_readstring(virp, (int)(lp - virp->vir_line + 1),
1493c3328169SBram Moolenaar TRUE);
1494c3328169SBram Moolenaar if (val != NULL)
1495c3328169SBram Moolenaar {
1496c3328169SBram Moolenaar set_last_search_pat(val, idx, magic, setlast);
1497c3328169SBram Moolenaar vim_free(val);
1498c3328169SBram Moolenaar spat->no_scs = no_scs;
1499c3328169SBram Moolenaar spat->off.line = off_line;
1500c3328169SBram Moolenaar spat->off.end = off_end;
1501c3328169SBram Moolenaar spat->off.off = off;
1502c3328169SBram Moolenaar #ifdef FEAT_SEARCH_EXTRA
1503c3328169SBram Moolenaar if (setlast)
1504c3328169SBram Moolenaar set_no_hlsearch(!hlsearch_on);
1505c3328169SBram Moolenaar #endif
1506c3328169SBram Moolenaar }
1507c3328169SBram Moolenaar }
1508c3328169SBram Moolenaar }
1509c3328169SBram Moolenaar return viminfo_readline(virp);
1510c3328169SBram Moolenaar }
1511c3328169SBram Moolenaar
1512c3328169SBram Moolenaar static void
wvsp_one(FILE * fp,int idx,char * s,int sc)1513c3328169SBram Moolenaar wvsp_one(
1514c3328169SBram Moolenaar FILE *fp, // file to write to
1515c3328169SBram Moolenaar int idx, // spats[] index
1516c3328169SBram Moolenaar char *s, // search pat
1517c3328169SBram Moolenaar int sc) // dir char
1518c3328169SBram Moolenaar {
1519c3328169SBram Moolenaar spat_T *spat = get_spat(idx);
1520c3328169SBram Moolenaar if (spat->pat != NULL)
1521c3328169SBram Moolenaar {
1522c3328169SBram Moolenaar fprintf(fp, _("\n# Last %sSearch Pattern:\n~"), s);
1523c3328169SBram Moolenaar // off.dir is not stored, it's reset to forward
1524c3328169SBram Moolenaar fprintf(fp, "%c%c%c%c%ld%s%c",
1525c3328169SBram Moolenaar spat->magic ? 'M' : 'm', // magic
1526c3328169SBram Moolenaar spat->no_scs ? 's' : 'S', // smartcase
1527c3328169SBram Moolenaar spat->off.line ? 'L' : 'l', // line offset
1528c3328169SBram Moolenaar spat->off.end ? 'E' : 'e', // offset from end
1529c3328169SBram Moolenaar spat->off.off, // offset
1530c3328169SBram Moolenaar get_spat_last_idx() == idx ? "~" : "", // last used pat
1531c3328169SBram Moolenaar sc);
1532c3328169SBram Moolenaar viminfo_writestring(fp, spat->pat);
1533c3328169SBram Moolenaar }
1534c3328169SBram Moolenaar }
1535c3328169SBram Moolenaar
1536c3328169SBram Moolenaar static void
write_viminfo_search_pattern(FILE * fp)1537c3328169SBram Moolenaar write_viminfo_search_pattern(FILE *fp)
1538c3328169SBram Moolenaar {
1539c3328169SBram Moolenaar if (get_viminfo_parameter('/') != 0)
1540c3328169SBram Moolenaar {
1541c3328169SBram Moolenaar #ifdef FEAT_SEARCH_EXTRA
1542c3328169SBram Moolenaar fprintf(fp, "\n# hlsearch on (H) or off (h):\n~%c",
1543c3328169SBram Moolenaar (no_hlsearch || find_viminfo_parameter('h') != NULL) ? 'h' : 'H');
1544c3328169SBram Moolenaar #endif
1545c3328169SBram Moolenaar wvsp_one(fp, RE_SEARCH, "", '/');
1546c3328169SBram Moolenaar wvsp_one(fp, RE_SUBST, _("Substitute "), '&');
1547c3328169SBram Moolenaar }
1548c3328169SBram Moolenaar }
1549c3328169SBram Moolenaar
1550c3328169SBram Moolenaar /*
1551c3328169SBram Moolenaar * Functions relating to reading/writing registers from viminfo
1552c3328169SBram Moolenaar */
1553c3328169SBram Moolenaar
1554c3328169SBram Moolenaar static yankreg_T *y_read_regs = NULL;
1555c3328169SBram Moolenaar
1556c3328169SBram Moolenaar #define REG_PREVIOUS 1
1557c3328169SBram Moolenaar #define REG_EXEC 2
1558c3328169SBram Moolenaar
1559c3328169SBram Moolenaar /*
1560c3328169SBram Moolenaar * Prepare for reading viminfo registers when writing viminfo later.
1561c3328169SBram Moolenaar */
1562c3328169SBram Moolenaar static void
prepare_viminfo_registers(void)1563c3328169SBram Moolenaar prepare_viminfo_registers(void)
1564c3328169SBram Moolenaar {
1565c3328169SBram Moolenaar y_read_regs = ALLOC_CLEAR_MULT(yankreg_T, NUM_REGISTERS);
1566c3328169SBram Moolenaar }
1567c3328169SBram Moolenaar
1568c3328169SBram Moolenaar static void
finish_viminfo_registers(void)1569c3328169SBram Moolenaar finish_viminfo_registers(void)
1570c3328169SBram Moolenaar {
1571c3328169SBram Moolenaar int i;
1572c3328169SBram Moolenaar int j;
1573c3328169SBram Moolenaar
1574c3328169SBram Moolenaar if (y_read_regs != NULL)
1575c3328169SBram Moolenaar {
1576c3328169SBram Moolenaar for (i = 0; i < NUM_REGISTERS; ++i)
1577c3328169SBram Moolenaar if (y_read_regs[i].y_array != NULL)
1578c3328169SBram Moolenaar {
1579c3328169SBram Moolenaar for (j = 0; j < y_read_regs[i].y_size; j++)
1580c3328169SBram Moolenaar vim_free(y_read_regs[i].y_array[j]);
1581c3328169SBram Moolenaar vim_free(y_read_regs[i].y_array);
1582c3328169SBram Moolenaar }
1583c3328169SBram Moolenaar VIM_CLEAR(y_read_regs);
1584c3328169SBram Moolenaar }
1585c3328169SBram Moolenaar }
1586c3328169SBram Moolenaar
1587c3328169SBram Moolenaar static int
read_viminfo_register(vir_T * virp,int force)1588c3328169SBram Moolenaar read_viminfo_register(vir_T *virp, int force)
1589c3328169SBram Moolenaar {
1590c3328169SBram Moolenaar int eof;
1591c3328169SBram Moolenaar int do_it = TRUE;
1592c3328169SBram Moolenaar int size;
1593c3328169SBram Moolenaar int limit;
1594c3328169SBram Moolenaar int i;
1595c3328169SBram Moolenaar int set_prev = FALSE;
1596c3328169SBram Moolenaar char_u *str;
1597c3328169SBram Moolenaar char_u **array = NULL;
1598c3328169SBram Moolenaar int new_type = MCHAR; // init to shut up compiler
1599c3328169SBram Moolenaar colnr_T new_width = 0; // init to shut up compiler
1600c3328169SBram Moolenaar yankreg_T *y_current_p;
1601c3328169SBram Moolenaar
1602c3328169SBram Moolenaar // We only get here (hopefully) if line[0] == '"'
1603c3328169SBram Moolenaar str = virp->vir_line + 1;
1604c3328169SBram Moolenaar
1605c3328169SBram Moolenaar // If the line starts with "" this is the y_previous register.
1606c3328169SBram Moolenaar if (*str == '"')
1607c3328169SBram Moolenaar {
1608c3328169SBram Moolenaar set_prev = TRUE;
1609c3328169SBram Moolenaar str++;
1610c3328169SBram Moolenaar }
1611c3328169SBram Moolenaar
1612c3328169SBram Moolenaar if (!ASCII_ISALNUM(*str) && *str != '-')
1613c3328169SBram Moolenaar {
1614c3328169SBram Moolenaar if (viminfo_error("E577: ", _("Illegal register name"), virp->vir_line))
1615c3328169SBram Moolenaar return TRUE; // too many errors, pretend end-of-file
1616c3328169SBram Moolenaar do_it = FALSE;
1617c3328169SBram Moolenaar }
1618c3328169SBram Moolenaar get_yank_register(*str++, FALSE);
1619c3328169SBram Moolenaar y_current_p = get_y_current();
1620c3328169SBram Moolenaar if (!force && y_current_p->y_array != NULL)
1621c3328169SBram Moolenaar do_it = FALSE;
1622c3328169SBram Moolenaar
1623c3328169SBram Moolenaar if (*str == '@')
1624c3328169SBram Moolenaar {
1625c3328169SBram Moolenaar // "x@: register x used for @@
1626c3328169SBram Moolenaar if (force || get_execreg_lastc() == NUL)
1627c3328169SBram Moolenaar set_execreg_lastc(str[-1]);
1628c3328169SBram Moolenaar }
1629c3328169SBram Moolenaar
1630c3328169SBram Moolenaar size = 0;
1631c3328169SBram Moolenaar limit = 100; // Optimized for registers containing <= 100 lines
1632c3328169SBram Moolenaar if (do_it)
1633c3328169SBram Moolenaar {
1634c3328169SBram Moolenaar // Build the new register in array[].
1635c3328169SBram Moolenaar // y_array is kept as-is until done.
1636c3328169SBram Moolenaar // The "do_it" flag is reset when something is wrong, in which case
1637c3328169SBram Moolenaar // array[] needs to be freed.
1638c3328169SBram Moolenaar if (set_prev)
1639c3328169SBram Moolenaar set_y_previous(y_current_p);
1640c3328169SBram Moolenaar array = ALLOC_MULT(char_u *, limit);
1641c3328169SBram Moolenaar str = skipwhite(skiptowhite(str));
1642c3328169SBram Moolenaar if (STRNCMP(str, "CHAR", 4) == 0)
1643c3328169SBram Moolenaar new_type = MCHAR;
1644c3328169SBram Moolenaar else if (STRNCMP(str, "BLOCK", 5) == 0)
1645c3328169SBram Moolenaar new_type = MBLOCK;
1646c3328169SBram Moolenaar else
1647c3328169SBram Moolenaar new_type = MLINE;
1648c3328169SBram Moolenaar // get the block width; if it's missing we get a zero, which is OK
1649c3328169SBram Moolenaar str = skipwhite(skiptowhite(str));
1650c3328169SBram Moolenaar new_width = getdigits(&str);
1651c3328169SBram Moolenaar }
1652c3328169SBram Moolenaar
1653c3328169SBram Moolenaar while (!(eof = viminfo_readline(virp))
1654c3328169SBram Moolenaar && (virp->vir_line[0] == TAB || virp->vir_line[0] == '<'))
1655c3328169SBram Moolenaar {
1656c3328169SBram Moolenaar if (do_it)
1657c3328169SBram Moolenaar {
1658c3328169SBram Moolenaar if (size == limit)
1659c3328169SBram Moolenaar {
1660c3328169SBram Moolenaar char_u **new_array = (char_u **)
1661c3328169SBram Moolenaar alloc(limit * 2 * sizeof(char_u *));
1662c3328169SBram Moolenaar
1663c3328169SBram Moolenaar if (new_array == NULL)
1664c3328169SBram Moolenaar {
1665c3328169SBram Moolenaar do_it = FALSE;
1666c3328169SBram Moolenaar break;
1667c3328169SBram Moolenaar }
1668c3328169SBram Moolenaar for (i = 0; i < limit; i++)
1669c3328169SBram Moolenaar new_array[i] = array[i];
1670c3328169SBram Moolenaar vim_free(array);
1671c3328169SBram Moolenaar array = new_array;
1672c3328169SBram Moolenaar limit *= 2;
1673c3328169SBram Moolenaar }
1674c3328169SBram Moolenaar str = viminfo_readstring(virp, 1, TRUE);
1675c3328169SBram Moolenaar if (str != NULL)
1676c3328169SBram Moolenaar array[size++] = str;
1677c3328169SBram Moolenaar else
1678c3328169SBram Moolenaar // error, don't store the result
1679c3328169SBram Moolenaar do_it = FALSE;
1680c3328169SBram Moolenaar }
1681c3328169SBram Moolenaar }
1682c3328169SBram Moolenaar
1683c3328169SBram Moolenaar if (do_it)
1684c3328169SBram Moolenaar {
1685c3328169SBram Moolenaar // free y_array[]
1686c3328169SBram Moolenaar for (i = 0; i < y_current_p->y_size; i++)
1687c3328169SBram Moolenaar vim_free(y_current_p->y_array[i]);
1688c3328169SBram Moolenaar vim_free(y_current_p->y_array);
1689c3328169SBram Moolenaar
1690c3328169SBram Moolenaar y_current_p->y_type = new_type;
1691c3328169SBram Moolenaar y_current_p->y_width = new_width;
1692c3328169SBram Moolenaar y_current_p->y_size = size;
1693c3328169SBram Moolenaar y_current_p->y_time_set = 0;
1694c3328169SBram Moolenaar if (size == 0)
1695c3328169SBram Moolenaar {
1696c3328169SBram Moolenaar y_current_p->y_array = NULL;
1697c3328169SBram Moolenaar }
1698c3328169SBram Moolenaar else
1699c3328169SBram Moolenaar {
1700c3328169SBram Moolenaar // Move the lines from array[] to y_array[].
1701c3328169SBram Moolenaar y_current_p->y_array = ALLOC_MULT(char_u *, size);
1702c3328169SBram Moolenaar for (i = 0; i < size; i++)
1703c3328169SBram Moolenaar {
1704c3328169SBram Moolenaar if (y_current_p->y_array == NULL)
1705c3328169SBram Moolenaar vim_free(array[i]);
1706c3328169SBram Moolenaar else
1707c3328169SBram Moolenaar y_current_p->y_array[i] = array[i];
1708c3328169SBram Moolenaar }
1709c3328169SBram Moolenaar }
1710c3328169SBram Moolenaar }
1711c3328169SBram Moolenaar else
1712c3328169SBram Moolenaar {
1713c3328169SBram Moolenaar // Free array[] if it was filled.
1714c3328169SBram Moolenaar for (i = 0; i < size; i++)
1715c3328169SBram Moolenaar vim_free(array[i]);
1716c3328169SBram Moolenaar }
1717c3328169SBram Moolenaar vim_free(array);
1718c3328169SBram Moolenaar
1719c3328169SBram Moolenaar return eof;
1720c3328169SBram Moolenaar }
1721c3328169SBram Moolenaar
1722c3328169SBram Moolenaar /*
1723c3328169SBram Moolenaar * Accept a new style register line from the viminfo, store it when it's new.
1724c3328169SBram Moolenaar */
1725c3328169SBram Moolenaar static void
handle_viminfo_register(garray_T * values,int force)1726c3328169SBram Moolenaar handle_viminfo_register(garray_T *values, int force)
1727c3328169SBram Moolenaar {
1728c3328169SBram Moolenaar bval_T *vp = (bval_T *)values->ga_data;
1729c3328169SBram Moolenaar int flags;
1730c3328169SBram Moolenaar int name;
1731c3328169SBram Moolenaar int type;
1732c3328169SBram Moolenaar int linecount;
1733c3328169SBram Moolenaar int width;
1734c3328169SBram Moolenaar time_t timestamp;
1735c3328169SBram Moolenaar yankreg_T *y_ptr;
1736c3328169SBram Moolenaar yankreg_T *y_regs_p = get_y_regs();
1737c3328169SBram Moolenaar int i;
1738c3328169SBram Moolenaar
1739c3328169SBram Moolenaar // Check the format:
1740c3328169SBram Moolenaar // |{bartype},{flags},{name},{type},
1741c3328169SBram Moolenaar // {linecount},{width},{timestamp},"line1","line2"
1742c3328169SBram Moolenaar if (values->ga_len < 6
1743c3328169SBram Moolenaar || vp[0].bv_type != BVAL_NR
1744c3328169SBram Moolenaar || vp[1].bv_type != BVAL_NR
1745c3328169SBram Moolenaar || vp[2].bv_type != BVAL_NR
1746c3328169SBram Moolenaar || vp[3].bv_type != BVAL_NR
1747c3328169SBram Moolenaar || vp[4].bv_type != BVAL_NR
1748c3328169SBram Moolenaar || vp[5].bv_type != BVAL_NR)
1749c3328169SBram Moolenaar return;
1750c3328169SBram Moolenaar flags = vp[0].bv_nr;
1751c3328169SBram Moolenaar name = vp[1].bv_nr;
1752c3328169SBram Moolenaar if (name < 0 || name >= NUM_REGISTERS)
1753c3328169SBram Moolenaar return;
1754c3328169SBram Moolenaar type = vp[2].bv_nr;
1755c3328169SBram Moolenaar if (type != MCHAR && type != MLINE && type != MBLOCK)
1756c3328169SBram Moolenaar return;
1757c3328169SBram Moolenaar linecount = vp[3].bv_nr;
1758c3328169SBram Moolenaar if (values->ga_len < 6 + linecount)
1759c3328169SBram Moolenaar return;
1760c3328169SBram Moolenaar width = vp[4].bv_nr;
1761c3328169SBram Moolenaar if (width < 0)
1762c3328169SBram Moolenaar return;
1763c3328169SBram Moolenaar
1764c3328169SBram Moolenaar if (y_read_regs != NULL)
1765c3328169SBram Moolenaar // Reading viminfo for merging and writing. Store the register
1766c3328169SBram Moolenaar // content, don't update the current registers.
1767c3328169SBram Moolenaar y_ptr = &y_read_regs[name];
1768c3328169SBram Moolenaar else
1769c3328169SBram Moolenaar y_ptr = &y_regs_p[name];
1770c3328169SBram Moolenaar
1771c3328169SBram Moolenaar // Do not overwrite unless forced or the timestamp is newer.
1772c3328169SBram Moolenaar timestamp = (time_t)vp[5].bv_nr;
1773c3328169SBram Moolenaar if (y_ptr->y_array != NULL && !force
1774c3328169SBram Moolenaar && (timestamp == 0 || y_ptr->y_time_set > timestamp))
1775c3328169SBram Moolenaar return;
1776c3328169SBram Moolenaar
1777c3328169SBram Moolenaar if (y_ptr->y_array != NULL)
1778c3328169SBram Moolenaar for (i = 0; i < y_ptr->y_size; i++)
1779c3328169SBram Moolenaar vim_free(y_ptr->y_array[i]);
1780c3328169SBram Moolenaar vim_free(y_ptr->y_array);
1781c3328169SBram Moolenaar
1782c3328169SBram Moolenaar if (y_read_regs == NULL)
1783c3328169SBram Moolenaar {
1784c3328169SBram Moolenaar if (flags & REG_PREVIOUS)
1785c3328169SBram Moolenaar set_y_previous(y_ptr);
1786c3328169SBram Moolenaar if ((flags & REG_EXEC) && (force || get_execreg_lastc() == NUL))
1787c3328169SBram Moolenaar set_execreg_lastc(get_register_name(name));
1788c3328169SBram Moolenaar }
1789c3328169SBram Moolenaar y_ptr->y_type = type;
1790c3328169SBram Moolenaar y_ptr->y_width = width;
1791c3328169SBram Moolenaar y_ptr->y_size = linecount;
1792c3328169SBram Moolenaar y_ptr->y_time_set = timestamp;
1793c3328169SBram Moolenaar if (linecount == 0)
1794c3328169SBram Moolenaar {
1795c3328169SBram Moolenaar y_ptr->y_array = NULL;
1796c3328169SBram Moolenaar return;
1797c3328169SBram Moolenaar }
1798c3328169SBram Moolenaar y_ptr->y_array = ALLOC_MULT(char_u *, linecount);
1799c3328169SBram Moolenaar if (y_ptr->y_array == NULL)
1800c3328169SBram Moolenaar {
1801c3328169SBram Moolenaar y_ptr->y_size = 0; // ensure object state is consistent
1802c3328169SBram Moolenaar return;
1803c3328169SBram Moolenaar }
1804c3328169SBram Moolenaar for (i = 0; i < linecount; i++)
1805c3328169SBram Moolenaar {
1806c3328169SBram Moolenaar if (vp[i + 6].bv_allocated)
1807c3328169SBram Moolenaar {
1808c3328169SBram Moolenaar y_ptr->y_array[i] = vp[i + 6].bv_string;
1809c3328169SBram Moolenaar vp[i + 6].bv_string = NULL;
1810c3328169SBram Moolenaar }
1811c3328169SBram Moolenaar else
1812c3328169SBram Moolenaar y_ptr->y_array[i] = vim_strsave(vp[i + 6].bv_string);
1813c3328169SBram Moolenaar }
1814c3328169SBram Moolenaar }
1815c3328169SBram Moolenaar
1816c3328169SBram Moolenaar static void
write_viminfo_registers(FILE * fp)1817c3328169SBram Moolenaar write_viminfo_registers(FILE *fp)
1818c3328169SBram Moolenaar {
1819c3328169SBram Moolenaar int i, j;
1820c3328169SBram Moolenaar char_u *type;
1821c3328169SBram Moolenaar char_u c;
1822c3328169SBram Moolenaar int num_lines;
1823c3328169SBram Moolenaar int max_num_lines;
1824c3328169SBram Moolenaar int max_kbyte;
1825c3328169SBram Moolenaar long len;
1826c3328169SBram Moolenaar yankreg_T *y_ptr;
1827c3328169SBram Moolenaar yankreg_T *y_regs_p = get_y_regs();;
1828c3328169SBram Moolenaar
1829c3328169SBram Moolenaar fputs(_("\n# Registers:\n"), fp);
1830c3328169SBram Moolenaar
1831c3328169SBram Moolenaar // Get '<' value, use old '"' value if '<' is not found.
1832c3328169SBram Moolenaar max_num_lines = get_viminfo_parameter('<');
1833c3328169SBram Moolenaar if (max_num_lines < 0)
1834c3328169SBram Moolenaar max_num_lines = get_viminfo_parameter('"');
1835c3328169SBram Moolenaar if (max_num_lines == 0)
1836c3328169SBram Moolenaar return;
1837c3328169SBram Moolenaar max_kbyte = get_viminfo_parameter('s');
1838c3328169SBram Moolenaar if (max_kbyte == 0)
1839c3328169SBram Moolenaar return;
1840c3328169SBram Moolenaar
1841c3328169SBram Moolenaar for (i = 0; i < NUM_REGISTERS; i++)
1842c3328169SBram Moolenaar {
1843c3328169SBram Moolenaar #ifdef FEAT_CLIPBOARD
1844c3328169SBram Moolenaar // Skip '*'/'+' register, we don't want them back next time
1845c3328169SBram Moolenaar if (i == STAR_REGISTER || i == PLUS_REGISTER)
1846c3328169SBram Moolenaar continue;
1847c3328169SBram Moolenaar #endif
1848c3328169SBram Moolenaar #ifdef FEAT_DND
1849c3328169SBram Moolenaar // Neither do we want the '~' register
1850c3328169SBram Moolenaar if (i == TILDE_REGISTER)
1851c3328169SBram Moolenaar continue;
1852c3328169SBram Moolenaar #endif
1853c3328169SBram Moolenaar // When reading viminfo for merging and writing: Use the register from
1854c3328169SBram Moolenaar // viminfo if it's newer.
1855c3328169SBram Moolenaar if (y_read_regs != NULL
1856c3328169SBram Moolenaar && y_read_regs[i].y_array != NULL
1857c3328169SBram Moolenaar && (y_regs_p[i].y_array == NULL ||
1858c3328169SBram Moolenaar y_read_regs[i].y_time_set > y_regs_p[i].y_time_set))
1859c3328169SBram Moolenaar y_ptr = &y_read_regs[i];
1860c3328169SBram Moolenaar else if (y_regs_p[i].y_array == NULL)
1861c3328169SBram Moolenaar continue;
1862c3328169SBram Moolenaar else
1863c3328169SBram Moolenaar y_ptr = &y_regs_p[i];
1864c3328169SBram Moolenaar
1865c3328169SBram Moolenaar // Skip empty registers.
1866c3328169SBram Moolenaar num_lines = y_ptr->y_size;
1867c3328169SBram Moolenaar if (num_lines == 0
1868c3328169SBram Moolenaar || (num_lines == 1 && y_ptr->y_type == MCHAR
1869c3328169SBram Moolenaar && *y_ptr->y_array[0] == NUL))
1870c3328169SBram Moolenaar continue;
1871c3328169SBram Moolenaar
1872c3328169SBram Moolenaar if (max_kbyte > 0)
1873c3328169SBram Moolenaar {
1874c3328169SBram Moolenaar // Skip register if there is more text than the maximum size.
1875c3328169SBram Moolenaar len = 0;
1876c3328169SBram Moolenaar for (j = 0; j < num_lines; j++)
1877c3328169SBram Moolenaar len += (long)STRLEN(y_ptr->y_array[j]) + 1L;
1878c3328169SBram Moolenaar if (len > (long)max_kbyte * 1024L)
1879c3328169SBram Moolenaar continue;
1880c3328169SBram Moolenaar }
1881c3328169SBram Moolenaar
1882c3328169SBram Moolenaar switch (y_ptr->y_type)
1883c3328169SBram Moolenaar {
1884c3328169SBram Moolenaar case MLINE:
1885c3328169SBram Moolenaar type = (char_u *)"LINE";
1886c3328169SBram Moolenaar break;
1887c3328169SBram Moolenaar case MCHAR:
1888c3328169SBram Moolenaar type = (char_u *)"CHAR";
1889c3328169SBram Moolenaar break;
1890c3328169SBram Moolenaar case MBLOCK:
1891c3328169SBram Moolenaar type = (char_u *)"BLOCK";
1892c3328169SBram Moolenaar break;
1893c3328169SBram Moolenaar default:
1894c3328169SBram Moolenaar semsg(_("E574: Unknown register type %d"), y_ptr->y_type);
1895c3328169SBram Moolenaar type = (char_u *)"LINE";
1896c3328169SBram Moolenaar break;
1897c3328169SBram Moolenaar }
1898c3328169SBram Moolenaar if (get_y_previous() == &y_regs_p[i])
1899c3328169SBram Moolenaar fprintf(fp, "\"");
1900c3328169SBram Moolenaar c = get_register_name(i);
1901c3328169SBram Moolenaar fprintf(fp, "\"%c", c);
1902c3328169SBram Moolenaar if (c == get_execreg_lastc())
1903c3328169SBram Moolenaar fprintf(fp, "@");
1904c3328169SBram Moolenaar fprintf(fp, "\t%s\t%d\n", type, (int)y_ptr->y_width);
1905c3328169SBram Moolenaar
1906c3328169SBram Moolenaar // If max_num_lines < 0, then we save ALL the lines in the register
1907c3328169SBram Moolenaar if (max_num_lines > 0 && num_lines > max_num_lines)
1908c3328169SBram Moolenaar num_lines = max_num_lines;
1909c3328169SBram Moolenaar for (j = 0; j < num_lines; j++)
1910c3328169SBram Moolenaar {
1911c3328169SBram Moolenaar putc('\t', fp);
1912c3328169SBram Moolenaar viminfo_writestring(fp, y_ptr->y_array[j]);
1913c3328169SBram Moolenaar }
1914c3328169SBram Moolenaar
1915c3328169SBram Moolenaar {
1916c3328169SBram Moolenaar int flags = 0;
1917c3328169SBram Moolenaar int remaining;
1918c3328169SBram Moolenaar
1919c3328169SBram Moolenaar // New style with a bar line. Format:
1920c3328169SBram Moolenaar // |{bartype},{flags},{name},{type},
1921c3328169SBram Moolenaar // {linecount},{width},{timestamp},"line1","line2"
1922c3328169SBram Moolenaar // flags: REG_PREVIOUS - register is y_previous
1923c3328169SBram Moolenaar // REG_EXEC - used for @@
1924c3328169SBram Moolenaar if (get_y_previous() == &y_regs_p[i])
1925c3328169SBram Moolenaar flags |= REG_PREVIOUS;
1926c3328169SBram Moolenaar if (c == get_execreg_lastc())
1927c3328169SBram Moolenaar flags |= REG_EXEC;
1928c3328169SBram Moolenaar fprintf(fp, "|%d,%d,%d,%d,%d,%d,%ld", BARTYPE_REGISTER, flags,
1929c3328169SBram Moolenaar i, y_ptr->y_type, num_lines, (int)y_ptr->y_width,
1930c3328169SBram Moolenaar (long)y_ptr->y_time_set);
1931c3328169SBram Moolenaar // 11 chars for type/flags/name/type, 3 * 20 for numbers
1932c3328169SBram Moolenaar remaining = LSIZE - 71;
1933c3328169SBram Moolenaar for (j = 0; j < num_lines; j++)
1934c3328169SBram Moolenaar {
1935c3328169SBram Moolenaar putc(',', fp);
1936c3328169SBram Moolenaar --remaining;
1937c3328169SBram Moolenaar remaining = barline_writestring(fp, y_ptr->y_array[j],
1938c3328169SBram Moolenaar remaining);
1939c3328169SBram Moolenaar }
1940c3328169SBram Moolenaar putc('\n', fp);
1941c3328169SBram Moolenaar }
1942c3328169SBram Moolenaar }
1943c3328169SBram Moolenaar }
1944c3328169SBram Moolenaar
1945c3328169SBram Moolenaar /*
1946c3328169SBram Moolenaar * Functions relating to reading/writing marks from viminfo
1947c3328169SBram Moolenaar */
1948c3328169SBram Moolenaar
1949c3328169SBram Moolenaar static xfmark_T *vi_namedfm = NULL;
1950c3328169SBram Moolenaar #ifdef FEAT_JUMPLIST
1951c3328169SBram Moolenaar static xfmark_T *vi_jumplist = NULL;
1952c3328169SBram Moolenaar static int vi_jumplist_len = 0;
1953c3328169SBram Moolenaar #endif
1954c3328169SBram Moolenaar
1955c3328169SBram Moolenaar static void
write_one_mark(FILE * fp_out,int c,pos_T * pos)1956c3328169SBram Moolenaar write_one_mark(FILE *fp_out, int c, pos_T *pos)
1957c3328169SBram Moolenaar {
1958c3328169SBram Moolenaar if (pos->lnum != 0)
1959c3328169SBram Moolenaar fprintf(fp_out, "\t%c\t%ld\t%d\n", c, (long)pos->lnum, (int)pos->col);
1960c3328169SBram Moolenaar }
1961c3328169SBram Moolenaar
1962c3328169SBram Moolenaar static void
write_buffer_marks(buf_T * buf,FILE * fp_out)1963c3328169SBram Moolenaar write_buffer_marks(buf_T *buf, FILE *fp_out)
1964c3328169SBram Moolenaar {
1965c3328169SBram Moolenaar int i;
1966c3328169SBram Moolenaar pos_T pos;
1967c3328169SBram Moolenaar
1968c3328169SBram Moolenaar home_replace(NULL, buf->b_ffname, IObuff, IOSIZE, TRUE);
1969c3328169SBram Moolenaar fprintf(fp_out, "\n> ");
1970c3328169SBram Moolenaar viminfo_writestring(fp_out, IObuff);
1971c3328169SBram Moolenaar
1972c3328169SBram Moolenaar // Write the last used timestamp as the lnum of the non-existing mark '*'.
1973c3328169SBram Moolenaar // Older Vims will ignore it and/or copy it.
1974c3328169SBram Moolenaar pos.lnum = (linenr_T)buf->b_last_used;
1975c3328169SBram Moolenaar pos.col = 0;
1976c3328169SBram Moolenaar write_one_mark(fp_out, '*', &pos);
1977c3328169SBram Moolenaar
1978c3328169SBram Moolenaar write_one_mark(fp_out, '"', &buf->b_last_cursor);
1979c3328169SBram Moolenaar write_one_mark(fp_out, '^', &buf->b_last_insert);
1980c3328169SBram Moolenaar write_one_mark(fp_out, '.', &buf->b_last_change);
1981c3328169SBram Moolenaar #ifdef FEAT_JUMPLIST
1982c3328169SBram Moolenaar // changelist positions are stored oldest first
1983c3328169SBram Moolenaar for (i = 0; i < buf->b_changelistlen; ++i)
1984c3328169SBram Moolenaar {
1985c3328169SBram Moolenaar // skip duplicates
1986c3328169SBram Moolenaar if (i == 0 || !EQUAL_POS(buf->b_changelist[i - 1],
1987c3328169SBram Moolenaar buf->b_changelist[i]))
1988c3328169SBram Moolenaar write_one_mark(fp_out, '+', &buf->b_changelist[i]);
1989c3328169SBram Moolenaar }
1990c3328169SBram Moolenaar #endif
1991c3328169SBram Moolenaar for (i = 0; i < NMARKS; i++)
1992c3328169SBram Moolenaar write_one_mark(fp_out, 'a' + i, &buf->b_namedm[i]);
1993c3328169SBram Moolenaar }
1994c3328169SBram Moolenaar
1995c3328169SBram Moolenaar /*
1996c3328169SBram Moolenaar * Return TRUE if marks for "buf" should not be written.
1997c3328169SBram Moolenaar */
1998c3328169SBram Moolenaar static int
skip_for_viminfo(buf_T * buf)1999c3328169SBram Moolenaar skip_for_viminfo(buf_T *buf)
2000c3328169SBram Moolenaar {
2001c3328169SBram Moolenaar return
2002c3328169SBram Moolenaar #ifdef FEAT_TERMINAL
2003c3328169SBram Moolenaar bt_terminal(buf) ||
2004c3328169SBram Moolenaar #endif
2005c3328169SBram Moolenaar removable(buf->b_ffname);
2006c3328169SBram Moolenaar }
2007c3328169SBram Moolenaar
2008c3328169SBram Moolenaar /*
2009c3328169SBram Moolenaar * Write all the named marks for all buffers.
2010c3328169SBram Moolenaar * When "buflist" is not NULL fill it with the buffers for which marks are to
2011c3328169SBram Moolenaar * be written.
2012c3328169SBram Moolenaar */
2013c3328169SBram Moolenaar static void
write_viminfo_marks(FILE * fp_out,garray_T * buflist)2014c3328169SBram Moolenaar write_viminfo_marks(FILE *fp_out, garray_T *buflist)
2015c3328169SBram Moolenaar {
2016c3328169SBram Moolenaar buf_T *buf;
2017c3328169SBram Moolenaar int is_mark_set;
2018c3328169SBram Moolenaar int i;
2019c3328169SBram Moolenaar win_T *win;
2020c3328169SBram Moolenaar tabpage_T *tp;
2021c3328169SBram Moolenaar
2022c3328169SBram Moolenaar // Set b_last_cursor for the all buffers that have a window.
2023c3328169SBram Moolenaar FOR_ALL_TAB_WINDOWS(tp, win)
2024c3328169SBram Moolenaar set_last_cursor(win);
2025c3328169SBram Moolenaar
2026c3328169SBram Moolenaar fputs(_("\n# History of marks within files (newest to oldest):\n"), fp_out);
2027c3328169SBram Moolenaar FOR_ALL_BUFFERS(buf)
2028c3328169SBram Moolenaar {
2029c3328169SBram Moolenaar // Only write something if buffer has been loaded and at least one
2030c3328169SBram Moolenaar // mark is set.
2031c3328169SBram Moolenaar if (buf->b_marks_read)
2032c3328169SBram Moolenaar {
2033c3328169SBram Moolenaar if (buf->b_last_cursor.lnum != 0)
2034c3328169SBram Moolenaar is_mark_set = TRUE;
2035c3328169SBram Moolenaar else
2036c3328169SBram Moolenaar {
2037c3328169SBram Moolenaar is_mark_set = FALSE;
2038c3328169SBram Moolenaar for (i = 0; i < NMARKS; i++)
2039c3328169SBram Moolenaar if (buf->b_namedm[i].lnum != 0)
2040c3328169SBram Moolenaar {
2041c3328169SBram Moolenaar is_mark_set = TRUE;
2042c3328169SBram Moolenaar break;
2043c3328169SBram Moolenaar }
2044c3328169SBram Moolenaar }
2045c3328169SBram Moolenaar if (is_mark_set && buf->b_ffname != NULL
2046c3328169SBram Moolenaar && buf->b_ffname[0] != NUL
2047c3328169SBram Moolenaar && !skip_for_viminfo(buf))
2048c3328169SBram Moolenaar {
2049c3328169SBram Moolenaar if (buflist == NULL)
2050c3328169SBram Moolenaar write_buffer_marks(buf, fp_out);
2051c3328169SBram Moolenaar else if (ga_grow(buflist, 1) == OK)
2052c3328169SBram Moolenaar ((buf_T **)buflist->ga_data)[buflist->ga_len++] = buf;
2053c3328169SBram Moolenaar }
2054c3328169SBram Moolenaar }
2055c3328169SBram Moolenaar }
2056c3328169SBram Moolenaar }
2057c3328169SBram Moolenaar
2058c3328169SBram Moolenaar static void
write_one_filemark(FILE * fp,xfmark_T * fm,int c1,int c2)2059c3328169SBram Moolenaar write_one_filemark(
2060c3328169SBram Moolenaar FILE *fp,
2061c3328169SBram Moolenaar xfmark_T *fm,
2062c3328169SBram Moolenaar int c1,
2063c3328169SBram Moolenaar int c2)
2064c3328169SBram Moolenaar {
2065c3328169SBram Moolenaar char_u *name;
2066c3328169SBram Moolenaar
2067c3328169SBram Moolenaar if (fm->fmark.mark.lnum == 0) // not set
2068c3328169SBram Moolenaar return;
2069c3328169SBram Moolenaar
2070c3328169SBram Moolenaar if (fm->fmark.fnum != 0) // there is a buffer
2071c3328169SBram Moolenaar name = buflist_nr2name(fm->fmark.fnum, TRUE, FALSE);
2072c3328169SBram Moolenaar else
2073c3328169SBram Moolenaar name = fm->fname; // use name from .viminfo
2074c3328169SBram Moolenaar if (name != NULL && *name != NUL)
2075c3328169SBram Moolenaar {
2076c3328169SBram Moolenaar fprintf(fp, "%c%c %ld %ld ", c1, c2, (long)fm->fmark.mark.lnum,
2077c3328169SBram Moolenaar (long)fm->fmark.mark.col);
2078c3328169SBram Moolenaar viminfo_writestring(fp, name);
2079c3328169SBram Moolenaar
2080c3328169SBram Moolenaar // Barline: |{bartype},{name},{lnum},{col},{timestamp},{filename}
2081c3328169SBram Moolenaar // size up to filename: 8 + 3 * 20
2082c3328169SBram Moolenaar fprintf(fp, "|%d,%d,%ld,%ld,%ld,", BARTYPE_MARK, c2,
2083c3328169SBram Moolenaar (long)fm->fmark.mark.lnum, (long)fm->fmark.mark.col,
2084c3328169SBram Moolenaar (long)fm->time_set);
2085c3328169SBram Moolenaar barline_writestring(fp, name, LSIZE - 70);
2086c3328169SBram Moolenaar putc('\n', fp);
2087c3328169SBram Moolenaar }
2088c3328169SBram Moolenaar
2089c3328169SBram Moolenaar if (fm->fmark.fnum != 0)
2090c3328169SBram Moolenaar vim_free(name);
2091c3328169SBram Moolenaar }
2092c3328169SBram Moolenaar
2093c3328169SBram Moolenaar static void
write_viminfo_filemarks(FILE * fp)2094c3328169SBram Moolenaar write_viminfo_filemarks(FILE *fp)
2095c3328169SBram Moolenaar {
2096c3328169SBram Moolenaar int i;
2097c3328169SBram Moolenaar char_u *name;
2098c3328169SBram Moolenaar buf_T *buf;
2099c3328169SBram Moolenaar xfmark_T *namedfm_p = get_namedfm();
2100c3328169SBram Moolenaar xfmark_T *fm;
2101c3328169SBram Moolenaar int vi_idx;
2102c3328169SBram Moolenaar int idx;
2103c3328169SBram Moolenaar
2104c3328169SBram Moolenaar if (get_viminfo_parameter('f') == 0)
2105c3328169SBram Moolenaar return;
2106c3328169SBram Moolenaar
2107c3328169SBram Moolenaar fputs(_("\n# File marks:\n"), fp);
2108c3328169SBram Moolenaar
2109c3328169SBram Moolenaar // Write the filemarks 'A - 'Z
2110c3328169SBram Moolenaar for (i = 0; i < NMARKS; i++)
2111c3328169SBram Moolenaar {
2112c3328169SBram Moolenaar if (vi_namedfm != NULL
21138cd6cd80SBram Moolenaar && (vi_namedfm[i].time_set > namedfm_p[i].time_set))
2114c3328169SBram Moolenaar fm = &vi_namedfm[i];
2115c3328169SBram Moolenaar else
2116c3328169SBram Moolenaar fm = &namedfm_p[i];
2117c3328169SBram Moolenaar write_one_filemark(fp, fm, '\'', i + 'A');
2118c3328169SBram Moolenaar }
2119c3328169SBram Moolenaar
2120c3328169SBram Moolenaar // Find a mark that is the same file and position as the cursor.
2121c3328169SBram Moolenaar // That one, or else the last one is deleted.
2122c3328169SBram Moolenaar // Move '0 to '1, '1 to '2, etc. until the matching one or '9
2123c3328169SBram Moolenaar // Set the '0 mark to current cursor position.
2124c3328169SBram Moolenaar if (curbuf->b_ffname != NULL && !skip_for_viminfo(curbuf))
2125c3328169SBram Moolenaar {
2126c3328169SBram Moolenaar name = buflist_nr2name(curbuf->b_fnum, TRUE, FALSE);
2127c3328169SBram Moolenaar for (i = NMARKS; i < NMARKS + EXTRA_MARKS - 1; ++i)
2128c3328169SBram Moolenaar if (namedfm_p[i].fmark.mark.lnum == curwin->w_cursor.lnum
2129c3328169SBram Moolenaar && (namedfm_p[i].fname == NULL
2130c3328169SBram Moolenaar ? namedfm_p[i].fmark.fnum == curbuf->b_fnum
2131c3328169SBram Moolenaar : (name != NULL
2132c3328169SBram Moolenaar && STRCMP(name, namedfm_p[i].fname) == 0)))
2133c3328169SBram Moolenaar break;
2134c3328169SBram Moolenaar vim_free(name);
2135c3328169SBram Moolenaar
2136c3328169SBram Moolenaar vim_free(namedfm_p[i].fname);
2137c3328169SBram Moolenaar for ( ; i > NMARKS; --i)
2138c3328169SBram Moolenaar namedfm_p[i] = namedfm_p[i - 1];
2139c3328169SBram Moolenaar namedfm_p[NMARKS].fmark.mark = curwin->w_cursor;
2140c3328169SBram Moolenaar namedfm_p[NMARKS].fmark.fnum = curbuf->b_fnum;
2141c3328169SBram Moolenaar namedfm_p[NMARKS].fname = NULL;
2142c3328169SBram Moolenaar namedfm_p[NMARKS].time_set = vim_time();
2143c3328169SBram Moolenaar }
2144c3328169SBram Moolenaar
2145c3328169SBram Moolenaar // Write the filemarks '0 - '9. Newest (highest timestamp) first.
2146c3328169SBram Moolenaar vi_idx = NMARKS;
2147c3328169SBram Moolenaar idx = NMARKS;
2148c3328169SBram Moolenaar for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
2149c3328169SBram Moolenaar {
2150c3328169SBram Moolenaar xfmark_T *vi_fm = vi_namedfm != NULL ? &vi_namedfm[vi_idx] : NULL;
2151c3328169SBram Moolenaar
2152c3328169SBram Moolenaar if (vi_fm != NULL
2153c3328169SBram Moolenaar && vi_fm->fmark.mark.lnum != 0
2154c3328169SBram Moolenaar && (vi_fm->time_set > namedfm_p[idx].time_set
2155c3328169SBram Moolenaar || namedfm_p[idx].fmark.mark.lnum == 0))
2156c3328169SBram Moolenaar {
2157c3328169SBram Moolenaar fm = vi_fm;
2158c3328169SBram Moolenaar ++vi_idx;
2159c3328169SBram Moolenaar }
2160c3328169SBram Moolenaar else
2161c3328169SBram Moolenaar {
2162c3328169SBram Moolenaar fm = &namedfm_p[idx++];
2163c3328169SBram Moolenaar if (vi_fm != NULL
2164c3328169SBram Moolenaar && vi_fm->fmark.mark.lnum == fm->fmark.mark.lnum
2165c3328169SBram Moolenaar && vi_fm->time_set == fm->time_set
2166c3328169SBram Moolenaar && ((vi_fm->fmark.fnum != 0
2167c3328169SBram Moolenaar && vi_fm->fmark.fnum == fm->fmark.fnum)
2168c3328169SBram Moolenaar || (vi_fm->fname != NULL
2169c3328169SBram Moolenaar && fm->fname != NULL
2170c3328169SBram Moolenaar && STRCMP(vi_fm->fname, fm->fname) == 0)))
2171c3328169SBram Moolenaar ++vi_idx; // skip duplicate
2172c3328169SBram Moolenaar }
2173c3328169SBram Moolenaar write_one_filemark(fp, fm, '\'', i - NMARKS + '0');
2174c3328169SBram Moolenaar }
2175c3328169SBram Moolenaar
2176c3328169SBram Moolenaar #ifdef FEAT_JUMPLIST
2177c3328169SBram Moolenaar // Write the jumplist with -'
2178c3328169SBram Moolenaar fputs(_("\n# Jumplist (newest first):\n"), fp);
2179c3328169SBram Moolenaar setpcmark(); // add current cursor position
2180c3328169SBram Moolenaar cleanup_jumplist(curwin, FALSE);
2181c3328169SBram Moolenaar vi_idx = 0;
2182c3328169SBram Moolenaar idx = curwin->w_jumplistlen - 1;
2183c3328169SBram Moolenaar for (i = 0; i < JUMPLISTSIZE; ++i)
2184c3328169SBram Moolenaar {
2185c3328169SBram Moolenaar xfmark_T *vi_fm;
2186c3328169SBram Moolenaar
2187c3328169SBram Moolenaar fm = idx >= 0 ? &curwin->w_jumplist[idx] : NULL;
21884ad739fcSBram Moolenaar vi_fm = (vi_jumplist != NULL && vi_idx < vi_jumplist_len)
21894ad739fcSBram Moolenaar ? &vi_jumplist[vi_idx] : NULL;
2190c3328169SBram Moolenaar if (fm == NULL && vi_fm == NULL)
2191c3328169SBram Moolenaar break;
2192c3328169SBram Moolenaar if (fm == NULL || (vi_fm != NULL && fm->time_set < vi_fm->time_set))
2193c3328169SBram Moolenaar {
2194c3328169SBram Moolenaar fm = vi_fm;
2195c3328169SBram Moolenaar ++vi_idx;
2196c3328169SBram Moolenaar }
2197c3328169SBram Moolenaar else
2198c3328169SBram Moolenaar --idx;
2199c3328169SBram Moolenaar if (fm->fmark.fnum == 0
2200c3328169SBram Moolenaar || ((buf = buflist_findnr(fm->fmark.fnum)) != NULL
2201c3328169SBram Moolenaar && !skip_for_viminfo(buf)))
2202c3328169SBram Moolenaar write_one_filemark(fp, fm, '-', '\'');
2203c3328169SBram Moolenaar }
2204c3328169SBram Moolenaar #endif
2205c3328169SBram Moolenaar }
2206c3328169SBram Moolenaar
2207c3328169SBram Moolenaar /*
2208c3328169SBram Moolenaar * Compare functions for qsort() below, that compares b_last_used.
2209c3328169SBram Moolenaar */
221052410575SBram Moolenaar int
buf_compare(const void * s1,const void * s2)2211c3328169SBram Moolenaar buf_compare(const void *s1, const void *s2)
2212c3328169SBram Moolenaar {
2213c3328169SBram Moolenaar buf_T *buf1 = *(buf_T **)s1;
2214c3328169SBram Moolenaar buf_T *buf2 = *(buf_T **)s2;
2215c3328169SBram Moolenaar
2216c3328169SBram Moolenaar if (buf1->b_last_used == buf2->b_last_used)
2217c3328169SBram Moolenaar return 0;
2218c3328169SBram Moolenaar return buf1->b_last_used > buf2->b_last_used ? -1 : 1;
2219c3328169SBram Moolenaar }
2220c3328169SBram Moolenaar
2221c3328169SBram Moolenaar /*
2222c3328169SBram Moolenaar * Handle marks in the viminfo file:
2223c3328169SBram Moolenaar * fp_out != NULL: copy marks, in time order with buffers in "buflist".
22243ff656f6SBram Moolenaar * fp_out == NULL && (flags & VIF_WANT_MARKS): read marks for curbuf
22253ff656f6SBram Moolenaar * fp_out == NULL && (flags & VIF_ONLY_CURBUF): bail out after curbuf marks
2226c3328169SBram Moolenaar * fp_out == NULL && (flags & VIF_GET_OLDFILES | VIF_FORCEIT): fill v:oldfiles
2227c3328169SBram Moolenaar */
2228c3328169SBram Moolenaar static void
copy_viminfo_marks(vir_T * virp,FILE * fp_out,garray_T * buflist,int eof,int flags)2229c3328169SBram Moolenaar copy_viminfo_marks(
2230c3328169SBram Moolenaar vir_T *virp,
2231c3328169SBram Moolenaar FILE *fp_out,
2232c3328169SBram Moolenaar garray_T *buflist,
2233c3328169SBram Moolenaar int eof,
2234c3328169SBram Moolenaar int flags)
2235c3328169SBram Moolenaar {
2236c3328169SBram Moolenaar char_u *line = virp->vir_line;
2237c3328169SBram Moolenaar buf_T *buf;
2238c3328169SBram Moolenaar int num_marked_files;
2239c3328169SBram Moolenaar int load_marks;
2240c3328169SBram Moolenaar int copy_marks_out;
2241c3328169SBram Moolenaar char_u *str;
2242c3328169SBram Moolenaar int i;
2243c3328169SBram Moolenaar char_u *p;
2244c3328169SBram Moolenaar char_u *name_buf;
2245c3328169SBram Moolenaar pos_T pos;
2246c3328169SBram Moolenaar #ifdef FEAT_EVAL
2247c3328169SBram Moolenaar list_T *list = NULL;
2248c3328169SBram Moolenaar #endif
2249c3328169SBram Moolenaar int count = 0;
2250c3328169SBram Moolenaar int buflist_used = 0;
2251c3328169SBram Moolenaar buf_T *buflist_buf = NULL;
2252c3328169SBram Moolenaar
2253c3328169SBram Moolenaar if ((name_buf = alloc(LSIZE)) == NULL)
2254c3328169SBram Moolenaar return;
2255c3328169SBram Moolenaar *name_buf = NUL;
2256c3328169SBram Moolenaar
2257c3328169SBram Moolenaar if (fp_out != NULL && buflist->ga_len > 0)
2258c3328169SBram Moolenaar {
2259c3328169SBram Moolenaar // Sort the list of buffers on b_last_used.
2260c3328169SBram Moolenaar qsort(buflist->ga_data, (size_t)buflist->ga_len,
2261c3328169SBram Moolenaar sizeof(buf_T *), buf_compare);
2262c3328169SBram Moolenaar buflist_buf = ((buf_T **)buflist->ga_data)[0];
2263c3328169SBram Moolenaar }
2264c3328169SBram Moolenaar
2265c3328169SBram Moolenaar #ifdef FEAT_EVAL
2266c3328169SBram Moolenaar if (fp_out == NULL && (flags & (VIF_GET_OLDFILES | VIF_FORCEIT)))
2267c3328169SBram Moolenaar {
2268c3328169SBram Moolenaar list = list_alloc();
2269c3328169SBram Moolenaar if (list != NULL)
2270c3328169SBram Moolenaar set_vim_var_list(VV_OLDFILES, list);
2271c3328169SBram Moolenaar }
2272c3328169SBram Moolenaar #endif
2273c3328169SBram Moolenaar
2274c3328169SBram Moolenaar num_marked_files = get_viminfo_parameter('\'');
2275c3328169SBram Moolenaar while (!eof && (count < num_marked_files || fp_out == NULL))
2276c3328169SBram Moolenaar {
2277c3328169SBram Moolenaar if (line[0] != '>')
2278c3328169SBram Moolenaar {
2279c3328169SBram Moolenaar if (line[0] != '\n' && line[0] != '\r' && line[0] != '#')
2280c3328169SBram Moolenaar {
2281c3328169SBram Moolenaar if (viminfo_error("E576: ", _("Missing '>'"), line))
2282c3328169SBram Moolenaar break; // too many errors, return now
2283c3328169SBram Moolenaar }
2284c3328169SBram Moolenaar eof = vim_fgets(line, LSIZE, virp->vir_fd);
2285c3328169SBram Moolenaar continue; // Skip this dud line
2286c3328169SBram Moolenaar }
2287c3328169SBram Moolenaar
2288c3328169SBram Moolenaar // Handle long line and translate escaped characters.
2289c3328169SBram Moolenaar // Find file name, set str to start.
2290c3328169SBram Moolenaar // Ignore leading and trailing white space.
2291c3328169SBram Moolenaar str = skipwhite(line + 1);
2292c3328169SBram Moolenaar str = viminfo_readstring(virp, (int)(str - virp->vir_line), FALSE);
2293c3328169SBram Moolenaar if (str == NULL)
2294c3328169SBram Moolenaar continue;
2295c3328169SBram Moolenaar p = str + STRLEN(str);
2296c3328169SBram Moolenaar while (p != str && (*p == NUL || vim_isspace(*p)))
2297c3328169SBram Moolenaar p--;
2298c3328169SBram Moolenaar if (*p)
2299c3328169SBram Moolenaar p++;
2300c3328169SBram Moolenaar *p = NUL;
2301c3328169SBram Moolenaar
2302c3328169SBram Moolenaar #ifdef FEAT_EVAL
2303c3328169SBram Moolenaar if (list != NULL)
2304c3328169SBram Moolenaar list_append_string(list, str, -1);
2305c3328169SBram Moolenaar #endif
2306c3328169SBram Moolenaar
2307c3328169SBram Moolenaar // If fp_out == NULL, load marks for current buffer.
2308c3328169SBram Moolenaar // If fp_out != NULL, copy marks for buffers not in buflist.
2309c3328169SBram Moolenaar load_marks = copy_marks_out = FALSE;
2310c3328169SBram Moolenaar if (fp_out == NULL)
2311c3328169SBram Moolenaar {
2312c3328169SBram Moolenaar if ((flags & VIF_WANT_MARKS) && curbuf->b_ffname != NULL)
2313c3328169SBram Moolenaar {
2314c3328169SBram Moolenaar if (*name_buf == NUL) // only need to do this once
2315c3328169SBram Moolenaar home_replace(NULL, curbuf->b_ffname, name_buf, LSIZE, TRUE);
2316c3328169SBram Moolenaar if (fnamecmp(str, name_buf) == 0)
2317c3328169SBram Moolenaar load_marks = TRUE;
2318c3328169SBram Moolenaar }
2319c3328169SBram Moolenaar }
2320c3328169SBram Moolenaar else // fp_out != NULL
2321c3328169SBram Moolenaar {
2322c3328169SBram Moolenaar // This is slow if there are many buffers!!
2323c3328169SBram Moolenaar FOR_ALL_BUFFERS(buf)
2324c3328169SBram Moolenaar if (buf->b_ffname != NULL)
2325c3328169SBram Moolenaar {
2326c3328169SBram Moolenaar home_replace(NULL, buf->b_ffname, name_buf, LSIZE, TRUE);
2327c3328169SBram Moolenaar if (fnamecmp(str, name_buf) == 0)
2328c3328169SBram Moolenaar break;
2329c3328169SBram Moolenaar }
2330c3328169SBram Moolenaar
2331c3328169SBram Moolenaar // Copy marks if the buffer has not been loaded.
2332c3328169SBram Moolenaar if (buf == NULL || !buf->b_marks_read)
2333c3328169SBram Moolenaar {
2334c3328169SBram Moolenaar int did_read_line = FALSE;
2335c3328169SBram Moolenaar
2336c3328169SBram Moolenaar if (buflist_buf != NULL)
2337c3328169SBram Moolenaar {
2338c3328169SBram Moolenaar // Read the next line. If it has the "*" mark compare the
2339c3328169SBram Moolenaar // time stamps. Write entries from "buflist" that are
2340c3328169SBram Moolenaar // newer.
2341c3328169SBram Moolenaar if (!(eof = viminfo_readline(virp)) && line[0] == TAB)
2342c3328169SBram Moolenaar {
2343c3328169SBram Moolenaar did_read_line = TRUE;
2344c3328169SBram Moolenaar if (line[1] == '*')
2345c3328169SBram Moolenaar {
2346c3328169SBram Moolenaar long ltime;
2347c3328169SBram Moolenaar
2348c3328169SBram Moolenaar sscanf((char *)line + 2, "%ld ", <ime);
2349c3328169SBram Moolenaar while ((time_T)ltime < buflist_buf->b_last_used)
2350c3328169SBram Moolenaar {
2351c3328169SBram Moolenaar write_buffer_marks(buflist_buf, fp_out);
2352c3328169SBram Moolenaar if (++count >= num_marked_files)
2353c3328169SBram Moolenaar break;
2354c3328169SBram Moolenaar if (++buflist_used == buflist->ga_len)
2355c3328169SBram Moolenaar {
2356c3328169SBram Moolenaar buflist_buf = NULL;
2357c3328169SBram Moolenaar break;
2358c3328169SBram Moolenaar }
2359c3328169SBram Moolenaar buflist_buf =
2360c3328169SBram Moolenaar ((buf_T **)buflist->ga_data)[buflist_used];
2361c3328169SBram Moolenaar }
2362c3328169SBram Moolenaar }
2363c3328169SBram Moolenaar else
2364c3328169SBram Moolenaar {
2365c3328169SBram Moolenaar // No timestamp, must be written by an older Vim.
236632aa1020SBram Moolenaar // Assume all remaining buffers are older than
2367c3328169SBram Moolenaar // ours.
2368c3328169SBram Moolenaar while (count < num_marked_files
2369c3328169SBram Moolenaar && buflist_used < buflist->ga_len)
2370c3328169SBram Moolenaar {
2371c3328169SBram Moolenaar buflist_buf = ((buf_T **)buflist->ga_data)
2372c3328169SBram Moolenaar [buflist_used++];
2373c3328169SBram Moolenaar write_buffer_marks(buflist_buf, fp_out);
2374c3328169SBram Moolenaar ++count;
2375c3328169SBram Moolenaar }
2376c3328169SBram Moolenaar buflist_buf = NULL;
2377c3328169SBram Moolenaar }
2378c3328169SBram Moolenaar
2379c3328169SBram Moolenaar if (count >= num_marked_files)
2380c3328169SBram Moolenaar {
2381c3328169SBram Moolenaar vim_free(str);
2382c3328169SBram Moolenaar break;
2383c3328169SBram Moolenaar }
2384c3328169SBram Moolenaar }
2385c3328169SBram Moolenaar }
2386c3328169SBram Moolenaar
2387c3328169SBram Moolenaar fputs("\n> ", fp_out);
2388c3328169SBram Moolenaar viminfo_writestring(fp_out, str);
2389c3328169SBram Moolenaar if (did_read_line)
2390c3328169SBram Moolenaar fputs((char *)line, fp_out);
2391c3328169SBram Moolenaar
2392c3328169SBram Moolenaar count++;
2393c3328169SBram Moolenaar copy_marks_out = TRUE;
2394c3328169SBram Moolenaar }
2395c3328169SBram Moolenaar }
2396c3328169SBram Moolenaar vim_free(str);
2397c3328169SBram Moolenaar
2398c3328169SBram Moolenaar pos.coladd = 0;
2399c3328169SBram Moolenaar while (!(eof = viminfo_readline(virp)) && line[0] == TAB)
2400c3328169SBram Moolenaar {
2401c3328169SBram Moolenaar if (load_marks)
2402c3328169SBram Moolenaar {
2403c3328169SBram Moolenaar if (line[1] != NUL)
2404c3328169SBram Moolenaar {
2405c3328169SBram Moolenaar unsigned u;
2406c3328169SBram Moolenaar
2407c3328169SBram Moolenaar sscanf((char *)line + 2, "%ld %u", &pos.lnum, &u);
2408c3328169SBram Moolenaar pos.col = u;
2409c3328169SBram Moolenaar switch (line[1])
2410c3328169SBram Moolenaar {
2411c3328169SBram Moolenaar case '"': curbuf->b_last_cursor = pos; break;
2412c3328169SBram Moolenaar case '^': curbuf->b_last_insert = pos; break;
2413c3328169SBram Moolenaar case '.': curbuf->b_last_change = pos; break;
2414c3328169SBram Moolenaar case '+':
2415c3328169SBram Moolenaar #ifdef FEAT_JUMPLIST
2416c3328169SBram Moolenaar // changelist positions are stored oldest
2417c3328169SBram Moolenaar // first
2418c3328169SBram Moolenaar if (curbuf->b_changelistlen == JUMPLISTSIZE)
2419c3328169SBram Moolenaar // list is full, remove oldest entry
2420c3328169SBram Moolenaar mch_memmove(curbuf->b_changelist,
2421c3328169SBram Moolenaar curbuf->b_changelist + 1,
2422c3328169SBram Moolenaar sizeof(pos_T) * (JUMPLISTSIZE - 1));
2423c3328169SBram Moolenaar else
2424c3328169SBram Moolenaar ++curbuf->b_changelistlen;
2425c3328169SBram Moolenaar curbuf->b_changelist[
2426c3328169SBram Moolenaar curbuf->b_changelistlen - 1] = pos;
2427c3328169SBram Moolenaar #endif
2428c3328169SBram Moolenaar break;
2429c3328169SBram Moolenaar
2430c3328169SBram Moolenaar // Using the line number for the last-used
2431c3328169SBram Moolenaar // timestamp.
2432c3328169SBram Moolenaar case '*': curbuf->b_last_used = pos.lnum; break;
2433c3328169SBram Moolenaar
2434c3328169SBram Moolenaar default: if ((i = line[1] - 'a') >= 0 && i < NMARKS)
2435c3328169SBram Moolenaar curbuf->b_namedm[i] = pos;
2436c3328169SBram Moolenaar }
2437c3328169SBram Moolenaar }
2438c3328169SBram Moolenaar }
2439c3328169SBram Moolenaar else if (copy_marks_out)
2440c3328169SBram Moolenaar fputs((char *)line, fp_out);
2441c3328169SBram Moolenaar }
2442c3328169SBram Moolenaar
2443c3328169SBram Moolenaar if (load_marks)
2444c3328169SBram Moolenaar {
2445c3328169SBram Moolenaar #ifdef FEAT_JUMPLIST
2446c3328169SBram Moolenaar win_T *wp;
2447c3328169SBram Moolenaar
2448c3328169SBram Moolenaar FOR_ALL_WINDOWS(wp)
2449c3328169SBram Moolenaar {
2450c3328169SBram Moolenaar if (wp->w_buffer == curbuf)
2451c3328169SBram Moolenaar wp->w_changelistidx = curbuf->b_changelistlen;
2452c3328169SBram Moolenaar }
2453c3328169SBram Moolenaar #endif
24543ff656f6SBram Moolenaar if (flags & VIF_ONLY_CURBUF)
2455c3328169SBram Moolenaar break;
2456c3328169SBram Moolenaar }
2457c3328169SBram Moolenaar }
2458c3328169SBram Moolenaar
2459c3328169SBram Moolenaar if (fp_out != NULL)
2460c3328169SBram Moolenaar // Write any remaining entries from buflist.
2461c3328169SBram Moolenaar while (count < num_marked_files && buflist_used < buflist->ga_len)
2462c3328169SBram Moolenaar {
2463c3328169SBram Moolenaar buflist_buf = ((buf_T **)buflist->ga_data)[buflist_used++];
2464c3328169SBram Moolenaar write_buffer_marks(buflist_buf, fp_out);
2465c3328169SBram Moolenaar ++count;
2466c3328169SBram Moolenaar }
2467c3328169SBram Moolenaar
2468c3328169SBram Moolenaar vim_free(name_buf);
2469c3328169SBram Moolenaar }
2470c3328169SBram Moolenaar
2471c3328169SBram Moolenaar /*
2472c3328169SBram Moolenaar * Read marks for the current buffer from the viminfo file, when we support
2473c3328169SBram Moolenaar * buffer marks and the buffer has a name.
2474c3328169SBram Moolenaar */
2475c3328169SBram Moolenaar void
check_marks_read(void)2476c3328169SBram Moolenaar check_marks_read(void)
2477c3328169SBram Moolenaar {
2478c3328169SBram Moolenaar if (!curbuf->b_marks_read && get_viminfo_parameter('\'') > 0
2479c3328169SBram Moolenaar && curbuf->b_ffname != NULL)
24803ff656f6SBram Moolenaar read_viminfo(NULL, VIF_WANT_MARKS | VIF_ONLY_CURBUF);
2481c3328169SBram Moolenaar
2482c3328169SBram Moolenaar // Always set b_marks_read; needed when 'viminfo' is changed to include
2483c3328169SBram Moolenaar // the ' parameter after opening a buffer.
2484c3328169SBram Moolenaar curbuf->b_marks_read = TRUE;
2485c3328169SBram Moolenaar }
2486c3328169SBram Moolenaar
2487c3328169SBram Moolenaar static int
read_viminfo_filemark(vir_T * virp,int force)2488c3328169SBram Moolenaar read_viminfo_filemark(vir_T *virp, int force)
2489c3328169SBram Moolenaar {
2490c3328169SBram Moolenaar char_u *str;
2491c3328169SBram Moolenaar xfmark_T *namedfm_p = get_namedfm();
2492c3328169SBram Moolenaar xfmark_T *fm;
2493c3328169SBram Moolenaar int i;
2494c3328169SBram Moolenaar
2495c3328169SBram Moolenaar // We only get here if line[0] == '\'' or '-'.
2496c3328169SBram Moolenaar // Illegal mark names are ignored (for future expansion).
2497c3328169SBram Moolenaar str = virp->vir_line + 1;
2498c3328169SBram Moolenaar if (
2499c3328169SBram Moolenaar #ifndef EBCDIC
2500c3328169SBram Moolenaar *str <= 127 &&
2501c3328169SBram Moolenaar #endif
2502c3328169SBram Moolenaar ((*virp->vir_line == '\'' && (VIM_ISDIGIT(*str) || isupper(*str)))
2503c3328169SBram Moolenaar || (*virp->vir_line == '-' && *str == '\'')))
2504c3328169SBram Moolenaar {
2505c3328169SBram Moolenaar if (*str == '\'')
2506c3328169SBram Moolenaar {
2507c3328169SBram Moolenaar #ifdef FEAT_JUMPLIST
2508c3328169SBram Moolenaar // If the jumplist isn't full insert fmark as oldest entry
2509c3328169SBram Moolenaar if (curwin->w_jumplistlen == JUMPLISTSIZE)
2510c3328169SBram Moolenaar fm = NULL;
2511c3328169SBram Moolenaar else
2512c3328169SBram Moolenaar {
2513c3328169SBram Moolenaar for (i = curwin->w_jumplistlen; i > 0; --i)
2514c3328169SBram Moolenaar curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
2515c3328169SBram Moolenaar ++curwin->w_jumplistidx;
2516c3328169SBram Moolenaar ++curwin->w_jumplistlen;
2517c3328169SBram Moolenaar fm = &curwin->w_jumplist[0];
2518c3328169SBram Moolenaar fm->fmark.mark.lnum = 0;
2519c3328169SBram Moolenaar fm->fname = NULL;
2520c3328169SBram Moolenaar }
2521c3328169SBram Moolenaar #else
2522c3328169SBram Moolenaar fm = NULL;
2523c3328169SBram Moolenaar #endif
2524c3328169SBram Moolenaar }
2525c3328169SBram Moolenaar else if (VIM_ISDIGIT(*str))
2526c3328169SBram Moolenaar fm = &namedfm_p[*str - '0' + NMARKS];
2527c3328169SBram Moolenaar else
2528c3328169SBram Moolenaar fm = &namedfm_p[*str - 'A'];
2529c3328169SBram Moolenaar if (fm != NULL && (fm->fmark.mark.lnum == 0 || force))
2530c3328169SBram Moolenaar {
2531c3328169SBram Moolenaar str = skipwhite(str + 1);
2532c3328169SBram Moolenaar fm->fmark.mark.lnum = getdigits(&str);
2533c3328169SBram Moolenaar str = skipwhite(str);
2534c3328169SBram Moolenaar fm->fmark.mark.col = getdigits(&str);
2535c3328169SBram Moolenaar fm->fmark.mark.coladd = 0;
2536c3328169SBram Moolenaar fm->fmark.fnum = 0;
2537c3328169SBram Moolenaar str = skipwhite(str);
2538c3328169SBram Moolenaar vim_free(fm->fname);
2539c3328169SBram Moolenaar fm->fname = viminfo_readstring(virp, (int)(str - virp->vir_line),
2540c3328169SBram Moolenaar FALSE);
2541c3328169SBram Moolenaar fm->time_set = 0;
2542c3328169SBram Moolenaar }
2543c3328169SBram Moolenaar }
2544c3328169SBram Moolenaar return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
2545c3328169SBram Moolenaar }
2546c3328169SBram Moolenaar
2547c3328169SBram Moolenaar /*
2548c3328169SBram Moolenaar * Prepare for reading viminfo marks when writing viminfo later.
2549c3328169SBram Moolenaar */
2550c3328169SBram Moolenaar static void
prepare_viminfo_marks(void)2551c3328169SBram Moolenaar prepare_viminfo_marks(void)
2552c3328169SBram Moolenaar {
2553c3328169SBram Moolenaar vi_namedfm = ALLOC_CLEAR_MULT(xfmark_T, NMARKS + EXTRA_MARKS);
2554c3328169SBram Moolenaar #ifdef FEAT_JUMPLIST
2555c3328169SBram Moolenaar vi_jumplist = ALLOC_CLEAR_MULT(xfmark_T, JUMPLISTSIZE);
2556c3328169SBram Moolenaar vi_jumplist_len = 0;
2557c3328169SBram Moolenaar #endif
2558c3328169SBram Moolenaar }
2559c3328169SBram Moolenaar
2560c3328169SBram Moolenaar static void
finish_viminfo_marks(void)2561c3328169SBram Moolenaar finish_viminfo_marks(void)
2562c3328169SBram Moolenaar {
2563c3328169SBram Moolenaar int i;
2564c3328169SBram Moolenaar
2565c3328169SBram Moolenaar if (vi_namedfm != NULL)
2566c3328169SBram Moolenaar {
2567c3328169SBram Moolenaar for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
2568c3328169SBram Moolenaar vim_free(vi_namedfm[i].fname);
2569c3328169SBram Moolenaar VIM_CLEAR(vi_namedfm);
2570c3328169SBram Moolenaar }
2571c3328169SBram Moolenaar #ifdef FEAT_JUMPLIST
2572c3328169SBram Moolenaar if (vi_jumplist != NULL)
2573c3328169SBram Moolenaar {
2574c3328169SBram Moolenaar for (i = 0; i < vi_jumplist_len; ++i)
2575c3328169SBram Moolenaar vim_free(vi_jumplist[i].fname);
2576c3328169SBram Moolenaar VIM_CLEAR(vi_jumplist);
2577c3328169SBram Moolenaar }
2578c3328169SBram Moolenaar #endif
2579c3328169SBram Moolenaar }
2580c3328169SBram Moolenaar
2581c3328169SBram Moolenaar /*
2582c3328169SBram Moolenaar * Accept a new style mark line from the viminfo, store it when it's new.
2583c3328169SBram Moolenaar */
2584c3328169SBram Moolenaar static void
handle_viminfo_mark(garray_T * values,int force)2585c3328169SBram Moolenaar handle_viminfo_mark(garray_T *values, int force)
2586c3328169SBram Moolenaar {
2587c3328169SBram Moolenaar bval_T *vp = (bval_T *)values->ga_data;
2588c3328169SBram Moolenaar int name;
2589c3328169SBram Moolenaar linenr_T lnum;
2590c3328169SBram Moolenaar colnr_T col;
2591c3328169SBram Moolenaar time_t timestamp;
2592c3328169SBram Moolenaar xfmark_T *fm = NULL;
2593c3328169SBram Moolenaar
2594c3328169SBram Moolenaar // Check the format:
2595c3328169SBram Moolenaar // |{bartype},{name},{lnum},{col},{timestamp},{filename}
2596c3328169SBram Moolenaar if (values->ga_len < 5
2597c3328169SBram Moolenaar || vp[0].bv_type != BVAL_NR
2598c3328169SBram Moolenaar || vp[1].bv_type != BVAL_NR
2599c3328169SBram Moolenaar || vp[2].bv_type != BVAL_NR
2600c3328169SBram Moolenaar || vp[3].bv_type != BVAL_NR
2601c3328169SBram Moolenaar || vp[4].bv_type != BVAL_STRING)
2602c3328169SBram Moolenaar return;
2603c3328169SBram Moolenaar
2604c3328169SBram Moolenaar name = vp[0].bv_nr;
2605c3328169SBram Moolenaar if (name != '\'' && !VIM_ISDIGIT(name) && !ASCII_ISUPPER(name))
2606c3328169SBram Moolenaar return;
2607c3328169SBram Moolenaar lnum = vp[1].bv_nr;
2608c3328169SBram Moolenaar col = vp[2].bv_nr;
2609c3328169SBram Moolenaar if (lnum <= 0 || col < 0)
2610c3328169SBram Moolenaar return;
2611c3328169SBram Moolenaar timestamp = (time_t)vp[3].bv_nr;
2612c3328169SBram Moolenaar
2613c3328169SBram Moolenaar if (name == '\'')
2614c3328169SBram Moolenaar {
2615c3328169SBram Moolenaar #ifdef FEAT_JUMPLIST
2616c3328169SBram Moolenaar if (vi_jumplist != NULL)
2617c3328169SBram Moolenaar {
2618c3328169SBram Moolenaar if (vi_jumplist_len < JUMPLISTSIZE)
2619c3328169SBram Moolenaar fm = &vi_jumplist[vi_jumplist_len++];
2620c3328169SBram Moolenaar }
2621c3328169SBram Moolenaar else
2622c3328169SBram Moolenaar {
2623c3328169SBram Moolenaar int idx;
2624c3328169SBram Moolenaar int i;
2625c3328169SBram Moolenaar
2626c3328169SBram Moolenaar // If we have a timestamp insert it in the right place.
2627c3328169SBram Moolenaar if (timestamp != 0)
2628c3328169SBram Moolenaar {
2629c3328169SBram Moolenaar for (idx = curwin->w_jumplistlen - 1; idx >= 0; --idx)
2630c3328169SBram Moolenaar if (curwin->w_jumplist[idx].time_set < timestamp)
2631c3328169SBram Moolenaar {
2632c3328169SBram Moolenaar ++idx;
2633c3328169SBram Moolenaar break;
2634c3328169SBram Moolenaar }
2635c3328169SBram Moolenaar // idx cannot be zero now
2636c3328169SBram Moolenaar if (idx < 0 && curwin->w_jumplistlen < JUMPLISTSIZE)
2637c3328169SBram Moolenaar // insert as the oldest entry
2638c3328169SBram Moolenaar idx = 0;
2639c3328169SBram Moolenaar }
2640c3328169SBram Moolenaar else if (curwin->w_jumplistlen < JUMPLISTSIZE)
2641c3328169SBram Moolenaar // insert as oldest entry
2642c3328169SBram Moolenaar idx = 0;
2643c3328169SBram Moolenaar else
2644c3328169SBram Moolenaar idx = -1;
2645c3328169SBram Moolenaar
2646c3328169SBram Moolenaar if (idx >= 0)
2647c3328169SBram Moolenaar {
2648c3328169SBram Moolenaar if (curwin->w_jumplistlen == JUMPLISTSIZE)
2649c3328169SBram Moolenaar {
2650c3328169SBram Moolenaar // Drop the oldest entry.
2651c3328169SBram Moolenaar --idx;
2652c3328169SBram Moolenaar vim_free(curwin->w_jumplist[0].fname);
2653c3328169SBram Moolenaar for (i = 0; i < idx; ++i)
2654c3328169SBram Moolenaar curwin->w_jumplist[i] = curwin->w_jumplist[i + 1];
2655c3328169SBram Moolenaar }
2656c3328169SBram Moolenaar else
2657c3328169SBram Moolenaar {
2658c3328169SBram Moolenaar // Move newer entries forward.
2659c3328169SBram Moolenaar for (i = curwin->w_jumplistlen; i > idx; --i)
2660c3328169SBram Moolenaar curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
2661c3328169SBram Moolenaar ++curwin->w_jumplistidx;
2662c3328169SBram Moolenaar ++curwin->w_jumplistlen;
2663c3328169SBram Moolenaar }
2664c3328169SBram Moolenaar fm = &curwin->w_jumplist[idx];
2665c3328169SBram Moolenaar fm->fmark.mark.lnum = 0;
2666c3328169SBram Moolenaar fm->fname = NULL;
2667c3328169SBram Moolenaar fm->time_set = 0;
2668c3328169SBram Moolenaar }
2669c3328169SBram Moolenaar }
2670c3328169SBram Moolenaar #endif
2671c3328169SBram Moolenaar }
2672c3328169SBram Moolenaar else
2673c3328169SBram Moolenaar {
2674c3328169SBram Moolenaar int idx;
2675c3328169SBram Moolenaar xfmark_T *namedfm_p = get_namedfm();
2676c3328169SBram Moolenaar
2677c3328169SBram Moolenaar if (VIM_ISDIGIT(name))
2678c3328169SBram Moolenaar {
2679c3328169SBram Moolenaar if (vi_namedfm != NULL)
2680c3328169SBram Moolenaar idx = name - '0' + NMARKS;
2681c3328169SBram Moolenaar else
2682c3328169SBram Moolenaar {
2683c3328169SBram Moolenaar int i;
2684c3328169SBram Moolenaar
2685c3328169SBram Moolenaar // Do not use the name from the viminfo file, insert in time
2686c3328169SBram Moolenaar // order.
2687c3328169SBram Moolenaar for (idx = NMARKS; idx < NMARKS + EXTRA_MARKS; ++idx)
2688c3328169SBram Moolenaar if (namedfm_p[idx].time_set < timestamp)
2689c3328169SBram Moolenaar break;
2690c3328169SBram Moolenaar if (idx == NMARKS + EXTRA_MARKS)
2691c3328169SBram Moolenaar // All existing entries are newer.
2692c3328169SBram Moolenaar return;
2693c3328169SBram Moolenaar i = NMARKS + EXTRA_MARKS - 1;
2694c3328169SBram Moolenaar
2695c3328169SBram Moolenaar vim_free(namedfm_p[i].fname);
2696c3328169SBram Moolenaar for ( ; i > idx; --i)
2697c3328169SBram Moolenaar namedfm_p[i] = namedfm_p[i - 1];
2698c3328169SBram Moolenaar namedfm_p[idx].fname = NULL;
2699c3328169SBram Moolenaar }
2700c3328169SBram Moolenaar }
2701c3328169SBram Moolenaar else
2702c3328169SBram Moolenaar idx = name - 'A';
2703c3328169SBram Moolenaar if (vi_namedfm != NULL)
2704c3328169SBram Moolenaar fm = &vi_namedfm[idx];
2705c3328169SBram Moolenaar else
2706c3328169SBram Moolenaar fm = &namedfm_p[idx];
2707c3328169SBram Moolenaar }
2708c3328169SBram Moolenaar
2709c3328169SBram Moolenaar if (fm != NULL)
2710c3328169SBram Moolenaar {
2711c3328169SBram Moolenaar if (vi_namedfm != NULL || fm->fmark.mark.lnum == 0
2712c3328169SBram Moolenaar || fm->time_set < timestamp || force)
2713c3328169SBram Moolenaar {
2714c3328169SBram Moolenaar fm->fmark.mark.lnum = lnum;
2715c3328169SBram Moolenaar fm->fmark.mark.col = col;
2716c3328169SBram Moolenaar fm->fmark.mark.coladd = 0;
2717c3328169SBram Moolenaar fm->fmark.fnum = 0;
2718c3328169SBram Moolenaar vim_free(fm->fname);
2719c3328169SBram Moolenaar if (vp[4].bv_allocated)
2720c3328169SBram Moolenaar {
2721c3328169SBram Moolenaar fm->fname = vp[4].bv_string;
2722c3328169SBram Moolenaar vp[4].bv_string = NULL;
2723c3328169SBram Moolenaar }
2724c3328169SBram Moolenaar else
2725c3328169SBram Moolenaar fm->fname = vim_strsave(vp[4].bv_string);
2726c3328169SBram Moolenaar fm->time_set = timestamp;
2727c3328169SBram Moolenaar }
2728c3328169SBram Moolenaar }
2729c3328169SBram Moolenaar }
2730c3328169SBram Moolenaar
2731c3328169SBram Moolenaar static int
read_viminfo_barline(vir_T * virp,int got_encoding,int force,int writing)2732c3328169SBram Moolenaar read_viminfo_barline(vir_T *virp, int got_encoding, int force, int writing)
2733c3328169SBram Moolenaar {
2734c3328169SBram Moolenaar char_u *p = virp->vir_line + 1;
2735c3328169SBram Moolenaar int bartype;
2736c3328169SBram Moolenaar garray_T values;
2737c3328169SBram Moolenaar bval_T *vp;
2738c3328169SBram Moolenaar int i;
2739c3328169SBram Moolenaar int read_next = TRUE;
2740c3328169SBram Moolenaar
27416bd1d770SBram Moolenaar // The format is: |{bartype},{value},...
27426bd1d770SBram Moolenaar // For a very long string:
27436bd1d770SBram Moolenaar // |{bartype},>{length of "{text}{text2}"}
27446bd1d770SBram Moolenaar // |<{text1}
27456bd1d770SBram Moolenaar // |<{text2},{value}
27466bd1d770SBram Moolenaar // For a long line not using a string
27476bd1d770SBram Moolenaar // |{bartype},{lots of values},>
27486bd1d770SBram Moolenaar // |<{value},{value}
2749c3328169SBram Moolenaar if (*p == '<')
2750c3328169SBram Moolenaar {
2751c3328169SBram Moolenaar // Continuation line of an unrecognized item.
2752c3328169SBram Moolenaar if (writing)
2753c3328169SBram Moolenaar ga_add_string(&virp->vir_barlines, virp->vir_line);
2754c3328169SBram Moolenaar }
2755c3328169SBram Moolenaar else
2756c3328169SBram Moolenaar {
2757c3328169SBram Moolenaar ga_init2(&values, sizeof(bval_T), 20);
2758c3328169SBram Moolenaar bartype = getdigits(&p);
2759c3328169SBram Moolenaar switch (bartype)
2760c3328169SBram Moolenaar {
2761c3328169SBram Moolenaar case BARTYPE_VERSION:
2762c3328169SBram Moolenaar // Only use the version when it comes before the encoding.
2763c3328169SBram Moolenaar // If it comes later it was copied by a Vim version that
2764c3328169SBram Moolenaar // doesn't understand the version.
2765c3328169SBram Moolenaar if (!got_encoding)
2766c3328169SBram Moolenaar {
2767c3328169SBram Moolenaar read_next = barline_parse(virp, p, &values);
2768c3328169SBram Moolenaar vp = (bval_T *)values.ga_data;
2769c3328169SBram Moolenaar if (values.ga_len > 0 && vp->bv_type == BVAL_NR)
2770c3328169SBram Moolenaar virp->vir_version = vp->bv_nr;
2771c3328169SBram Moolenaar }
2772c3328169SBram Moolenaar break;
2773c3328169SBram Moolenaar
2774c3328169SBram Moolenaar case BARTYPE_HISTORY:
2775c3328169SBram Moolenaar read_next = barline_parse(virp, p, &values);
2776c3328169SBram Moolenaar handle_viminfo_history(&values, writing);
2777c3328169SBram Moolenaar break;
2778c3328169SBram Moolenaar
2779c3328169SBram Moolenaar case BARTYPE_REGISTER:
2780c3328169SBram Moolenaar read_next = barline_parse(virp, p, &values);
2781c3328169SBram Moolenaar handle_viminfo_register(&values, force);
2782c3328169SBram Moolenaar break;
2783c3328169SBram Moolenaar
2784c3328169SBram Moolenaar case BARTYPE_MARK:
2785c3328169SBram Moolenaar read_next = barline_parse(virp, p, &values);
2786c3328169SBram Moolenaar handle_viminfo_mark(&values, force);
2787c3328169SBram Moolenaar break;
2788c3328169SBram Moolenaar
2789c3328169SBram Moolenaar default:
2790c3328169SBram Moolenaar // copy unrecognized line (for future use)
2791c3328169SBram Moolenaar if (writing)
2792c3328169SBram Moolenaar ga_add_string(&virp->vir_barlines, virp->vir_line);
2793c3328169SBram Moolenaar }
2794c3328169SBram Moolenaar for (i = 0; i < values.ga_len; ++i)
2795c3328169SBram Moolenaar {
2796c3328169SBram Moolenaar vp = (bval_T *)values.ga_data + i;
2797c3328169SBram Moolenaar if (vp->bv_type == BVAL_STRING && vp->bv_allocated)
2798c3328169SBram Moolenaar vim_free(vp->bv_string);
2799408030e8SBram Moolenaar vim_free(vp->bv_tofree);
2800c3328169SBram Moolenaar }
2801c3328169SBram Moolenaar ga_clear(&values);
2802c3328169SBram Moolenaar }
2803c3328169SBram Moolenaar
2804c3328169SBram Moolenaar if (read_next)
2805c3328169SBram Moolenaar return viminfo_readline(virp);
2806c3328169SBram Moolenaar return FALSE;
2807c3328169SBram Moolenaar }
2808c3328169SBram Moolenaar
2809defa067cSBram Moolenaar /*
2810defa067cSBram Moolenaar * read_viminfo_up_to_marks() -- Only called from do_viminfo(). Reads in the
2811defa067cSBram Moolenaar * first part of the viminfo file which contains everything but the marks that
2812defa067cSBram Moolenaar * are local to a file. Returns TRUE when end-of-file is reached. -- webb
2813defa067cSBram Moolenaar */
2814defa067cSBram Moolenaar static int
read_viminfo_up_to_marks(vir_T * virp,int forceit,int writing)2815defa067cSBram Moolenaar read_viminfo_up_to_marks(
2816defa067cSBram Moolenaar vir_T *virp,
2817defa067cSBram Moolenaar int forceit,
2818defa067cSBram Moolenaar int writing)
2819defa067cSBram Moolenaar {
2820defa067cSBram Moolenaar int eof;
2821defa067cSBram Moolenaar buf_T *buf;
2822defa067cSBram Moolenaar int got_encoding = FALSE;
2823defa067cSBram Moolenaar
2824defa067cSBram Moolenaar prepare_viminfo_history(forceit ? 9999 : 0, writing);
2825defa067cSBram Moolenaar
2826defa067cSBram Moolenaar eof = viminfo_readline(virp);
2827defa067cSBram Moolenaar while (!eof && virp->vir_line[0] != '>')
2828defa067cSBram Moolenaar {
2829defa067cSBram Moolenaar switch (virp->vir_line[0])
2830defa067cSBram Moolenaar {
2831defa067cSBram Moolenaar // Characters reserved for future expansion, ignored now
2832defa067cSBram Moolenaar case '+': // "+40 /path/dir file", for running vim without args
2833defa067cSBram Moolenaar case '^': // to be defined
2834defa067cSBram Moolenaar case '<': // long line - ignored
2835defa067cSBram Moolenaar // A comment or empty line.
2836defa067cSBram Moolenaar case NUL:
2837defa067cSBram Moolenaar case '\r':
2838defa067cSBram Moolenaar case '\n':
2839defa067cSBram Moolenaar case '#':
2840defa067cSBram Moolenaar eof = viminfo_readline(virp);
2841defa067cSBram Moolenaar break;
2842defa067cSBram Moolenaar case '|':
2843defa067cSBram Moolenaar eof = read_viminfo_barline(virp, got_encoding,
2844defa067cSBram Moolenaar forceit, writing);
2845defa067cSBram Moolenaar break;
2846defa067cSBram Moolenaar case '*': // "*encoding=value"
2847defa067cSBram Moolenaar got_encoding = TRUE;
2848defa067cSBram Moolenaar eof = viminfo_encoding(virp);
2849defa067cSBram Moolenaar break;
2850defa067cSBram Moolenaar case '!': // global variable
2851defa067cSBram Moolenaar #ifdef FEAT_EVAL
2852defa067cSBram Moolenaar eof = read_viminfo_varlist(virp, writing);
2853defa067cSBram Moolenaar #else
2854defa067cSBram Moolenaar eof = viminfo_readline(virp);
2855defa067cSBram Moolenaar #endif
2856defa067cSBram Moolenaar break;
2857defa067cSBram Moolenaar case '%': // entry for buffer list
2858defa067cSBram Moolenaar eof = read_viminfo_bufferlist(virp, writing);
2859defa067cSBram Moolenaar break;
2860defa067cSBram Moolenaar case '"':
2861defa067cSBram Moolenaar // When registers are in bar lines skip the old style register
2862defa067cSBram Moolenaar // lines.
2863defa067cSBram Moolenaar if (virp->vir_version < VIMINFO_VERSION_WITH_REGISTERS)
2864defa067cSBram Moolenaar eof = read_viminfo_register(virp, forceit);
2865defa067cSBram Moolenaar else
2866defa067cSBram Moolenaar do {
2867defa067cSBram Moolenaar eof = viminfo_readline(virp);
2868defa067cSBram Moolenaar } while (!eof && (virp->vir_line[0] == TAB
2869defa067cSBram Moolenaar || virp->vir_line[0] == '<'));
2870defa067cSBram Moolenaar break;
2871defa067cSBram Moolenaar case '/': // Search string
2872defa067cSBram Moolenaar case '&': // Substitute search string
2873defa067cSBram Moolenaar case '~': // Last search string, followed by '/' or '&'
2874defa067cSBram Moolenaar eof = read_viminfo_search_pattern(virp, forceit);
2875defa067cSBram Moolenaar break;
2876defa067cSBram Moolenaar case '$':
2877defa067cSBram Moolenaar eof = read_viminfo_sub_string(virp, forceit);
2878defa067cSBram Moolenaar break;
2879defa067cSBram Moolenaar case ':':
2880defa067cSBram Moolenaar case '?':
2881defa067cSBram Moolenaar case '=':
2882defa067cSBram Moolenaar case '@':
2883defa067cSBram Moolenaar // When history is in bar lines skip the old style history
2884defa067cSBram Moolenaar // lines.
2885defa067cSBram Moolenaar if (virp->vir_version < VIMINFO_VERSION_WITH_HISTORY)
2886defa067cSBram Moolenaar eof = read_viminfo_history(virp, writing);
2887defa067cSBram Moolenaar else
2888defa067cSBram Moolenaar eof = viminfo_readline(virp);
2889defa067cSBram Moolenaar break;
2890defa067cSBram Moolenaar case '-':
2891defa067cSBram Moolenaar case '\'':
2892defa067cSBram Moolenaar // When file marks are in bar lines skip the old style lines.
2893defa067cSBram Moolenaar if (virp->vir_version < VIMINFO_VERSION_WITH_MARKS)
2894defa067cSBram Moolenaar eof = read_viminfo_filemark(virp, forceit);
2895defa067cSBram Moolenaar else
2896defa067cSBram Moolenaar eof = viminfo_readline(virp);
2897defa067cSBram Moolenaar break;
2898defa067cSBram Moolenaar default:
2899defa067cSBram Moolenaar if (viminfo_error("E575: ", _("Illegal starting char"),
2900defa067cSBram Moolenaar virp->vir_line))
2901defa067cSBram Moolenaar eof = TRUE;
2902defa067cSBram Moolenaar else
2903defa067cSBram Moolenaar eof = viminfo_readline(virp);
2904defa067cSBram Moolenaar break;
2905defa067cSBram Moolenaar }
2906defa067cSBram Moolenaar }
2907defa067cSBram Moolenaar
2908defa067cSBram Moolenaar // Finish reading history items.
2909defa067cSBram Moolenaar if (!writing)
2910defa067cSBram Moolenaar finish_viminfo_history(virp);
2911defa067cSBram Moolenaar
2912defa067cSBram Moolenaar // Change file names to buffer numbers for fmarks.
2913defa067cSBram Moolenaar FOR_ALL_BUFFERS(buf)
2914defa067cSBram Moolenaar fmarks_check_names(buf);
2915defa067cSBram Moolenaar
2916defa067cSBram Moolenaar return eof;
2917defa067cSBram Moolenaar }
2918defa067cSBram Moolenaar
2919defa067cSBram Moolenaar /*
2920defa067cSBram Moolenaar * do_viminfo() -- Should only be called from read_viminfo() & write_viminfo().
2921defa067cSBram Moolenaar */
2922defa067cSBram Moolenaar static void
do_viminfo(FILE * fp_in,FILE * fp_out,int flags)2923defa067cSBram Moolenaar do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
2924defa067cSBram Moolenaar {
2925defa067cSBram Moolenaar int eof = FALSE;
2926defa067cSBram Moolenaar vir_T vir;
2927defa067cSBram Moolenaar int merge = FALSE;
2928defa067cSBram Moolenaar int do_copy_marks = FALSE;
2929defa067cSBram Moolenaar garray_T buflist;
2930defa067cSBram Moolenaar
2931defa067cSBram Moolenaar if ((vir.vir_line = alloc(LSIZE)) == NULL)
2932defa067cSBram Moolenaar return;
2933defa067cSBram Moolenaar vir.vir_fd = fp_in;
2934defa067cSBram Moolenaar vir.vir_conv.vc_type = CONV_NONE;
2935defa067cSBram Moolenaar ga_init2(&vir.vir_barlines, (int)sizeof(char_u *), 100);
2936defa067cSBram Moolenaar vir.vir_version = -1;
2937defa067cSBram Moolenaar
2938defa067cSBram Moolenaar if (fp_in != NULL)
2939defa067cSBram Moolenaar {
2940defa067cSBram Moolenaar if (flags & VIF_WANT_INFO)
2941defa067cSBram Moolenaar {
2942defa067cSBram Moolenaar if (fp_out != NULL)
2943defa067cSBram Moolenaar {
2944defa067cSBram Moolenaar // Registers and marks are read and kept separate from what
2945defa067cSBram Moolenaar // this Vim is using. They are merged when writing.
2946defa067cSBram Moolenaar prepare_viminfo_registers();
2947defa067cSBram Moolenaar prepare_viminfo_marks();
2948defa067cSBram Moolenaar }
2949defa067cSBram Moolenaar
2950defa067cSBram Moolenaar eof = read_viminfo_up_to_marks(&vir,
2951defa067cSBram Moolenaar flags & VIF_FORCEIT, fp_out != NULL);
2952defa067cSBram Moolenaar merge = TRUE;
2953defa067cSBram Moolenaar }
2954defa067cSBram Moolenaar else if (flags != 0)
2955defa067cSBram Moolenaar // Skip info, find start of marks
2956defa067cSBram Moolenaar while (!(eof = viminfo_readline(&vir))
2957defa067cSBram Moolenaar && vir.vir_line[0] != '>')
2958defa067cSBram Moolenaar ;
2959defa067cSBram Moolenaar
29603ff656f6SBram Moolenaar do_copy_marks = (flags & (VIF_WANT_MARKS | VIF_ONLY_CURBUF
29613ff656f6SBram Moolenaar | VIF_GET_OLDFILES | VIF_FORCEIT));
2962defa067cSBram Moolenaar }
2963defa067cSBram Moolenaar
2964defa067cSBram Moolenaar if (fp_out != NULL)
2965defa067cSBram Moolenaar {
2966defa067cSBram Moolenaar // Write the info:
2967defa067cSBram Moolenaar fprintf(fp_out, _("# This viminfo file was generated by Vim %s.\n"),
2968defa067cSBram Moolenaar VIM_VERSION_MEDIUM);
2969defa067cSBram Moolenaar fputs(_("# You may edit it if you're careful!\n\n"), fp_out);
2970defa067cSBram Moolenaar write_viminfo_version(fp_out);
2971defa067cSBram Moolenaar fputs(_("# Value of 'encoding' when this file was written\n"), fp_out);
2972defa067cSBram Moolenaar fprintf(fp_out, "*encoding=%s\n\n", p_enc);
2973defa067cSBram Moolenaar write_viminfo_search_pattern(fp_out);
2974defa067cSBram Moolenaar write_viminfo_sub_string(fp_out);
2975defa067cSBram Moolenaar write_viminfo_history(fp_out, merge);
2976defa067cSBram Moolenaar write_viminfo_registers(fp_out);
2977defa067cSBram Moolenaar finish_viminfo_registers();
2978defa067cSBram Moolenaar #ifdef FEAT_EVAL
2979defa067cSBram Moolenaar write_viminfo_varlist(fp_out);
2980defa067cSBram Moolenaar #endif
2981defa067cSBram Moolenaar write_viminfo_filemarks(fp_out);
2982defa067cSBram Moolenaar finish_viminfo_marks();
2983defa067cSBram Moolenaar write_viminfo_bufferlist(fp_out);
2984defa067cSBram Moolenaar write_viminfo_barlines(&vir, fp_out);
2985defa067cSBram Moolenaar
2986defa067cSBram Moolenaar if (do_copy_marks)
2987defa067cSBram Moolenaar ga_init2(&buflist, sizeof(buf_T *), 50);
2988defa067cSBram Moolenaar write_viminfo_marks(fp_out, do_copy_marks ? &buflist : NULL);
2989defa067cSBram Moolenaar }
2990defa067cSBram Moolenaar
2991defa067cSBram Moolenaar if (do_copy_marks)
2992defa067cSBram Moolenaar {
2993defa067cSBram Moolenaar copy_viminfo_marks(&vir, fp_out, &buflist, eof, flags);
2994defa067cSBram Moolenaar if (fp_out != NULL)
2995defa067cSBram Moolenaar ga_clear(&buflist);
2996defa067cSBram Moolenaar }
2997defa067cSBram Moolenaar
2998defa067cSBram Moolenaar vim_free(vir.vir_line);
2999defa067cSBram Moolenaar if (vir.vir_conv.vc_type != CONV_NONE)
3000defa067cSBram Moolenaar convert_setup(&vir.vir_conv, NULL, NULL);
3001defa067cSBram Moolenaar ga_clear_strings(&vir.vir_barlines);
3002defa067cSBram Moolenaar }
3003defa067cSBram Moolenaar
3004defa067cSBram Moolenaar /*
3005defa067cSBram Moolenaar * read_viminfo() -- Read the viminfo file. Registers etc. which are already
3006defa067cSBram Moolenaar * set are not over-written unless "flags" includes VIF_FORCEIT. -- webb
3007defa067cSBram Moolenaar */
3008defa067cSBram Moolenaar int
read_viminfo(char_u * file,int flags)3009defa067cSBram Moolenaar read_viminfo(
3010defa067cSBram Moolenaar char_u *file, // file name or NULL to use default name
3011defa067cSBram Moolenaar int flags) // VIF_WANT_INFO et al.
3012defa067cSBram Moolenaar {
3013defa067cSBram Moolenaar FILE *fp;
3014defa067cSBram Moolenaar char_u *fname;
3015b86abadfSBram Moolenaar stat_T st; // mch_stat() of existing viminfo file
3016defa067cSBram Moolenaar
3017defa067cSBram Moolenaar if (no_viminfo())
3018defa067cSBram Moolenaar return FAIL;
3019defa067cSBram Moolenaar
3020defa067cSBram Moolenaar fname = viminfo_filename(file); // get file name in allocated buffer
3021defa067cSBram Moolenaar if (fname == NULL)
3022defa067cSBram Moolenaar return FAIL;
3023defa067cSBram Moolenaar fp = mch_fopen((char *)fname, READBIN);
3024defa067cSBram Moolenaar
3025defa067cSBram Moolenaar if (p_verbose > 0)
3026defa067cSBram Moolenaar {
3027defa067cSBram Moolenaar verbose_enter();
3028db99f9f2SBram Moolenaar smsg(_("Reading viminfo file \"%s\"%s%s%s%s"),
3029defa067cSBram Moolenaar fname,
3030defa067cSBram Moolenaar (flags & VIF_WANT_INFO) ? _(" info") : "",
3031defa067cSBram Moolenaar (flags & VIF_WANT_MARKS) ? _(" marks") : "",
3032defa067cSBram Moolenaar (flags & VIF_GET_OLDFILES) ? _(" oldfiles") : "",
3033defa067cSBram Moolenaar fp == NULL ? _(" FAILED") : "");
3034defa067cSBram Moolenaar verbose_leave();
3035defa067cSBram Moolenaar }
3036defa067cSBram Moolenaar
3037defa067cSBram Moolenaar vim_free(fname);
3038defa067cSBram Moolenaar if (fp == NULL)
3039defa067cSBram Moolenaar return FAIL;
3040b86abadfSBram Moolenaar if (mch_fstat(fileno(fp), &st) < 0 || S_ISDIR(st.st_mode))
3041b86abadfSBram Moolenaar {
3042b86abadfSBram Moolenaar fclose(fp);
3043b86abadfSBram Moolenaar return FAIL;
3044b86abadfSBram Moolenaar }
3045defa067cSBram Moolenaar
3046defa067cSBram Moolenaar viminfo_errcnt = 0;
3047defa067cSBram Moolenaar do_viminfo(fp, NULL, flags);
3048defa067cSBram Moolenaar
3049defa067cSBram Moolenaar fclose(fp);
3050defa067cSBram Moolenaar return OK;
3051defa067cSBram Moolenaar }
3052defa067cSBram Moolenaar
3053defa067cSBram Moolenaar /*
3054defa067cSBram Moolenaar * Write the viminfo file. The old one is read in first so that effectively a
3055defa067cSBram Moolenaar * merge of current info and old info is done. This allows multiple vims to
3056defa067cSBram Moolenaar * run simultaneously, without losing any marks etc.
3057defa067cSBram Moolenaar * If "forceit" is TRUE, then the old file is not read in, and only internal
3058defa067cSBram Moolenaar * info is written to the file.
3059defa067cSBram Moolenaar */
3060defa067cSBram Moolenaar void
write_viminfo(char_u * file,int forceit)3061defa067cSBram Moolenaar write_viminfo(char_u *file, int forceit)
3062defa067cSBram Moolenaar {
3063defa067cSBram Moolenaar char_u *fname;
3064defa067cSBram Moolenaar FILE *fp_in = NULL; // input viminfo file, if any
3065defa067cSBram Moolenaar FILE *fp_out = NULL; // output viminfo file
3066defa067cSBram Moolenaar char_u *tempname = NULL; // name of temp viminfo file
3067defa067cSBram Moolenaar stat_T st_new; // mch_stat() of potential new file
3068b86abadfSBram Moolenaar stat_T st_old; // mch_stat() of existing viminfo file
3069defa067cSBram Moolenaar #if defined(UNIX) || defined(VMS)
3070defa067cSBram Moolenaar mode_t umask_save;
3071defa067cSBram Moolenaar #endif
3072defa067cSBram Moolenaar #ifdef UNIX
3073defa067cSBram Moolenaar int shortname = FALSE; // use 8.3 file name
3074defa067cSBram Moolenaar #endif
3075defa067cSBram Moolenaar #ifdef MSWIN
3076defa067cSBram Moolenaar int hidden = FALSE;
3077defa067cSBram Moolenaar #endif
3078defa067cSBram Moolenaar
3079defa067cSBram Moolenaar if (no_viminfo())
3080defa067cSBram Moolenaar return;
3081defa067cSBram Moolenaar
3082defa067cSBram Moolenaar fname = viminfo_filename(file); // may set to default if NULL
3083defa067cSBram Moolenaar if (fname == NULL)
3084defa067cSBram Moolenaar return;
3085defa067cSBram Moolenaar
3086defa067cSBram Moolenaar fp_in = mch_fopen((char *)fname, READBIN);
3087defa067cSBram Moolenaar if (fp_in == NULL)
3088defa067cSBram Moolenaar {
3089defa067cSBram Moolenaar int fd;
3090defa067cSBram Moolenaar
3091defa067cSBram Moolenaar // if it does exist, but we can't read it, don't try writing
3092defa067cSBram Moolenaar if (mch_stat((char *)fname, &st_new) == 0)
3093defa067cSBram Moolenaar goto end;
3094defa067cSBram Moolenaar
3095defa067cSBram Moolenaar // Create the new .viminfo non-accessible for others, because it may
3096defa067cSBram Moolenaar // contain text from non-accessible documents. It is up to the user to
3097defa067cSBram Moolenaar // widen access (e.g. to a group). This may also fail if there is a
3098defa067cSBram Moolenaar // race condition, then just give up.
3099defa067cSBram Moolenaar fd = mch_open((char *)fname,
3100defa067cSBram Moolenaar O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
3101defa067cSBram Moolenaar if (fd < 0)
3102defa067cSBram Moolenaar goto end;
3103defa067cSBram Moolenaar fp_out = fdopen(fd, WRITEBIN);
3104defa067cSBram Moolenaar }
3105defa067cSBram Moolenaar else
3106defa067cSBram Moolenaar {
31076bd1d770SBram Moolenaar // There is an existing viminfo file. Create a temporary file to
31086bd1d770SBram Moolenaar // write the new viminfo into, in the same directory as the
31096bd1d770SBram Moolenaar // existing viminfo file, which will be renamed once all writing is
31106bd1d770SBram Moolenaar // successful.
3111b86abadfSBram Moolenaar if (mch_fstat(fileno(fp_in), &st_old) < 0
3112b86abadfSBram Moolenaar || S_ISDIR(st_old.st_mode)
3113defa067cSBram Moolenaar #ifdef UNIX
3114b86abadfSBram Moolenaar // For Unix we check the owner of the file. It's not very nice
3115b86abadfSBram Moolenaar // to overwrite a user's viminfo file after a "su root", with a
31166bd1d770SBram Moolenaar // viminfo file that the user can't read.
3117b86abadfSBram Moolenaar || (getuid() != ROOT_UID
3118defa067cSBram Moolenaar && !(st_old.st_uid == getuid()
3119defa067cSBram Moolenaar ? (st_old.st_mode & 0200)
3120defa067cSBram Moolenaar : (st_old.st_gid == getgid()
3121defa067cSBram Moolenaar ? (st_old.st_mode & 0020)
3122defa067cSBram Moolenaar : (st_old.st_mode & 0002))))
3123b86abadfSBram Moolenaar #endif
3124b86abadfSBram Moolenaar )
3125defa067cSBram Moolenaar {
3126defa067cSBram Moolenaar int tt = msg_didany;
3127defa067cSBram Moolenaar
3128defa067cSBram Moolenaar // avoid a wait_return for this message, it's annoying
3129defa067cSBram Moolenaar semsg(_("E137: Viminfo file is not writable: %s"), fname);
3130defa067cSBram Moolenaar msg_didany = tt;
3131defa067cSBram Moolenaar fclose(fp_in);
3132defa067cSBram Moolenaar goto end;
3133defa067cSBram Moolenaar }
3134defa067cSBram Moolenaar #ifdef MSWIN
3135defa067cSBram Moolenaar // Get the file attributes of the existing viminfo file.
3136defa067cSBram Moolenaar hidden = mch_ishidden(fname);
3137defa067cSBram Moolenaar #endif
3138defa067cSBram Moolenaar
31396bd1d770SBram Moolenaar // Make tempname, find one that does not exist yet.
31406bd1d770SBram Moolenaar // Beware of a race condition: If someone logs out and all Vim
31416bd1d770SBram Moolenaar // instances exit at the same time a temp file might be created between
31426bd1d770SBram Moolenaar // stat() and open(). Use mch_open() with O_EXCL to avoid that.
31436bd1d770SBram Moolenaar // May try twice: Once normal and once with shortname set, just in
31446bd1d770SBram Moolenaar // case somebody puts his viminfo file in an 8.3 filesystem.
3145defa067cSBram Moolenaar for (;;)
3146defa067cSBram Moolenaar {
3147defa067cSBram Moolenaar int next_char = 'z';
3148defa067cSBram Moolenaar char_u *wp;
3149defa067cSBram Moolenaar
3150defa067cSBram Moolenaar tempname = buf_modname(
3151defa067cSBram Moolenaar #ifdef UNIX
3152defa067cSBram Moolenaar shortname,
3153defa067cSBram Moolenaar #else
3154defa067cSBram Moolenaar FALSE,
3155defa067cSBram Moolenaar #endif
3156defa067cSBram Moolenaar fname,
3157defa067cSBram Moolenaar #ifdef VMS
3158defa067cSBram Moolenaar (char_u *)"-tmp",
3159defa067cSBram Moolenaar #else
3160defa067cSBram Moolenaar (char_u *)".tmp",
3161defa067cSBram Moolenaar #endif
3162defa067cSBram Moolenaar FALSE);
3163defa067cSBram Moolenaar if (tempname == NULL) // out of memory
3164defa067cSBram Moolenaar break;
3165defa067cSBram Moolenaar
31666bd1d770SBram Moolenaar // Try a series of names. Change one character, just before
31676bd1d770SBram Moolenaar // the extension. This should also work for an 8.3
31686bd1d770SBram Moolenaar // file name, when after adding the extension it still is
31696bd1d770SBram Moolenaar // the same file as the original.
3170defa067cSBram Moolenaar wp = tempname + STRLEN(tempname) - 5;
3171defa067cSBram Moolenaar if (wp < gettail(tempname)) // empty file name?
3172defa067cSBram Moolenaar wp = gettail(tempname);
3173defa067cSBram Moolenaar for (;;)
3174defa067cSBram Moolenaar {
31756bd1d770SBram Moolenaar // Check if tempfile already exists. Never overwrite an
31766bd1d770SBram Moolenaar // existing file!
3177defa067cSBram Moolenaar if (mch_stat((char *)tempname, &st_new) == 0)
3178defa067cSBram Moolenaar {
3179defa067cSBram Moolenaar #ifdef UNIX
31806bd1d770SBram Moolenaar // Check if tempfile is same as original file. May happen
31816bd1d770SBram Moolenaar // when modname() gave the same file back. E.g. silly
31826bd1d770SBram Moolenaar // link, or file name-length reached. Try again with
31836bd1d770SBram Moolenaar // shortname set.
3184defa067cSBram Moolenaar if (!shortname && st_new.st_dev == st_old.st_dev
3185defa067cSBram Moolenaar && st_new.st_ino == st_old.st_ino)
3186defa067cSBram Moolenaar {
3187defa067cSBram Moolenaar VIM_CLEAR(tempname);
3188defa067cSBram Moolenaar shortname = TRUE;
3189defa067cSBram Moolenaar break;
3190defa067cSBram Moolenaar }
3191defa067cSBram Moolenaar #endif
3192defa067cSBram Moolenaar }
3193defa067cSBram Moolenaar else
3194defa067cSBram Moolenaar {
3195defa067cSBram Moolenaar // Try creating the file exclusively. This may fail if
3196defa067cSBram Moolenaar // another Vim tries to do it at the same time.
3197defa067cSBram Moolenaar #ifdef VMS
3198defa067cSBram Moolenaar // fdopen() fails for some reason
3199defa067cSBram Moolenaar umask_save = umask(077);
3200defa067cSBram Moolenaar fp_out = mch_fopen((char *)tempname, WRITEBIN);
3201defa067cSBram Moolenaar (void)umask(umask_save);
3202defa067cSBram Moolenaar #else
3203defa067cSBram Moolenaar int fd;
3204defa067cSBram Moolenaar
3205defa067cSBram Moolenaar // Use mch_open() to be able to use O_NOFOLLOW and set file
3206defa067cSBram Moolenaar // protection:
3207defa067cSBram Moolenaar // Unix: same as original file, but strip s-bit. Reset
3208defa067cSBram Moolenaar // umask to avoid it getting in the way.
3209defa067cSBram Moolenaar // Others: r&w for user only.
3210defa067cSBram Moolenaar # ifdef UNIX
3211defa067cSBram Moolenaar umask_save = umask(0);
3212defa067cSBram Moolenaar fd = mch_open((char *)tempname,
3213defa067cSBram Moolenaar O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW,
3214defa067cSBram Moolenaar (int)((st_old.st_mode & 0777) | 0600));
3215defa067cSBram Moolenaar (void)umask(umask_save);
3216defa067cSBram Moolenaar # else
3217defa067cSBram Moolenaar fd = mch_open((char *)tempname,
3218defa067cSBram Moolenaar O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
3219defa067cSBram Moolenaar # endif
3220defa067cSBram Moolenaar if (fd < 0)
3221defa067cSBram Moolenaar {
3222defa067cSBram Moolenaar fp_out = NULL;
3223defa067cSBram Moolenaar # ifdef EEXIST
3224defa067cSBram Moolenaar // Avoid trying lots of names while the problem is lack
3225defa067cSBram Moolenaar // of permission, only retry if the file already
3226defa067cSBram Moolenaar // exists.
3227defa067cSBram Moolenaar if (errno != EEXIST)
3228defa067cSBram Moolenaar break;
3229defa067cSBram Moolenaar # endif
3230defa067cSBram Moolenaar }
3231defa067cSBram Moolenaar else
3232defa067cSBram Moolenaar fp_out = fdopen(fd, WRITEBIN);
3233defa067cSBram Moolenaar #endif // VMS
3234defa067cSBram Moolenaar if (fp_out != NULL)
3235defa067cSBram Moolenaar break;
3236defa067cSBram Moolenaar }
3237defa067cSBram Moolenaar
3238defa067cSBram Moolenaar // Assume file exists, try again with another name.
3239defa067cSBram Moolenaar if (next_char == 'a' - 1)
3240defa067cSBram Moolenaar {
3241defa067cSBram Moolenaar // They all exist? Must be something wrong! Don't write
3242defa067cSBram Moolenaar // the viminfo file then.
3243defa067cSBram Moolenaar semsg(_("E929: Too many viminfo temp files, like %s!"),
3244defa067cSBram Moolenaar tempname);
3245defa067cSBram Moolenaar break;
3246defa067cSBram Moolenaar }
3247defa067cSBram Moolenaar *wp = next_char;
3248defa067cSBram Moolenaar --next_char;
3249defa067cSBram Moolenaar }
3250defa067cSBram Moolenaar
3251defa067cSBram Moolenaar if (tempname != NULL)
3252defa067cSBram Moolenaar break;
3253defa067cSBram Moolenaar // continue if shortname was set
3254defa067cSBram Moolenaar }
3255defa067cSBram Moolenaar
3256defa067cSBram Moolenaar #if defined(UNIX) && defined(HAVE_FCHOWN)
3257defa067cSBram Moolenaar if (tempname != NULL && fp_out != NULL)
3258defa067cSBram Moolenaar {
3259defa067cSBram Moolenaar stat_T tmp_st;
3260defa067cSBram Moolenaar
32616bd1d770SBram Moolenaar // Make sure the original owner can read/write the tempfile and
32626bd1d770SBram Moolenaar // otherwise preserve permissions, making sure the group matches.
3263defa067cSBram Moolenaar if (mch_stat((char *)tempname, &tmp_st) >= 0)
3264defa067cSBram Moolenaar {
3265defa067cSBram Moolenaar if (st_old.st_uid != tmp_st.st_uid)
3266defa067cSBram Moolenaar // Changing the owner might fail, in which case the
326732aa1020SBram Moolenaar // file will now be owned by the current user, oh well.
3268defa067cSBram Moolenaar vim_ignored = fchown(fileno(fp_out), st_old.st_uid, -1);
3269defa067cSBram Moolenaar if (st_old.st_gid != tmp_st.st_gid
3270defa067cSBram Moolenaar && fchown(fileno(fp_out), -1, st_old.st_gid) == -1)
3271defa067cSBram Moolenaar // can't set the group to what it should be, remove
3272defa067cSBram Moolenaar // group permissions
3273defa067cSBram Moolenaar (void)mch_setperm(tempname, 0600);
3274defa067cSBram Moolenaar }
3275defa067cSBram Moolenaar else
3276defa067cSBram Moolenaar // can't stat the file, set conservative permissions
3277defa067cSBram Moolenaar (void)mch_setperm(tempname, 0600);
3278defa067cSBram Moolenaar }
3279defa067cSBram Moolenaar #endif
3280defa067cSBram Moolenaar }
3281defa067cSBram Moolenaar
32826bd1d770SBram Moolenaar // Check if the new viminfo file can be written to.
3283defa067cSBram Moolenaar if (fp_out == NULL)
3284defa067cSBram Moolenaar {
3285defa067cSBram Moolenaar semsg(_("E138: Can't write viminfo file %s!"),
3286defa067cSBram Moolenaar (fp_in == NULL || tempname == NULL) ? fname : tempname);
3287defa067cSBram Moolenaar if (fp_in != NULL)
3288defa067cSBram Moolenaar fclose(fp_in);
3289defa067cSBram Moolenaar goto end;
3290defa067cSBram Moolenaar }
3291defa067cSBram Moolenaar
3292defa067cSBram Moolenaar if (p_verbose > 0)
3293defa067cSBram Moolenaar {
3294defa067cSBram Moolenaar verbose_enter();
3295defa067cSBram Moolenaar smsg(_("Writing viminfo file \"%s\""), fname);
3296defa067cSBram Moolenaar verbose_leave();
3297defa067cSBram Moolenaar }
3298defa067cSBram Moolenaar
3299defa067cSBram Moolenaar viminfo_errcnt = 0;
3300defa067cSBram Moolenaar do_viminfo(fp_in, fp_out, forceit ? 0 : (VIF_WANT_INFO | VIF_WANT_MARKS));
3301defa067cSBram Moolenaar
3302defa067cSBram Moolenaar if (fclose(fp_out) == EOF)
3303defa067cSBram Moolenaar ++viminfo_errcnt;
3304defa067cSBram Moolenaar
3305defa067cSBram Moolenaar if (fp_in != NULL)
3306defa067cSBram Moolenaar {
3307defa067cSBram Moolenaar fclose(fp_in);
3308defa067cSBram Moolenaar
3309defa067cSBram Moolenaar // In case of an error keep the original viminfo file. Otherwise
3310defa067cSBram Moolenaar // rename the newly written file. Give an error if that fails.
3311defa067cSBram Moolenaar if (viminfo_errcnt == 0)
3312defa067cSBram Moolenaar {
3313defa067cSBram Moolenaar if (vim_rename(tempname, fname) == -1)
3314defa067cSBram Moolenaar {
3315defa067cSBram Moolenaar ++viminfo_errcnt;
3316defa067cSBram Moolenaar semsg(_("E886: Can't rename viminfo file to %s!"), fname);
3317defa067cSBram Moolenaar }
3318defa067cSBram Moolenaar # ifdef MSWIN
3319defa067cSBram Moolenaar // If the viminfo file was hidden then also hide the new file.
3320defa067cSBram Moolenaar else if (hidden)
3321defa067cSBram Moolenaar mch_hide(fname);
3322defa067cSBram Moolenaar # endif
3323defa067cSBram Moolenaar }
3324defa067cSBram Moolenaar if (viminfo_errcnt > 0)
3325defa067cSBram Moolenaar mch_remove(tempname);
3326defa067cSBram Moolenaar }
3327defa067cSBram Moolenaar
3328defa067cSBram Moolenaar end:
3329defa067cSBram Moolenaar vim_free(fname);
3330defa067cSBram Moolenaar vim_free(tempname);
3331defa067cSBram Moolenaar }
3332defa067cSBram Moolenaar
3333defa067cSBram Moolenaar /*
3334defa067cSBram Moolenaar * ":rviminfo" and ":wviminfo".
3335defa067cSBram Moolenaar */
3336defa067cSBram Moolenaar void
ex_viminfo(exarg_T * eap)3337defa067cSBram Moolenaar ex_viminfo(
3338defa067cSBram Moolenaar exarg_T *eap)
3339defa067cSBram Moolenaar {
3340defa067cSBram Moolenaar char_u *save_viminfo;
3341defa067cSBram Moolenaar
3342defa067cSBram Moolenaar save_viminfo = p_viminfo;
3343defa067cSBram Moolenaar if (*p_viminfo == NUL)
3344defa067cSBram Moolenaar p_viminfo = (char_u *)"'100";
3345defa067cSBram Moolenaar if (eap->cmdidx == CMD_rviminfo)
3346defa067cSBram Moolenaar {
3347defa067cSBram Moolenaar if (read_viminfo(eap->arg, VIF_WANT_INFO | VIF_WANT_MARKS
3348defa067cSBram Moolenaar | (eap->forceit ? VIF_FORCEIT : 0)) == FAIL)
3349defa067cSBram Moolenaar emsg(_("E195: Cannot open viminfo file for reading"));
3350defa067cSBram Moolenaar }
3351defa067cSBram Moolenaar else
3352defa067cSBram Moolenaar write_viminfo(eap->arg, eap->forceit);
3353defa067cSBram Moolenaar p_viminfo = save_viminfo;
3354defa067cSBram Moolenaar }
3355defa067cSBram Moolenaar
3356defa067cSBram Moolenaar #endif // FEAT_VIMINFO
3357