xref: /vim-8.2.3635/src/viminfo.c (revision ed7cb2df)
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 ", &ltime);
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