Mercurial > vim
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 ", <ime); | |
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 ", <ime); | |
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 |