comparison src/viminfo.c @ 17476:d4b2a212fa2f v8.1.1736

patch 8.1.1736: viminfo support is spread out commit https://github.com/vim/vim/commit/c3328169d5566b97a6a6921067017e4369dd7cd6 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Jul 23 22:15:25 2019 +0200 patch 8.1.1736: viminfo support is spread out Problem: Viminfo support is spread out. Solution: Move more viminfo code to viminfo.c. (Yegappan Lakshmanan, closes #4717) Reorder code to make most functions static.
author Bram Moolenaar <Bram@vim.org>
date Tue, 23 Jul 2019 22:30:07 +0200
parents 15de78cb9f39
children bc6088919610
comparison
equal deleted inserted replaced
17475:8584e1c0e426 17476:d4b2a212fa2f
15 #include "version.h" 15 #include "version.h"
16 16
17 #if defined(FEAT_VIMINFO) || defined(PROTO) 17 #if defined(FEAT_VIMINFO) || defined(PROTO)
18 18
19 static int viminfo_errcnt; 19 static int viminfo_errcnt;
20
21 /*
22 * Find the parameter represented by the given character (eg ''', ':', '"', or
23 * '/') in the 'viminfo' option and return a pointer to the string after it.
24 * Return NULL if the parameter is not specified in the string.
25 */
26 static char_u *
27 find_viminfo_parameter(int type)
28 {
29 char_u *p;
30
31 for (p = p_viminfo; *p; ++p)
32 {
33 if (*p == type)
34 return p + 1;
35 if (*p == 'n') // 'n' is always the last one
36 break;
37 p = vim_strchr(p, ','); // skip until next ','
38 if (p == NULL) // hit the end without finding parameter
39 break;
40 }
41 return NULL;
42 }
43
44 /*
45 * Find the parameter represented by the given character (eg ', :, ", or /),
46 * and return its associated value in the 'viminfo' string.
47 * Only works for number parameters, not for 'r' or 'n'.
48 * If the parameter is not specified in the string or there is no following
49 * number, return -1.
50 */
51 int
52 get_viminfo_parameter(int type)
53 {
54 char_u *p;
55
56 p = find_viminfo_parameter(type);
57 if (p != NULL && VIM_ISDIGIT(*p))
58 return atoi((char *)p);
59 return -1;
60 }
20 61
21 /* 62 /*
22 * Get the viminfo file name to use. 63 * Get the viminfo file name to use.
23 * If "file" is given and not empty, use it (has already been expanded by 64 * If "file" is given and not empty, use it (has already been expanded by
24 * cmdline functions). 65 * cmdline functions).
63 file = NameBuff; 104 file = NameBuff;
64 } 105 }
65 return vim_strsave(file); 106 return vim_strsave(file);
66 } 107 }
67 108
109 /*
110 * write string to viminfo file
111 * - replace CTRL-V with CTRL-V CTRL-V
112 * - replace '\n' with CTRL-V 'n'
113 * - add a '\n' at the end
114 *
115 * For a long line:
116 * - write " CTRL-V <length> \n " in first line
117 * - write " < <string> \n " in second line
118 */
119 static void
120 viminfo_writestring(FILE *fd, char_u *p)
121 {
122 int c;
123 char_u *s;
124 int len = 0;
125
126 for (s = p; *s != NUL; ++s)
127 {
128 if (*s == Ctrl_V || *s == '\n')
129 ++len;
130 ++len;
131 }
132
133 // If the string will be too long, write its length and put it in the next
134 // line. Take into account that some room is needed for what comes before
135 // the string (e.g., variable name). Add something to the length for the
136 // '<', NL and trailing NUL.
137 if (len > LSIZE / 2)
138 fprintf(fd, IF_EB("\026%d\n<", CTRL_V_STR "%d\n<"), len + 3);
139
140 while ((c = *p++) != NUL)
141 {
142 if (c == Ctrl_V || c == '\n')
143 {
144 putc(Ctrl_V, fd);
145 if (c == '\n')
146 c = 'n';
147 }
148 putc(c, fd);
149 }
150 putc('\n', fd);
151 }
152
153 /*
154 * Write a string in quotes that barline_parse() can read back.
155 * Breaks the line in less than LSIZE pieces when needed.
156 * Returns remaining characters in the line.
157 */
158 static int
159 barline_writestring(FILE *fd, char_u *s, int remaining_start)
160 {
161 char_u *p;
162 int remaining = remaining_start;
163 int len = 2;
164
165 // Count the number of characters produced, including quotes.
166 for (p = s; *p != NUL; ++p)
167 {
168 if (*p == NL)
169 len += 2;
170 else if (*p == '"' || *p == '\\')
171 len += 2;
172 else
173 ++len;
174 }
175 if (len > remaining - 2)
176 {
177 fprintf(fd, ">%d\n|<", len);
178 remaining = LSIZE - 20;
179 }
180
181 putc('"', fd);
182 for (p = s; *p != NUL; ++p)
183 {
184 if (*p == NL)
185 {
186 putc('\\', fd);
187 putc('n', fd);
188 --remaining;
189 }
190 else if (*p == '"' || *p == '\\')
191 {
192 putc('\\', fd);
193 putc(*p, fd);
194 --remaining;
195 }
196 else
197 putc(*p, fd);
198 --remaining;
199
200 if (remaining < 3)
201 {
202 putc('\n', fd);
203 putc('|', fd);
204 putc('<', fd);
205 // Leave enough space for another continuation.
206 remaining = LSIZE - 20;
207 }
208 }
209 putc('"', fd);
210 return remaining - 2;
211 }
212
213 /*
214 * Check string read from viminfo file.
215 * Remove '\n' at the end of the line.
216 * - replace CTRL-V CTRL-V with CTRL-V
217 * - replace CTRL-V 'n' with '\n'
218 *
219 * Check for a long line as written by viminfo_writestring().
220 *
221 * Return the string in allocated memory (NULL when out of memory).
222 */
223 static char_u *
224 viminfo_readstring(
225 vir_T *virp,
226 int off, // offset for virp->vir_line
227 int convert UNUSED) // convert the string
228 {
229 char_u *retval;
230 char_u *s, *d;
231 long len;
232
233 if (virp->vir_line[off] == Ctrl_V && vim_isdigit(virp->vir_line[off + 1]))
234 {
235 len = atol((char *)virp->vir_line + off + 1);
236 retval = lalloc(len, TRUE);
237 if (retval == NULL)
238 {
239 // Line too long? File messed up? Skip next line.
240 (void)vim_fgets(virp->vir_line, 10, virp->vir_fd);
241 return NULL;
242 }
243 (void)vim_fgets(retval, (int)len, virp->vir_fd);
244 s = retval + 1; // Skip the leading '<'
245 }
246 else
247 {
248 retval = vim_strsave(virp->vir_line + off);
249 if (retval == NULL)
250 return NULL;
251 s = retval;
252 }
253
254 // Change CTRL-V CTRL-V to CTRL-V and CTRL-V n to \n in-place.
255 d = retval;
256 while (*s != NUL && *s != '\n')
257 {
258 if (s[0] == Ctrl_V && s[1] != NUL)
259 {
260 if (s[1] == 'n')
261 *d++ = '\n';
262 else
263 *d++ = Ctrl_V;
264 s += 2;
265 }
266 else
267 *d++ = *s++;
268 }
269 *d = NUL;
270
271 if (convert && virp->vir_conv.vc_type != CONV_NONE && *retval != NUL)
272 {
273 d = string_convert(&virp->vir_conv, retval, NULL);
274 if (d != NULL)
275 {
276 vim_free(retval);
277 retval = d;
278 }
279 }
280
281 return retval;
282 }
283
284 /*
285 * Read a line from the viminfo file.
286 * Returns TRUE for end-of-file;
287 */
288 static int
289 viminfo_readline(vir_T *virp)
290 {
291 return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
292 }
293
68 static int 294 static int
69 read_viminfo_bufferlist( 295 read_viminfo_bufferlist(
70 vir_T *virp, 296 vir_T *virp,
71 int writing) 297 int writing)
72 { 298 {
115 } 341 }
116 } 342 }
117 vim_free(xline); 343 vim_free(xline);
118 344
119 return viminfo_readline(virp); 345 return viminfo_readline(virp);
346 }
347
348 /*
349 * Return TRUE if "name" is on removable media (depending on 'viminfo').
350 */
351 static int
352 removable(char_u *name)
353 {
354 char_u *p;
355 char_u part[51];
356 int retval = FALSE;
357 size_t n;
358
359 name = home_replace_save(NULL, name);
360 if (name != NULL)
361 {
362 for (p = p_viminfo; *p; )
363 {
364 copy_option_part(&p, part, 51, ", ");
365 if (part[0] == 'r')
366 {
367 n = STRLEN(part + 1);
368 if (MB_STRNICMP(part + 1, name, n) == 0)
369 {
370 retval = TRUE;
371 break;
372 }
373 }
374 }
375 vim_free(name);
376 }
377 return retval;
120 } 378 }
121 379
122 static void 380 static void
123 write_viminfo_bufferlist(FILE *fp) 381 write_viminfo_bufferlist(FILE *fp)
124 { 382 {
653 vim_free(viminfo_history[type][i].hisstr); 911 vim_free(viminfo_history[type][i].hisstr);
654 VIM_CLEAR(viminfo_history[type]); 912 VIM_CLEAR(viminfo_history[type]);
655 viminfo_hisidx[type] = 0; 913 viminfo_hisidx[type] = 0;
656 } 914 }
657 } 915 }
658 #endif // FEAT_VIMINFO 916 #endif // FEAT_CMDHIST
659 917
660 static void 918 static void
661 write_viminfo_barlines(vir_T *virp, FILE *fp_out) 919 write_viminfo_barlines(vir_T *virp, FILE *fp_out)
662 { 920 {
663 int i; 921 int i;
859 break; 1117 break;
860 } 1118 }
861 return TRUE; 1119 return TRUE;
862 } 1120 }
863 1121
864 static int
865 read_viminfo_barline(vir_T *virp, int got_encoding, int force, int writing)
866 {
867 char_u *p = virp->vir_line + 1;
868 int bartype;
869 garray_T values;
870 bval_T *vp;
871 int i;
872 int read_next = TRUE;
873
874 /*
875 * The format is: |{bartype},{value},...
876 * For a very long string:
877 * |{bartype},>{length of "{text}{text2}"}
878 * |<{text1}
879 * |<{text2},{value}
880 * For a long line not using a string
881 * |{bartype},{lots of values},>
882 * |<{value},{value}
883 */
884 if (*p == '<')
885 {
886 // Continuation line of an unrecognized item.
887 if (writing)
888 ga_add_string(&virp->vir_barlines, virp->vir_line);
889 }
890 else
891 {
892 ga_init2(&values, sizeof(bval_T), 20);
893 bartype = getdigits(&p);
894 switch (bartype)
895 {
896 case BARTYPE_VERSION:
897 // Only use the version when it comes before the encoding.
898 // If it comes later it was copied by a Vim version that
899 // doesn't understand the version.
900 if (!got_encoding)
901 {
902 read_next = barline_parse(virp, p, &values);
903 vp = (bval_T *)values.ga_data;
904 if (values.ga_len > 0 && vp->bv_type == BVAL_NR)
905 virp->vir_version = vp->bv_nr;
906 }
907 break;
908
909 case BARTYPE_HISTORY:
910 read_next = barline_parse(virp, p, &values);
911 handle_viminfo_history(&values, writing);
912 break;
913
914 case BARTYPE_REGISTER:
915 read_next = barline_parse(virp, p, &values);
916 handle_viminfo_register(&values, force);
917 break;
918
919 case BARTYPE_MARK:
920 read_next = barline_parse(virp, p, &values);
921 handle_viminfo_mark(&values, force);
922 break;
923
924 default:
925 // copy unrecognized line (for future use)
926 if (writing)
927 ga_add_string(&virp->vir_barlines, virp->vir_line);
928 }
929 for (i = 0; i < values.ga_len; ++i)
930 {
931 vp = (bval_T *)values.ga_data + i;
932 if (vp->bv_type == BVAL_STRING && vp->bv_allocated)
933 vim_free(vp->bv_string);
934 }
935 ga_clear(&values);
936 }
937
938 if (read_next)
939 return viminfo_readline(virp);
940 return FALSE;
941 }
942
943 static void 1122 static void
944 write_viminfo_version(FILE *fp_out) 1123 write_viminfo_version(FILE *fp_out)
945 { 1124 {
946 fprintf(fp_out, "# Viminfo version\n|%d,%d\n\n", 1125 fprintf(fp_out, "# Viminfo version\n|%d,%d\n\n",
947 BARTYPE_VERSION, VIMINFO_VERSION); 1126 BARTYPE_VERSION, VIMINFO_VERSION);
956 1135
957 /* 1136 /*
958 * Report an error for reading a viminfo file. 1137 * Report an error for reading a viminfo file.
959 * Count the number of errors. When there are more than 10, return TRUE. 1138 * Count the number of errors. When there are more than 10, return TRUE.
960 */ 1139 */
961 int 1140 static int
962 viminfo_error(char *errnum, char *message, char_u *line) 1141 viminfo_error(char *errnum, char *message, char_u *line)
963 { 1142 {
964 vim_snprintf((char *)IObuff, IOSIZE, _("%sviminfo: %s in line: "), 1143 vim_snprintf((char *)IObuff, IOSIZE, _("%sviminfo: %s in line: "),
965 errnum, message); 1144 errnum, message);
966 STRNCAT(IObuff, line, IOSIZE - STRLEN(IObuff) - 1); 1145 STRNCAT(IObuff, line, IOSIZE - STRLEN(IObuff) - 1);
1155 } 1334 }
1156 } 1335 }
1157 } 1336 }
1158 } 1337 }
1159 #endif // FEAT_EVAL 1338 #endif // FEAT_EVAL
1339
1340 static int
1341 read_viminfo_sub_string(vir_T *virp, int force)
1342 {
1343 if (force || get_old_sub() == NULL)
1344 set_old_sub(viminfo_readstring(virp, 1, TRUE));
1345 return viminfo_readline(virp);
1346 }
1347
1348 static void
1349 write_viminfo_sub_string(FILE *fp)
1350 {
1351 char_u *old_sub = get_old_sub();
1352
1353 if (get_viminfo_parameter('/') != 0 && old_sub != NULL)
1354 {
1355 fputs(_("\n# Last Substitute String:\n$"), fp);
1356 viminfo_writestring(fp, old_sub);
1357 }
1358 }
1359
1360 /*
1361 * Functions relating to reading/writing the search pattern from viminfo
1362 */
1363
1364 static int
1365 read_viminfo_search_pattern(vir_T *virp, int force)
1366 {
1367 char_u *lp;
1368 int idx = -1;
1369 int magic = FALSE;
1370 int no_scs = FALSE;
1371 int off_line = FALSE;
1372 int off_end = 0;
1373 long off = 0;
1374 int setlast = FALSE;
1375 #ifdef FEAT_SEARCH_EXTRA
1376 static int hlsearch_on = FALSE;
1377 #endif
1378 char_u *val;
1379 spat_T *spat;
1380
1381 // Old line types:
1382 // "/pat", "&pat": search/subst. pat
1383 // "~/pat", "~&pat": last used search/subst. pat
1384 // New line types:
1385 // "~h", "~H": hlsearch highlighting off/on
1386 // "~<magic><smartcase><line><end><off><last><which>pat"
1387 // <magic>: 'm' off, 'M' on
1388 // <smartcase>: 's' off, 'S' on
1389 // <line>: 'L' line offset, 'l' char offset
1390 // <end>: 'E' from end, 'e' from start
1391 // <off>: decimal, offset
1392 // <last>: '~' last used pattern
1393 // <which>: '/' search pat, '&' subst. pat
1394 lp = virp->vir_line;
1395 if (lp[0] == '~' && (lp[1] == 'm' || lp[1] == 'M')) // new line type
1396 {
1397 if (lp[1] == 'M') // magic on
1398 magic = TRUE;
1399 if (lp[2] == 's')
1400 no_scs = TRUE;
1401 if (lp[3] == 'L')
1402 off_line = TRUE;
1403 if (lp[4] == 'E')
1404 off_end = SEARCH_END;
1405 lp += 5;
1406 off = getdigits(&lp);
1407 }
1408 if (lp[0] == '~') // use this pattern for last-used pattern
1409 {
1410 setlast = TRUE;
1411 lp++;
1412 }
1413 if (lp[0] == '/')
1414 idx = RE_SEARCH;
1415 else if (lp[0] == '&')
1416 idx = RE_SUBST;
1417 #ifdef FEAT_SEARCH_EXTRA
1418 else if (lp[0] == 'h') // ~h: 'hlsearch' highlighting off
1419 hlsearch_on = FALSE;
1420 else if (lp[0] == 'H') // ~H: 'hlsearch' highlighting on
1421 hlsearch_on = TRUE;
1422 #endif
1423 spat = get_spat(idx);
1424 if (idx >= 0)
1425 {
1426 if (force || spat->pat == NULL)
1427 {
1428 val = viminfo_readstring(virp, (int)(lp - virp->vir_line + 1),
1429 TRUE);
1430 if (val != NULL)
1431 {
1432 set_last_search_pat(val, idx, magic, setlast);
1433 vim_free(val);
1434 spat->no_scs = no_scs;
1435 spat->off.line = off_line;
1436 spat->off.end = off_end;
1437 spat->off.off = off;
1438 #ifdef FEAT_SEARCH_EXTRA
1439 if (setlast)
1440 set_no_hlsearch(!hlsearch_on);
1441 #endif
1442 }
1443 }
1444 }
1445 return viminfo_readline(virp);
1446 }
1447
1448 static void
1449 wvsp_one(
1450 FILE *fp, // file to write to
1451 int idx, // spats[] index
1452 char *s, // search pat
1453 int sc) // dir char
1454 {
1455 spat_T *spat = get_spat(idx);
1456 if (spat->pat != NULL)
1457 {
1458 fprintf(fp, _("\n# Last %sSearch Pattern:\n~"), s);
1459 // off.dir is not stored, it's reset to forward
1460 fprintf(fp, "%c%c%c%c%ld%s%c",
1461 spat->magic ? 'M' : 'm', // magic
1462 spat->no_scs ? 's' : 'S', // smartcase
1463 spat->off.line ? 'L' : 'l', // line offset
1464 spat->off.end ? 'E' : 'e', // offset from end
1465 spat->off.off, // offset
1466 get_spat_last_idx() == idx ? "~" : "", // last used pat
1467 sc);
1468 viminfo_writestring(fp, spat->pat);
1469 }
1470 }
1471
1472 static void
1473 write_viminfo_search_pattern(FILE *fp)
1474 {
1475 if (get_viminfo_parameter('/') != 0)
1476 {
1477 #ifdef FEAT_SEARCH_EXTRA
1478 fprintf(fp, "\n# hlsearch on (H) or off (h):\n~%c",
1479 (no_hlsearch || find_viminfo_parameter('h') != NULL) ? 'h' : 'H');
1480 #endif
1481 wvsp_one(fp, RE_SEARCH, "", '/');
1482 wvsp_one(fp, RE_SUBST, _("Substitute "), '&');
1483 }
1484 }
1485
1486 /*
1487 * Functions relating to reading/writing registers from viminfo
1488 */
1489
1490 static yankreg_T *y_read_regs = NULL;
1491
1492 #define REG_PREVIOUS 1
1493 #define REG_EXEC 2
1494
1495 /*
1496 * Prepare for reading viminfo registers when writing viminfo later.
1497 */
1498 static void
1499 prepare_viminfo_registers(void)
1500 {
1501 y_read_regs = ALLOC_CLEAR_MULT(yankreg_T, NUM_REGISTERS);
1502 }
1503
1504 static void
1505 finish_viminfo_registers(void)
1506 {
1507 int i;
1508 int j;
1509
1510 if (y_read_regs != NULL)
1511 {
1512 for (i = 0; i < NUM_REGISTERS; ++i)
1513 if (y_read_regs[i].y_array != NULL)
1514 {
1515 for (j = 0; j < y_read_regs[i].y_size; j++)
1516 vim_free(y_read_regs[i].y_array[j]);
1517 vim_free(y_read_regs[i].y_array);
1518 }
1519 VIM_CLEAR(y_read_regs);
1520 }
1521 }
1522
1523 static int
1524 read_viminfo_register(vir_T *virp, int force)
1525 {
1526 int eof;
1527 int do_it = TRUE;
1528 int size;
1529 int limit;
1530 int i;
1531 int set_prev = FALSE;
1532 char_u *str;
1533 char_u **array = NULL;
1534 int new_type = MCHAR; // init to shut up compiler
1535 colnr_T new_width = 0; // init to shut up compiler
1536 yankreg_T *y_current_p;
1537
1538 // We only get here (hopefully) if line[0] == '"'
1539 str = virp->vir_line + 1;
1540
1541 // If the line starts with "" this is the y_previous register.
1542 if (*str == '"')
1543 {
1544 set_prev = TRUE;
1545 str++;
1546 }
1547
1548 if (!ASCII_ISALNUM(*str) && *str != '-')
1549 {
1550 if (viminfo_error("E577: ", _("Illegal register name"), virp->vir_line))
1551 return TRUE; // too many errors, pretend end-of-file
1552 do_it = FALSE;
1553 }
1554 get_yank_register(*str++, FALSE);
1555 y_current_p = get_y_current();
1556 if (!force && y_current_p->y_array != NULL)
1557 do_it = FALSE;
1558
1559 if (*str == '@')
1560 {
1561 // "x@: register x used for @@
1562 if (force || get_execreg_lastc() == NUL)
1563 set_execreg_lastc(str[-1]);
1564 }
1565
1566 size = 0;
1567 limit = 100; // Optimized for registers containing <= 100 lines
1568 if (do_it)
1569 {
1570 // Build the new register in array[].
1571 // y_array is kept as-is until done.
1572 // The "do_it" flag is reset when something is wrong, in which case
1573 // array[] needs to be freed.
1574 if (set_prev)
1575 set_y_previous(y_current_p);
1576 array = ALLOC_MULT(char_u *, limit);
1577 str = skipwhite(skiptowhite(str));
1578 if (STRNCMP(str, "CHAR", 4) == 0)
1579 new_type = MCHAR;
1580 else if (STRNCMP(str, "BLOCK", 5) == 0)
1581 new_type = MBLOCK;
1582 else
1583 new_type = MLINE;
1584 // get the block width; if it's missing we get a zero, which is OK
1585 str = skipwhite(skiptowhite(str));
1586 new_width = getdigits(&str);
1587 }
1588
1589 while (!(eof = viminfo_readline(virp))
1590 && (virp->vir_line[0] == TAB || virp->vir_line[0] == '<'))
1591 {
1592 if (do_it)
1593 {
1594 if (size == limit)
1595 {
1596 char_u **new_array = (char_u **)
1597 alloc(limit * 2 * sizeof(char_u *));
1598
1599 if (new_array == NULL)
1600 {
1601 do_it = FALSE;
1602 break;
1603 }
1604 for (i = 0; i < limit; i++)
1605 new_array[i] = array[i];
1606 vim_free(array);
1607 array = new_array;
1608 limit *= 2;
1609 }
1610 str = viminfo_readstring(virp, 1, TRUE);
1611 if (str != NULL)
1612 array[size++] = str;
1613 else
1614 // error, don't store the result
1615 do_it = FALSE;
1616 }
1617 }
1618
1619 if (do_it)
1620 {
1621 // free y_array[]
1622 for (i = 0; i < y_current_p->y_size; i++)
1623 vim_free(y_current_p->y_array[i]);
1624 vim_free(y_current_p->y_array);
1625
1626 y_current_p->y_type = new_type;
1627 y_current_p->y_width = new_width;
1628 y_current_p->y_size = size;
1629 y_current_p->y_time_set = 0;
1630 if (size == 0)
1631 {
1632 y_current_p->y_array = NULL;
1633 }
1634 else
1635 {
1636 // Move the lines from array[] to y_array[].
1637 y_current_p->y_array = ALLOC_MULT(char_u *, size);
1638 for (i = 0; i < size; i++)
1639 {
1640 if (y_current_p->y_array == NULL)
1641 vim_free(array[i]);
1642 else
1643 y_current_p->y_array[i] = array[i];
1644 }
1645 }
1646 }
1647 else
1648 {
1649 // Free array[] if it was filled.
1650 for (i = 0; i < size; i++)
1651 vim_free(array[i]);
1652 }
1653 vim_free(array);
1654
1655 return eof;
1656 }
1657
1658 /*
1659 * Accept a new style register line from the viminfo, store it when it's new.
1660 */
1661 static void
1662 handle_viminfo_register(garray_T *values, int force)
1663 {
1664 bval_T *vp = (bval_T *)values->ga_data;
1665 int flags;
1666 int name;
1667 int type;
1668 int linecount;
1669 int width;
1670 time_t timestamp;
1671 yankreg_T *y_ptr;
1672 yankreg_T *y_regs_p = get_y_regs();
1673 int i;
1674
1675 // Check the format:
1676 // |{bartype},{flags},{name},{type},
1677 // {linecount},{width},{timestamp},"line1","line2"
1678 if (values->ga_len < 6
1679 || vp[0].bv_type != BVAL_NR
1680 || vp[1].bv_type != BVAL_NR
1681 || vp[2].bv_type != BVAL_NR
1682 || vp[3].bv_type != BVAL_NR
1683 || vp[4].bv_type != BVAL_NR
1684 || vp[5].bv_type != BVAL_NR)
1685 return;
1686 flags = vp[0].bv_nr;
1687 name = vp[1].bv_nr;
1688 if (name < 0 || name >= NUM_REGISTERS)
1689 return;
1690 type = vp[2].bv_nr;
1691 if (type != MCHAR && type != MLINE && type != MBLOCK)
1692 return;
1693 linecount = vp[3].bv_nr;
1694 if (values->ga_len < 6 + linecount)
1695 return;
1696 width = vp[4].bv_nr;
1697 if (width < 0)
1698 return;
1699
1700 if (y_read_regs != NULL)
1701 // Reading viminfo for merging and writing. Store the register
1702 // content, don't update the current registers.
1703 y_ptr = &y_read_regs[name];
1704 else
1705 y_ptr = &y_regs_p[name];
1706
1707 // Do not overwrite unless forced or the timestamp is newer.
1708 timestamp = (time_t)vp[5].bv_nr;
1709 if (y_ptr->y_array != NULL && !force
1710 && (timestamp == 0 || y_ptr->y_time_set > timestamp))
1711 return;
1712
1713 if (y_ptr->y_array != NULL)
1714 for (i = 0; i < y_ptr->y_size; i++)
1715 vim_free(y_ptr->y_array[i]);
1716 vim_free(y_ptr->y_array);
1717
1718 if (y_read_regs == NULL)
1719 {
1720 if (flags & REG_PREVIOUS)
1721 set_y_previous(y_ptr);
1722 if ((flags & REG_EXEC) && (force || get_execreg_lastc() == NUL))
1723 set_execreg_lastc(get_register_name(name));
1724 }
1725 y_ptr->y_type = type;
1726 y_ptr->y_width = width;
1727 y_ptr->y_size = linecount;
1728 y_ptr->y_time_set = timestamp;
1729 if (linecount == 0)
1730 {
1731 y_ptr->y_array = NULL;
1732 return;
1733 }
1734 y_ptr->y_array = ALLOC_MULT(char_u *, linecount);
1735 if (y_ptr->y_array == NULL)
1736 {
1737 y_ptr->y_size = 0; // ensure object state is consistent
1738 return;
1739 }
1740 for (i = 0; i < linecount; i++)
1741 {
1742 if (vp[i + 6].bv_allocated)
1743 {
1744 y_ptr->y_array[i] = vp[i + 6].bv_string;
1745 vp[i + 6].bv_string = NULL;
1746 }
1747 else
1748 y_ptr->y_array[i] = vim_strsave(vp[i + 6].bv_string);
1749 }
1750 }
1751
1752 static void
1753 write_viminfo_registers(FILE *fp)
1754 {
1755 int i, j;
1756 char_u *type;
1757 char_u c;
1758 int num_lines;
1759 int max_num_lines;
1760 int max_kbyte;
1761 long len;
1762 yankreg_T *y_ptr;
1763 yankreg_T *y_regs_p = get_y_regs();;
1764
1765 fputs(_("\n# Registers:\n"), fp);
1766
1767 // Get '<' value, use old '"' value if '<' is not found.
1768 max_num_lines = get_viminfo_parameter('<');
1769 if (max_num_lines < 0)
1770 max_num_lines = get_viminfo_parameter('"');
1771 if (max_num_lines == 0)
1772 return;
1773 max_kbyte = get_viminfo_parameter('s');
1774 if (max_kbyte == 0)
1775 return;
1776
1777 for (i = 0; i < NUM_REGISTERS; i++)
1778 {
1779 #ifdef FEAT_CLIPBOARD
1780 // Skip '*'/'+' register, we don't want them back next time
1781 if (i == STAR_REGISTER || i == PLUS_REGISTER)
1782 continue;
1783 #endif
1784 #ifdef FEAT_DND
1785 // Neither do we want the '~' register
1786 if (i == TILDE_REGISTER)
1787 continue;
1788 #endif
1789 // When reading viminfo for merging and writing: Use the register from
1790 // viminfo if it's newer.
1791 if (y_read_regs != NULL
1792 && y_read_regs[i].y_array != NULL
1793 && (y_regs_p[i].y_array == NULL ||
1794 y_read_regs[i].y_time_set > y_regs_p[i].y_time_set))
1795 y_ptr = &y_read_regs[i];
1796 else if (y_regs_p[i].y_array == NULL)
1797 continue;
1798 else
1799 y_ptr = &y_regs_p[i];
1800
1801 // Skip empty registers.
1802 num_lines = y_ptr->y_size;
1803 if (num_lines == 0
1804 || (num_lines == 1 && y_ptr->y_type == MCHAR
1805 && *y_ptr->y_array[0] == NUL))
1806 continue;
1807
1808 if (max_kbyte > 0)
1809 {
1810 // Skip register if there is more text than the maximum size.
1811 len = 0;
1812 for (j = 0; j < num_lines; j++)
1813 len += (long)STRLEN(y_ptr->y_array[j]) + 1L;
1814 if (len > (long)max_kbyte * 1024L)
1815 continue;
1816 }
1817
1818 switch (y_ptr->y_type)
1819 {
1820 case MLINE:
1821 type = (char_u *)"LINE";
1822 break;
1823 case MCHAR:
1824 type = (char_u *)"CHAR";
1825 break;
1826 case MBLOCK:
1827 type = (char_u *)"BLOCK";
1828 break;
1829 default:
1830 semsg(_("E574: Unknown register type %d"), y_ptr->y_type);
1831 type = (char_u *)"LINE";
1832 break;
1833 }
1834 if (get_y_previous() == &y_regs_p[i])
1835 fprintf(fp, "\"");
1836 c = get_register_name(i);
1837 fprintf(fp, "\"%c", c);
1838 if (c == get_execreg_lastc())
1839 fprintf(fp, "@");
1840 fprintf(fp, "\t%s\t%d\n", type, (int)y_ptr->y_width);
1841
1842 // If max_num_lines < 0, then we save ALL the lines in the register
1843 if (max_num_lines > 0 && num_lines > max_num_lines)
1844 num_lines = max_num_lines;
1845 for (j = 0; j < num_lines; j++)
1846 {
1847 putc('\t', fp);
1848 viminfo_writestring(fp, y_ptr->y_array[j]);
1849 }
1850
1851 {
1852 int flags = 0;
1853 int remaining;
1854
1855 // New style with a bar line. Format:
1856 // |{bartype},{flags},{name},{type},
1857 // {linecount},{width},{timestamp},"line1","line2"
1858 // flags: REG_PREVIOUS - register is y_previous
1859 // REG_EXEC - used for @@
1860 if (get_y_previous() == &y_regs_p[i])
1861 flags |= REG_PREVIOUS;
1862 if (c == get_execreg_lastc())
1863 flags |= REG_EXEC;
1864 fprintf(fp, "|%d,%d,%d,%d,%d,%d,%ld", BARTYPE_REGISTER, flags,
1865 i, y_ptr->y_type, num_lines, (int)y_ptr->y_width,
1866 (long)y_ptr->y_time_set);
1867 // 11 chars for type/flags/name/type, 3 * 20 for numbers
1868 remaining = LSIZE - 71;
1869 for (j = 0; j < num_lines; j++)
1870 {
1871 putc(',', fp);
1872 --remaining;
1873 remaining = barline_writestring(fp, y_ptr->y_array[j],
1874 remaining);
1875 }
1876 putc('\n', fp);
1877 }
1878 }
1879 }
1880
1881 /*
1882 * Functions relating to reading/writing marks from viminfo
1883 */
1884
1885 static xfmark_T *vi_namedfm = NULL;
1886 #ifdef FEAT_JUMPLIST
1887 static xfmark_T *vi_jumplist = NULL;
1888 static int vi_jumplist_len = 0;
1889 #endif
1890
1891 static void
1892 write_one_mark(FILE *fp_out, int c, pos_T *pos)
1893 {
1894 if (pos->lnum != 0)
1895 fprintf(fp_out, "\t%c\t%ld\t%d\n", c, (long)pos->lnum, (int)pos->col);
1896 }
1897
1898 static void
1899 write_buffer_marks(buf_T *buf, FILE *fp_out)
1900 {
1901 int i;
1902 pos_T pos;
1903
1904 home_replace(NULL, buf->b_ffname, IObuff, IOSIZE, TRUE);
1905 fprintf(fp_out, "\n> ");
1906 viminfo_writestring(fp_out, IObuff);
1907
1908 // Write the last used timestamp as the lnum of the non-existing mark '*'.
1909 // Older Vims will ignore it and/or copy it.
1910 pos.lnum = (linenr_T)buf->b_last_used;
1911 pos.col = 0;
1912 write_one_mark(fp_out, '*', &pos);
1913
1914 write_one_mark(fp_out, '"', &buf->b_last_cursor);
1915 write_one_mark(fp_out, '^', &buf->b_last_insert);
1916 write_one_mark(fp_out, '.', &buf->b_last_change);
1917 #ifdef FEAT_JUMPLIST
1918 // changelist positions are stored oldest first
1919 for (i = 0; i < buf->b_changelistlen; ++i)
1920 {
1921 // skip duplicates
1922 if (i == 0 || !EQUAL_POS(buf->b_changelist[i - 1],
1923 buf->b_changelist[i]))
1924 write_one_mark(fp_out, '+', &buf->b_changelist[i]);
1925 }
1926 #endif
1927 for (i = 0; i < NMARKS; i++)
1928 write_one_mark(fp_out, 'a' + i, &buf->b_namedm[i]);
1929 }
1930
1931 /*
1932 * Return TRUE if marks for "buf" should not be written.
1933 */
1934 static int
1935 skip_for_viminfo(buf_T *buf)
1936 {
1937 return
1938 #ifdef FEAT_TERMINAL
1939 bt_terminal(buf) ||
1940 #endif
1941 removable(buf->b_ffname);
1942 }
1943
1944 /*
1945 * Write all the named marks for all buffers.
1946 * When "buflist" is not NULL fill it with the buffers for which marks are to
1947 * be written.
1948 */
1949 static void
1950 write_viminfo_marks(FILE *fp_out, garray_T *buflist)
1951 {
1952 buf_T *buf;
1953 int is_mark_set;
1954 int i;
1955 win_T *win;
1956 tabpage_T *tp;
1957
1958 // Set b_last_cursor for the all buffers that have a window.
1959 FOR_ALL_TAB_WINDOWS(tp, win)
1960 set_last_cursor(win);
1961
1962 fputs(_("\n# History of marks within files (newest to oldest):\n"), fp_out);
1963 FOR_ALL_BUFFERS(buf)
1964 {
1965 // Only write something if buffer has been loaded and at least one
1966 // mark is set.
1967 if (buf->b_marks_read)
1968 {
1969 if (buf->b_last_cursor.lnum != 0)
1970 is_mark_set = TRUE;
1971 else
1972 {
1973 is_mark_set = FALSE;
1974 for (i = 0; i < NMARKS; i++)
1975 if (buf->b_namedm[i].lnum != 0)
1976 {
1977 is_mark_set = TRUE;
1978 break;
1979 }
1980 }
1981 if (is_mark_set && buf->b_ffname != NULL
1982 && buf->b_ffname[0] != NUL
1983 && !skip_for_viminfo(buf))
1984 {
1985 if (buflist == NULL)
1986 write_buffer_marks(buf, fp_out);
1987 else if (ga_grow(buflist, 1) == OK)
1988 ((buf_T **)buflist->ga_data)[buflist->ga_len++] = buf;
1989 }
1990 }
1991 }
1992 }
1993
1994 static void
1995 write_one_filemark(
1996 FILE *fp,
1997 xfmark_T *fm,
1998 int c1,
1999 int c2)
2000 {
2001 char_u *name;
2002
2003 if (fm->fmark.mark.lnum == 0) // not set
2004 return;
2005
2006 if (fm->fmark.fnum != 0) // there is a buffer
2007 name = buflist_nr2name(fm->fmark.fnum, TRUE, FALSE);
2008 else
2009 name = fm->fname; // use name from .viminfo
2010 if (name != NULL && *name != NUL)
2011 {
2012 fprintf(fp, "%c%c %ld %ld ", c1, c2, (long)fm->fmark.mark.lnum,
2013 (long)fm->fmark.mark.col);
2014 viminfo_writestring(fp, name);
2015
2016 // Barline: |{bartype},{name},{lnum},{col},{timestamp},{filename}
2017 // size up to filename: 8 + 3 * 20
2018 fprintf(fp, "|%d,%d,%ld,%ld,%ld,", BARTYPE_MARK, c2,
2019 (long)fm->fmark.mark.lnum, (long)fm->fmark.mark.col,
2020 (long)fm->time_set);
2021 barline_writestring(fp, name, LSIZE - 70);
2022 putc('\n', fp);
2023 }
2024
2025 if (fm->fmark.fnum != 0)
2026 vim_free(name);
2027 }
2028
2029 static void
2030 write_viminfo_filemarks(FILE *fp)
2031 {
2032 int i;
2033 char_u *name;
2034 buf_T *buf;
2035 xfmark_T *namedfm_p = get_namedfm();
2036 xfmark_T *fm;
2037 int vi_idx;
2038 int idx;
2039
2040 if (get_viminfo_parameter('f') == 0)
2041 return;
2042
2043 fputs(_("\n# File marks:\n"), fp);
2044
2045 // Write the filemarks 'A - 'Z
2046 for (i = 0; i < NMARKS; i++)
2047 {
2048 if (vi_namedfm != NULL
2049 && (vi_namedfm[i].time_set > namedfm_p[i].time_set
2050 || namedfm_p[i].fmark.mark.lnum == 0))
2051 fm = &vi_namedfm[i];
2052 else
2053 fm = &namedfm_p[i];
2054 write_one_filemark(fp, fm, '\'', i + 'A');
2055 }
2056
2057 // Find a mark that is the same file and position as the cursor.
2058 // That one, or else the last one is deleted.
2059 // Move '0 to '1, '1 to '2, etc. until the matching one or '9
2060 // Set the '0 mark to current cursor position.
2061 if (curbuf->b_ffname != NULL && !skip_for_viminfo(curbuf))
2062 {
2063 name = buflist_nr2name(curbuf->b_fnum, TRUE, FALSE);
2064 for (i = NMARKS; i < NMARKS + EXTRA_MARKS - 1; ++i)
2065 if (namedfm_p[i].fmark.mark.lnum == curwin->w_cursor.lnum
2066 && (namedfm_p[i].fname == NULL
2067 ? namedfm_p[i].fmark.fnum == curbuf->b_fnum
2068 : (name != NULL
2069 && STRCMP(name, namedfm_p[i].fname) == 0)))
2070 break;
2071 vim_free(name);
2072
2073 vim_free(namedfm_p[i].fname);
2074 for ( ; i > NMARKS; --i)
2075 namedfm_p[i] = namedfm_p[i - 1];
2076 namedfm_p[NMARKS].fmark.mark = curwin->w_cursor;
2077 namedfm_p[NMARKS].fmark.fnum = curbuf->b_fnum;
2078 namedfm_p[NMARKS].fname = NULL;
2079 namedfm_p[NMARKS].time_set = vim_time();
2080 }
2081
2082 // Write the filemarks '0 - '9. Newest (highest timestamp) first.
2083 vi_idx = NMARKS;
2084 idx = NMARKS;
2085 for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
2086 {
2087 xfmark_T *vi_fm = vi_namedfm != NULL ? &vi_namedfm[vi_idx] : NULL;
2088
2089 if (vi_fm != NULL
2090 && vi_fm->fmark.mark.lnum != 0
2091 && (vi_fm->time_set > namedfm_p[idx].time_set
2092 || namedfm_p[idx].fmark.mark.lnum == 0))
2093 {
2094 fm = vi_fm;
2095 ++vi_idx;
2096 }
2097 else
2098 {
2099 fm = &namedfm_p[idx++];
2100 if (vi_fm != NULL
2101 && vi_fm->fmark.mark.lnum == fm->fmark.mark.lnum
2102 && vi_fm->time_set == fm->time_set
2103 && ((vi_fm->fmark.fnum != 0
2104 && vi_fm->fmark.fnum == fm->fmark.fnum)
2105 || (vi_fm->fname != NULL
2106 && fm->fname != NULL
2107 && STRCMP(vi_fm->fname, fm->fname) == 0)))
2108 ++vi_idx; // skip duplicate
2109 }
2110 write_one_filemark(fp, fm, '\'', i - NMARKS + '0');
2111 }
2112
2113 #ifdef FEAT_JUMPLIST
2114 // Write the jumplist with -'
2115 fputs(_("\n# Jumplist (newest first):\n"), fp);
2116 setpcmark(); // add current cursor position
2117 cleanup_jumplist(curwin, FALSE);
2118 vi_idx = 0;
2119 idx = curwin->w_jumplistlen - 1;
2120 for (i = 0; i < JUMPLISTSIZE; ++i)
2121 {
2122 xfmark_T *vi_fm;
2123
2124 fm = idx >= 0 ? &curwin->w_jumplist[idx] : NULL;
2125 vi_fm = vi_idx < vi_jumplist_len ? &vi_jumplist[vi_idx] : NULL;
2126 if (fm == NULL && vi_fm == NULL)
2127 break;
2128 if (fm == NULL || (vi_fm != NULL && fm->time_set < vi_fm->time_set))
2129 {
2130 fm = vi_fm;
2131 ++vi_idx;
2132 }
2133 else
2134 --idx;
2135 if (fm->fmark.fnum == 0
2136 || ((buf = buflist_findnr(fm->fmark.fnum)) != NULL
2137 && !skip_for_viminfo(buf)))
2138 write_one_filemark(fp, fm, '-', '\'');
2139 }
2140 #endif
2141 }
2142
2143 /*
2144 * Compare functions for qsort() below, that compares b_last_used.
2145 */
2146 static int
2147 buf_compare(const void *s1, const void *s2)
2148 {
2149 buf_T *buf1 = *(buf_T **)s1;
2150 buf_T *buf2 = *(buf_T **)s2;
2151
2152 if (buf1->b_last_used == buf2->b_last_used)
2153 return 0;
2154 return buf1->b_last_used > buf2->b_last_used ? -1 : 1;
2155 }
2156
2157 /*
2158 * Handle marks in the viminfo file:
2159 * fp_out != NULL: copy marks, in time order with buffers in "buflist".
2160 * fp_out == NULL && (flags & VIF_WANT_MARKS): read marks for curbuf only
2161 * fp_out == NULL && (flags & VIF_GET_OLDFILES | VIF_FORCEIT): fill v:oldfiles
2162 */
2163 static void
2164 copy_viminfo_marks(
2165 vir_T *virp,
2166 FILE *fp_out,
2167 garray_T *buflist,
2168 int eof,
2169 int flags)
2170 {
2171 char_u *line = virp->vir_line;
2172 buf_T *buf;
2173 int num_marked_files;
2174 int load_marks;
2175 int copy_marks_out;
2176 char_u *str;
2177 int i;
2178 char_u *p;
2179 char_u *name_buf;
2180 pos_T pos;
2181 #ifdef FEAT_EVAL
2182 list_T *list = NULL;
2183 #endif
2184 int count = 0;
2185 int buflist_used = 0;
2186 buf_T *buflist_buf = NULL;
2187
2188 if ((name_buf = alloc(LSIZE)) == NULL)
2189 return;
2190 *name_buf = NUL;
2191
2192 if (fp_out != NULL && buflist->ga_len > 0)
2193 {
2194 // Sort the list of buffers on b_last_used.
2195 qsort(buflist->ga_data, (size_t)buflist->ga_len,
2196 sizeof(buf_T *), buf_compare);
2197 buflist_buf = ((buf_T **)buflist->ga_data)[0];
2198 }
2199
2200 #ifdef FEAT_EVAL
2201 if (fp_out == NULL && (flags & (VIF_GET_OLDFILES | VIF_FORCEIT)))
2202 {
2203 list = list_alloc();
2204 if (list != NULL)
2205 set_vim_var_list(VV_OLDFILES, list);
2206 }
2207 #endif
2208
2209 num_marked_files = get_viminfo_parameter('\'');
2210 while (!eof && (count < num_marked_files || fp_out == NULL))
2211 {
2212 if (line[0] != '>')
2213 {
2214 if (line[0] != '\n' && line[0] != '\r' && line[0] != '#')
2215 {
2216 if (viminfo_error("E576: ", _("Missing '>'"), line))
2217 break; // too many errors, return now
2218 }
2219 eof = vim_fgets(line, LSIZE, virp->vir_fd);
2220 continue; // Skip this dud line
2221 }
2222
2223 // Handle long line and translate escaped characters.
2224 // Find file name, set str to start.
2225 // Ignore leading and trailing white space.
2226 str = skipwhite(line + 1);
2227 str = viminfo_readstring(virp, (int)(str - virp->vir_line), FALSE);
2228 if (str == NULL)
2229 continue;
2230 p = str + STRLEN(str);
2231 while (p != str && (*p == NUL || vim_isspace(*p)))
2232 p--;
2233 if (*p)
2234 p++;
2235 *p = NUL;
2236
2237 #ifdef FEAT_EVAL
2238 if (list != NULL)
2239 list_append_string(list, str, -1);
2240 #endif
2241
2242 // If fp_out == NULL, load marks for current buffer.
2243 // If fp_out != NULL, copy marks for buffers not in buflist.
2244 load_marks = copy_marks_out = FALSE;
2245 if (fp_out == NULL)
2246 {
2247 if ((flags & VIF_WANT_MARKS) && curbuf->b_ffname != NULL)
2248 {
2249 if (*name_buf == NUL) // only need to do this once
2250 home_replace(NULL, curbuf->b_ffname, name_buf, LSIZE, TRUE);
2251 if (fnamecmp(str, name_buf) == 0)
2252 load_marks = TRUE;
2253 }
2254 }
2255 else // fp_out != NULL
2256 {
2257 // This is slow if there are many buffers!!
2258 FOR_ALL_BUFFERS(buf)
2259 if (buf->b_ffname != NULL)
2260 {
2261 home_replace(NULL, buf->b_ffname, name_buf, LSIZE, TRUE);
2262 if (fnamecmp(str, name_buf) == 0)
2263 break;
2264 }
2265
2266 // Copy marks if the buffer has not been loaded.
2267 if (buf == NULL || !buf->b_marks_read)
2268 {
2269 int did_read_line = FALSE;
2270
2271 if (buflist_buf != NULL)
2272 {
2273 // Read the next line. If it has the "*" mark compare the
2274 // time stamps. Write entries from "buflist" that are
2275 // newer.
2276 if (!(eof = viminfo_readline(virp)) && line[0] == TAB)
2277 {
2278 did_read_line = TRUE;
2279 if (line[1] == '*')
2280 {
2281 long ltime;
2282
2283 sscanf((char *)line + 2, "%ld ", &ltime);
2284 while ((time_T)ltime < buflist_buf->b_last_used)
2285 {
2286 write_buffer_marks(buflist_buf, fp_out);
2287 if (++count >= num_marked_files)
2288 break;
2289 if (++buflist_used == buflist->ga_len)
2290 {
2291 buflist_buf = NULL;
2292 break;
2293 }
2294 buflist_buf =
2295 ((buf_T **)buflist->ga_data)[buflist_used];
2296 }
2297 }
2298 else
2299 {
2300 // No timestamp, must be written by an older Vim.
2301 // Assume all remaining buffers are older then
2302 // ours.
2303 while (count < num_marked_files
2304 && buflist_used < buflist->ga_len)
2305 {
2306 buflist_buf = ((buf_T **)buflist->ga_data)
2307 [buflist_used++];
2308 write_buffer_marks(buflist_buf, fp_out);
2309 ++count;
2310 }
2311 buflist_buf = NULL;
2312 }
2313
2314 if (count >= num_marked_files)
2315 {
2316 vim_free(str);
2317 break;
2318 }
2319 }
2320 }
2321
2322 fputs("\n> ", fp_out);
2323 viminfo_writestring(fp_out, str);
2324 if (did_read_line)
2325 fputs((char *)line, fp_out);
2326
2327 count++;
2328 copy_marks_out = TRUE;
2329 }
2330 }
2331 vim_free(str);
2332
2333 pos.coladd = 0;
2334 while (!(eof = viminfo_readline(virp)) && line[0] == TAB)
2335 {
2336 if (load_marks)
2337 {
2338 if (line[1] != NUL)
2339 {
2340 unsigned u;
2341
2342 sscanf((char *)line + 2, "%ld %u", &pos.lnum, &u);
2343 pos.col = u;
2344 switch (line[1])
2345 {
2346 case '"': curbuf->b_last_cursor = pos; break;
2347 case '^': curbuf->b_last_insert = pos; break;
2348 case '.': curbuf->b_last_change = pos; break;
2349 case '+':
2350 #ifdef FEAT_JUMPLIST
2351 // changelist positions are stored oldest
2352 // first
2353 if (curbuf->b_changelistlen == JUMPLISTSIZE)
2354 // list is full, remove oldest entry
2355 mch_memmove(curbuf->b_changelist,
2356 curbuf->b_changelist + 1,
2357 sizeof(pos_T) * (JUMPLISTSIZE - 1));
2358 else
2359 ++curbuf->b_changelistlen;
2360 curbuf->b_changelist[
2361 curbuf->b_changelistlen - 1] = pos;
2362 #endif
2363 break;
2364
2365 // Using the line number for the last-used
2366 // timestamp.
2367 case '*': curbuf->b_last_used = pos.lnum; break;
2368
2369 default: if ((i = line[1] - 'a') >= 0 && i < NMARKS)
2370 curbuf->b_namedm[i] = pos;
2371 }
2372 }
2373 }
2374 else if (copy_marks_out)
2375 fputs((char *)line, fp_out);
2376 }
2377
2378 if (load_marks)
2379 {
2380 #ifdef FEAT_JUMPLIST
2381 win_T *wp;
2382
2383 FOR_ALL_WINDOWS(wp)
2384 {
2385 if (wp->w_buffer == curbuf)
2386 wp->w_changelistidx = curbuf->b_changelistlen;
2387 }
2388 #endif
2389 break;
2390 }
2391 }
2392
2393 if (fp_out != NULL)
2394 // Write any remaining entries from buflist.
2395 while (count < num_marked_files && buflist_used < buflist->ga_len)
2396 {
2397 buflist_buf = ((buf_T **)buflist->ga_data)[buflist_used++];
2398 write_buffer_marks(buflist_buf, fp_out);
2399 ++count;
2400 }
2401
2402 vim_free(name_buf);
2403 }
2404
2405 /*
2406 * Read marks for the current buffer from the viminfo file, when we support
2407 * buffer marks and the buffer has a name.
2408 */
2409 void
2410 check_marks_read(void)
2411 {
2412 if (!curbuf->b_marks_read && get_viminfo_parameter('\'') > 0
2413 && curbuf->b_ffname != NULL)
2414 read_viminfo(NULL, VIF_WANT_MARKS);
2415
2416 // Always set b_marks_read; needed when 'viminfo' is changed to include
2417 // the ' parameter after opening a buffer.
2418 curbuf->b_marks_read = TRUE;
2419 }
2420
2421 static int
2422 read_viminfo_filemark(vir_T *virp, int force)
2423 {
2424 char_u *str;
2425 xfmark_T *namedfm_p = get_namedfm();
2426 xfmark_T *fm;
2427 int i;
2428
2429 // We only get here if line[0] == '\'' or '-'.
2430 // Illegal mark names are ignored (for future expansion).
2431 str = virp->vir_line + 1;
2432 if (
2433 #ifndef EBCDIC
2434 *str <= 127 &&
2435 #endif
2436 ((*virp->vir_line == '\'' && (VIM_ISDIGIT(*str) || isupper(*str)))
2437 || (*virp->vir_line == '-' && *str == '\'')))
2438 {
2439 if (*str == '\'')
2440 {
2441 #ifdef FEAT_JUMPLIST
2442 // If the jumplist isn't full insert fmark as oldest entry
2443 if (curwin->w_jumplistlen == JUMPLISTSIZE)
2444 fm = NULL;
2445 else
2446 {
2447 for (i = curwin->w_jumplistlen; i > 0; --i)
2448 curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
2449 ++curwin->w_jumplistidx;
2450 ++curwin->w_jumplistlen;
2451 fm = &curwin->w_jumplist[0];
2452 fm->fmark.mark.lnum = 0;
2453 fm->fname = NULL;
2454 }
2455 #else
2456 fm = NULL;
2457 #endif
2458 }
2459 else if (VIM_ISDIGIT(*str))
2460 fm = &namedfm_p[*str - '0' + NMARKS];
2461 else
2462 fm = &namedfm_p[*str - 'A'];
2463 if (fm != NULL && (fm->fmark.mark.lnum == 0 || force))
2464 {
2465 str = skipwhite(str + 1);
2466 fm->fmark.mark.lnum = getdigits(&str);
2467 str = skipwhite(str);
2468 fm->fmark.mark.col = getdigits(&str);
2469 fm->fmark.mark.coladd = 0;
2470 fm->fmark.fnum = 0;
2471 str = skipwhite(str);
2472 vim_free(fm->fname);
2473 fm->fname = viminfo_readstring(virp, (int)(str - virp->vir_line),
2474 FALSE);
2475 fm->time_set = 0;
2476 }
2477 }
2478 return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
2479 }
2480
2481 /*
2482 * Prepare for reading viminfo marks when writing viminfo later.
2483 */
2484 static void
2485 prepare_viminfo_marks(void)
2486 {
2487 vi_namedfm = ALLOC_CLEAR_MULT(xfmark_T, NMARKS + EXTRA_MARKS);
2488 #ifdef FEAT_JUMPLIST
2489 vi_jumplist = ALLOC_CLEAR_MULT(xfmark_T, JUMPLISTSIZE);
2490 vi_jumplist_len = 0;
2491 #endif
2492 }
2493
2494 static void
2495 finish_viminfo_marks(void)
2496 {
2497 int i;
2498
2499 if (vi_namedfm != NULL)
2500 {
2501 for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
2502 vim_free(vi_namedfm[i].fname);
2503 VIM_CLEAR(vi_namedfm);
2504 }
2505 #ifdef FEAT_JUMPLIST
2506 if (vi_jumplist != NULL)
2507 {
2508 for (i = 0; i < vi_jumplist_len; ++i)
2509 vim_free(vi_jumplist[i].fname);
2510 VIM_CLEAR(vi_jumplist);
2511 }
2512 #endif
2513 }
2514
2515 /*
2516 * Accept a new style mark line from the viminfo, store it when it's new.
2517 */
2518 static void
2519 handle_viminfo_mark(garray_T *values, int force)
2520 {
2521 bval_T *vp = (bval_T *)values->ga_data;
2522 int name;
2523 linenr_T lnum;
2524 colnr_T col;
2525 time_t timestamp;
2526 xfmark_T *fm = NULL;
2527
2528 // Check the format:
2529 // |{bartype},{name},{lnum},{col},{timestamp},{filename}
2530 if (values->ga_len < 5
2531 || vp[0].bv_type != BVAL_NR
2532 || vp[1].bv_type != BVAL_NR
2533 || vp[2].bv_type != BVAL_NR
2534 || vp[3].bv_type != BVAL_NR
2535 || vp[4].bv_type != BVAL_STRING)
2536 return;
2537
2538 name = vp[0].bv_nr;
2539 if (name != '\'' && !VIM_ISDIGIT(name) && !ASCII_ISUPPER(name))
2540 return;
2541 lnum = vp[1].bv_nr;
2542 col = vp[2].bv_nr;
2543 if (lnum <= 0 || col < 0)
2544 return;
2545 timestamp = (time_t)vp[3].bv_nr;
2546
2547 if (name == '\'')
2548 {
2549 #ifdef FEAT_JUMPLIST
2550 if (vi_jumplist != NULL)
2551 {
2552 if (vi_jumplist_len < JUMPLISTSIZE)
2553 fm = &vi_jumplist[vi_jumplist_len++];
2554 }
2555 else
2556 {
2557 int idx;
2558 int i;
2559
2560 // If we have a timestamp insert it in the right place.
2561 if (timestamp != 0)
2562 {
2563 for (idx = curwin->w_jumplistlen - 1; idx >= 0; --idx)
2564 if (curwin->w_jumplist[idx].time_set < timestamp)
2565 {
2566 ++idx;
2567 break;
2568 }
2569 // idx cannot be zero now
2570 if (idx < 0 && curwin->w_jumplistlen < JUMPLISTSIZE)
2571 // insert as the oldest entry
2572 idx = 0;
2573 }
2574 else if (curwin->w_jumplistlen < JUMPLISTSIZE)
2575 // insert as oldest entry
2576 idx = 0;
2577 else
2578 idx = -1;
2579
2580 if (idx >= 0)
2581 {
2582 if (curwin->w_jumplistlen == JUMPLISTSIZE)
2583 {
2584 // Drop the oldest entry.
2585 --idx;
2586 vim_free(curwin->w_jumplist[0].fname);
2587 for (i = 0; i < idx; ++i)
2588 curwin->w_jumplist[i] = curwin->w_jumplist[i + 1];
2589 }
2590 else
2591 {
2592 // Move newer entries forward.
2593 for (i = curwin->w_jumplistlen; i > idx; --i)
2594 curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
2595 ++curwin->w_jumplistidx;
2596 ++curwin->w_jumplistlen;
2597 }
2598 fm = &curwin->w_jumplist[idx];
2599 fm->fmark.mark.lnum = 0;
2600 fm->fname = NULL;
2601 fm->time_set = 0;
2602 }
2603 }
2604 #endif
2605 }
2606 else
2607 {
2608 int idx;
2609 xfmark_T *namedfm_p = get_namedfm();
2610
2611 if (VIM_ISDIGIT(name))
2612 {
2613 if (vi_namedfm != NULL)
2614 idx = name - '0' + NMARKS;
2615 else
2616 {
2617 int i;
2618
2619 // Do not use the name from the viminfo file, insert in time
2620 // order.
2621 for (idx = NMARKS; idx < NMARKS + EXTRA_MARKS; ++idx)
2622 if (namedfm_p[idx].time_set < timestamp)
2623 break;
2624 if (idx == NMARKS + EXTRA_MARKS)
2625 // All existing entries are newer.
2626 return;
2627 i = NMARKS + EXTRA_MARKS - 1;
2628
2629 vim_free(namedfm_p[i].fname);
2630 for ( ; i > idx; --i)
2631 namedfm_p[i] = namedfm_p[i - 1];
2632 namedfm_p[idx].fname = NULL;
2633 }
2634 }
2635 else
2636 idx = name - 'A';
2637 if (vi_namedfm != NULL)
2638 fm = &vi_namedfm[idx];
2639 else
2640 fm = &namedfm_p[idx];
2641 }
2642
2643 if (fm != NULL)
2644 {
2645 if (vi_namedfm != NULL || fm->fmark.mark.lnum == 0
2646 || fm->time_set < timestamp || force)
2647 {
2648 fm->fmark.mark.lnum = lnum;
2649 fm->fmark.mark.col = col;
2650 fm->fmark.mark.coladd = 0;
2651 fm->fmark.fnum = 0;
2652 vim_free(fm->fname);
2653 if (vp[4].bv_allocated)
2654 {
2655 fm->fname = vp[4].bv_string;
2656 vp[4].bv_string = NULL;
2657 }
2658 else
2659 fm->fname = vim_strsave(vp[4].bv_string);
2660 fm->time_set = timestamp;
2661 }
2662 }
2663 }
2664
2665 static int
2666 read_viminfo_barline(vir_T *virp, int got_encoding, int force, int writing)
2667 {
2668 char_u *p = virp->vir_line + 1;
2669 int bartype;
2670 garray_T values;
2671 bval_T *vp;
2672 int i;
2673 int read_next = TRUE;
2674
2675 /*
2676 * The format is: |{bartype},{value},...
2677 * For a very long string:
2678 * |{bartype},>{length of "{text}{text2}"}
2679 * |<{text1}
2680 * |<{text2},{value}
2681 * For a long line not using a string
2682 * |{bartype},{lots of values},>
2683 * |<{value},{value}
2684 */
2685 if (*p == '<')
2686 {
2687 // Continuation line of an unrecognized item.
2688 if (writing)
2689 ga_add_string(&virp->vir_barlines, virp->vir_line);
2690 }
2691 else
2692 {
2693 ga_init2(&values, sizeof(bval_T), 20);
2694 bartype = getdigits(&p);
2695 switch (bartype)
2696 {
2697 case BARTYPE_VERSION:
2698 // Only use the version when it comes before the encoding.
2699 // If it comes later it was copied by a Vim version that
2700 // doesn't understand the version.
2701 if (!got_encoding)
2702 {
2703 read_next = barline_parse(virp, p, &values);
2704 vp = (bval_T *)values.ga_data;
2705 if (values.ga_len > 0 && vp->bv_type == BVAL_NR)
2706 virp->vir_version = vp->bv_nr;
2707 }
2708 break;
2709
2710 case BARTYPE_HISTORY:
2711 read_next = barline_parse(virp, p, &values);
2712 handle_viminfo_history(&values, writing);
2713 break;
2714
2715 case BARTYPE_REGISTER:
2716 read_next = barline_parse(virp, p, &values);
2717 handle_viminfo_register(&values, force);
2718 break;
2719
2720 case BARTYPE_MARK:
2721 read_next = barline_parse(virp, p, &values);
2722 handle_viminfo_mark(&values, force);
2723 break;
2724
2725 default:
2726 // copy unrecognized line (for future use)
2727 if (writing)
2728 ga_add_string(&virp->vir_barlines, virp->vir_line);
2729 }
2730 for (i = 0; i < values.ga_len; ++i)
2731 {
2732 vp = (bval_T *)values.ga_data + i;
2733 if (vp->bv_type == BVAL_STRING && vp->bv_allocated)
2734 vim_free(vp->bv_string);
2735 }
2736 ga_clear(&values);
2737 }
2738
2739 if (read_next)
2740 return viminfo_readline(virp);
2741 return FALSE;
2742 }
1160 2743
1161 /* 2744 /*
1162 * read_viminfo_up_to_marks() -- Only called from do_viminfo(). Reads in the 2745 * read_viminfo_up_to_marks() -- Only called from do_viminfo(). Reads in the
1163 * first part of the viminfo file which contains everything but the marks that 2746 * first part of the viminfo file which contains everything but the marks that
1164 * are local to a file. Returns TRUE when end-of-file is reached. -- webb 2747 * are local to a file. Returns TRUE when end-of-file is reached. -- webb
1700 vim_free(fname); 3283 vim_free(fname);
1701 vim_free(tempname); 3284 vim_free(tempname);
1702 } 3285 }
1703 3286
1704 /* 3287 /*
1705 * Read a line from the viminfo file.
1706 * Returns TRUE for end-of-file;
1707 */
1708 int
1709 viminfo_readline(vir_T *virp)
1710 {
1711 return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
1712 }
1713
1714 /*
1715 * Check string read from viminfo file.
1716 * Remove '\n' at the end of the line.
1717 * - replace CTRL-V CTRL-V with CTRL-V
1718 * - replace CTRL-V 'n' with '\n'
1719 *
1720 * Check for a long line as written by viminfo_writestring().
1721 *
1722 * Return the string in allocated memory (NULL when out of memory).
1723 */
1724 char_u *
1725 viminfo_readstring(
1726 vir_T *virp,
1727 int off, // offset for virp->vir_line
1728 int convert UNUSED) // convert the string
1729 {
1730 char_u *retval;
1731 char_u *s, *d;
1732 long len;
1733
1734 if (virp->vir_line[off] == Ctrl_V && vim_isdigit(virp->vir_line[off + 1]))
1735 {
1736 len = atol((char *)virp->vir_line + off + 1);
1737 retval = lalloc(len, TRUE);
1738 if (retval == NULL)
1739 {
1740 // Line too long? File messed up? Skip next line.
1741 (void)vim_fgets(virp->vir_line, 10, virp->vir_fd);
1742 return NULL;
1743 }
1744 (void)vim_fgets(retval, (int)len, virp->vir_fd);
1745 s = retval + 1; // Skip the leading '<'
1746 }
1747 else
1748 {
1749 retval = vim_strsave(virp->vir_line + off);
1750 if (retval == NULL)
1751 return NULL;
1752 s = retval;
1753 }
1754
1755 // Change CTRL-V CTRL-V to CTRL-V and CTRL-V n to \n in-place.
1756 d = retval;
1757 while (*s != NUL && *s != '\n')
1758 {
1759 if (s[0] == Ctrl_V && s[1] != NUL)
1760 {
1761 if (s[1] == 'n')
1762 *d++ = '\n';
1763 else
1764 *d++ = Ctrl_V;
1765 s += 2;
1766 }
1767 else
1768 *d++ = *s++;
1769 }
1770 *d = NUL;
1771
1772 if (convert && virp->vir_conv.vc_type != CONV_NONE && *retval != NUL)
1773 {
1774 d = string_convert(&virp->vir_conv, retval, NULL);
1775 if (d != NULL)
1776 {
1777 vim_free(retval);
1778 retval = d;
1779 }
1780 }
1781
1782 return retval;
1783 }
1784
1785 /*
1786 * write string to viminfo file
1787 * - replace CTRL-V with CTRL-V CTRL-V
1788 * - replace '\n' with CTRL-V 'n'
1789 * - add a '\n' at the end
1790 *
1791 * For a long line:
1792 * - write " CTRL-V <length> \n " in first line
1793 * - write " < <string> \n " in second line
1794 */
1795 void
1796 viminfo_writestring(FILE *fd, char_u *p)
1797 {
1798 int c;
1799 char_u *s;
1800 int len = 0;
1801
1802 for (s = p; *s != NUL; ++s)
1803 {
1804 if (*s == Ctrl_V || *s == '\n')
1805 ++len;
1806 ++len;
1807 }
1808
1809 // If the string will be too long, write its length and put it in the next
1810 // line. Take into account that some room is needed for what comes before
1811 // the string (e.g., variable name). Add something to the length for the
1812 // '<', NL and trailing NUL.
1813 if (len > LSIZE / 2)
1814 fprintf(fd, IF_EB("\026%d\n<", CTRL_V_STR "%d\n<"), len + 3);
1815
1816 while ((c = *p++) != NUL)
1817 {
1818 if (c == Ctrl_V || c == '\n')
1819 {
1820 putc(Ctrl_V, fd);
1821 if (c == '\n')
1822 c = 'n';
1823 }
1824 putc(c, fd);
1825 }
1826 putc('\n', fd);
1827 }
1828
1829 /*
1830 * Write a string in quotes that barline_parse() can read back.
1831 * Breaks the line in less than LSIZE pieces when needed.
1832 * Returns remaining characters in the line.
1833 */
1834 int
1835 barline_writestring(FILE *fd, char_u *s, int remaining_start)
1836 {
1837 char_u *p;
1838 int remaining = remaining_start;
1839 int len = 2;
1840
1841 // Count the number of characters produced, including quotes.
1842 for (p = s; *p != NUL; ++p)
1843 {
1844 if (*p == NL)
1845 len += 2;
1846 else if (*p == '"' || *p == '\\')
1847 len += 2;
1848 else
1849 ++len;
1850 }
1851 if (len > remaining - 2)
1852 {
1853 fprintf(fd, ">%d\n|<", len);
1854 remaining = LSIZE - 20;
1855 }
1856
1857 putc('"', fd);
1858 for (p = s; *p != NUL; ++p)
1859 {
1860 if (*p == NL)
1861 {
1862 putc('\\', fd);
1863 putc('n', fd);
1864 --remaining;
1865 }
1866 else if (*p == '"' || *p == '\\')
1867 {
1868 putc('\\', fd);
1869 putc(*p, fd);
1870 --remaining;
1871 }
1872 else
1873 putc(*p, fd);
1874 --remaining;
1875
1876 if (remaining < 3)
1877 {
1878 putc('\n', fd);
1879 putc('|', fd);
1880 putc('<', fd);
1881 // Leave enough space for another continuation.
1882 remaining = LSIZE - 20;
1883 }
1884 }
1885 putc('"', fd);
1886 return remaining - 2;
1887 }
1888
1889 /*
1890 * ":rviminfo" and ":wviminfo". 3288 * ":rviminfo" and ":wviminfo".
1891 */ 3289 */
1892 void 3290 void
1893 ex_viminfo( 3291 ex_viminfo(
1894 exarg_T *eap) 3292 exarg_T *eap)
1907 else 3305 else
1908 write_viminfo(eap->arg, eap->forceit); 3306 write_viminfo(eap->arg, eap->forceit);
1909 p_viminfo = save_viminfo; 3307 p_viminfo = save_viminfo;
1910 } 3308 }
1911 3309
1912 int
1913 read_viminfo_filemark(vir_T *virp, int force)
1914 {
1915 char_u *str;
1916 xfmark_T *namedfm_p = get_namedfm();
1917 xfmark_T *fm;
1918 int i;
1919
1920 // We only get here if line[0] == '\'' or '-'.
1921 // Illegal mark names are ignored (for future expansion).
1922 str = virp->vir_line + 1;
1923 if (
1924 #ifndef EBCDIC
1925 *str <= 127 &&
1926 #endif
1927 ((*virp->vir_line == '\'' && (VIM_ISDIGIT(*str) || isupper(*str)))
1928 || (*virp->vir_line == '-' && *str == '\'')))
1929 {
1930 if (*str == '\'')
1931 {
1932 #ifdef FEAT_JUMPLIST
1933 // If the jumplist isn't full insert fmark as oldest entry
1934 if (curwin->w_jumplistlen == JUMPLISTSIZE)
1935 fm = NULL;
1936 else
1937 {
1938 for (i = curwin->w_jumplistlen; i > 0; --i)
1939 curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
1940 ++curwin->w_jumplistidx;
1941 ++curwin->w_jumplistlen;
1942 fm = &curwin->w_jumplist[0];
1943 fm->fmark.mark.lnum = 0;
1944 fm->fname = NULL;
1945 }
1946 #else
1947 fm = NULL;
1948 #endif
1949 }
1950 else if (VIM_ISDIGIT(*str))
1951 fm = &namedfm_p[*str - '0' + NMARKS];
1952 else
1953 fm = &namedfm_p[*str - 'A'];
1954 if (fm != NULL && (fm->fmark.mark.lnum == 0 || force))
1955 {
1956 str = skipwhite(str + 1);
1957 fm->fmark.mark.lnum = getdigits(&str);
1958 str = skipwhite(str);
1959 fm->fmark.mark.col = getdigits(&str);
1960 fm->fmark.mark.coladd = 0;
1961 fm->fmark.fnum = 0;
1962 str = skipwhite(str);
1963 vim_free(fm->fname);
1964 fm->fname = viminfo_readstring(virp, (int)(str - virp->vir_line),
1965 FALSE);
1966 fm->time_set = 0;
1967 }
1968 }
1969 return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
1970 }
1971
1972 static xfmark_T *vi_namedfm = NULL;
1973 #ifdef FEAT_JUMPLIST
1974 static xfmark_T *vi_jumplist = NULL;
1975 static int vi_jumplist_len = 0;
1976 #endif
1977
1978 /*
1979 * Prepare for reading viminfo marks when writing viminfo later.
1980 */
1981 void
1982 prepare_viminfo_marks(void)
1983 {
1984 vi_namedfm = ALLOC_CLEAR_MULT(xfmark_T, NMARKS + EXTRA_MARKS);
1985 #ifdef FEAT_JUMPLIST
1986 vi_jumplist = ALLOC_CLEAR_MULT(xfmark_T, JUMPLISTSIZE);
1987 vi_jumplist_len = 0;
1988 #endif
1989 }
1990
1991 void
1992 finish_viminfo_marks(void)
1993 {
1994 int i;
1995
1996 if (vi_namedfm != NULL)
1997 {
1998 for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
1999 vim_free(vi_namedfm[i].fname);
2000 VIM_CLEAR(vi_namedfm);
2001 }
2002 #ifdef FEAT_JUMPLIST
2003 if (vi_jumplist != NULL)
2004 {
2005 for (i = 0; i < vi_jumplist_len; ++i)
2006 vim_free(vi_jumplist[i].fname);
2007 VIM_CLEAR(vi_jumplist);
2008 }
2009 #endif
2010 }
2011
2012 /*
2013 * Accept a new style mark line from the viminfo, store it when it's new.
2014 */
2015 void
2016 handle_viminfo_mark(garray_T *values, int force)
2017 {
2018 bval_T *vp = (bval_T *)values->ga_data;
2019 int name;
2020 linenr_T lnum;
2021 colnr_T col;
2022 time_t timestamp;
2023 xfmark_T *fm = NULL;
2024
2025 // Check the format:
2026 // |{bartype},{name},{lnum},{col},{timestamp},{filename}
2027 if (values->ga_len < 5
2028 || vp[0].bv_type != BVAL_NR
2029 || vp[1].bv_type != BVAL_NR
2030 || vp[2].bv_type != BVAL_NR
2031 || vp[3].bv_type != BVAL_NR
2032 || vp[4].bv_type != BVAL_STRING)
2033 return;
2034
2035 name = vp[0].bv_nr;
2036 if (name != '\'' && !VIM_ISDIGIT(name) && !ASCII_ISUPPER(name))
2037 return;
2038 lnum = vp[1].bv_nr;
2039 col = vp[2].bv_nr;
2040 if (lnum <= 0 || col < 0)
2041 return;
2042 timestamp = (time_t)vp[3].bv_nr;
2043
2044 if (name == '\'')
2045 {
2046 #ifdef FEAT_JUMPLIST
2047 if (vi_jumplist != NULL)
2048 {
2049 if (vi_jumplist_len < JUMPLISTSIZE)
2050 fm = &vi_jumplist[vi_jumplist_len++];
2051 }
2052 else
2053 {
2054 int idx;
2055 int i;
2056
2057 // If we have a timestamp insert it in the right place.
2058 if (timestamp != 0)
2059 {
2060 for (idx = curwin->w_jumplistlen - 1; idx >= 0; --idx)
2061 if (curwin->w_jumplist[idx].time_set < timestamp)
2062 {
2063 ++idx;
2064 break;
2065 }
2066 // idx cannot be zero now
2067 if (idx < 0 && curwin->w_jumplistlen < JUMPLISTSIZE)
2068 // insert as the oldest entry
2069 idx = 0;
2070 }
2071 else if (curwin->w_jumplistlen < JUMPLISTSIZE)
2072 // insert as oldest entry
2073 idx = 0;
2074 else
2075 idx = -1;
2076
2077 if (idx >= 0)
2078 {
2079 if (curwin->w_jumplistlen == JUMPLISTSIZE)
2080 {
2081 // Drop the oldest entry.
2082 --idx;
2083 vim_free(curwin->w_jumplist[0].fname);
2084 for (i = 0; i < idx; ++i)
2085 curwin->w_jumplist[i] = curwin->w_jumplist[i + 1];
2086 }
2087 else
2088 {
2089 // Move newer entries forward.
2090 for (i = curwin->w_jumplistlen; i > idx; --i)
2091 curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
2092 ++curwin->w_jumplistidx;
2093 ++curwin->w_jumplistlen;
2094 }
2095 fm = &curwin->w_jumplist[idx];
2096 fm->fmark.mark.lnum = 0;
2097 fm->fname = NULL;
2098 fm->time_set = 0;
2099 }
2100 }
2101 #endif
2102 }
2103 else
2104 {
2105 int idx;
2106 xfmark_T *namedfm_p = get_namedfm();
2107
2108 if (VIM_ISDIGIT(name))
2109 {
2110 if (vi_namedfm != NULL)
2111 idx = name - '0' + NMARKS;
2112 else
2113 {
2114 int i;
2115
2116 // Do not use the name from the viminfo file, insert in time
2117 // order.
2118 for (idx = NMARKS; idx < NMARKS + EXTRA_MARKS; ++idx)
2119 if (namedfm_p[idx].time_set < timestamp)
2120 break;
2121 if (idx == NMARKS + EXTRA_MARKS)
2122 // All existing entries are newer.
2123 return;
2124 i = NMARKS + EXTRA_MARKS - 1;
2125
2126 vim_free(namedfm_p[i].fname);
2127 for ( ; i > idx; --i)
2128 namedfm_p[i] = namedfm_p[i - 1];
2129 namedfm_p[idx].fname = NULL;
2130 }
2131 }
2132 else
2133 idx = name - 'A';
2134 if (vi_namedfm != NULL)
2135 fm = &vi_namedfm[idx];
2136 else
2137 fm = &namedfm_p[idx];
2138 }
2139
2140 if (fm != NULL)
2141 {
2142 if (vi_namedfm != NULL || fm->fmark.mark.lnum == 0
2143 || fm->time_set < timestamp || force)
2144 {
2145 fm->fmark.mark.lnum = lnum;
2146 fm->fmark.mark.col = col;
2147 fm->fmark.mark.coladd = 0;
2148 fm->fmark.fnum = 0;
2149 vim_free(fm->fname);
2150 if (vp[4].bv_allocated)
2151 {
2152 fm->fname = vp[4].bv_string;
2153 vp[4].bv_string = NULL;
2154 }
2155 else
2156 fm->fname = vim_strsave(vp[4].bv_string);
2157 fm->time_set = timestamp;
2158 }
2159 }
2160 }
2161
2162 /*
2163 * Return TRUE if marks for "buf" should not be written.
2164 */
2165 static int
2166 skip_for_viminfo(buf_T *buf)
2167 {
2168 return
2169 #ifdef FEAT_TERMINAL
2170 bt_terminal(buf) ||
2171 #endif
2172 removable(buf->b_ffname);
2173 }
2174
2175 static void
2176 write_one_filemark(
2177 FILE *fp,
2178 xfmark_T *fm,
2179 int c1,
2180 int c2)
2181 {
2182 char_u *name;
2183
2184 if (fm->fmark.mark.lnum == 0) // not set
2185 return;
2186
2187 if (fm->fmark.fnum != 0) // there is a buffer
2188 name = buflist_nr2name(fm->fmark.fnum, TRUE, FALSE);
2189 else
2190 name = fm->fname; // use name from .viminfo
2191 if (name != NULL && *name != NUL)
2192 {
2193 fprintf(fp, "%c%c %ld %ld ", c1, c2, (long)fm->fmark.mark.lnum,
2194 (long)fm->fmark.mark.col);
2195 viminfo_writestring(fp, name);
2196
2197 // Barline: |{bartype},{name},{lnum},{col},{timestamp},{filename}
2198 // size up to filename: 8 + 3 * 20
2199 fprintf(fp, "|%d,%d,%ld,%ld,%ld,", BARTYPE_MARK, c2,
2200 (long)fm->fmark.mark.lnum, (long)fm->fmark.mark.col,
2201 (long)fm->time_set);
2202 barline_writestring(fp, name, LSIZE - 70);
2203 putc('\n', fp);
2204 }
2205
2206 if (fm->fmark.fnum != 0)
2207 vim_free(name);
2208 }
2209
2210 void
2211 write_viminfo_filemarks(FILE *fp)
2212 {
2213 int i;
2214 char_u *name;
2215 buf_T *buf;
2216 xfmark_T *namedfm_p = get_namedfm();
2217 xfmark_T *fm;
2218 int vi_idx;
2219 int idx;
2220
2221 if (get_viminfo_parameter('f') == 0)
2222 return;
2223
2224 fputs(_("\n# File marks:\n"), fp);
2225
2226 // Write the filemarks 'A - 'Z
2227 for (i = 0; i < NMARKS; i++)
2228 {
2229 if (vi_namedfm != NULL
2230 && (vi_namedfm[i].time_set > namedfm_p[i].time_set
2231 || namedfm_p[i].fmark.mark.lnum == 0))
2232 fm = &vi_namedfm[i];
2233 else
2234 fm = &namedfm_p[i];
2235 write_one_filemark(fp, fm, '\'', i + 'A');
2236 }
2237
2238 // Find a mark that is the same file and position as the cursor.
2239 // That one, or else the last one is deleted.
2240 // Move '0 to '1, '1 to '2, etc. until the matching one or '9
2241 // Set the '0 mark to current cursor position.
2242 if (curbuf->b_ffname != NULL && !skip_for_viminfo(curbuf))
2243 {
2244 name = buflist_nr2name(curbuf->b_fnum, TRUE, FALSE);
2245 for (i = NMARKS; i < NMARKS + EXTRA_MARKS - 1; ++i)
2246 if (namedfm_p[i].fmark.mark.lnum == curwin->w_cursor.lnum
2247 && (namedfm_p[i].fname == NULL
2248 ? namedfm_p[i].fmark.fnum == curbuf->b_fnum
2249 : (name != NULL
2250 && STRCMP(name, namedfm_p[i].fname) == 0)))
2251 break;
2252 vim_free(name);
2253
2254 vim_free(namedfm_p[i].fname);
2255 for ( ; i > NMARKS; --i)
2256 namedfm_p[i] = namedfm_p[i - 1];
2257 namedfm_p[NMARKS].fmark.mark = curwin->w_cursor;
2258 namedfm_p[NMARKS].fmark.fnum = curbuf->b_fnum;
2259 namedfm_p[NMARKS].fname = NULL;
2260 namedfm_p[NMARKS].time_set = vim_time();
2261 }
2262
2263 // Write the filemarks '0 - '9. Newest (highest timestamp) first.
2264 vi_idx = NMARKS;
2265 idx = NMARKS;
2266 for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
2267 {
2268 xfmark_T *vi_fm = vi_namedfm != NULL ? &vi_namedfm[vi_idx] : NULL;
2269
2270 if (vi_fm != NULL
2271 && vi_fm->fmark.mark.lnum != 0
2272 && (vi_fm->time_set > namedfm_p[idx].time_set
2273 || namedfm_p[idx].fmark.mark.lnum == 0))
2274 {
2275 fm = vi_fm;
2276 ++vi_idx;
2277 }
2278 else
2279 {
2280 fm = &namedfm_p[idx++];
2281 if (vi_fm != NULL
2282 && vi_fm->fmark.mark.lnum == fm->fmark.mark.lnum
2283 && vi_fm->time_set == fm->time_set
2284 && ((vi_fm->fmark.fnum != 0
2285 && vi_fm->fmark.fnum == fm->fmark.fnum)
2286 || (vi_fm->fname != NULL
2287 && fm->fname != NULL
2288 && STRCMP(vi_fm->fname, fm->fname) == 0)))
2289 ++vi_idx; // skip duplicate
2290 }
2291 write_one_filemark(fp, fm, '\'', i - NMARKS + '0');
2292 }
2293
2294 #ifdef FEAT_JUMPLIST
2295 // Write the jumplist with -'
2296 fputs(_("\n# Jumplist (newest first):\n"), fp);
2297 setpcmark(); // add current cursor position
2298 cleanup_jumplist(curwin, FALSE);
2299 vi_idx = 0;
2300 idx = curwin->w_jumplistlen - 1;
2301 for (i = 0; i < JUMPLISTSIZE; ++i)
2302 {
2303 xfmark_T *vi_fm;
2304
2305 fm = idx >= 0 ? &curwin->w_jumplist[idx] : NULL;
2306 vi_fm = vi_idx < vi_jumplist_len ? &vi_jumplist[vi_idx] : NULL;
2307 if (fm == NULL && vi_fm == NULL)
2308 break;
2309 if (fm == NULL || (vi_fm != NULL && fm->time_set < vi_fm->time_set))
2310 {
2311 fm = vi_fm;
2312 ++vi_idx;
2313 }
2314 else
2315 --idx;
2316 if (fm->fmark.fnum == 0
2317 || ((buf = buflist_findnr(fm->fmark.fnum)) != NULL
2318 && !skip_for_viminfo(buf)))
2319 write_one_filemark(fp, fm, '-', '\'');
2320 }
2321 #endif
2322 }
2323
2324 /*
2325 * Return TRUE if "name" is on removable media (depending on 'viminfo').
2326 */
2327 int
2328 removable(char_u *name)
2329 {
2330 char_u *p;
2331 char_u part[51];
2332 int retval = FALSE;
2333 size_t n;
2334
2335 name = home_replace_save(NULL, name);
2336 if (name != NULL)
2337 {
2338 for (p = p_viminfo; *p; )
2339 {
2340 copy_option_part(&p, part, 51, ", ");
2341 if (part[0] == 'r')
2342 {
2343 n = STRLEN(part + 1);
2344 if (MB_STRNICMP(part + 1, name, n) == 0)
2345 {
2346 retval = TRUE;
2347 break;
2348 }
2349 }
2350 }
2351 vim_free(name);
2352 }
2353 return retval;
2354 }
2355
2356 static void
2357 write_one_mark(FILE *fp_out, int c, pos_T *pos)
2358 {
2359 if (pos->lnum != 0)
2360 fprintf(fp_out, "\t%c\t%ld\t%d\n", c, (long)pos->lnum, (int)pos->col);
2361 }
2362
2363
2364 static void
2365 write_buffer_marks(buf_T *buf, FILE *fp_out)
2366 {
2367 int i;
2368 pos_T pos;
2369
2370 home_replace(NULL, buf->b_ffname, IObuff, IOSIZE, TRUE);
2371 fprintf(fp_out, "\n> ");
2372 viminfo_writestring(fp_out, IObuff);
2373
2374 // Write the last used timestamp as the lnum of the non-existing mark '*'.
2375 // Older Vims will ignore it and/or copy it.
2376 pos.lnum = (linenr_T)buf->b_last_used;
2377 pos.col = 0;
2378 write_one_mark(fp_out, '*', &pos);
2379
2380 write_one_mark(fp_out, '"', &buf->b_last_cursor);
2381 write_one_mark(fp_out, '^', &buf->b_last_insert);
2382 write_one_mark(fp_out, '.', &buf->b_last_change);
2383 #ifdef FEAT_JUMPLIST
2384 // changelist positions are stored oldest first
2385 for (i = 0; i < buf->b_changelistlen; ++i)
2386 {
2387 // skip duplicates
2388 if (i == 0 || !EQUAL_POS(buf->b_changelist[i - 1],
2389 buf->b_changelist[i]))
2390 write_one_mark(fp_out, '+', &buf->b_changelist[i]);
2391 }
2392 #endif
2393 for (i = 0; i < NMARKS; i++)
2394 write_one_mark(fp_out, 'a' + i, &buf->b_namedm[i]);
2395 }
2396
2397 /*
2398 * Write all the named marks for all buffers.
2399 * When "buflist" is not NULL fill it with the buffers for which marks are to
2400 * be written.
2401 */
2402 void
2403 write_viminfo_marks(FILE *fp_out, garray_T *buflist)
2404 {
2405 buf_T *buf;
2406 int is_mark_set;
2407 int i;
2408 win_T *win;
2409 tabpage_T *tp;
2410
2411 // Set b_last_cursor for the all buffers that have a window.
2412 FOR_ALL_TAB_WINDOWS(tp, win)
2413 set_last_cursor(win);
2414
2415 fputs(_("\n# History of marks within files (newest to oldest):\n"), fp_out);
2416 FOR_ALL_BUFFERS(buf)
2417 {
2418 // Only write something if buffer has been loaded and at least one
2419 // mark is set.
2420 if (buf->b_marks_read)
2421 {
2422 if (buf->b_last_cursor.lnum != 0)
2423 is_mark_set = TRUE;
2424 else
2425 {
2426 is_mark_set = FALSE;
2427 for (i = 0; i < NMARKS; i++)
2428 if (buf->b_namedm[i].lnum != 0)
2429 {
2430 is_mark_set = TRUE;
2431 break;
2432 }
2433 }
2434 if (is_mark_set && buf->b_ffname != NULL
2435 && buf->b_ffname[0] != NUL
2436 && !skip_for_viminfo(buf))
2437 {
2438 if (buflist == NULL)
2439 write_buffer_marks(buf, fp_out);
2440 else if (ga_grow(buflist, 1) == OK)
2441 ((buf_T **)buflist->ga_data)[buflist->ga_len++] = buf;
2442 }
2443 }
2444 }
2445 }
2446
2447 /*
2448 * Compare functions for qsort() below, that compares b_last_used.
2449 */
2450 static int
2451 buf_compare(const void *s1, const void *s2)
2452 {
2453 buf_T *buf1 = *(buf_T **)s1;
2454 buf_T *buf2 = *(buf_T **)s2;
2455
2456 if (buf1->b_last_used == buf2->b_last_used)
2457 return 0;
2458 return buf1->b_last_used > buf2->b_last_used ? -1 : 1;
2459 }
2460
2461 /*
2462 * Handle marks in the viminfo file:
2463 * fp_out != NULL: copy marks, in time order with buffers in "buflist".
2464 * fp_out == NULL && (flags & VIF_WANT_MARKS): read marks for curbuf only
2465 * fp_out == NULL && (flags & VIF_GET_OLDFILES | VIF_FORCEIT): fill v:oldfiles
2466 */
2467 void
2468 copy_viminfo_marks(
2469 vir_T *virp,
2470 FILE *fp_out,
2471 garray_T *buflist,
2472 int eof,
2473 int flags)
2474 {
2475 char_u *line = virp->vir_line;
2476 buf_T *buf;
2477 int num_marked_files;
2478 int load_marks;
2479 int copy_marks_out;
2480 char_u *str;
2481 int i;
2482 char_u *p;
2483 char_u *name_buf;
2484 pos_T pos;
2485 #ifdef FEAT_EVAL
2486 list_T *list = NULL;
2487 #endif
2488 int count = 0;
2489 int buflist_used = 0;
2490 buf_T *buflist_buf = NULL;
2491
2492 if ((name_buf = alloc(LSIZE)) == NULL)
2493 return;
2494 *name_buf = NUL;
2495
2496 if (fp_out != NULL && buflist->ga_len > 0)
2497 {
2498 // Sort the list of buffers on b_last_used.
2499 qsort(buflist->ga_data, (size_t)buflist->ga_len,
2500 sizeof(buf_T *), buf_compare);
2501 buflist_buf = ((buf_T **)buflist->ga_data)[0];
2502 }
2503
2504 #ifdef FEAT_EVAL
2505 if (fp_out == NULL && (flags & (VIF_GET_OLDFILES | VIF_FORCEIT)))
2506 {
2507 list = list_alloc();
2508 if (list != NULL)
2509 set_vim_var_list(VV_OLDFILES, list);
2510 }
2511 #endif
2512
2513 num_marked_files = get_viminfo_parameter('\'');
2514 while (!eof && (count < num_marked_files || fp_out == NULL))
2515 {
2516 if (line[0] != '>')
2517 {
2518 if (line[0] != '\n' && line[0] != '\r' && line[0] != '#')
2519 {
2520 if (viminfo_error("E576: ", _("Missing '>'"), line))
2521 break; // too many errors, return now
2522 }
2523 eof = vim_fgets(line, LSIZE, virp->vir_fd);
2524 continue; // Skip this dud line
2525 }
2526
2527 // Handle long line and translate escaped characters.
2528 // Find file name, set str to start.
2529 // Ignore leading and trailing white space.
2530 str = skipwhite(line + 1);
2531 str = viminfo_readstring(virp, (int)(str - virp->vir_line), FALSE);
2532 if (str == NULL)
2533 continue;
2534 p = str + STRLEN(str);
2535 while (p != str && (*p == NUL || vim_isspace(*p)))
2536 p--;
2537 if (*p)
2538 p++;
2539 *p = NUL;
2540
2541 #ifdef FEAT_EVAL
2542 if (list != NULL)
2543 list_append_string(list, str, -1);
2544 #endif
2545
2546 // If fp_out == NULL, load marks for current buffer.
2547 // If fp_out != NULL, copy marks for buffers not in buflist.
2548 load_marks = copy_marks_out = FALSE;
2549 if (fp_out == NULL)
2550 {
2551 if ((flags & VIF_WANT_MARKS) && curbuf->b_ffname != NULL)
2552 {
2553 if (*name_buf == NUL) // only need to do this once
2554 home_replace(NULL, curbuf->b_ffname, name_buf, LSIZE, TRUE);
2555 if (fnamecmp(str, name_buf) == 0)
2556 load_marks = TRUE;
2557 }
2558 }
2559 else // fp_out != NULL
2560 {
2561 // This is slow if there are many buffers!!
2562 FOR_ALL_BUFFERS(buf)
2563 if (buf->b_ffname != NULL)
2564 {
2565 home_replace(NULL, buf->b_ffname, name_buf, LSIZE, TRUE);
2566 if (fnamecmp(str, name_buf) == 0)
2567 break;
2568 }
2569
2570 // Copy marks if the buffer has not been loaded.
2571 if (buf == NULL || !buf->b_marks_read)
2572 {
2573 int did_read_line = FALSE;
2574
2575 if (buflist_buf != NULL)
2576 {
2577 // Read the next line. If it has the "*" mark compare the
2578 // time stamps. Write entries from "buflist" that are
2579 // newer.
2580 if (!(eof = viminfo_readline(virp)) && line[0] == TAB)
2581 {
2582 did_read_line = TRUE;
2583 if (line[1] == '*')
2584 {
2585 long ltime;
2586
2587 sscanf((char *)line + 2, "%ld ", &ltime);
2588 while ((time_T)ltime < buflist_buf->b_last_used)
2589 {
2590 write_buffer_marks(buflist_buf, fp_out);
2591 if (++count >= num_marked_files)
2592 break;
2593 if (++buflist_used == buflist->ga_len)
2594 {
2595 buflist_buf = NULL;
2596 break;
2597 }
2598 buflist_buf =
2599 ((buf_T **)buflist->ga_data)[buflist_used];
2600 }
2601 }
2602 else
2603 {
2604 // No timestamp, must be written by an older Vim.
2605 // Assume all remaining buffers are older then
2606 // ours.
2607 while (count < num_marked_files
2608 && buflist_used < buflist->ga_len)
2609 {
2610 buflist_buf = ((buf_T **)buflist->ga_data)
2611 [buflist_used++];
2612 write_buffer_marks(buflist_buf, fp_out);
2613 ++count;
2614 }
2615 buflist_buf = NULL;
2616 }
2617
2618 if (count >= num_marked_files)
2619 {
2620 vim_free(str);
2621 break;
2622 }
2623 }
2624 }
2625
2626 fputs("\n> ", fp_out);
2627 viminfo_writestring(fp_out, str);
2628 if (did_read_line)
2629 fputs((char *)line, fp_out);
2630
2631 count++;
2632 copy_marks_out = TRUE;
2633 }
2634 }
2635 vim_free(str);
2636
2637 pos.coladd = 0;
2638 while (!(eof = viminfo_readline(virp)) && line[0] == TAB)
2639 {
2640 if (load_marks)
2641 {
2642 if (line[1] != NUL)
2643 {
2644 unsigned u;
2645
2646 sscanf((char *)line + 2, "%ld %u", &pos.lnum, &u);
2647 pos.col = u;
2648 switch (line[1])
2649 {
2650 case '"': curbuf->b_last_cursor = pos; break;
2651 case '^': curbuf->b_last_insert = pos; break;
2652 case '.': curbuf->b_last_change = pos; break;
2653 case '+':
2654 #ifdef FEAT_JUMPLIST
2655 // changelist positions are stored oldest
2656 // first
2657 if (curbuf->b_changelistlen == JUMPLISTSIZE)
2658 // list is full, remove oldest entry
2659 mch_memmove(curbuf->b_changelist,
2660 curbuf->b_changelist + 1,
2661 sizeof(pos_T) * (JUMPLISTSIZE - 1));
2662 else
2663 ++curbuf->b_changelistlen;
2664 curbuf->b_changelist[
2665 curbuf->b_changelistlen - 1] = pos;
2666 #endif
2667 break;
2668
2669 // Using the line number for the last-used
2670 // timestamp.
2671 case '*': curbuf->b_last_used = pos.lnum; break;
2672
2673 default: if ((i = line[1] - 'a') >= 0 && i < NMARKS)
2674 curbuf->b_namedm[i] = pos;
2675 }
2676 }
2677 }
2678 else if (copy_marks_out)
2679 fputs((char *)line, fp_out);
2680 }
2681
2682 if (load_marks)
2683 {
2684 #ifdef FEAT_JUMPLIST
2685 win_T *wp;
2686
2687 FOR_ALL_WINDOWS(wp)
2688 {
2689 if (wp->w_buffer == curbuf)
2690 wp->w_changelistidx = curbuf->b_changelistlen;
2691 }
2692 #endif
2693 break;
2694 }
2695 }
2696
2697 if (fp_out != NULL)
2698 // Write any remaining entries from buflist.
2699 while (count < num_marked_files && buflist_used < buflist->ga_len)
2700 {
2701 buflist_buf = ((buf_T **)buflist->ga_data)[buflist_used++];
2702 write_buffer_marks(buflist_buf, fp_out);
2703 ++count;
2704 }
2705
2706 vim_free(name_buf);
2707 }
2708 #endif // FEAT_VIMINFO 3310 #endif // FEAT_VIMINFO